1 2 /* Copyright 1998 by the Massachusetts Institute of Technology. 3 * Copyright (C) 2019 by Andrew Selivanov 4 * 5 * Permission to use, copy, modify, and distribute this 6 * software and its documentation for any purpose and without 7 * fee is hereby granted, provided that the above copyright 8 * notice appear in all copies and that both that copyright 9 * notice and this permission notice appear in supporting 10 * documentation, and that the name of M.I.T. not be used in 11 * advertising or publicity pertaining to distribution of the 12 * software without specific, written prior permission. 13 * M.I.T. makes no representations about the suitability of 14 * this software for any purpose. It is provided "as is" 15 * without express or implied warranty. 16 */ 17 18 #include "ares_setup.h" 19 20 #ifdef HAVE_NETINET_IN_H 21 # include <netinet/in.h> 22 #endif 23 #ifdef HAVE_NETDB_H 24 # include <netdb.h> 25 #endif 26 #ifdef HAVE_ARPA_INET_H 27 # include <arpa/inet.h> 28 #endif 29 30 #include "ares_nameser.h" 31 32 #ifdef HAVE_STRINGS_H 33 # include <strings.h> 34 #endif 35 36 #ifdef HAVE_LIMITS_H 37 # include <limits.h> 38 #endif 39 40 #include "ares.h" 41 #include "ares_dns.h" 42 #include "ares_private.h" 43 44 int ares_parse_a_reply(const unsigned char *abuf, int alen, 45 struct hostent **host, 46 struct ares_addrttl *addrttls, int *naddrttls) 47 { 48 struct ares_addrinfo ai; 49 struct ares_addrinfo_node *next; 50 struct ares_addrinfo_cname *next_cname; 51 char **aliases = NULL; 52 char *question_hostname = NULL; 53 struct hostent *hostent = NULL; 54 struct in_addr *addrs = NULL; 55 int naliases = 0, naddrs = 0, alias = 0, i; 56 int cname_ttl = INT_MAX; 57 int status; 58 59 memset(&ai, 0, sizeof(ai)); 60 61 status = ares__parse_into_addrinfo2(abuf, alen, &question_hostname, &ai); 62 if (status != ARES_SUCCESS) 63 { 64 ares_free(question_hostname); 65 66 if (naddrttls) 67 { 68 *naddrttls = 0; 69 } 70 71 return status; 72 } 73 74 hostent = ares_malloc(sizeof(struct hostent)); 75 if (!hostent) 76 { 77 goto enomem; 78 } 79 80 next = ai.nodes; 81 while (next) 82 { 83 if (next->ai_family == AF_INET) 84 { 85 ++naddrs; 86 } 87 next = next->ai_next; 88 } 89 90 next_cname = ai.cnames; 91 while (next_cname) 92 { 93 if(next_cname->alias) 94 ++naliases; 95 next_cname = next_cname->next; 96 } 97 98 aliases = ares_malloc((naliases + 1) * sizeof(char *)); 99 if (!aliases) 100 { 101 goto enomem; 102 } 103 104 if (naliases) 105 { 106 next_cname = ai.cnames; 107 while (next_cname) 108 { 109 if(next_cname->alias) 110 aliases[alias++] = strdup(next_cname->alias); 111 if(next_cname->ttl < cname_ttl) 112 cname_ttl = next_cname->ttl; 113 next_cname = next_cname->next; 114 } 115 } 116 117 aliases[alias] = NULL; 118 119 hostent->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *)); 120 if (!hostent->h_addr_list) 121 { 122 goto enomem; 123 } 124 125 for (i = 0; i < naddrs + 1; ++i) 126 { 127 hostent->h_addr_list[i] = NULL; 128 } 129 130 if (ai.cnames) 131 { 132 hostent->h_name = strdup(ai.cnames->name); 133 ares_free(question_hostname); 134 } 135 else 136 { 137 hostent->h_name = question_hostname; 138 } 139 140 hostent->h_aliases = aliases; 141 hostent->h_addrtype = AF_INET; 142 hostent->h_length = sizeof(struct in_addr); 143 144 if (naddrs) 145 { 146 addrs = ares_malloc(naddrs * sizeof(struct in_addr)); 147 if (!addrs) 148 { 149 goto enomem; 150 } 151 152 i = 0; 153 next = ai.nodes; 154 while (next) 155 { 156 if (next->ai_family == AF_INET) 157 { 158 hostent->h_addr_list[i] = (char *)&addrs[i]; 159 memcpy(hostent->h_addr_list[i], 160 &(CARES_INADDR_CAST(struct sockaddr_in *, next->ai_addr)->sin_addr), 161 sizeof(struct in_addr)); 162 if (naddrttls && i < *naddrttls) 163 { 164 if (next->ai_ttl > cname_ttl) 165 addrttls[i].ttl = cname_ttl; 166 else 167 addrttls[i].ttl = next->ai_ttl; 168 169 memcpy(&addrttls[i].ipaddr, 170 &(CARES_INADDR_CAST(struct sockaddr_in *, next->ai_addr)->sin_addr), 171 sizeof(struct in_addr)); 172 } 173 ++i; 174 } 175 next = next->ai_next; 176 } 177 if (i == 0) 178 { 179 ares_free(addrs); 180 } 181 } 182 183 if (host) 184 { 185 *host = hostent; 186 } 187 else 188 { 189 ares_free_hostent(hostent); 190 } 191 192 if (naddrttls) 193 { 194 /* Truncated to at most *naddrttls entries */ 195 *naddrttls = (naddrs > *naddrttls)?*naddrttls:naddrs; 196 } 197 198 ares__freeaddrinfo_cnames(ai.cnames); 199 ares__freeaddrinfo_nodes(ai.nodes); 200 return ARES_SUCCESS; 201 202 enomem: 203 ares_free(aliases); 204 ares_free(hostent); 205 ares__freeaddrinfo_cnames(ai.cnames); 206 ares__freeaddrinfo_nodes(ai.nodes); 207 ares_free(question_hostname); 208 return ARES_ENOMEM; 209 } 210