/* Like ares_expand_name but returns EBADRESP in case of invalid input. */ int ares__expand_name_for_response(const unsigned char *encoded, const unsigned char *abuf, int alen, char **s, long *enclen) { int status = ares_expand_name(encoded, abuf, alen, s, enclen); if (status == ARES_EBADNAME) status = ARES_EBADRESP; return status; }
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; } }
static const unsigned char *skip_query(const unsigned char *aptr, const unsigned char *abuf, int alen) { int status; long len; char *name; dbg("skipping query section...\n"); status = ares_expand_name(aptr, abuf, alen, &name, &len); aptr += len; aptr += NS_QFIXEDSZ; free(name); return aptr; }
static const unsigned char *skip_rr(const unsigned char *aptr, const unsigned char *abuf, int alen) { int status, dlen; long len; char *name; dbg("skipping rr section...\n"); status = ares_expand_name(aptr, abuf, alen, &name, &len); aptr += len; dlen = DNS_RR_LEN(aptr); aptr += NS_RRFIXEDSZ; aptr += dlen; free(name); return aptr; }
int LLAres::expandName(const char *encoded, const char *abuf, size_t alen, std::string &s, size_t &enclen) { char *t; int ret; long e; ret = ares_expand_name((const unsigned char *) encoded, (const unsigned char *) abuf, alen, &t, &e); if (ret == ARES_SUCCESS) { s.assign(t); enclen = e; ares_free_string(t); } return ret; }
static const unsigned char *display_question(const unsigned char *aptr, const unsigned char *abuf, int alen, dns_resp_t *response) { char *name; int type, dnsclass, status; long len; /* Parse the question name. */ status = ares_expand_name(aptr, abuf, alen, &name, &len); if (status != ARES_SUCCESS) return NULL; aptr += len; /* Make sure there's enough data after the name for the fixed part * of the question. */ if (aptr + QFIXEDSZ > abuf + alen) { xfree(name); return NULL; } /* Parse the question type and class. */ type = DNS_QUESTION_TYPE(aptr); dnsclass = DNS_QUESTION_CLASS(aptr); aptr += QFIXEDSZ; /* * Display the question, in a format sort of similar to how we will * display RRs. */ sprintf(msg, "\t%-15s.\t", name); addtobuffer(response->msgbuf, msg); if (dnsclass != C_IN) { sprintf(msg, "\t%s", class_name(dnsclass)); addtobuffer(response->msgbuf, msg); } sprintf(msg, "\t%s\n", type_name(type)); addtobuffer(response->msgbuf, msg); xfree(name); return aptr; }
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 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 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 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; }
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 const unsigned char *parse_rr(const unsigned char *aptr, const unsigned char *abuf, int alen) { char *name; long len; int status, type, dnsclass, dlen; struct in_addr addr; dbg("ca_tmpname: %s\n", ca_tmpname); status = ares_expand_name(aptr, abuf, alen, &name, &len); if (status != ARES_SUCCESS) { printf("error: failed to expand query name\n"); exit_code(2, __PRETTY_FUNCTION__, "failed to expand query name"); } aptr += len; if (aptr + NS_RRFIXEDSZ > abuf + alen) { printf("error: not enough data in DNS answer 1\n"); free(name); return NULL; } type = DNS_RR_TYPE(aptr); dnsclass = DNS_RR_CLASS(aptr); dlen = DNS_RR_LEN(aptr); aptr += NS_RRFIXEDSZ; if (aptr + dlen > abuf + alen) { printf("error: not enough data in DNS answer 2\n"); free(name); return NULL; } if (dnsclass != CARES_CLASS_C_IN) { printf("error: unsupported dnsclass (%i) in DNS answer\n", dnsclass); free(name); return NULL; } if (type != CARES_TYPE_SRV && type != CARES_TYPE_A && type != CARES_TYPE_CNAME) { printf("error: unsupported DNS response type (%i)\n", type); free(name); return NULL; } if (type == CARES_TYPE_SRV) { free(name); caport = DNS__16BIT(aptr + 4); dbg("caport: %i\n", caport); status = ares_expand_name(aptr + 6, abuf, alen, &name, &len); if (status != ARES_SUCCESS) { printf("error: failed to expand SRV name\n"); return NULL; } dbg("SRV name: %s\n", name); if (is_ip(name)) { caadr = inet_addr(name); free(name); } else { ca_tmpname = name; } } else if (type == CARES_TYPE_CNAME) { if ((ca_tmpname != NULL) && (STRNCASECMP(ca_tmpname, name, strlen(ca_tmpname)) == 0)) { ca_tmpname = malloc(strlen(name)); if (ca_tmpname == NULL) { printf("error: failed to allocate memory\n"); exit_code(2, __PRETTY_FUNCTION__, "memory allocation failure"); } strcpy(ca_tmpname, name); free(name); } else { free(name); status = ares_expand_name(aptr, abuf, alen, &name, &len); if (status != ARES_SUCCESS) { printf("error: failed to expand CNAME\n"); return NULL; } dbg("CNAME: %s\n", name); if (is_ip(name)) { caadr = inet_addr(name); free(name); } else { ca_tmpname = name; } } } else if (type == CARES_TYPE_A) { if (dlen == 4 && STRNCASECMP(ca_tmpname, name, strlen(ca_tmpname)) == 0) { memcpy(&addr, aptr, sizeof(struct in_addr)); caadr = addr.s_addr; } free(name); } return aptr + dlen; }
int getaddress(char *host, int rport, int transport, struct addrinfo *ret) { struct addrinfo *result; struct addrinfo *res; int error; struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = transport == SIP_TCP_TRANSPORT ? SOCK_STREAM : SOCK_DGRAM }; if (rport) { char strport[INT_DIGITS10]; snprintf(strport, INT_DIGITS10, "%i", rport); error = getaddrinfo(host, strport, &hints, &result); } else { error = getaddrinfo(host, "sip", &hints, &result); } /* resolve the domain name into a list of addresses */ if (error != 0) { if (error == EAI_SYSTEM) { perror("getaddrinfo"); } else { fprintf(stderr, "error in getaddrinfo for %s: %s\n", host, gai_strerror(error)); } return -1; } /* loop over all returned results and do inverse lookup */ for (res = result; res != NULL; res = res->ai_next) { char hostname[NI_MAXHOST]; error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0); if (error != 0) { fprintf(stderr, "error in getnameinfo: %s\n", gai_strerror(error)); continue; } if (*hostname != '\0') { memset(ret, 0, sizeof(struct addrinfo)); memcpy(ret, res, sizeof(struct addrinfo)); ret->ai_addr = malloc(res->ai_addrlen); memcpy(ret->ai_addr, res->ai_addr, res->ai_addrlen); break; } } freeaddrinfo(result); return 0; } #ifdef HAVE_CARES_H static const unsigned char *parse_rr(const unsigned char *aptr, const unsigned char *abuf, int alen) { char *name; long len; int status, type, dnsclass, dlen; struct in_addr addr; dbg("ca_tmpname: %s\n", ca_tmpname); status = ares_expand_name(aptr, abuf, alen, &name, &len); if (status != ARES_SUCCESS) { printf("error: failed to expand query name\n"); exit_code(2, __PRETTY_FUNCTION__, "failed to expand query name"); } aptr += len; if (aptr + NS_RRFIXEDSZ > abuf + alen) { printf("error: not enough data in DNS answer 1\n"); free(name); return NULL; } type = DNS_RR_TYPE(aptr); dnsclass = DNS_RR_CLASS(aptr); dlen = DNS_RR_LEN(aptr); aptr += NS_RRFIXEDSZ; if (aptr + dlen > abuf + alen) { printf("error: not enough data in DNS answer 2\n"); free(name); return NULL; } if (dnsclass != CARES_CLASS_C_IN) { printf("error: unsupported dnsclass (%i) in DNS answer\n", dnsclass); free(name); return NULL; } if ((ca_tmpname == NULL && type != CARES_TYPE_SRV) || (ca_tmpname != NULL && (type != CARES_TYPE_A && type != CARES_TYPE_CNAME))) { printf("error: unsupported DNS response type (%i)\n", type); free(name); return NULL; } if (type == CARES_TYPE_SRV) { free(name); caport = DNS__16BIT(aptr + 4); dbg("caport: %i\n", caport); status = ares_expand_name(aptr + 6, abuf, alen, &name, &len); if (status != ARES_SUCCESS) { printf("error: failed to expand SRV name\n"); return NULL; } dbg("SRV name: %s\n", name); if (is_ip(name)) { caadr = inet_addr(name); free(name); } else { ca_tmpname = name; } } else if (type == CARES_TYPE_CNAME) { if ((ca_tmpname != NULL) && (STRNCASECMP(ca_tmpname, name, strlen(ca_tmpname)) == 0)) { ca_tmpname = malloc(strlen(name)); if (ca_tmpname == NULL) { printf("error: failed to allocate memory\n"); exit_code(2, __PRETTY_FUNCTION__, "memory allocation failure"); } strcpy(ca_tmpname, name); free(name); } else { free(name); status = ares_expand_name(aptr, abuf, alen, &name, &len); if (status != ARES_SUCCESS) { printf("error: failed to expand CNAME\n"); return NULL; } dbg("CNAME: %s\n", name); if (is_ip(name)) { caadr = inet_addr(name); free(name); } else { ca_tmpname = name; } } } else if (type == CARES_TYPE_A) { if (dlen == 4 && STRNCASECMP(ca_tmpname, name, strlen(ca_tmpname)) == 0) { memcpy(&addr, aptr, sizeof(struct in_addr)); caadr = addr.s_addr; } free(name); } return aptr + dlen; }
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; }
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_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; }
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, len, rr_type, rr_class, rr_len; const unsigned char *aptr; char *ptrname, *hostname, *rr_name, *rr_data; 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, &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; 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 (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(aptr, abuf, alen, &rr_data, &len); if (status != ARES_SUCCESS) break; if (hostname) free(hostname); hostname = rr_data; } if (rr_class == C_IN && rr_type == T_CNAME) { /* Decode the RR data and replace ptrname with it. */ status = ares_expand_name(aptr, abuf, alen, &rr_data, &len); if (status != ARES_SUCCESS) 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(sizeof (char *)); if (hostent->h_aliases) { /* Fill in the hostent and return successfully. */ hostent->h_name = hostname; hostent->h_aliases[0] = NULL; hostent->h_addrtype = family; hostent->h_length = addrlen; memcpy(hostent->h_addr_list[0], addr, addrlen); hostent->h_addr_list[1] = NULL; *host = hostent; free(ptrname); return ARES_SUCCESS; } free(hostent->h_addr_list[0]); } free(hostent->h_addr_list); } free(hostent); } status = ARES_ENOMEM; } if (hostname) free(hostname); free(ptrname); return status; }