1 2 /* Copyright 1998 by the Massachusetts Institute of Technology. 3 * 4 * Permission to use, copy, modify, and distribute this 5 * software and its documentation for any purpose and without 6 * fee is hereby granted, provided that the above copyright 7 * notice appear in all copies and that both that copyright 8 * notice and this permission notice appear in supporting 9 * documentation, and that the name of M.I.T. not be used in 10 * advertising or publicity pertaining to distribution of the 11 * software without specific, written prior permission. 12 * M.I.T. makes no representations about the suitability of 13 * this software for any purpose. It is provided "as is" 14 * without express or implied warranty. 15 */ 16 17 #include "ares_setup.h" 18 19 #ifdef HAVE_SYS_SOCKET_H 20 # include <sys/socket.h> 21 #endif 22 #ifdef HAVE_NETINET_IN_H 23 # include <netinet/in.h> 24 #endif 25 #ifdef HAVE_NETDB_H 26 # include <netdb.h> 27 #endif 28 #ifdef HAVE_ARPA_NAMESER_H 29 # include <arpa/nameser.h> 30 #else 31 # include "nameser.h" 32 #endif 33 #ifdef HAVE_ARPA_NAMESER_COMPAT_H 34 # include <arpa/nameser_compat.h> 35 #endif 36 37 #ifdef HAVE_STRINGS_H 38 # include <strings.h> 39 #endif 40 41 #include <stdlib.h> 42 #include <string.h> 43 #include "ares.h" 44 #include "ares_dns.h" 45 #include "ares_private.h" 46 47 int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr, 48 int addrlen, int family, struct hostent **host) 49 { 50 unsigned int qdcount, ancount; 51 int status, i, rr_type, rr_class, rr_len; 52 long len; 53 const unsigned char *aptr; 54 char *ptrname, *hostname, *rr_name, *rr_data; 55 struct hostent *hostent; 56 int aliascnt = 0; 57 int alias_alloc = 8; 58 char ** aliases; 59 60 /* Set *host to NULL for all failure cases. */ 61 *host = NULL; 62 63 /* Give up if abuf doesn't have room for a header. */ 64 if (alen < HFIXEDSZ) 65 return ARES_EBADRESP; 66 67 /* Fetch the question and answer count from the header. */ 68 qdcount = DNS_HEADER_QDCOUNT(abuf); 69 ancount = DNS_HEADER_ANCOUNT(abuf); 70 if (qdcount != 1) 71 return ARES_EBADRESP; 72 73 /* Expand the name from the question, and skip past the question. */ 74 aptr = abuf + HFIXEDSZ; 75 status = ares__expand_name_for_response(aptr, abuf, alen, &ptrname, &len); 76 if (status != ARES_SUCCESS) 77 return status; 78 if (aptr + len + QFIXEDSZ > abuf + alen) 79 { 80 free(ptrname); 81 return ARES_EBADRESP; 82 } 83 aptr += len + QFIXEDSZ; 84 85 /* Examine each answer resource record (RR) in turn. */ 86 hostname = NULL; 87 aliases = malloc(alias_alloc * sizeof(char *)); 88 if (!aliases) 89 { 90 free(ptrname); 91 return ARES_ENOMEM; 92 } 93 for (i = 0; i < (int)ancount; i++) 94 { 95 /* Decode the RR up to the data field. */ 96 status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len); 97 if (status != ARES_SUCCESS) 98 break; 99 aptr += len; 100 if (aptr + RRFIXEDSZ > abuf + alen) 101 { 102 free(rr_name); 103 status = ARES_EBADRESP; 104 break; 105 } 106 rr_type = DNS_RR_TYPE(aptr); 107 rr_class = DNS_RR_CLASS(aptr); 108 rr_len = DNS_RR_LEN(aptr); 109 aptr += RRFIXEDSZ; 110 111 if (rr_class == C_IN && rr_type == T_PTR 112 && strcasecmp(rr_name, ptrname) == 0) 113 { 114 /* Decode the RR data and set hostname to it. */ 115 status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data, 116 &len); 117 if (status != ARES_SUCCESS) 118 { 119 free(rr_name); 120 break; 121 } 122 if (hostname) 123 free(hostname); 124 hostname = rr_data; 125 aliases[aliascnt] = malloc((strlen(rr_data)+1) * sizeof(char)); 126 if (!aliases[aliascnt]) 127 { 128 free(rr_name); 129 status = ARES_ENOMEM; 130 break; 131 } 132 strncpy(aliases[aliascnt], rr_data, strlen(rr_data)+1); 133 aliascnt++; 134 if (aliascnt >= alias_alloc) { 135 char **ptr; 136 alias_alloc *= 2; 137 ptr = realloc(aliases, alias_alloc * sizeof(char *)); 138 if(!ptr) { 139 free(rr_name); 140 status = ARES_ENOMEM; 141 break; 142 } 143 aliases = ptr; 144 } 145 } 146 147 if (rr_class == C_IN && rr_type == T_CNAME) 148 { 149 /* Decode the RR data and replace ptrname with it. */ 150 status = ares__expand_name_for_response(aptr, abuf, alen, &rr_data, 151 &len); 152 if (status != ARES_SUCCESS) 153 { 154 free(rr_name); 155 break; 156 } 157 free(ptrname); 158 ptrname = rr_data; 159 } 160 161 free(rr_name); 162 aptr += rr_len; 163 if (aptr > abuf + alen) 164 { 165 status = ARES_EBADRESP; 166 break; 167 } 168 } 169 170 if (status == ARES_SUCCESS && !hostname) 171 status = ARES_ENODATA; 172 if (status == ARES_SUCCESS) 173 { 174 /* We got our answer. Allocate memory to build the host entry. */ 175 hostent = malloc(sizeof(struct hostent)); 176 if (hostent) 177 { 178 hostent->h_addr_list = malloc(2 * sizeof(char *)); 179 if (hostent->h_addr_list) 180 { 181 hostent->h_addr_list[0] = malloc(addrlen); 182 if (hostent->h_addr_list[0]) 183 { 184 hostent->h_aliases = malloc((aliascnt+1) * sizeof (char *)); 185 if (hostent->h_aliases) 186 { 187 /* Fill in the hostent and return successfully. */ 188 hostent->h_name = hostname; 189 for (i=0 ; i<aliascnt ; i++) 190 hostent->h_aliases[i] = aliases[i]; 191 hostent->h_aliases[aliascnt] = NULL; 192 hostent->h_addrtype = family; 193 hostent->h_length = addrlen; 194 memcpy(hostent->h_addr_list[0], addr, addrlen); 195 hostent->h_addr_list[1] = NULL; 196 *host = hostent; 197 free(aliases); 198 free(ptrname); 199 return ARES_SUCCESS; 200 } 201 free(hostent->h_addr_list[0]); 202 } 203 free(hostent->h_addr_list); 204 } 205 free(hostent); 206 } 207 status = ARES_ENOMEM; 208 } 209 for (i=0 ; i<aliascnt ; i++) 210 if (aliases[i]) 211 free(aliases[i]); 212 free(aliases); 213 if (hostname) 214 free(hostname); 215 free(ptrname); 216 return status; 217 } 218