ares_parse_ns_reply.c (4682B)
1 /* MIT License 2 * 3 * Copyright (c) 2023 Brad House 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and associated documentation files (the "Software"), to deal 7 * in the Software without restriction, including without limitation the rights 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 * copies of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 * SPDX-License-Identifier: MIT 25 */ 26 27 #include "ares_private.h" 28 29 #ifdef HAVE_NETINET_IN_H 30 # include <netinet/in.h> 31 #endif 32 #ifdef HAVE_NETDB_H 33 # include <netdb.h> 34 #endif 35 #ifdef HAVE_ARPA_INET_H 36 # include <arpa/inet.h> 37 #endif 38 39 int ares_parse_ns_reply(const unsigned char *abuf, int alen_int, 40 struct hostent **host) 41 { 42 ares_status_t status; 43 size_t alen; 44 size_t nscount = 0; 45 struct hostent *hostent = NULL; 46 const char *hostname = NULL; 47 ares_dns_record_t *dnsrec = NULL; 48 size_t i; 49 size_t ancount; 50 51 *host = NULL; 52 53 if (alen_int < 0) { 54 return ARES_EBADRESP; 55 } 56 57 alen = (size_t)alen_int; 58 59 status = ares_dns_parse(abuf, alen, 0, &dnsrec); 60 if (status != ARES_SUCCESS) { 61 goto done; 62 } 63 64 ancount = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); 65 if (ancount == 0) { 66 status = ARES_ENODATA; 67 goto done; 68 } 69 70 /* Response structure */ 71 hostent = ares_malloc(sizeof(*hostent)); 72 if (hostent == NULL) { 73 status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ 74 goto done; /* LCOV_EXCL_LINE: OutOfMemory */ 75 } 76 77 memset(hostent, 0, sizeof(*hostent)); 78 79 hostent->h_addr_list = ares_malloc(sizeof(*hostent->h_addr_list)); 80 if (hostent->h_addr_list == NULL) { 81 status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ 82 goto done; /* LCOV_EXCL_LINE: OutOfMemory */ 83 } 84 hostent->h_addr_list[0] = NULL; 85 hostent->h_addrtype = AF_INET; 86 hostent->h_length = sizeof(struct in_addr); 87 88 /* Fill in hostname */ 89 status = ares_dns_record_query_get(dnsrec, 0, &hostname, NULL, NULL); 90 if (status != ARES_SUCCESS) { 91 goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ 92 } 93 hostent->h_name = ares_strdup(hostname); 94 if (hostent->h_name == NULL) { 95 status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ 96 goto done; /* LCOV_EXCL_LINE: OutOfMemory */ 97 } 98 99 /* Preallocate the maximum number + 1 */ 100 hostent->h_aliases = ares_malloc((ancount + 1) * sizeof(*hostent->h_aliases)); 101 if (hostent->h_aliases == NULL) { 102 status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ 103 goto done; /* LCOV_EXCL_LINE: OutOfMemory */ 104 } 105 memset(hostent->h_aliases, 0, (ancount + 1) * sizeof(*hostent->h_aliases)); 106 107 for (i = 0; i < ancount; i++) { 108 const ares_dns_rr_t *rr = 109 ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, i); 110 111 if (rr == NULL) { 112 /* Shouldn't be possible */ 113 status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ 114 goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ 115 } 116 117 if (ares_dns_rr_get_class(rr) != ARES_CLASS_IN || 118 ares_dns_rr_get_type(rr) != ARES_REC_TYPE_NS) { 119 continue; 120 } 121 122 hostname = ares_dns_rr_get_str(rr, ARES_RR_NS_NSDNAME); 123 if (hostname == NULL) { 124 status = ARES_EBADRESP; /* LCOV_EXCL_LINE: DefensiveCoding */ 125 goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ 126 } 127 128 hostent->h_aliases[nscount] = ares_strdup(hostname); 129 if (hostent->h_aliases[nscount] == NULL) { 130 status = ARES_ENOMEM; 131 goto done; 132 } 133 nscount++; 134 } 135 136 if (nscount == 0) { 137 status = ARES_ENODATA; 138 } else { 139 status = ARES_SUCCESS; 140 } 141 142 done: 143 if (status != ARES_SUCCESS) { 144 ares_free_hostent(hostent); 145 /* Compatibility */ 146 if (status == ARES_EBADNAME) { 147 status = ARES_EBADRESP; 148 } 149 } else { 150 *host = hostent; 151 } 152 ares_dns_record_destroy(dnsrec); 153 return (int)status; 154 }