ares_addrinfo2hostent.c (8908B)
1 /* MIT License 2 * 3 * Copyright (c) 1998 Massachusetts Institute of Technology 4 * Copyright (c) 2005 Dominick Meglio 5 * Copyright (c) 2019 Andrew Selivanov 6 * Copyright (c) 2021 Brad House 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a copy 9 * of this software and associated documentation files (the "Software"), to deal 10 * in the Software without restriction, including without limitation the rights 11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 * copies of the Software, and to permit persons to whom the Software is 13 * furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the next 16 * paragraph) shall be included in all copies or substantial portions of the 17 * Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 * SOFTWARE. 26 * 27 * SPDX-License-Identifier: MIT 28 */ 29 30 #include "ares_private.h" 31 32 #ifdef HAVE_NETINET_IN_H 33 # include <netinet/in.h> 34 #endif 35 #ifdef HAVE_NETDB_H 36 # include <netdb.h> 37 #endif 38 #ifdef HAVE_ARPA_INET_H 39 # include <arpa/inet.h> 40 #endif 41 42 #ifdef HAVE_STRINGS_H 43 # include <strings.h> 44 #endif 45 46 #ifdef HAVE_LIMITS_H 47 # include <limits.h> 48 #endif 49 50 static size_t hostent_nalias(const struct hostent *host) 51 { 52 size_t i; 53 for (i=0; host->h_aliases != NULL && host->h_aliases[i] != NULL; i++) 54 ; 55 56 return i; 57 } 58 59 static size_t ai_nalias(const struct ares_addrinfo *ai) 60 { 61 const struct ares_addrinfo_cname *cname; 62 size_t i = 0; 63 64 for (cname = ai->cnames; cname != NULL; cname=cname->next) { 65 i++; 66 } 67 68 return i; 69 } 70 71 static size_t hostent_naddr(const struct hostent *host) 72 { 73 size_t i; 74 for (i=0; host->h_addr_list != NULL && host->h_addr_list[i] != NULL; i++) 75 ; 76 77 return i; 78 } 79 80 static size_t ai_naddr(const struct ares_addrinfo *ai, int af) 81 { 82 const struct ares_addrinfo_node *node; 83 size_t i = 0; 84 85 for (node = ai->nodes; node != NULL; node=node->ai_next) { 86 if (af != AF_UNSPEC && af != node->ai_family) 87 continue; 88 i++; 89 } 90 91 return i; 92 } 93 94 ares_status_t ares_addrinfo2hostent(const struct ares_addrinfo *ai, int family, 95 struct hostent **host) 96 { 97 struct ares_addrinfo_node *next; 98 char **aliases = NULL; 99 char **addrs = NULL; 100 size_t naliases = 0; 101 size_t naddrs = 0; 102 size_t i; 103 size_t ealiases = 0; 104 size_t eaddrs = 0; 105 106 if (ai == NULL || host == NULL) { 107 return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ 108 } 109 110 /* Use either the host set in the passed in hosts to be filled in, or the 111 * first node of the response as the family, since hostent can only 112 * represent one family. We assume getaddrinfo() returned a sorted list if 113 * the user requested AF_UNSPEC. */ 114 if (family == AF_UNSPEC) { 115 if (*host != NULL && (*host)->h_addrtype != AF_UNSPEC) { 116 family = (*host)->h_addrtype; 117 } else if (ai->nodes != NULL) { 118 family = ai->nodes->ai_family; 119 } 120 } 121 122 if (family != AF_INET && family != AF_INET6) { 123 return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ 124 } 125 126 if (*host == NULL) { 127 *host = ares_malloc_zero(sizeof(**host)); 128 if (!(*host)) { 129 goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ 130 } 131 } 132 133 (*host)->h_addrtype = (HOSTENT_ADDRTYPE_TYPE)family; 134 if (family == AF_INET) { 135 (*host)->h_length = sizeof(struct in_addr); 136 } else if (family == AF_INET6) { 137 (*host)->h_length = sizeof(struct ares_in6_addr); 138 } 139 140 if ((*host)->h_name == NULL) { 141 if (ai->cnames) { 142 (*host)->h_name = ares_strdup(ai->cnames->name); 143 if ((*host)->h_name == NULL && ai->cnames->name) { 144 goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ 145 } 146 } else { 147 (*host)->h_name = ares_strdup(ai->name); 148 if ((*host)->h_name == NULL && ai->name) { 149 goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ 150 } 151 } 152 } 153 154 naliases = ai_nalias(ai); 155 ealiases = hostent_nalias(*host); 156 aliases = ares_realloc_zero((*host)->h_aliases, 157 ealiases * sizeof(char *), 158 (naliases + ealiases + 1) * sizeof(char *)); 159 if (!aliases) { 160 goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ 161 } 162 (*host)->h_aliases = aliases; 163 164 if (naliases) { 165 const struct ares_addrinfo_cname *cname; 166 i = ealiases; 167 for (cname = ai->cnames; cname != NULL; cname = cname->next) { 168 if (cname->alias == NULL) { 169 continue; 170 } 171 (*host)->h_aliases[i] = ares_strdup(cname->alias); 172 if ((*host)->h_aliases[i] == NULL) { 173 goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ 174 } 175 i++; 176 } 177 } 178 179 naddrs = ai_naddr(ai, family); 180 eaddrs = hostent_naddr(*host); 181 addrs = ares_realloc_zero((*host)->h_addr_list, eaddrs * sizeof(char *), 182 (naddrs + eaddrs + 1) * sizeof(char *)); 183 if (addrs == NULL) { 184 goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ 185 } 186 (*host)->h_addr_list = addrs; 187 188 if (naddrs) { 189 i = eaddrs; 190 for (next = ai->nodes; next != NULL; next = next->ai_next) { 191 if (next->ai_family != family) { 192 continue; 193 } 194 (*host)->h_addr_list[i] = ares_malloc_zero((size_t)(*host)->h_length); 195 if ((*host)->h_addr_list[i] == NULL) { 196 goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */ 197 } 198 if (family == AF_INET6) { 199 memcpy((*host)->h_addr_list[i], 200 &(CARES_INADDR_CAST(const struct sockaddr_in6 *, next->ai_addr) 201 ->sin6_addr), 202 (size_t)(*host)->h_length); 203 } 204 if (family == AF_INET) { 205 memcpy((*host)->h_addr_list[i], 206 &(CARES_INADDR_CAST(const struct sockaddr_in *, next->ai_addr) 207 ->sin_addr), 208 (size_t)(*host)->h_length); 209 } 210 i++; 211 } 212 } 213 214 if (naddrs + eaddrs == 0 && naliases + ealiases == 0) { 215 ares_free_hostent(*host); 216 *host = NULL; 217 return ARES_ENODATA; 218 } 219 220 return ARES_SUCCESS; 221 222 /* LCOV_EXCL_START: OutOfMemory */ 223 enomem: 224 ares_free_hostent(*host); 225 *host = NULL; 226 return ARES_ENOMEM; 227 /* LCOV_EXCL_STOP */ 228 } 229 230 ares_status_t ares_addrinfo2addrttl(const struct ares_addrinfo *ai, int family, 231 size_t req_naddrttls, 232 struct ares_addrttl *addrttls, 233 struct ares_addr6ttl *addr6ttls, 234 size_t *naddrttls) 235 { 236 struct ares_addrinfo_node *next; 237 struct ares_addrinfo_cname *next_cname; 238 int cname_ttl = INT_MAX; 239 240 if (family != AF_INET && family != AF_INET6) { 241 return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ 242 } 243 244 if (ai == NULL || naddrttls == NULL) { 245 return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ 246 } 247 248 if (family == AF_INET && addrttls == NULL) { 249 return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ 250 } 251 252 if (family == AF_INET6 && addr6ttls == NULL) { 253 return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ 254 } 255 256 if (req_naddrttls == 0) { 257 return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */ 258 } 259 260 *naddrttls = 0; 261 262 next_cname = ai->cnames; 263 while (next_cname) { 264 if (next_cname->ttl < cname_ttl) { 265 cname_ttl = next_cname->ttl; 266 } 267 next_cname = next_cname->next; 268 } 269 270 for (next = ai->nodes; next != NULL; next = next->ai_next) { 271 if (next->ai_family != family) { 272 continue; 273 } 274 275 if (*naddrttls >= req_naddrttls) { 276 break; 277 } 278 279 if (family == AF_INET6) { 280 if (next->ai_ttl > cname_ttl) { 281 addr6ttls[*naddrttls].ttl = cname_ttl; 282 } else { 283 addr6ttls[*naddrttls].ttl = next->ai_ttl; 284 } 285 286 memcpy(&addr6ttls[*naddrttls].ip6addr, 287 &(CARES_INADDR_CAST(const struct sockaddr_in6 *, next->ai_addr) 288 ->sin6_addr), 289 sizeof(struct ares_in6_addr)); 290 } else { 291 if (next->ai_ttl > cname_ttl) { 292 addrttls[*naddrttls].ttl = cname_ttl; 293 } else { 294 addrttls[*naddrttls].ttl = next->ai_ttl; 295 } 296 memcpy(&addrttls[*naddrttls].ipaddr, 297 &(CARES_INADDR_CAST(const struct sockaddr_in *, next->ai_addr) 298 ->sin_addr), 299 sizeof(struct in_addr)); 300 } 301 (*naddrttls)++; 302 } 303 304 return ARES_SUCCESS; 305 }