static const unsigned char *display_rr(const unsigned char *aptr, const unsigned char *abuf, int alen) { const unsigned char *p; int type, dnsclass, ttl, dlen, status; long len; char addr[46]; union { unsigned char * as_uchar; char * as_char; } name; /* Parse the RR name. */ status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) return NULL; aptr += len; /* Make sure there is enough data after the RR name for the fixed * part of the RR. */ if (aptr + RRFIXEDSZ > abuf + alen) { ares_free_string(name.as_char); return NULL; } /* Parse the fixed part of the RR, and advance to the RR data * field. */ type = DNS_RR_TYPE(aptr); dnsclass = DNS_RR_CLASS(aptr); ttl = DNS_RR_TTL(aptr); dlen = DNS_RR_LEN(aptr); aptr += RRFIXEDSZ; if (aptr + dlen > abuf + alen) { ares_free_string(name.as_char); return NULL; } /* Display the RR name, class, and type. */ printf("\t%-15s.\t%d", name.as_char, ttl); if (dnsclass != C_IN) printf("\t%s", class_name(dnsclass)); printf("\t%s", type_name(type)); ares_free_string(name.as_char); /* Display the RR data. Don't touch aptr. */ switch (type) { case T_CNAME: case T_MB: case T_MD: case T_MF: case T_MG: case T_MR: case T_NS: case T_PTR: /* For these types, the RR data is just a domain name. */ status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) return NULL; printf("\t%s.", name.as_char); ares_free_string(name.as_char); break; case T_HINFO: /* The RR data is two length-counted character strings. */ p = aptr; len = *p; if (p + len + 1 > aptr + dlen) return NULL; status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len); if (status != ARES_SUCCESS) return NULL; printf("\t%s", name.as_char); ares_free_string(name.as_char); p += len; len = *p; if (p + len + 1 > aptr + dlen) return NULL; status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len); if (status != ARES_SUCCESS) return NULL; printf("\t%s", name.as_char); ares_free_string(name.as_char); break; case T_MINFO: /* The RR data is two domain names. */ p = aptr; status = ares_expand_name(p, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) return NULL; printf("\t%s.", name.as_char); ares_free_string(name.as_char); p += len; status = ares_expand_name(p, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) return NULL; printf("\t%s.", name.as_char); ares_free_string(name.as_char); break; case T_MX: /* The RR data is two bytes giving a preference ordering, and * then a domain name. */ if (dlen < 2) return NULL; printf("\t%d", DNS__16BIT(aptr)); status = ares_expand_name(aptr + 2, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) return NULL; printf("\t%s.", name.as_char); ares_free_string(name.as_char); break; case T_SOA: /* The RR data is two domain names and then five four-byte * numbers giving the serial number and some timeouts. */ p = aptr; status = ares_expand_name(p, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) return NULL; printf("\t%s.\n", name.as_char); ares_free_string(name.as_char); p += len; status = ares_expand_name(p, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) return NULL; printf("\t\t\t\t\t\t%s.\n", name.as_char); ares_free_string(name.as_char); p += len; if (p + 20 > aptr + dlen) return NULL; printf("\t\t\t\t\t\t( %lu %lu %lu %lu %lu )", (unsigned long)DNS__32BIT(p), (unsigned long)DNS__32BIT(p+4), (unsigned long)DNS__32BIT(p+8), (unsigned long)DNS__32BIT(p+12), (unsigned long)DNS__32BIT(p+16)); break; case T_TXT: /* The RR data is one or more length-counted character * strings. */ p = aptr; while (p < aptr + dlen) { len = *p; if (p + len + 1 > aptr + dlen) return NULL; status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len); if (status != ARES_SUCCESS) return NULL; printf("\t%s", name.as_char); ares_free_string(name.as_char); p += len; } break; case T_A: /* The RR data is a four-byte Internet address. */ if (dlen != 4) return NULL; printf("\t%s", ares_inet_ntop(AF_INET,aptr,addr,sizeof(addr))); break; case T_AAAA: /* The RR data is a 16-byte IPv6 address. */ if (dlen != 16) return NULL; printf("\t%s", ares_inet_ntop(AF_INET6,aptr,addr,sizeof(addr))); break; case T_WKS: /* Not implemented yet */ break; case T_SRV: /* The RR data is three two-byte numbers representing the * priority, weight, and port, followed by a domain name. */ printf("\t%d", DNS__16BIT(aptr)); printf(" %d", DNS__16BIT(aptr + 2)); printf(" %d", DNS__16BIT(aptr + 4)); status = ares_expand_name(aptr + 6, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) return NULL; printf("\t%s.", name.as_char); ares_free_string(name.as_char); break; case T_NAPTR: printf("\t%d", DNS__16BIT(aptr)); /* order */ printf(" %d\n", DNS__16BIT(aptr + 2)); /* preference */ p = aptr + 4; status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len); if (status != ARES_SUCCESS) return NULL; printf("\t\t\t\t\t\t%s\n", name.as_char); ares_free_string(name.as_char); p += len; status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len); if (status != ARES_SUCCESS) return NULL; printf("\t\t\t\t\t\t%s\n", name.as_char); ares_free_string(name.as_char); p += len; status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len); if (status != ARES_SUCCESS) return NULL; printf("\t\t\t\t\t\t%s\n", name.as_char); ares_free_string(name.as_char); p += len; status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len); if (status != ARES_SUCCESS) return NULL; printf("\t\t\t\t\t\t%s", name.as_char); ares_free_string(name.as_char); break; default: printf("\t[Unknown RR; cannot parse]"); break; } printf("\n"); return aptr + dlen; }
static int ev_ares_parse_a_reply (const unsigned char *abuf, int alen, struct ev_ares_a_reply **a_out) { unsigned int qdcount, ancount, i; const unsigned char *aptr, *vptr; int status, rr_type, rr_class, rr_len, rr_ttl, cname_ttl = INT_MAX; int naddrs = 0, naliases = 0; long len; char *hostname = NULL, *rr_name = NULL, *rr_data = NULL; struct ev_ares_a_reply *a_head = NULL; struct ev_ares_a_reply *a_last = NULL; struct ev_ares_a_reply *a_curr; /* Set *a_out to NULL for all failure cases. */ *a_out = NULL; /* Give up if abuf doesn't have room for a header. */ if (alen < HFIXEDSZ) return ARES_EBADRESP; /* Fetch the question and answer count from the header. */ qdcount = DNS_HEADER_QDCOUNT (abuf); ancount = DNS_HEADER_ANCOUNT (abuf); if (qdcount != 1) return ARES_EBADRESP; if (ancount == 0) return ARES_ENODATA; /* Expand the name from the question, and skip past the question. */ aptr = abuf + HFIXEDSZ; status = ares_expand_name (aptr, abuf, alen, &hostname, &len); if (status != ARES_SUCCESS) return status; if (aptr + len + QFIXEDSZ > abuf + alen) { free (hostname); return ARES_EBADRESP; } aptr += len + QFIXEDSZ; /* Examine each answer resource record (RR) in turn. */ for (i = 0; i < ancount; i++) { /* Decode the RR up to the data field. */ status = ares_expand_name (aptr, abuf, alen, &rr_name, &len); //cwarn("expanded name: %s",rr_name); if (status != ARES_SUCCESS) { break; } aptr += len; if (aptr + RRFIXEDSZ > abuf + alen) { status = ARES_EBADRESP; break; } rr_type = DNS_RR_TYPE (aptr); rr_class = DNS_RR_CLASS (aptr); rr_ttl = DNS_RR_TTL (aptr); rr_len = DNS_RR_LEN (aptr); aptr += RRFIXEDSZ; if (aptr + rr_len > abuf + alen) { status = ARES_EBADRESP; break; } /* Check if we are really looking at a A record */ if (rr_class == C_IN && rr_type == T_A) { if ( rr_len == sizeof(struct in_addr) && strcasecmp(rr_name, hostname) == 0 ) { if (aptr + sizeof(struct in_addr) > abuf + alen) { status = ARES_EBADRESP; break; } a_curr = calloc(1,sizeof(struct ev_ares_a_reply)); if (!a_curr) { status = ARES_ENOMEM; break; } if (a_last) { a_last->next = a_curr; } else { a_head = a_curr; } a_last = a_curr; a_curr->ttl = rr_ttl; a_curr->host = rr_name; rr_name = NULL; memcpy(&a_curr->ip, aptr, sizeof(struct in_addr)); naddrs++; } } else if (rr_class == C_IN && rr_type == T_CNAME) { naliases++; status = ares_expand_name(aptr, abuf, alen, &rr_data, &len); if (status != ARES_SUCCESS) break; if (cname_ttl > rr_ttl) cname_ttl = rr_ttl; free(hostname); hostname = rr_data; } if (rr_name) free(rr_name); rr_name = NULL; /* Move on to the next record */ aptr += rr_len; } if (hostname) free (hostname); if (rr_name) free (rr_name); if (status == ARES_SUCCESS && naddrs == 0 && naliases == 0) /* the check for naliases to be zero is to make sure CNAME responses don't get caught here */ status = ARES_ENODATA; /* clean up on error */ if (status == ARES_SUCCESS) { if (naliases > 0) { for (a_curr = a_head;a_curr;a_curr = a_curr->next) { if (a_curr->ttl > cname_ttl) a_curr->ttl = cname_ttl; } } } else { if (a_head) ev_ares_free_a_reply (a_head); return status; } /* everything looks fine, return the data */ *a_out = a_head; return ARES_SUCCESS; }
static const unsigned char *display_rr(const unsigned char *aptr, const unsigned char *abuf, int alen, dns_resp_t *response) { const unsigned char *p; char *name; int type, dnsclass, ttl, dlen, status; long len; struct in_addr addr; /* Parse the RR name. */ status = ares_expand_name(aptr, abuf, alen, &name, &len); if (status != ARES_SUCCESS) return NULL; aptr += len; /* Make sure there is enough data after the RR name for the fixed * part of the RR. */ if (aptr + RRFIXEDSZ > abuf + alen) { xfree(name); return NULL; } /* Parse the fixed part of the RR, and advance to the RR data field. */ type = DNS_RR_TYPE(aptr); dnsclass = DNS_RR_CLASS(aptr); ttl = DNS_RR_TTL(aptr); dlen = DNS_RR_LEN(aptr); aptr += RRFIXEDSZ; if (aptr + dlen > abuf + alen) { xfree(name); return NULL; } /* Display the RR name, class, and type. */ sprintf(msg, "\t%-15s.\t%d", name, ttl); addtobuffer(response->msgbuf, msg); if (dnsclass != C_IN) { sprintf(msg, "\t%s", class_name(dnsclass)); addtobuffer(response->msgbuf, msg); } sprintf(msg, "\t%s", type_name(type)); addtobuffer(response->msgbuf, msg); xfree(name); /* Display the RR data. Don't touch aptr. */ switch (type) { case T_CNAME: case T_MB: case T_MD: case T_MF: case T_MG: case T_MR: case T_NS: case T_PTR: /* For these types, the RR data is just a domain name. */ status = ares_expand_name(aptr, abuf, alen, &name, &len); if (status != ARES_SUCCESS) return NULL; sprintf(msg, "\t%s.", name); addtobuffer(response->msgbuf, msg); xfree(name); break; case T_HINFO: /* The RR data is two length-counted character strings. */ p = aptr; len = *p; if (p + len + 1 > aptr + dlen) return NULL; sprintf(msg, "\t%.*s", (int) len, p + 1); addtobuffer(response->msgbuf, msg); p += len + 1; len = *p; if (p + len + 1 > aptr + dlen) return NULL; sprintf(msg, "\t%.*s", (int) len, p + 1); addtobuffer(response->msgbuf, msg); break; case T_MINFO: /* The RR data is two domain names. */ p = aptr; status = ares_expand_name(p, abuf, alen, &name, &len); if (status != ARES_SUCCESS) return NULL; sprintf(msg, "\t%s.", name); addtobuffer(response->msgbuf, msg); xfree(name); p += len; status = ares_expand_name(p, abuf, alen, &name, &len); if (status != ARES_SUCCESS) return NULL; sprintf(msg, "\t%s.", name); addtobuffer(response->msgbuf, msg); xfree(name); break; case T_MX: /* The RR data is two bytes giving a preference ordering, and then a domain name. */ if (dlen < 2) return NULL; sprintf(msg, "\t%d", (aptr[0] << 8) | aptr[1]); addtobuffer(response->msgbuf, msg); status = ares_expand_name(aptr + 2, abuf, alen, &name, &len); if (status != ARES_SUCCESS) return NULL; sprintf(msg, "\t%s.", name); addtobuffer(response->msgbuf, msg); xfree(name); break; case T_SOA: /* * The RR data is two domain names and then five four-byte * numbers giving the serial number and some timeouts. */ p = aptr; status = ares_expand_name(p, abuf, alen, &name, &len); if (status != ARES_SUCCESS) return NULL; sprintf(msg, "\t%s.\n", name); addtobuffer(response->msgbuf, msg); xfree(name); p += len; status = ares_expand_name(p, abuf, alen, &name, &len); if (status != ARES_SUCCESS) return NULL; sprintf(msg, "\t\t\t\t\t\t%s.\n", name); addtobuffer(response->msgbuf, msg); xfree(name); p += len; if (p + 20 > aptr + dlen) return NULL; sprintf(msg, "\t\t\t\t\t\t( %d %d %d %d %d )", (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3], (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7], (p[8] << 24) | (p[9] << 16) | (p[10] << 8) | p[11], (p[12] << 24) | (p[13] << 16) | (p[14] << 8) | p[15], (p[16] << 24) | (p[17] << 16) | (p[18] << 8) | p[19]); addtobuffer(response->msgbuf, msg); break; case T_TXT: /* The RR data is one or more length-counted character strings. */ p = aptr; while (p < aptr + dlen) { len = *p; if (p + len + 1 > aptr + dlen) return NULL; sprintf(msg, "\t%.*s", (int)len, p + 1); addtobuffer(response->msgbuf, msg); p += len + 1; } break; case T_A: /* The RR data is a four-byte Internet address. */ if (dlen != 4) return NULL; memcpy(&addr, aptr, sizeof(struct in_addr)); sprintf(msg, "\t%s", inet_ntoa(addr)); addtobuffer(response->msgbuf, msg); break; case T_WKS: /* Not implemented yet */ break; case T_SRV: /* * The RR data is three two-byte numbers representing the * priority, weight, and port, followed by a domain name. */ sprintf(msg, "\t%d", DNS__16BIT(aptr)); addtobuffer(response->msgbuf, msg); sprintf(msg, " %d", DNS__16BIT(aptr + 2)); addtobuffer(response->msgbuf, msg); sprintf(msg, " %d", DNS__16BIT(aptr + 4)); addtobuffer(response->msgbuf, msg); status = ares_expand_name(aptr + 6, abuf, alen, &name, &len); if (status != ARES_SUCCESS) return NULL; sprintf(msg, "\t%s.", name); addtobuffer(response->msgbuf, msg); xfree(name); break; default: sprintf(msg, "\t[Unknown RR; cannot parse]"); addtobuffer(response->msgbuf, msg); } sprintf(msg, "\n"); addtobuffer(response->msgbuf, msg); return aptr + dlen; }
int LLQueryResponder::parseRR(const char *buf, size_t len, const char *&pos, LLPointer<LLDnsRecord> &r) { std::string rrname; size_t enclen; int ret; // RR name. ret = LLAres::expandName(pos, buf, len, rrname, enclen); if (ret != ARES_SUCCESS) { return ret; } pos += enclen; if (pos + NS_RRFIXEDSZ > buf + len) { return ARES_EBADRESP; } int rrtype = DNS_RR_TYPE(pos); int rrclass = DNS_RR_CLASS(pos); int rrttl = DNS_RR_TTL(pos); int rrlen = DNS_RR_LEN(pos); if (rrclass != ns_c_in) { return ARES_EBADRESP; } pos += NS_RRFIXEDSZ; if (pos + rrlen > buf + len) { return ARES_EBADRESP; } switch (rrtype) { case RES_A: r = new LLARecord(rrname, rrttl); break; case RES_NS: r = new LLNsRecord(rrname, rrttl); break; case RES_CNAME: r = new LLCnameRecord(rrname, rrttl); break; case RES_PTR: r = new LLPtrRecord(rrname, rrttl); break; case RES_AAAA: r = new LLAaaaRecord(rrname, rrttl); break; case RES_SRV: r = new LLSrvRecord(rrname, rrttl); break; default: LL_INFOS() << "LLQueryResponder::parseRR got unknown RR type " << rrtype << LL_ENDL; return ARES_EBADRESP; } ret = r->parse(buf, len, pos, rrlen); if (ret == ARES_SUCCESS) { pos += rrlen; } else { r = NULL; } return ret; }
int ares_parse_aaaa_reply(const unsigned char *abuf, int alen, struct hostent **host, struct ares_addr6ttl *addrttls, int *naddrttls) { unsigned int qdcount, ancount; int status, i, rr_type, rr_class, rr_len, rr_ttl, naddrs; int cname_ttl = INT_MAX; /* the TTL imposed by the CNAME chain */ int naliases; long len; const unsigned char *aptr; char *hostname, *rr_name, *rr_data, **aliases; struct ares_in6_addr *addrs; struct hostent *hostent; const int max_addr_ttls = (addrttls && naddrttls) ? *naddrttls : 0; /* Set *host to NULL for all failure cases. */ if (host) *host = NULL; /* Same with *naddrttls. */ if (naddrttls) *naddrttls = 0; /* Give up if abuf doesn't have room for a header. */ if (alen < HFIXEDSZ) return ARES_EBADRESP; /* Fetch the question and answer count from the header. */ qdcount = DNS_HEADER_QDCOUNT(abuf); ancount = DNS_HEADER_ANCOUNT(abuf); if (qdcount != 1) return ARES_EBADRESP; /* Expand the name from the question, and skip past the question. */ aptr = abuf + HFIXEDSZ; status = ares__expand_name_for_response(aptr, abuf, alen, &hostname, &len); if (status != ARES_SUCCESS) return status; if (aptr + len + QFIXEDSZ > abuf + alen) { free(hostname); return ARES_EBADRESP; } aptr += len + QFIXEDSZ; /* Allocate addresses and aliases; ancount gives an upper bound for both. */ if (host) { addrs = malloc(ancount * sizeof(struct ares_in6_addr)); if (!addrs) { free(hostname); return ARES_ENOMEM; } aliases = malloc((ancount + 1) * sizeof(char *)); if (!aliases) { free(hostname); free(addrs); return ARES_ENOMEM; } } else { addrs = NULL; aliases = NULL; } naddrs = 0; naliases = 0; /* Examine each answer resource record (RR) in turn. */ for (i = 0; i < (int)ancount; i++) { /* Decode the RR up to the data field. */ status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len); if (status != ARES_SUCCESS) break; aptr += len; if (aptr + RRFIXEDSZ > abuf + alen) { status = ARES_EBADRESP; break; } rr_type = DNS_RR_TYPE(aptr); rr_class = DNS_RR_CLASS(aptr); rr_len = DNS_RR_LEN(aptr); rr_ttl = DNS_RR_TTL(aptr); aptr += RRFIXEDSZ; if (rr_class == C_IN && rr_type == T_AAAA && rr_len == sizeof(struct ares_in6_addr) && strcasecmp(rr_name, hostname) == 0) { if (addrs) { if (aptr + sizeof(struct ares_in6_addr) > abuf + alen) { status = ARES_EBADRESP; break; } memcpy(&addrs[naddrs], aptr, sizeof(struct ares_in6_addr)); } if (naddrs < max_addr_ttls) { struct ares_addr6ttl * const at = &addrttls[naddrs]; if (aptr + sizeof(struct ares_in6_addr) > abuf + alen) { status = ARES_EBADRESP; break; } memcpy(&at->ip6addr, aptr, sizeof(struct ares_in6_addr)); at->ttl = rr_ttl; } naddrs++; status = ARES_SUCCESS; } if (rr_class == C_IN && rr_type == T_CNAME) { /* Record the RR name as an alias. */ if (aliases) aliases[naliases] = rr_name; else free(rr_name); naliases++; /* Decode the RR data and replace the hostname with it. */ status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data, &len); if (status != ARES_SUCCESS) break; free(hostname); hostname = rr_data; /* Take the min of the TTLs we see in the CNAME chain. */ if (cname_ttl > rr_ttl) cname_ttl = rr_ttl; } else free(rr_name); aptr += rr_len; if (aptr > abuf + alen) { status = ARES_EBADRESP; break; } } if (status == ARES_SUCCESS && naddrs == 0) status = ARES_ENODATA; if (status == ARES_SUCCESS) { /* We got our answer. */ if (naddrttls) { const int n = naddrs < max_addr_ttls ? naddrs : max_addr_ttls; for (i = 0; i < n; i++) { /* Ensure that each A TTL is no larger than the CNAME TTL. */ if (addrttls[i].ttl > cname_ttl) addrttls[i].ttl = cname_ttl; } *naddrttls = n; } if (aliases) aliases[naliases] = NULL; if (host) { /* Allocate memory to build the host entry. */ hostent = malloc(sizeof(struct hostent)); if (hostent) { hostent->h_addr_list = malloc((naddrs + 1) * sizeof(char *)); if (hostent->h_addr_list) { /* Fill in the hostent and return successfully. */ hostent->h_name = hostname; hostent->h_aliases = aliases; hostent->h_addrtype = AF_INET6; hostent->h_length = sizeof(struct ares_in6_addr); for (i = 0; i < naddrs; i++) hostent->h_addr_list[i] = (char *) &addrs[i]; hostent->h_addr_list[naddrs] = NULL; *host = hostent; return ARES_SUCCESS; } free(hostent); } status = ARES_ENOMEM; } } if (aliases) { for (i = 0; i < naliases; i++) free(aliases[i]); free(aliases); } free(addrs); free(hostname); return status; }
/* parse reply record */ int evdns_parse_reply(unsigned char *buf, int nbuf, HOSTENT *hostent) { unsigned char *p = NULL, *end = NULL, *s = NULL, *ps = NULL; int i = 0, qdcount = 0, ancount = 0, nscount = 0, arcount = 0, qr = 0, opcode = 0, aa = 0, tc = 0, rd = 0, ra = 0, rcode = 0, type = 0, dnsclass = 0, ttl = 0, rrlen = 0; if(buf && nbuf > HFIXEDSZ) { hostent->naddrs = 0; hostent->nalias = 0; p = buf; end = buf + nbuf; hostent->qid = DNS_HEADER_QID(p); qr = DNS_HEADER_QR(p); opcode = DNS_HEADER_OPCODE(p); aa = DNS_HEADER_AA(p); tc = DNS_HEADER_TC(p); rd = DNS_HEADER_RD(p); ra = DNS_HEADER_RA(p); rcode = DNS_HEADER_RCODE(p); qdcount = DNS_HEADER_QDCOUNT(p); ancount = DNS_HEADER_ANCOUNT(p); nscount = DNS_HEADER_NSCOUNT(p); arcount = DNS_HEADER_ARCOUNT(p); p += HFIXEDSZ; /* Display the answer header. */ /* printf("id: %d\n", id); printf("flags: %s%s%s%s%s\n", qr ? "qr " : "", aa ? "aa " : "", tc ? "tc " : "", rd ? "rd " : "", ra ? "ra " : ""); printf("opcode: %s\n", opcodes[opcode]); printf("rcode: %s\n", rcodes[rcode]); fprintf(stdout, "qdcount:%d\nancount:%d\nnscount:%d\narcount:%d\n", qdcount, ancount, nscount, arcount); */ /* parse question */ for(i = 0; i < qdcount; i++) { ps = (unsigned char *)hostent->name; p = evdns_expand_name(p, buf, end, ps); /* Parse the question type and class. */ type = DNS_QUESTION_TYPE(p); dnsclass = DNS_QUESTION_CLASS(p); p += QFIXEDSZ; /* fprintf(stdout, "qname:%-15s", name); fprintf(stdout, "\tqtype:%d", type); fprintf(stdout, "\tqclass:%d\r\n", dnsclass); */ } /* parse A name */ for(i = 0; i < ancount; i++) { ps = (unsigned char *)hostent->alias[hostent->nalias++]; p = evdns_expand_name(p, buf, end, ps); type = DNS_RR_TYPE(p); dnsclass = DNS_RR_CLASS(p); ttl = DNS_RR_TTL(p); rrlen = DNS_RR_LEN(p); p += RRFIXEDSZ; /* fprintf(stdout, "name:%s type:%d dnsclass:%d ttl:%d rrlen:%d ", name, type, dnsclass, ttl, rrlen); */ /* addr name */ if(type == TYPE_ANAME) { hostent->addrs[hostent->naddrs++] = *((int *)p); } /* Canonical name */ else if(type == TYPE_CNAME) { ps = (unsigned char *)hostent->alias[hostent->nalias++]; s = evdns_expand_name(p, buf, end, ps); //fprintf(stdout, "cname:%s ", cname); } /* pointer */ else if(type == TYPE_PTR) { ps = (unsigned char *)hostent->alias[hostent->nalias++]; s = evdns_expand_name(p, buf, end, ps); //fprintf(stdout, "pointer:%s ", cname); } //fprintf(stdout, "\r\n"); p += rrlen; } return 0; } return -1; }
int ares_parse_soa_reply(const unsigned char *abuf, int alen, struct ares_soa_reply **soa_out) { const unsigned char *aptr; long len; char *qname = NULL, *rr_name = NULL; struct ares_soa_reply *soa = NULL; int qdcount, ancount; int status; if (alen < HFIXEDSZ) return ARES_EBADRESP; /* parse message header */ qdcount = DNS_HEADER_QDCOUNT(abuf); ancount = DNS_HEADER_ANCOUNT(abuf); if (qdcount != 1 || ancount != 1) return ARES_EBADRESP; aptr = abuf + HFIXEDSZ; /* query name */ status = ares__expand_name_for_response(aptr, abuf, alen, &qname, &len); if (status != ARES_SUCCESS) goto failed_stat; aptr += len; /* skip qtype & qclass */ if (aptr + QFIXEDSZ > abuf + alen) goto failed; aptr += QFIXEDSZ; /* rr_name */ status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len); if (status != ARES_SUCCESS) goto failed_stat; aptr += len; /* allocate result struct */ soa = ares_malloc_data(ARES_DATATYPE_SOA_REPLY); if (!soa) { status = ARES_ENOMEM; goto failed_stat; } /* skip rr_type, rr_class, rr_ttl, rr_rdlen */ if (aptr + RRFIXEDSZ > abuf + alen) goto failed; soa->ttl = DNS_RR_TTL(aptr); aptr += RRFIXEDSZ; /* nsname */ status = ares__expand_name_for_response(aptr, abuf, alen, &soa->nsname, &len); if (status != ARES_SUCCESS) goto failed_stat; aptr += len; /* hostmaster */ status = ares__expand_name_for_response(aptr, abuf, alen, &soa->hostmaster, &len); if (status != ARES_SUCCESS) goto failed_stat; aptr += len; /* integer fields */ if (aptr + 5 * 4 > abuf + alen) goto failed; soa->serial = DNS__32BIT(aptr + 0 * 4); soa->refresh = DNS__32BIT(aptr + 1 * 4); soa->retry = DNS__32BIT(aptr + 2 * 4); soa->expire = DNS__32BIT(aptr + 3 * 4); soa->minttl = DNS__32BIT(aptr + 4 * 4); ares_free(qname); ares_free(rr_name); *soa_out = soa; return ARES_SUCCESS; failed: status = ARES_EBADRESP; failed_stat: ares_free_data(soa); if (qname) ares_free(qname); if (rr_name) ares_free(rr_name); return status; }
inline static const unsigned char *CheckPatternAfterParseAnswer(struct DNSTask *dnstask, const unsigned char *aptr, const unsigned char *abuf, int alen) { const unsigned char *p; int type, dnsclass, ttl, dlen, status; long len; char addr[46]; /* if (task->LObjId == 1148) raise(SIGTRAP); */ union { unsigned char * as_uchar; char * as_char; } name; status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) return NULL; aptr += len; if (aptr + RRFIXEDSZ > abuf + alen) { ares_free_string(name.as_char); return NULL; } type = DNS_RR_TYPE(aptr); dnsclass = DNS_RR_CLASS(aptr); ttl = DNS_RR_TTL(aptr); dlen = DNS_RR_LEN(aptr); aptr += RRFIXEDSZ; if (aptr + dlen > abuf + alen) { ares_free_string(name.as_char); return NULL; } ares_free_string(name.as_char); switch (type) { case T_CNAME: case T_MB: case T_MD: case T_MF: case T_MG: case T_MR: case T_NS: case T_PTR: status = ares_expand_name(aptr, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) { debug("error T_%s compare, %s andd ttl %d error - %d", type_name(type), dnstask->taskPattern, dnstask->taskTTL, status); return NULL; } debug("T_%s compare, %s:%08x on %s and ttl %d on %d", type_name(type), dnstask->taskPattern, dnstask->taskPattern, name.as_char, ttl, dnstask->taskTTL); if ((dnstask->taskPattern[0] == 0 or !memcmp(name.as_char, dnstask->taskPattern, dnstask->taskPatternLen)) and(dnstask->taskTTL == 0 or ttl == dnstask->taskTTL)) { dnstask->task->code = STATE_DONE; } ares_free_string(name.as_char); break; case T_HINFO: /* The RR data is two length-counted character strings. */ p = aptr; len = *p; if (p + len + 1 > aptr + dlen) return NULL; debug("\t%.*s", (int) len, p + 1); p += len + 1; len = *p; if (p + len + 1 > aptr + dlen) return NULL; debug("\t%.*s", (int) len, p + 1); break; case T_MINFO: /* The RR data is two domain names. */ p = aptr; status = ares_expand_name(p, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) return NULL; debug("\t%s.", name.as_char); ares_free_string(name.as_char); p += len; status = ares_expand_name(p, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) return NULL; debug("\t%s.", name.as_char); ares_free_string(name.as_char); break; case T_MX: if (dlen < 2) { return NULL; } status = ares_expand_name(aptr + 2, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) { return NULL; } debug("T_MX compare %s on %s and ttl %d on %d\n", dnstask->taskPattern, name.as_char, ttl, dnstask->taskTTL); if ((dnstask->taskPattern[0] = 0 or !memcmp(name.as_char, dnstask->taskPattern, dnstask->taskPatternLen)) and(dnstask->taskTTL == 0 or ttl == dnstask->taskTTL)) { dnstask->task->code = STATE_DONE; } ares_free_string(name.as_char); break; case T_SOA: /* The RR data is two domain names and then five four-byte * numbers giving the serial number and some timeouts. */ p = aptr; status = ares_expand_name(p, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) return NULL; debug("\t%s.", name.as_char); ares_free_string(name.as_char); p += len; status = ares_expand_name(p, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) return NULL; debug("\t\t\t\t\t\t%s.", name.as_char); ares_free_string(name.as_char); p += len; if (p + 20 > aptr + dlen) return NULL; debug("\t\t\t\t\t\t( %lu %lu %lu %lu %lu )", (unsigned long) DNS__32BIT(p), (unsigned long) DNS__32BIT(p + 4), (unsigned long) DNS__32BIT(p + 8), (unsigned long) DNS__32BIT(p + 12), (unsigned long) DNS__32BIT(p + 16)); break; case T_TXT: /* The RR data is one or more length-counted character * strings. */ p = aptr; while (p < aptr + dlen) { len = *p; if (p + len + 1 > aptr + dlen) return NULL; //printf("\t%.*s", (int) len, p + 1); debug("T_TXT compare %s on %s and ttl %d on %d", dnstask->taskPattern, p + 1, ttl, dnstask->taskTTL); if (!memcmp(p + 1, dnstask->taskPattern, dnstask->taskPatternLen) and ttl == dnstask->taskTTL) { dnstask->task->code = STATE_DONE; } p += len + 1; } break; case T_A: /* The RR data is a four-byte Internet address. */ inet_ntop(AF_INET, aptr, addr, sizeof (addr)); debug("T_A compare %s on %s (size %d) and ttl %d on %d", dnstask->taskPattern, addr, dnstask->taskPatternLen, ttl, dnstask->taskTTL); /* if (dnstask->task->LObjId == 1056) raise(SIGSEGV); */ if (dlen == 4 and(dnstask->taskPattern[0] == 0 or !memcmp(addr, dnstask->taskPattern, dnstask->taskPatternLen)) and(dnstask->taskTTL == 0 or ttl == dnstask->taskTTL)) { dnstask->task->code = STATE_DONE; } break; case T_AAAA: /* The RR data is a 16-byte IPv6 address. */ if (dlen != 16) return NULL; debug("\t%s", inet_ntop(AF_INET6, aptr, addr, sizeof (addr))); break; case T_WKS: /* Not implemented yet */ break; case T_SRV: /* The RR data is three two-byte numbers representing the * priority, weight, and port, followed by a domain name. */ printf("\t%d", DNS__16BIT(aptr)); printf(" %d", DNS__16BIT(aptr + 2)); printf(" %d", DNS__16BIT(aptr + 4)); status = ares_expand_name(aptr + 6, abuf, alen, &name.as_char, &len); if (status != ARES_SUCCESS) return NULL; printf("\t%s.", name.as_char); ares_free_string(name.as_char); break; case T_NAPTR: printf("\t%d", DNS__16BIT(aptr)); /* order */ printf(" %d\n", DNS__16BIT(aptr + 2)); /* preference */ p = aptr + 4; status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len); if (status != ARES_SUCCESS) return NULL; printf("\t\t\t\t\t\t%s\n", name.as_char); ares_free_string(name.as_char); p += len; status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len); if (status != ARES_SUCCESS) return NULL; printf("\t\t\t\t\t\t%s\n", name.as_char); ares_free_string(name.as_char); p += len; status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len); if (status != ARES_SUCCESS) return NULL; printf("\t\t\t\t\t\t%s\n", name.as_char); ares_free_string(name.as_char); p += len; status = ares_expand_string(p, abuf, alen, &name.as_uchar, &len); if (status != ARES_SUCCESS) return NULL; printf("\t\t\t\t\t\t%s", name.as_char); ares_free_string(name.as_char); break; default: printf("\t[Unknown RR; cannot parse]"); break; } if (dnstask->task->code != STATE_DONE) { return aptr + dlen; } else { return NULL; } }
static int ev_ares_parse_ptr_reply (const unsigned char *abuf, int alen, struct ev_ares_ptr_reply **ptr_out) { unsigned int qdcount, ancount, i; const unsigned char *aptr, *vptr; int status, rr_type, rr_class, rr_len, rr_ttl; long len; char *hostname = NULL, *rr_name = NULL; struct ev_ares_ptr_reply *ptr_head = NULL; struct ev_ares_ptr_reply *ptr_last = NULL; struct ev_ares_ptr_reply *ptr_curr; /* Set *ptr_out to NULL for all failure cases. */ *ptr_out = NULL; /* Give up if abuf doesn't have room for a header. */ if (alen < HFIXEDSZ) return ARES_EBADRESP; /* Fetch the question and answer count from the header. */ qdcount = DNS_HEADER_QDCOUNT (abuf); ancount = DNS_HEADER_ANCOUNT (abuf); if (qdcount != 1) return ARES_EBADRESP; if (ancount == 0) return ARES_ENODATA; /* Expand the name from the question, and skip past the question. */ aptr = abuf + HFIXEDSZ; status = ares_expand_name (aptr, abuf, alen, &hostname, &len); if (status != ARES_SUCCESS) return status; if (aptr + len + QFIXEDSZ > abuf + alen) { free (hostname); return ARES_EBADRESP; } aptr += len + QFIXEDSZ; /* Examine each answer resource record (RR) in turn. */ for (i = 0; i < ancount; i++) { /* Decode the RR up to the data field. */ status = ares_expand_name (aptr, abuf, alen, &rr_name, &len); if (status != ARES_SUCCESS) { break; } aptr += len; if (aptr + RRFIXEDSZ > abuf + alen) { status = ARES_EBADRESP; break; } rr_type = DNS_RR_TYPE (aptr); rr_class = DNS_RR_CLASS (aptr); rr_ttl = DNS_RR_TTL (aptr); rr_len = DNS_RR_LEN (aptr); aptr += RRFIXEDSZ; if (aptr + rr_len > abuf + alen) { status = ARES_EBADRESP; break; } /* Check if we are really looking at a ns record */ if (rr_class == C_IN && rr_type == T_PTR) { /* parse the NS record itself */ if (rr_len < 2) { status = ARES_EBADRESP; break; } /* Allocate storage for this MX answer appending it to the list */ ptr_curr = calloc(1,sizeof(struct ev_ares_ptr_reply)); if (!ptr_curr) { status = ARES_ENOMEM; break; } if (ptr_last) { ptr_last->next = ptr_curr; } else { ptr_head = ptr_curr; } ptr_last = ptr_curr; ptr_curr->ttl = rr_ttl; vptr = aptr; status = ares_expand_name (vptr, abuf, alen, &ptr_curr->host, &len); if (status != ARES_SUCCESS) break; } /* Don't lose memory in the next iteration */ free (rr_name); rr_name = NULL; /* Move on to the next record */ aptr += rr_len; } if (hostname) free (hostname); if (rr_name) free (rr_name); /* clean up on error */ if (status != ARES_SUCCESS) { if (ptr_head) ev_ares_free_ptr_reply(ptr_head); return status; } /* everything looks fine, return the data */ *ptr_out = ptr_head; return ARES_SUCCESS; }