#include "ares_private.h"
#include "ares_dns.h"
Include dependency graph for ares_parse_a_reply.c:
Go to the source code of this file.
Functions | |
int | ares_parse_a_reply (const unsigned char *abuf, int alen, struct hostent **host) |
|
Definition at line 26 of file ares_parse_a_reply.c. References AF_INET, ARES_EBADRESP, ARES_ENODATA, ARES_ENOMEM, ares_expand_name(), ARES_SUCCESS, C_IN, DNS_HEADER_ANCOUNT, DNS_HEADER_QDCOUNT, DNS_RR_CLASS, DNS_RR_LEN, DNS_RR_TYPE, free, HFIXEDSZ, len, malloc, NULL, QFIXEDSZ, RRFIXEDSZ, status, strcasecmp, T_A, and T_CNAME. Referenced by host_callback().
00028 { 00029 unsigned int qdcount, ancount; 00030 int status, i, len, rr_type, rr_class, rr_len, naddrs; 00031 int naliases; 00032 const unsigned char *aptr; 00033 char *hostname, *rr_name, *rr_data, **aliases; 00034 struct in_addr *addrs; 00035 struct hostent *hostent; 00036 00037 /* Set *host to NULL for all failure cases. */ 00038 *host = NULL; 00039 00040 /* Give up if abuf doesn't have room for a header. */ 00041 if (alen < HFIXEDSZ) 00042 return ARES_EBADRESP; 00043 00044 /* Fetch the question and answer count from the header. */ 00045 qdcount = DNS_HEADER_QDCOUNT(abuf); 00046 ancount = DNS_HEADER_ANCOUNT(abuf); 00047 if (qdcount != 1) 00048 return ARES_EBADRESP; 00049 00050 /* Expand the name from the question, and skip past the question. */ 00051 aptr = abuf + HFIXEDSZ; 00052 status = ares_expand_name(aptr, abuf, alen, &hostname, &len); 00053 if (status != ARES_SUCCESS) 00054 return status; 00055 if (aptr + len + QFIXEDSZ > abuf + alen) 00056 { 00057 free(hostname); 00058 return ARES_EBADRESP; 00059 } 00060 aptr += len + QFIXEDSZ; 00061 00062 /* Allocate addresses and aliases; ancount gives an upper bound for both. */ 00063 addrs = malloc(ancount * sizeof(struct in_addr)); 00064 if (!addrs) 00065 { 00066 free(hostname); 00067 return ARES_ENOMEM; 00068 } 00069 aliases = malloc((ancount + 1) * sizeof(char *)); 00070 if (!aliases) 00071 { 00072 free(hostname); 00073 free(addrs); 00074 return ARES_ENOMEM; 00075 } 00076 naddrs = 0; 00077 naliases = 0; 00078 00079 /* Examine each answer resource record (RR) in turn. */ 00080 for (i = 0; i < ancount; i++) 00081 { 00082 /* Decode the RR up to the data field. */ 00083 status = ares_expand_name(aptr, abuf, alen, &rr_name, &len); 00084 if (status != ARES_SUCCESS) 00085 break; 00086 aptr += len; 00087 if (aptr + RRFIXEDSZ > abuf + alen) 00088 { 00089 status = ARES_EBADRESP; 00090 break; 00091 } 00092 rr_type = DNS_RR_TYPE(aptr); 00093 rr_class = DNS_RR_CLASS(aptr); 00094 rr_len = DNS_RR_LEN(aptr); 00095 aptr += RRFIXEDSZ; 00096 00097 if (rr_class == C_IN && rr_type == T_A 00098 && rr_len == sizeof(struct in_addr) 00099 && strcasecmp(rr_name, hostname) == 0) 00100 { 00101 memcpy(&addrs[naddrs], aptr, sizeof(struct in_addr)); 00102 naddrs++; 00103 status = ARES_SUCCESS; 00104 } 00105 00106 if (rr_class == C_IN && rr_type == T_CNAME) 00107 { 00108 /* Record the RR name as an alias. */ 00109 aliases[naliases] = rr_name; 00110 naliases++; 00111 00112 /* Decode the RR data and replace the hostname with it. */ 00113 status = ares_expand_name(aptr, abuf, alen, &rr_data, &len); 00114 if (status != ARES_SUCCESS) 00115 break; 00116 free(hostname); 00117 hostname = rr_data; 00118 } 00119 else 00120 free(rr_name); 00121 00122 aptr += rr_len; 00123 if (aptr > abuf + alen) 00124 { 00125 status = ARES_EBADRESP; 00126 break; 00127 } 00128 } 00129 00130 if (status == ARES_SUCCESS && naddrs == 0) 00131 status = ARES_ENODATA; 00132 if (status == ARES_SUCCESS) 00133 { 00134 /* We got our answer. Allocate memory to build the host entry. */ 00135 aliases[naliases] = NULL; 00136 hostent = malloc(sizeof(struct hostent)); 00137 if (hostent) 00138 { 00139 hostent->h_addr_list = malloc((naddrs + 1) * sizeof(char *)); 00140 if (hostent->h_addr_list) 00141 { 00142 /* Fill in the hostent and return successfully. */ 00143 hostent->h_name = hostname; 00144 hostent->h_aliases = aliases; 00145 hostent->h_addrtype = AF_INET; 00146 hostent->h_length = sizeof(struct in_addr); 00147 for (i = 0; i < naddrs; i++) 00148 hostent->h_addr_list[i] = (char *) &addrs[i]; 00149 hostent->h_addr_list[naddrs] = NULL; 00150 *host = hostent; 00151 return ARES_SUCCESS; 00152 } 00153 free(hostent); 00154 } 00155 status = ARES_ENOMEM; 00156 } 00157 for (i = 0; i < naliases; i++) 00158 free(aliases[i]); 00159 free(aliases); 00160 free(addrs); 00161 free(hostname); 00162 return status; 00163 } |
Here is the call graph for this function: