void DNSTaskResolvCallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen) { struct DNSTask *dnstask = (struct DNSTask *) arg; char *query; int id, qr, opcode, aa, tc, rd, ra, rcode; long len; unsigned int qdcount, ancount, nscount, arcount, i; const unsigned char *aptr; debug("LobjId:%d, Hostname %s", dnstask->task->LObjId, dnstask->task->Record.HostName); if (status != ARES_SUCCESS and status != ARES_ENODATA) { return; } /* Parse the answer header. */ id = DNS_HEADER_QID(abuf); qr = DNS_HEADER_QR(abuf); opcode = DNS_HEADER_OPCODE(abuf); aa = DNS_HEADER_AA(abuf); tc = DNS_HEADER_TC(abuf); rd = DNS_HEADER_RD(abuf); ra = DNS_HEADER_RA(abuf); rcode = DNS_HEADER_RCODE(abuf); qdcount = DNS_HEADER_QDCOUNT(abuf); ancount = DNS_HEADER_ANCOUNT(abuf); nscount = DNS_HEADER_NSCOUNT(abuf); arcount = DNS_HEADER_ARCOUNT(abuf); aptr = abuf + HFIXEDSZ; ares_expand_name(aptr, abuf, alen, &query, &len); for (i = 0; i < qdcount; i++) { aptr = skip_question(aptr, abuf, alen); if (aptr == NULL) return; } dnstask->task->code = STATE_ERROR; switch (dnstask->role) { case DNS_TASK: for (i = 0; i < ancount; i++) { debug("try %d %d ", dnstask->task->LObjId, ancount); aptr = CheckPatternAfterParseAnswer(dnstask, aptr, abuf, alen); if (aptr == NULL) break; } dnstask->task->callback(dnstask->task); break; } }
int ares_parse_mx_reply (const unsigned char *abuf, int alen, struct ares_mx_reply **mx_out) { unsigned int qdcount, ancount, i; const unsigned char *aptr, *vptr; int status, rr_type, rr_class, rr_len; long len; char *hostname = NULL, *rr_name = NULL; struct ares_mx_reply *mx_head = NULL; struct ares_mx_reply *mx_last = NULL; struct ares_mx_reply *mx_curr; /* Set *mx_out to NULL for all failure cases. */ *mx_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_len = DNS_RR_LEN (aptr); aptr += RRFIXEDSZ; /* Check if we are really looking at a MX record */ if (rr_class == C_IN && rr_type == T_MX) { /* parse the MX record itself */ if (rr_len < 2) { status = ARES_EBADRESP; break; } /* Allocate storage for this MX answer appending it to the list */ mx_curr = ares_malloc_data(ARES_DATATYPE_MX_REPLY); if (!mx_curr) { status = ARES_ENOMEM; break; } if (mx_last) { mx_last->next = mx_curr; } else { mx_head = mx_curr; } mx_last = mx_curr; vptr = aptr; mx_curr->priority = DNS__16BIT(vptr); vptr += sizeof(unsigned short); status = ares_expand_name (vptr, abuf, alen, &mx_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 (mx_head) ares_free_data (mx_head); return status; } /* everything looks fine, return the data */ *mx_out = mx_head; return ARES_SUCCESS; }
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; }
int ares_parse_ns_reply( const unsigned char* abuf, int alen, struct hostent** host ) { unsigned int qdcount, ancount; int status, i, rr_type, rr_class, rr_len; int nameservers_num; long len; const unsigned char *aptr; char* hostname, *rr_name, *rr_data, **nameservers; struct hostent *hostent; /* Set *host to NULL for all failure cases. */ *host = 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; /* 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; /* Allocate nameservers array; ancount gives an upper bound */ nameservers = malloc( ( ancount + 1 ) * sizeof( char * ) ); if ( !nameservers ) { free( hostname ); return ARES_ENOMEM; } nameservers_num = 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( 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 ); aptr += RRFIXEDSZ; if ( rr_class == C_IN && rr_type == T_NS ) { /* Decode the RR data and add it to the nameservers list */ status = ares_expand_name( aptr, abuf, alen, &rr_data, &len ); if ( status != ARES_SUCCESS ) { break; } nameservers[nameservers_num] = malloc(strlen(rr_data)+1); if (nameservers[nameservers_num]==NULL) { free(rr_name); free(rr_data); status=ARES_ENOMEM; break; } strcpy(nameservers[nameservers_num],rr_data); free(rr_data); nameservers_num++; } free( rr_name ); aptr += rr_len; if ( aptr > abuf + alen ) { status = ARES_EBADRESP; break; } } if ( status == ARES_SUCCESS && nameservers_num == 0 ) { status = ARES_ENODATA; } if ( status == ARES_SUCCESS ) { /* We got our answer. Allocate memory to build the host entry. */ nameservers[nameservers_num] = NULL; hostent = malloc( sizeof( struct hostent ) ); if ( hostent ) { hostent->h_addr_list = malloc( 1 * sizeof( char * ) ); if ( hostent->h_addr_list ) { /* Fill in the hostent and return successfully. */ hostent->h_name = hostname; hostent->h_aliases = nameservers; hostent->h_addrtype = AF_INET; hostent->h_length = sizeof( struct in_addr ); hostent->h_addr_list[0] = NULL; *host = hostent; return ARES_SUCCESS; } free( hostent ); } status = ARES_ENOMEM; } for ( i = 0; i < nameservers_num; i++ ) free( nameservers[i] ); free( nameservers ); free( hostname ); return status; }
static void callback(void *arg, int status, int timeouts, unsigned char *abuf, int alen) { char *name = (char *) arg; int id, qr, opcode, aa, tc, rd, ra, rcode; unsigned int qdcount, ancount, nscount, arcount, i; const unsigned char *aptr; (void) timeouts; /* Display the query name if given. */ if (name) printf("Answer for query %s:\n", name); /* Display an error message if there was an error, but only stop if * we actually didn't get an answer buffer. */ if (status != ARES_SUCCESS) { printf("%s\n", ares_strerror(status)); if (!abuf) return; } /* Won't happen, but check anyway, for safety. */ if (alen < HFIXEDSZ) return; /* Parse the answer header. */ id = DNS_HEADER_QID(abuf); qr = DNS_HEADER_QR(abuf); opcode = DNS_HEADER_OPCODE(abuf); aa = DNS_HEADER_AA(abuf); tc = DNS_HEADER_TC(abuf); rd = DNS_HEADER_RD(abuf); ra = DNS_HEADER_RA(abuf); rcode = DNS_HEADER_RCODE(abuf); qdcount = DNS_HEADER_QDCOUNT(abuf); ancount = DNS_HEADER_ANCOUNT(abuf); nscount = DNS_HEADER_NSCOUNT(abuf); arcount = DNS_HEADER_ARCOUNT(abuf); /* 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: %d %s\n", opcode, opcodes[opcode]); printf("rcode: %d %s\n", rcode, rcodes[rcode]); printf("qdcount: %d\n", qdcount); printf("ancount: %d\n", ancount); printf("nscount: %d\n", nscount); printf("arcount: %d\n", arcount); /* Display the questions. */ printf("Questions:\n"); aptr = abuf + HFIXEDSZ; for (i = 0; i < qdcount; i++) { aptr = display_question(aptr, abuf, alen); if (aptr == NULL) return; } /* Display the answers. */ printf("Answers:\n"); for (i = 0; i < ancount; i++) { aptr = display_rr(aptr, abuf, alen); if (aptr == NULL) return; } /* Display the NS records. */ printf("NS records:\n"); for (i = 0; i < nscount; i++) { aptr = display_rr(aptr, abuf, alen); if (aptr == NULL) return; } /* Display the additional records. */ printf("Additional records:\n"); for (i = 0; i < arcount; i++) { aptr = display_rr(aptr, abuf, alen); if (aptr == NULL) return; } }
void LLQueryResponder::queryResult(const char *buf, size_t len) { const char *pos = buf; int qdcount = DNS_HEADER_QDCOUNT(pos); int ancount = DNS_HEADER_ANCOUNT(pos); int nscount = DNS_HEADER_NSCOUNT(pos); int arcount = DNS_HEADER_ARCOUNT(pos); int ret; if (qdcount == 0 || ancount + nscount + arcount == 0) { ret = ARES_ENODATA; goto bail; } pos += NS_HFIXEDSZ; for (int i = 0; i < qdcount; i++) { std::string ignore; size_t enclen; ret = LLAres::expandName(pos, buf, len, i == 0 ? mQuery : ignore, enclen); if (ret != ARES_SUCCESS) { goto bail; } pos += enclen; if (i == 0) { int t = DNS_QUESTION_TYPE(pos); switch (t) { case RES_A: case RES_NS: case RES_CNAME: case RES_PTR: case RES_AAAA: case RES_SRV: mType = (LLResType) t; break; default: LL_INFOS() << "Cannot grok query type " << t << LL_ENDL; ret = ARES_EBADQUERY; goto bail; } } pos += NS_QFIXEDSZ; if (pos > buf + len) { ret = ARES_EBADRESP; goto bail; } } ret = parseSection(buf, len, ancount, pos, mAnswers); if (ret != ARES_SUCCESS) { goto bail; } ret = parseSection(buf, len, nscount, pos, mAuthorities); if (ret != ARES_SUCCESS) { goto bail; } ret = parseSection(buf, len, arcount, pos, mAdditional); bail: mResult = ret; if (mResult == ARES_SUCCESS) { querySuccess(); } else { queryError(mResult); } }
void dns_detail_callback(void *arg, int status, int timeouts, unsigned char *abuf, int alen) { int id, qr, opcode, aa, tc, rd, ra, rcode; unsigned int qdcount, ancount, nscount, arcount, i; const unsigned char *aptr; dns_resp_t *response = (dns_resp_t *) arg; clearstrbuffer(response->msgbuf); response->msgstatus = status; /* * Display an error message if there was an error, but only stop if * we actually didn't get an answer buffer. */ switch (status) { case ARES_SUCCESS: break; case ARES_ENODATA: addtobuffer(response->msgbuf, "No data returned from server\n"); if (!abuf) return; break; case ARES_EFORMERR: addtobuffer(response->msgbuf, "Server could not understand query\n"); if (!abuf) return; break; case ARES_ESERVFAIL: addtobuffer(response->msgbuf, "Server failed\n"); if (!abuf) return; break; case ARES_ENOTFOUND: addtobuffer(response->msgbuf, "Name not found\n"); if (!abuf) return; break; case ARES_ENOTIMP: addtobuffer(response->msgbuf, "Not implemented\n"); if (!abuf) return; break; case ARES_EREFUSED: addtobuffer(response->msgbuf, "Server refused query\n"); if (!abuf) return; break; case ARES_EBADNAME: addtobuffer(response->msgbuf, "Invalid name in query\n"); if (!abuf) return; break; case ARES_ETIMEOUT: addtobuffer(response->msgbuf, "Timeout\n"); if (!abuf) return; break; case ARES_ECONNREFUSED: addtobuffer(response->msgbuf, "Server unavailable\n"); if (!abuf) return; break; case ARES_ENOMEM: addtobuffer(response->msgbuf, "Out of memory\n"); if (!abuf) return; break; case ARES_EDESTRUCTION: addtobuffer(response->msgbuf, "Timeout (channel destroyed)\n"); if (!abuf) return; break; default: addtobuffer(response->msgbuf, "Undocumented ARES return code\n"); if (!abuf) return; break; } /* Won't happen, but check anyway, for safety. */ if (alen < HFIXEDSZ) return; /* Parse the answer header. */ id = DNS_HEADER_QID(abuf); qr = DNS_HEADER_QR(abuf); opcode = DNS_HEADER_OPCODE(abuf); aa = DNS_HEADER_AA(abuf); tc = DNS_HEADER_TC(abuf); rd = DNS_HEADER_RD(abuf); ra = DNS_HEADER_RA(abuf); rcode = DNS_HEADER_RCODE(abuf); qdcount = DNS_HEADER_QDCOUNT(abuf); ancount = DNS_HEADER_ANCOUNT(abuf); nscount = DNS_HEADER_NSCOUNT(abuf); arcount = DNS_HEADER_ARCOUNT(abuf); /* Display the answer header. */ sprintf(msg, "id: %d\n", id); addtobuffer(response->msgbuf, msg); sprintf(msg, "flags: %s%s%s%s%s\n", qr ? "qr " : "", aa ? "aa " : "", tc ? "tc " : "", rd ? "rd " : "", ra ? "ra " : ""); addtobuffer(response->msgbuf, msg); sprintf(msg, "opcode: %s\n", opcodes[opcode]); addtobuffer(response->msgbuf, msg); sprintf(msg, "rcode: %s\n", rcodes[rcode]); addtobuffer(response->msgbuf, msg); /* Display the questions. */ addtobuffer(response->msgbuf, "Questions:\n"); aptr = abuf + HFIXEDSZ; for (i = 0; i < qdcount; i++) { aptr = display_question(aptr, abuf, alen, response); if (aptr == NULL) return; } /* Display the answers. */ addtobuffer(response->msgbuf, "Answers:\n"); for (i = 0; i < ancount; i++) { aptr = display_rr(aptr, abuf, alen, response); if (aptr == NULL) return; } /* Display the NS records. */ addtobuffer(response->msgbuf, "NS records:\n"); for (i = 0; i < nscount; i++) { aptr = display_rr(aptr, abuf, alen, response); if (aptr == NULL) return; } /* Display the additional records. */ addtobuffer(response->msgbuf, "Additional records:\n"); for (i = 0; i < arcount; i++) { aptr = display_rr(aptr, abuf, alen, response); if (aptr == NULL) return; } return; }
int ares_parse_txt_reply (const unsigned char *abuf, int alen, struct ares_txt_reply **txt_out) { size_t substr_len; unsigned int qdcount, ancount, i; const unsigned char *aptr; const unsigned char *strptr; int status, rr_type, rr_class, rr_len; long len; char *hostname = NULL, *rr_name = NULL; struct ares_txt_reply *txt_head = NULL; struct ares_txt_reply *txt_last = NULL; struct ares_txt_reply *txt_curr; /* Set *txt_out to NULL for all failure cases. */ *txt_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_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 TXT record */ if (rr_class == C_IN && rr_type == T_TXT) { /* * There may be multiple substrings in a single TXT record. Each * substring may be up to 255 characters in length, with a * "length byte" indicating the size of the substring payload. * RDATA contains both the length-bytes and payloads of all * substrings contained therein. */ strptr = aptr; while (strptr < (aptr + rr_len)) { substr_len = (unsigned char)*strptr; if (strptr + substr_len + 1 > aptr + rr_len) { status = ARES_EBADRESP; break; } /* Allocate storage for this TXT answer appending it to the list */ txt_curr = ares_malloc_data(ARES_DATATYPE_TXT_REPLY); if (!txt_curr) { status = ARES_ENOMEM; break; } if (txt_last) { txt_last->next = txt_curr; } else { txt_head = txt_curr; } txt_last = txt_curr; txt_curr->record_start = strptr == aptr; txt_curr->length = substr_len; txt_curr->txt = malloc (substr_len + 1/* Including null byte */); if (txt_curr->txt == NULL) { status = ARES_ENOMEM; break; } ++strptr; memcpy ((char *) txt_curr->txt, strptr, substr_len); /* Make sure we NULL-terminate */ txt_curr->txt[substr_len] = 0; strptr += substr_len; } } /* 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 (txt_head) ares_free_data (txt_head); return status; } /* everything looks fine, return the data */ *txt_out = txt_head; return ARES_SUCCESS; }
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; /* skip rr_type, rr_class, rr_ttl, rr_rdlen */ if (aptr + RRFIXEDSZ > abuf + alen) goto failed; aptr += RRFIXEDSZ; /* allocate result struct */ soa = ares_malloc_data(ARES_DATATYPE_SOA_REPLY); if (!soa) { status = ARES_ENOMEM; goto failed_stat; } /* 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); free(qname); free(rr_name); *soa_out = soa; return ARES_SUCCESS; failed: status = ARES_EBADRESP; failed_stat: ares_free_data(soa); if (qname) free(qname); if (rr_name) free(rr_name); return status; }
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; }
static int same_questions(const unsigned char *qbuf, int qlen, const unsigned char *abuf, int alen) { struct { const unsigned char *p; int qdcount; char *name; long int namelen; int type; int dnsclass; } q, a; int i, j; if (qlen < HFIXEDSZ || alen < HFIXEDSZ) return 0; /* Extract qdcount from the request and reply buffers and compare them. */ q.qdcount = DNS_HEADER_QDCOUNT(qbuf); a.qdcount = DNS_HEADER_QDCOUNT(abuf); if (q.qdcount != a.qdcount) return 0; /* For each question in qbuf, find it in abuf. */ q.p = qbuf + HFIXEDSZ; for (i = 0; i < q.qdcount; i++) { /* Decode the question in the query. */ if (ares_expand_name(q.p, qbuf, qlen, &q.name, &q.namelen) != ARES_SUCCESS) return 0; q.p += q.namelen; if (q.p + QFIXEDSZ > qbuf + qlen) { free(q.name); return 0; } q.type = DNS_QUESTION_TYPE(q.p); q.dnsclass = DNS_QUESTION_CLASS(q.p); q.p += QFIXEDSZ; /* Search for this question in the answer. */ a.p = abuf + HFIXEDSZ; for (j = 0; j < a.qdcount; j++) { /* Decode the question in the answer. */ if (ares_expand_name(a.p, abuf, alen, &a.name, &a.namelen) != ARES_SUCCESS) { free(q.name); return 0; } a.p += a.namelen; if (a.p + QFIXEDSZ > abuf + alen) { free(q.name); free(a.name); return 0; } a.type = DNS_QUESTION_TYPE(a.p); a.dnsclass = DNS_QUESTION_CLASS(a.p); a.p += QFIXEDSZ; /* Compare the decoded questions. */ if (strcasecmp(q.name, a.name) == 0 && q.type == a.type && q.dnsclass == a.dnsclass) { free(a.name); break; } free(a.name); } free(q.name); if (j == a.qdcount) return 0; } return 1; }
int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr, int addrlen, int family, struct hostent **host) { unsigned int qdcount, ancount; int status, i, rr_type, rr_class, rr_len; long len; const unsigned char *aptr; char *ptrname, *hostname, *rr_name, *rr_data; struct hostent *hostent; int aliascnt = 0; int alias_alloc = 8; char ** aliases; /* Set *host to NULL for all failure cases. */ *host = 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; /* Expand the name from the question, and skip past the question. */ aptr = abuf + HFIXEDSZ; status = ares__expand_name_for_response(aptr, abuf, alen, &ptrname, &len); if (status != ARES_SUCCESS) return status; if (aptr + len + QFIXEDSZ > abuf + alen) { free(ptrname); return ARES_EBADRESP; } aptr += len + QFIXEDSZ; /* Examine each answer resource record (RR) in turn. */ hostname = NULL; aliases = malloc(alias_alloc * sizeof(char *)); if (!aliases) { free(ptrname); return ARES_ENOMEM; } 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) { free(rr_name); status = ARES_EBADRESP; break; } rr_type = DNS_RR_TYPE(aptr); rr_class = DNS_RR_CLASS(aptr); rr_len = DNS_RR_LEN(aptr); aptr += RRFIXEDSZ; if (rr_class == C_IN && rr_type == T_PTR && strcasecmp(rr_name, ptrname) == 0) { /* Decode the RR data and set hostname to it. */ status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data, &len); if (status != ARES_SUCCESS) { free(rr_name); break; } if (hostname) free(hostname); hostname = rr_data; aliases[aliascnt] = malloc((strlen(rr_data)+1) * sizeof(char)); if (!aliases[aliascnt]) { free(rr_name); status = ARES_ENOMEM; break; } strncpy(aliases[aliascnt], rr_data, strlen(rr_data)+1); aliascnt++; if (aliascnt >= alias_alloc) { char **ptr; alias_alloc *= 2; ptr = realloc(aliases, alias_alloc * sizeof(char *)); if(!ptr) { free(rr_name); status = ARES_ENOMEM; break; } aliases = ptr; } } if (rr_class == C_IN && rr_type == T_CNAME) { /* Decode the RR data and replace ptrname with it. */ status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data, &len); if (status != ARES_SUCCESS) { free(rr_name); break; } free(ptrname); ptrname = rr_data; } free(rr_name); aptr += rr_len; if (aptr > abuf + alen) { status = ARES_EBADRESP; break; } } if (status == ARES_SUCCESS && !hostname) status = ARES_ENODATA; if (status == ARES_SUCCESS) { /* We got our answer. Allocate memory to build the host entry. */ hostent = malloc(sizeof(struct hostent)); if (hostent) { hostent->h_addr_list = malloc(2 * sizeof(char *)); if (hostent->h_addr_list) { hostent->h_addr_list[0] = malloc(addrlen); if (hostent->h_addr_list[0]) { hostent->h_aliases = malloc((aliascnt+1) * sizeof (char *)); if (hostent->h_aliases) { /* Fill in the hostent and return successfully. */ hostent->h_name = hostname; for (i=0 ; i<aliascnt ; i++) hostent->h_aliases[i] = aliases[i]; hostent->h_aliases[aliascnt] = NULL; hostent->h_addrtype = aresx_sitoss(family); hostent->h_length = aresx_sitoss(addrlen); memcpy(hostent->h_addr_list[0], addr, addrlen); hostent->h_addr_list[1] = NULL; *host = hostent; free(aliases); free(ptrname); return ARES_SUCCESS; } free(hostent->h_addr_list[0]); } free(hostent->h_addr_list); } free(hostent); } status = ARES_ENOMEM; } for (i=0 ; i<aliascnt ; i++) if (aliases[i]) free(aliases[i]); free(aliases); if (hostname) free(hostname); free(ptrname); return status; }