00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "ares_private.h"
00024 #include "ares_dns.h"
00025
00026 int ares_parse_a_reply(const unsigned char *abuf, int alen,
00027 struct hostent **host)
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
00038 *host = NULL;
00039
00040
00041 if (alen < HFIXEDSZ)
00042 return ARES_EBADRESP;
00043
00044
00045 qdcount = DNS_HEADER_QDCOUNT(abuf);
00046 ancount = DNS_HEADER_ANCOUNT(abuf);
00047 if (qdcount != 1)
00048 return ARES_EBADRESP;
00049
00050
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
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
00080 for (i = 0; i < ancount; i++)
00081 {
00082
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
00109 aliases[naliases] = rr_name;
00110 naliases++;
00111
00112
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
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
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 }