/src/c-ares/src/lib/ares_parse_into_addrinfo.c
Line | Count | Source |
1 | | /* MIT License |
2 | | * |
3 | | * Copyright (c) 2019 Andrew Selivanov |
4 | | * Copyright (c) 2023 Brad House |
5 | | * |
6 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | | * of this software and associated documentation files (the "Software"), to deal |
8 | | * in the Software without restriction, including without limitation the rights |
9 | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
10 | | * copies of the Software, and to permit persons to whom the Software is |
11 | | * furnished to do so, subject to the following conditions: |
12 | | * |
13 | | * The above copyright notice and this permission notice (including the next |
14 | | * paragraph) shall be included in all copies or substantial portions of the |
15 | | * Software. |
16 | | * |
17 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
20 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
22 | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
23 | | * SOFTWARE. |
24 | | * |
25 | | * SPDX-License-Identifier: MIT |
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 | | #ifdef HAVE_STRINGS_H |
40 | | # include <strings.h> |
41 | | #endif |
42 | | |
43 | | #ifdef HAVE_LIMITS_H |
44 | | # include <limits.h> |
45 | | #endif |
46 | | |
47 | | |
48 | | ares_status_t ares_parse_into_addrinfo(const ares_dns_record_t *dnsrec, |
49 | | ares_bool_t cname_only_is_enodata, |
50 | | unsigned short port, |
51 | | struct ares_addrinfo *ai) |
52 | 0 | { |
53 | 0 | ares_status_t status; |
54 | 0 | size_t i; |
55 | 0 | size_t ancount; |
56 | 0 | const char *hostname = NULL; |
57 | 0 | ares_bool_t got_a = ARES_FALSE; |
58 | 0 | ares_bool_t got_aaaa = ARES_FALSE; |
59 | 0 | ares_bool_t got_cname = ARES_FALSE; |
60 | 0 | struct ares_addrinfo_cname *cnames = NULL; |
61 | 0 | struct ares_addrinfo_node *nodes = NULL; |
62 | | |
63 | | /* Save question hostname */ |
64 | 0 | status = ares_dns_record_query_get(dnsrec, 0, &hostname, NULL, NULL); |
65 | 0 | if (status != ARES_SUCCESS) { |
66 | 0 | goto done; /* LCOV_EXCL_LINE: DefensiveCoding */ |
67 | 0 | } |
68 | | |
69 | 0 | ancount = ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); |
70 | 0 | if (ancount == 0) { |
71 | 0 | status = ARES_ENODATA; |
72 | 0 | goto done; |
73 | 0 | } |
74 | | |
75 | 0 | for (i = 0; i < ancount; i++) { |
76 | 0 | ares_dns_rec_type_t rtype; |
77 | 0 | const ares_dns_rr_t *rr = |
78 | 0 | ares_dns_record_rr_get_const(dnsrec, ARES_SECTION_ANSWER, i); |
79 | |
|
80 | 0 | if (ares_dns_rr_get_class(rr) != ARES_CLASS_IN) { |
81 | 0 | continue; |
82 | 0 | } |
83 | | |
84 | 0 | rtype = ares_dns_rr_get_type(rr); |
85 | | |
86 | | /* Issue #683 |
87 | | * Old code did this hostname sanity check, however it appears this is |
88 | | * flawed logic. Other resolvers don't do this sanity check. Leaving |
89 | | * this code commented out for future reference. |
90 | | * |
91 | | * rname = ares_dns_rr_get_name(rr); |
92 | | * if ((rtype == ARES_REC_TYPE_A || rtype == ARES_REC_TYPE_AAAA) && |
93 | | * !ares_strcaseeq(rname, hostname)) { |
94 | | * continue; |
95 | | * } |
96 | | */ |
97 | |
|
98 | 0 | if (rtype == ARES_REC_TYPE_CNAME) { |
99 | 0 | struct ares_addrinfo_cname *cname; |
100 | |
|
101 | 0 | got_cname = ARES_TRUE; |
102 | | /* replace hostname with data from cname */ |
103 | 0 | hostname = ares_dns_rr_get_str(rr, ARES_RR_CNAME_CNAME); |
104 | |
|
105 | 0 | cname = ares_append_addrinfo_cname(&cnames); |
106 | 0 | if (cname == NULL) { |
107 | 0 | status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ |
108 | 0 | goto done; /* LCOV_EXCL_LINE: OutOfMemory */ |
109 | 0 | } |
110 | 0 | cname->ttl = (int)ares_dns_rr_get_ttl(rr); |
111 | 0 | cname->alias = ares_strdup(ares_dns_rr_get_name(rr)); |
112 | 0 | if (cname->alias == NULL) { |
113 | 0 | status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ |
114 | 0 | goto done; /* LCOV_EXCL_LINE: OutOfMemory */ |
115 | 0 | } |
116 | 0 | cname->name = ares_strdup(hostname); |
117 | 0 | if (cname->name == NULL) { |
118 | 0 | status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ |
119 | 0 | goto done; /* LCOV_EXCL_LINE: OutOfMemory */ |
120 | 0 | } |
121 | 0 | } else if (rtype == ARES_REC_TYPE_A) { |
122 | 0 | got_a = ARES_TRUE; |
123 | 0 | status = |
124 | 0 | ares_append_ai_node(AF_INET, port, ares_dns_rr_get_ttl(rr), |
125 | 0 | ares_dns_rr_get_addr(rr, ARES_RR_A_ADDR), &nodes); |
126 | 0 | if (status != ARES_SUCCESS) { |
127 | 0 | goto done; /* LCOV_EXCL_LINE: OutOfMemory */ |
128 | 0 | } |
129 | 0 | } else if (rtype == ARES_REC_TYPE_AAAA) { |
130 | 0 | got_aaaa = ARES_TRUE; |
131 | 0 | status = ares_append_ai_node(AF_INET6, port, ares_dns_rr_get_ttl(rr), |
132 | 0 | ares_dns_rr_get_addr6(rr, ARES_RR_AAAA_ADDR), |
133 | 0 | &nodes); |
134 | 0 | if (status != ARES_SUCCESS) { |
135 | 0 | goto done; /* LCOV_EXCL_LINE: OutOfMemory */ |
136 | 0 | } |
137 | 0 | } else { |
138 | 0 | continue; |
139 | 0 | } |
140 | 0 | } |
141 | | |
142 | 0 | if (!got_a && !got_aaaa && |
143 | 0 | (!got_cname || (got_cname && cname_only_is_enodata))) { |
144 | 0 | status = ARES_ENODATA; |
145 | 0 | goto done; |
146 | 0 | } |
147 | | |
148 | | /* save the hostname as ai->name */ |
149 | 0 | if (ai->name == NULL || !ares_strcaseeq(ai->name, hostname)) { |
150 | 0 | ares_free(ai->name); |
151 | 0 | ai->name = ares_strdup(hostname); |
152 | 0 | if (ai->name == NULL) { |
153 | 0 | status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ |
154 | 0 | goto done; /* LCOV_EXCL_LINE: OutOfMemory */ |
155 | 0 | } |
156 | 0 | } |
157 | | |
158 | 0 | if (got_a || got_aaaa) { |
159 | 0 | ares_addrinfo_cat_nodes(&ai->nodes, nodes); |
160 | 0 | nodes = NULL; |
161 | 0 | } |
162 | |
|
163 | 0 | if (got_cname) { |
164 | 0 | ares_addrinfo_cat_cnames(&ai->cnames, cnames); |
165 | 0 | cnames = NULL; |
166 | 0 | } |
167 | |
|
168 | 0 | done: |
169 | 0 | ares_freeaddrinfo_cnames(cnames); |
170 | 0 | ares_freeaddrinfo_nodes(nodes); |
171 | | |
172 | | /* compatibility */ |
173 | 0 | if (status == ARES_EBADNAME) { |
174 | 0 | status = ARES_EBADRESP; |
175 | 0 | } |
176 | |
|
177 | 0 | return status; |
178 | 0 | } |