1 /* MIT License
2 *
3 * Copyright (c) The c-ares project and its contributors
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 #include "ares-test.h"
27 #include "dns-proto.h"
28
29 #include <sstream>
30 #include <vector>
31
32 namespace ares {
33 namespace test {
34
TEST_F(LibraryTest,ParsePtrReplyOK)35 TEST_F(LibraryTest, ParsePtrReplyOK) {
36 byte addrv4[4] = {0x10, 0x20, 0x30, 0x40};
37 DNSPacket pkt;
38 pkt.set_qid(0x1234).set_response().set_aa()
39 .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", T_PTR))
40 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other.com"));
41 std::vector<byte> data = pkt.data();
42
43 struct hostent *host = nullptr;
44 EXPECT_EQ(ARES_SUCCESS, ares_parse_ptr_reply(data.data(), (int)data.size(),
45 addrv4, sizeof(addrv4), AF_INET, &host));
46 ASSERT_NE(nullptr, host);
47 std::stringstream ss;
48 ss << HostEnt(host);
49 EXPECT_EQ("{'other.com' aliases=[other.com] addrs=[16.32.48.64]}", ss.str());
50 ares_free_hostent(host);
51 }
52
TEST_F(LibraryTest,ParsePtrReplyCname)53 TEST_F(LibraryTest, ParsePtrReplyCname) {
54 byte addrv4[4] = {0x10, 0x20, 0x30, 0x40};
55 DNSPacket pkt;
56 pkt.set_qid(0x1234).set_response().set_aa()
57 .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", T_PTR))
58 .add_answer(new DNSCnameRR("64.48.32.16.in-addr.arpa", 50, "64.48.32.8.in-addr.arpa"))
59 .add_answer(new DNSPtrRR("64.48.32.8.in-addr.arpa", 100, "other.com"));
60 std::vector<byte> data = pkt.data();
61
62 struct hostent *host = nullptr;
63 EXPECT_EQ(ARES_SUCCESS, ares_parse_ptr_reply(data.data(), (int)data.size(),
64 addrv4, sizeof(addrv4), AF_INET, &host));
65 ASSERT_NE(nullptr, host);
66 std::stringstream ss;
67 ss << HostEnt(host);
68 EXPECT_EQ("{'other.com' aliases=[other.com] addrs=[16.32.48.64]}", ss.str());
69 ares_free_hostent(host);
70 }
71
72
73 struct DNSMalformedCnameRR : public DNSCnameRR {
DNSMalformedCnameRRares::test::DNSMalformedCnameRR74 DNSMalformedCnameRR(const std::string& name, int ttl, const std::string& other)
75 : DNSCnameRR(name, ttl, other) {}
dataares::test::DNSMalformedCnameRR76 std::vector<byte> data(const ares_dns_record_t *dnsrec) const {
77 std::vector<byte> data = DNSRR::data(dnsrec);
78 std::vector<byte> encname = EncodeString(other_);
79 encname[0] = encname[0] + 63; // invalid label length
80 int len = (int)encname.size();
81 PushInt16(&data, len);
82 data.insert(data.end(), encname.begin(), encname.end());
83 return data;
84 }
85 };
86
TEST_F(LibraryTest,ParsePtrReplyMalformedCname)87 TEST_F(LibraryTest, ParsePtrReplyMalformedCname) {
88 byte addrv4[4] = {0x10, 0x20, 0x30, 0x40};
89 DNSPacket pkt;
90 pkt.set_qid(0x1234).set_response().set_aa()
91 .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", T_PTR))
92 .add_answer(new DNSMalformedCnameRR("64.48.32.16.in-addr.arpa", 50, "64.48.32.8.in-addr.arpa"))
93 .add_answer(new DNSPtrRR("64.48.32.8.in-addr.arpa", 100, "other.com"));
94 std::vector<byte> data = pkt.data();
95
96 struct hostent *host = nullptr;
97 EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), (int)data.size(),
98 addrv4, sizeof(addrv4), AF_INET, &host));
99 ASSERT_EQ(nullptr, host);
100 }
101
TEST_F(LibraryTest,ParseManyPtrReply)102 TEST_F(LibraryTest, ParseManyPtrReply) {
103 byte addrv4[4] = {0x10, 0x20, 0x30, 0x40};
104 DNSPacket pkt;
105 pkt.set_qid(0x1234).set_response().set_aa()
106 .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", T_PTR))
107 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "main.com"))
108 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other1.com"))
109 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other2.com"))
110 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other3.com"))
111 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other4.com"))
112 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other5.com"))
113 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other6.com"))
114 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other7.com"))
115 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other8.com"))
116 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other9.com"));
117 std::vector<byte> data = pkt.data();
118
119 struct hostent *host = nullptr;
120 EXPECT_EQ(ARES_SUCCESS, ares_parse_ptr_reply(data.data(), (int)data.size(),
121 addrv4, sizeof(addrv4), AF_INET, &host));
122 ASSERT_NE(nullptr, host);
123 ares_free_hostent(host);
124 }
125
TEST_F(LibraryTest,ParsePtrReplyAdditional)126 TEST_F(LibraryTest, ParsePtrReplyAdditional) {
127 byte addrv4[4] = {0x10, 0x20, 0x30, 0x40};
128 DNSPacket pkt;
129 pkt.set_qid(0x1234).set_response().set_aa()
130 .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", T_PTR))
131 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 55, "other.com"))
132 .add_auth(new DNSNsRR("16.in-addr.arpa", 234, "ns1.other.com"))
133 .add_auth(new DNSNsRR("16.in-addr.arpa", 234, "bb.ns2.other.com"))
134 .add_auth(new DNSNsRR("16.in-addr.arpa", 234, "ns3.other.com"))
135 .add_additional(new DNSARR("ns1.other.com", 229, {10,20,30,41}))
136 .add_additional(new DNSARR("bb.ns2.other.com", 229, {10,20,30,42}))
137 .add_additional(new DNSARR("ns3.other.com", 229, {10,20,30,43}));
138 std::vector<byte> data = pkt.data();
139
140 struct hostent *host = nullptr;
141 EXPECT_EQ(ARES_SUCCESS, ares_parse_ptr_reply(data.data(), (int)data.size(),
142 addrv4, sizeof(addrv4), AF_INET, &host));
143 ASSERT_NE(nullptr, host);
144 std::stringstream ss;
145 ss << HostEnt(host);
146 EXPECT_EQ("{'other.com' aliases=[other.com] addrs=[16.32.48.64]}", ss.str());
147 ares_free_hostent(host);
148 }
149
TEST_F(LibraryTest,ParsePtrReplyErrors)150 TEST_F(LibraryTest, ParsePtrReplyErrors) {
151 byte addrv4[4] = {0x10, 0x20, 0x30, 0x40};
152 DNSPacket pkt;
153 pkt.set_qid(0x1234).set_response().set_aa()
154 .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", T_PTR))
155 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other.com"));
156 std::vector<byte> data;
157 struct hostent *host = nullptr;
158
159 // No question.
160 pkt.questions_.clear();
161 data = pkt.data();
162 EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), (int)data.size(),
163 addrv4, sizeof(addrv4), AF_INET, &host));
164 pkt.add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", T_PTR));
165
166 // Question != answer, ok after #683
167 host = nullptr;
168 pkt.questions_.clear();
169 pkt.add_question(new DNSQuestion("99.48.32.16.in-addr.arpa", T_PTR));
170 data = pkt.data();
171 EXPECT_EQ(ARES_SUCCESS, ares_parse_ptr_reply(data.data(), (int)data.size(),
172 addrv4, sizeof(addrv4), AF_INET, &host));
173 ASSERT_NE(nullptr, host);
174 std::stringstream ss;
175 ss << HostEnt(host);
176 EXPECT_EQ("{'other.com' aliases=[other.com] addrs=[16.32.48.64]}", ss.str());
177 ares_free_hostent(host);
178
179 host = nullptr;
180 pkt.questions_.clear();
181 pkt.add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", T_PTR));
182
183 // Two questions.
184 pkt.add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", T_PTR));
185 data = pkt.data();
186 EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), (int)data.size(),
187 addrv4, sizeof(addrv4), AF_INET, &host));
188 EXPECT_EQ(nullptr, host);
189 pkt.questions_.clear();
190 pkt.add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", T_PTR));
191
192 // Wrong sort of answer.
193 pkt.answers_.clear();
194 pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com"));
195 data = pkt.data();
196 EXPECT_EQ(ARES_ENODATA, ares_parse_ptr_reply(data.data(), (int)data.size(),
197 addrv4, sizeof(addrv4), AF_INET, &host));
198 EXPECT_EQ(nullptr, host);
199 pkt.answers_.clear();
200 pkt.add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other.com"));
201
202 // No answer.
203 pkt.answers_.clear();
204 data = pkt.data();
205 EXPECT_EQ(ARES_ENODATA, ares_parse_ptr_reply(data.data(), (int)data.size(),
206 addrv4, sizeof(addrv4), AF_INET, &host));
207 EXPECT_EQ(nullptr, host);
208 pkt.add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other.com"));
209
210 // Truncated packets.
211 data = pkt.data();
212 for (size_t len = 1; len < data.size(); len++) {
213 EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), (int)len,
214 addrv4, sizeof(addrv4), AF_INET, &host));
215 EXPECT_EQ(nullptr, host);
216 }
217
218 // Truncated packets with CNAME.
219 pkt.add_answer(new DNSCnameRR("64.48.32.16.in-addr.arpa", 50, "64.48.32.8.in-addr.arpa"));
220 data = pkt.data();
221 for (size_t len = 1; len < data.size(); len++) {
222 EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), (int)len,
223 addrv4, sizeof(addrv4), AF_INET, &host));
224 EXPECT_EQ(nullptr, host);
225 }
226
227 // Negative Length
228 EXPECT_EQ(ARES_EBADRESP, ares_parse_ptr_reply(data.data(), -1,
229 addrv4, sizeof(addrv4), AF_INET, &host));
230 }
231
TEST_F(LibraryTest,ParsePtrReplyAllocFailSome)232 TEST_F(LibraryTest, ParsePtrReplyAllocFailSome) {
233 byte addrv4[4] = {0x10, 0x20, 0x30, 0x40};
234 DNSPacket pkt;
235 pkt.set_qid(0x1234).set_response().set_aa()
236 .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", T_PTR))
237 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "main.com"))
238 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other1.com"))
239 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other2.com"))
240 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other3.com"));
241 std::vector<byte> data = pkt.data();
242 struct hostent *host = nullptr;
243
244 for (int ii = 1; ii <= 18; ii++) {
245 ClearFails();
246 SetAllocFail(ii);
247 EXPECT_EQ(ARES_ENOMEM, ares_parse_ptr_reply(data.data(), (int)data.size(),
248 addrv4, sizeof(addrv4), AF_INET, &host)) << ii;
249 }
250 }
251
TEST_F(LibraryTest,ParsePtrReplyAllocFailMany)252 TEST_F(LibraryTest, ParsePtrReplyAllocFailMany) {
253 byte addrv4[4] = {0x10, 0x20, 0x30, 0x40};
254 DNSPacket pkt;
255 pkt.set_qid(0x1234).set_response().set_aa()
256 .add_question(new DNSQuestion("64.48.32.16.in-addr.arpa", T_PTR))
257 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "main.com"))
258 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other1.com"))
259 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other2.com"))
260 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other3.com"))
261 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other4.com"))
262 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other5.com"))
263 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other6.com"))
264 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other7.com"))
265 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other8.com"))
266 .add_answer(new DNSPtrRR("64.48.32.16.in-addr.arpa", 100, "other9.com"));
267 std::vector<byte> data = pkt.data();
268 struct hostent *host = nullptr;
269
270 for (int ii = 1; ii <= 63; ii++) {
271 ClearFails();
272 SetAllocFail(ii);
273 int rc = ares_parse_ptr_reply(data.data(), (int)data.size(),
274 addrv4, sizeof(addrv4), AF_INET, &host);
275 if (rc != ARES_ENOMEM) {
276 EXPECT_EQ(ARES_SUCCESS, rc);
277 ares_free_hostent(host);
278 host = nullptr;
279 }
280 }
281 }
282
283
284 } // namespace test
285 } // namespace ares
286