DNS effective query under LinuxUNIX

xiaoxiao2021-03-06  14

#include #include #include / * bsdi stdarg.h uses abort () * / # include #include #include < CType.h>

/ * UTility library. * /

#include #include #include #include #include #include

/ * DNS Library. * /

#include "dns.h"

/ * Local stuff. * /

/ * * Structure to keeping a name server reply. * / # Define dns_reply_size 4096 / * in case we're using tcp * /

typedef struct DNS_REPLY {unsigned char buf [DNS_REPLY_SIZE]; / * raw reply data * / int query_count; / * number of queries * / int answer_count; / * number of answers * / unsigned char * query_start; / * start of query data * / Unsigned char * answer_start; / * start of answer data * / unsigned char * end; / * first byte paste reply * /} DNS_REPLY

#define inet_addr_len 4 / * xxx * / # define inet6_addr_len 16 / * xxx * /

/ * DNS_QUERY - Query Name Server and Pre-Parse the reply * /

STATIC INT DNS_QUERY (const char * name, int type, int flags, dns_reply * reply, vstring * why) {header * reply_header; int Len; unsigned long saved_options = _res.options

/ * Initialize the name service. * / If (_res.Options & res_init) == 0 && res_init () <0) {if (why) vString_STRCPY (Why, "Name Service Initialization Failure); Return (DNS_FAIL) }

/ * * SET SEARCH OPTIONS: DEBUGGING, PARENT DOMAIN Search, Append Local * Domain. Do Not ALOW The User to Control Other Features. * / # Define user_flags (res_debug | res_dnsrch | res_defnames)

IF ((Flags & User_Flags)! = flags) MSG_PANIC ("DNS_QUERY: BAD FLAGS:% D", FLAGS); _RES.Options & = (user_flags); _res.options | = flags; / * * Perform the lookup. Claim that the information cannot be found if and * only if the name server told us so. * / Len = res_search ((char *) Name, c_in, type, reply-> buf, sizeof (reply-> buf); _res .Options = saved_options; if (len <0) {if (why) vString_sprintf (why, "name service error for name =% s type =% s:% s", name, dns_strtype (type), DNS_STRERROR (H_ERRNO)) ; If (msg_verbose) MSG_INFO ("DNS_QUERY:% S (% s):% S", Name, DNS_STRTYPE (TYPE), DNS_STRERROR (H_ERRNO)); Switch (h_errno) {case no_recovery: return (DNS_FAIL); case host_not_found: Case no_data: return (DNS_NOTFOUND); Default: return (DNS_RETRY);}}} f (msg_verbose) msg_info ("DNS_QUERY:% S (% s): OK", Name, DNS_STRTYPE (TYPE));

/ * * Paraanoia. * / If (reply-> buf)) {msg_warn ("Reply Length% D> Buffer length% D for Name =% s type =% s", len, sizeof (reply-> BUF), Name, DNS_STRTYPE (TYPE)); LEN = SizeOf (reply-> buf);

/ * * Initialize the reply structure. Some structure members are filled on * the fly while the reply is being parsed. * / If ((reply-> end = reply-> buf len)> reply-> buf sizeof (reply -> BUF)) reply-> end = reply-> buf sizeof (reply-> buf); reply_header = (header *) reply-> buf; reply-> query_start = reply-> buf sizeof (header); reply -> answer_start = 0; reply-> query_count = ntohs (reply_header-> qdcount); reply-> answer_count = ntohs (reply_header-> ancount); return (DNS_OK);} / * dns_skip_query - skip query data in name server reply * /

Static int DNS_SKIP_QUERY (DNS_Reply * reply) {INT Query_count = reply-> query_count; unsigned char * pOS = reply-> query_start; char TEMP [DNS_NAME_LEN]; int Len;

/ * * For Each Query, Skip over the domain name and over the fixed query * data. * / While (query_count--> 0) {if (pOS> = reply-> end) Return DNS_RETRY; LEN = DN_EXPAND (reply- > buf, reply-> end, pOS, temp, dns_name_len; if (len <0) Return (DNS_RETRY); POS = LEN QFixedsz;} reply-> Answer_start = POS; RETURN (DNS_OK);

/ * DNS_GET_FIXED - EXTRACT FIXED DATA from Resource Record * /

Static int DNS_GET_FIXED (unsigned char * pos, dns_fixed * fixed) {getshort (fixed-> type, pos); getshort (fixed-> class, pos); getlong (fixed-> ttl, pos); getshort (fixed-> length , POS);

IF (Fixed-> Class! = C_IN) {msg_warn ("DNS_GET_FIXED: BAD Class:% U", Fixed-> Class); Return (DNS_RETRY);} Return (DNS_OK);

/ * VALID_RR_NAME - VALIDATE HOSTNAME IN RECORD * /

static int valid_rr_name (const char * name, const char * location, unsigned type, DNS_REPLY * reply) {char temp [DNS_NAME_LEN]; char * query_name; int len; char * gripe; int result; / * * People are not supposed to specify numeric names where domain names are * required, but it "works" with some mailers anyway, so people complain * when software does not bend over backwards. * / # define PASS_NAME 1 # define REJECT_NAME 0

if (valid_hostaddr (name, DONT_GRIPE)) {result = PASS_NAME; gripe = "numeric domain name";} else if (! valid_hostname (name, DO_GRIPE)) {result = REJECT_NAME; gripe = "malformed domain name";} else { Result = pass_name; gripe = 0;}

/ * * If we have a Gripe, Show Some Context, Including the name @ query and the type of reply what we're looking at. * / If (gripe) {len = dn_expand (reply-> buf, reply -> end, reply-> query_start, temp, dns_name_len; query_name = (LEN <0? "* unparsable *": TEMP); msg_warn ("% s IN% s OF% s Record for% s:% .100s" , Gripe, Location, DNS_STRTYPE (TYPE), QUERY_NAME, NAME);} return (result);

/ * DNS_GET_RR - Extract Resource Record from Name Server Reply * /

static DNS_RR * dns_get_rr (DNS_REPLY * reply, unsigned char * pos, char * rr_name, DNS_FIXED * fixed) {char temp [DNS_NAME_LEN]; int data_len; unsigned pref = 0; unsigned char * src; unsigned char * dst; int ch;

#define min2 (a, b) ((unsigned) (a) <(unsigned) (b)? (a): (b))

IF (POS Fixed-> Length> reply-> End) Return (0);

Switch (fixed-> type) {default: msg_panic ("DNS_GET_RR: DON't Know How To Extract Resource Type% S", DNS_STRTYPE (Fixed-> Type); case t_cname: Case T_MB: Case T_mg: Case T_MR: CASE T_ns: case t_ptr: IF (DN_EXPAND (reply-> buf, reply-> end, pos, temp, sizeof (temp)) <0) return (0); if (! Valid_rr_name (Temp, "Resource Data", Fixed- > type, reply) RETURN (0); DATA_LEN = Strlen (Temp) 1; Break; Case T_Mx: GetShort (Pref, POS); if (DN_Expand (reply-> buf, reply-> end, POS, TEMP, SizeOf (TEMP)) <0) Return (0); if (! Valid_rr_name (Temp, "Resource Data") Return (0); DATA_LEN = Strlen (TEMP) 1; Break; Case T_A: IF (Fixed-> Length! = INET_ADDR_LEN) {msg_warn ("Extract_answer: Bad Address Length:% D", Fixed-> Length); return (0);} if (fixed-> length> sizeof (temp)) MSG_PANIC ("DNS_GET_RR: Length", Fixed-> Length); Memcpy (Temp, POS, Fixed-> length); data_len = fixed-> length; break; #ifdef t_aaaaAa Case T_AAAA: IF (Fixed-> Length! = INET6_ADDR_LEN) {msg_warn ("Extract_answer: Bad Address Length:% D", Fixed-> Length); Return (0);} if (fixed-> length> sizeof (temp)) MSG_PANIC ( "DNS_GET_RR: Length", fixed-> length); Memcpy (Temp, Pos, fixed-> length); data_len = fixed-> length; break; #ENDIF case t_txt: Data_len = min2 (POS [0] 1, Min2 (Fixed-> Length 1, SIZEOF (TEMP))); for (SRC = POS 1, DST = (unsigned char *) (TEMP); DST <(unsigned char *) (TEMP) DATA_LEN - 1; / * * /) {CH = * SRC ;

* DST = (isprint (ch)? ch: ');} * DST = 0; Break;} Return (DNS_RR_CREATE (RR_NAME, FIXED, PREF, TEMP, DATA_LEN));} / * DNS_GET_ALIAS - EXTRACT CNAME from Name Server Reply * /

static int dns_get_alias (DNS_REPLY * reply, unsigned char * pos, DNS_FIXED * fixed, char * cname, int c_len) {if (! fixed-> type = T_CNAME) msg_panic ( "dns_get_alias: bad type% s", dns_strtype (fixed- > type)); if (DN_Expand (reply-> buf, reply-> end, pOS, cname, c_len) <0) Return (DNS_RETRY); if (! Valid_rr_name (cname, "resource data", fixed-> type, Reply)) Return (DNS_RETRY); RETURN (DNS_OK);

/ * DNS_GET_ANSWER - Extract Answers from name server reply * /

static int dns_get_answer (DNS_REPLY * reply, int type, DNS_RR ** rrlist, VSTRING * fqdn, char * cname, int c_len) {char rr_name [DNS_NAME_LEN]; unsigned char * pos; int answer_count = reply-> answer_count; int len; DNS_FIXED FIXED; DNS_RR * RR; int resource_found = 0; int CNAME_FOUND = 0; int not_found_status = DNS_NOTFOUND;

/ * * Initialize. Skip over the name server query if we have get '=== i (DNS_SKIP_QUERY (Reply) <0) Return (DNS_RETRY); POS = reply-> Answer_Start ; If (rllist) * rllist = 0;

/ * * Either this, or use a GOTO for emergency exits. The purpose is to * prevent incomplete answers from being passed back to the caller. * / # Define CORRUPT {/ if (rrlist && * rrlist) {/ dns_rr_free (* rrlist ); / * Rllist = 0; /} / return (DNS_RETRY); /}

/ * * Itereate over all answers. * / While (answer (answer_count -> 0) {

/ * OPTIONALLY EXTRACT the full-qualified domain name. * / If (pos> = reply-> end) Corrupt; LEN = DN_EXPAND (reply-> buf, reply-> end, pOS, r_name, dns_name_len); if (LEN) <0) Corrupt; POS = LEN; / * * Extract The Fixed Reply Data: Type, Class, TTL, Length. * / If (POS RRFIXEDSZ> Reply-> End) Corrupt; IF (DNS_GET_FIXED (POS, & Fixed) ! = DNS_OK) CORRUPT; if) CORRUPT; if (fqdn) vstring_strcpy (fqdn, rr_name); if (msg_verbose) msg_info ( "dns_get_answer (valid_rr_name (rr_name," resource name ", fixed.type, reply!): type% s For% s ", DNS_STRTYPE (Fixed.Type), RR_NAME); POS = rrfixedsz;

/ * OPTIONALLY EXTRACT The Requested Resource or CName Data. * / If (POS Fixed.Length> Reply-> End) Corrupt; IF (Type == Fixed.Type || Type == T_Any) {/ * Requested Type * / if (rrlist) {if ((rr = dns_get_rr (reply, pos, rr_name, & fixed)) = 0!) {resource_found ; * rrlist = dns_rr_append (* rrlist, rr);} else not_found_status = DNS_RETRY;} else resource_found ; } else if (fixed.type == t_cname) {/ * cname resource * / cname_found ; if (CNAME && C_LEN> 0) IF (DNS_GET_ALIAS (Reply, POS, & Fixed, CNAME, C_LEN)! = DNS_OK Corrupt;} POS = fixed.length;}

/ * * See what answer we came up with. Report success when the requested * information was found. Otherwise, when a CNAME was found, report that * more recursion is needed. Otherwise report failure. * / If (resource_found) return (DNS_OK ); If (cname_found) return (DNS_RECURSE); return (not_found_status);}

/ * Dns_lookup - DNS lookup user interface * / int dns_lookup (const char * name, unsigned type, unsigned flags, DNS_RR ** rrlist, VSTRING * fqdn, VSTRING * why) {char cname [DNS_NAME_LEN]; int c_len = sizeof (cname DNS_Reply reply; int count; int stat;

. (! Valid_hostname (name, DONT_GRIPE)) / * * The Linux resolver misbehaves when given an invalid domain name * / if {if (why) vstring_sprintf (why, "Name service error for% s: invalid host or domain name", Name); Return (DNS_NOTFOUND);

/ * * DJBDNS produces a bogus A record when given a numerical hostname * / if (valid_hostaddr (name, DONT_GRIPE)) {if (why) vstring_sprintf (why,. "Name service error for% s: invalid host or domain name", Name); Return (DNS_NOTFOUND);

/ * * Perform the look. FOLLOW CNAME CHAINS, But Only Up to a * pre-determined maximum. * / For (count = 0; count <10; count ) {

/ * * Perform The DNS Lookup, and pre-parse the name server reply. * / If ((Status = DNS_QUERY (Name, Type, Flags, & Reply, why)! = DNS_OK) Return (status);

/ * * Extract resource records of the requested type Pick up CNAME * information just in case the requested data is not found * / status = dns_get_answer (& reply, type, rrlist, fqdn, cname, c_len);.. Switch (status) { default: if (why) vstring_sprintf (why, "name service error for name =% s type =% s:" "Malformed name server reply", name, dns_strtype (type)); case DNS_NOTFOUND: case DNS_OK: return (status) Case DNS_Recurse: IF (MSG_Verbose) MSG_INFO ("DNS_LOOKUP:% S AliaSed to% S", Name, CNAME); Name = CNAME;}} f (why) vString_SPrintf (Why, "Name Server Loop for% S", Name ); Msg_warn ("DNS_LOOKUP: Name Server Loop for% S", Name); Return (DNS_NOTFOUND);} / * DNS_LOOKUP_TYPES - DNS LOOKUP Interface with Multiple Types * /

INT DNS_LOOKUP_TYPES (Const Char * Name, Unsigned Flags, DNS_RR ** RRLIST, VSTRING * FQDN, vString * why, ...) {va_list ap; unsigned type; int status = DNS_NOTFOUND; int solid_err = 0;

VA_START (AP, wh); while ((type = va_arg (ap, unsigned))! = 0) {if (msg_verbose) msg_info ("Lookup% S Type% D Flags% D", Name, Type, Flags; Status = DNS_LOOKUP (Name, Type, Flags, RRLIST, FQDN, why); if (status == DNS_OK) Break; if (status == DNS_RETRY) SOFT_ERR = 1;} VA_END (AP); Return ((status == DNS_OK | | SOFT_ERR == 0)? Status: DNS_RETRY);

转载请注明原文地址:https://www.9cbs.com/read-49080.html

New Post(0)