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,ParseTxtReplyOK)35 TEST_F(LibraryTest, ParseTxtReplyOK) {
36 DNSPacket pkt;
37 std::string expected1 = "txt1.example.com";
38 std::string expected2a = "txt2a";
39 std::string expected2b("ABC\0ABC", 7);
40 pkt.set_qid(0x1234).set_response().set_aa()
41 .add_question(new DNSQuestion("example.com", T_TXT))
42 .add_answer(new DNSTxtRR("example.com", 100, {expected1}))
43 .add_answer(new DNSTxtRR("example.com", 100, {expected2a, expected2b}));
44 std::vector<byte> data = pkt.data();
45
46 struct ares_txt_reply* txt = nullptr;
47 EXPECT_EQ(ARES_SUCCESS, ares_parse_txt_reply(data.data(), (int)data.size(), &txt));
48 ASSERT_NE(nullptr, txt);
49 EXPECT_EQ(std::vector<byte>(expected1.data(), expected1.data() + expected1.size()),
50 std::vector<byte>(txt->txt, txt->txt + txt->length));
51
52 struct ares_txt_reply* txt2 = txt->next;
53 ASSERT_NE(nullptr, txt2);
54 EXPECT_EQ(std::vector<byte>(expected2a.data(), expected2a.data() + expected2a.size()),
55 std::vector<byte>(txt2->txt, txt2->txt + txt2->length));
56
57 struct ares_txt_reply* txt3 = txt2->next;
58 ASSERT_NE(nullptr, txt3);
59 EXPECT_EQ(std::vector<byte>(expected2b.data(), expected2b.data() + expected2b.size()),
60 std::vector<byte>(txt3->txt, txt3->txt + txt3->length));
61 EXPECT_EQ(nullptr, txt3->next);
62 ares_free_data(txt);
63 }
64
TEST_F(LibraryTest,ParseTxtExtReplyOK)65 TEST_F(LibraryTest, ParseTxtExtReplyOK) {
66 DNSPacket pkt;
67 std::string expected1 = "txt1.example.com";
68 std::string expected2a = "txt2a";
69 std::string expected2b("ABC\0ABC", 7);
70 pkt.set_qid(0x1234).set_response().set_aa()
71 .add_question(new DNSQuestion("example.com", T_TXT))
72 .add_answer(new DNSTxtRR("example.com", 100, {expected1}))
73 .add_answer(new DNSTxtRR("example.com", 100, {expected2a, expected2b}));
74 std::vector<byte> data = pkt.data();
75
76 struct ares_txt_ext* txt = nullptr;
77 EXPECT_EQ(ARES_SUCCESS, ares_parse_txt_reply_ext(data.data(), (int)data.size(), &txt));
78 ASSERT_NE(nullptr, txt);
79 EXPECT_EQ(std::vector<byte>(expected1.data(), expected1.data() + expected1.size()),
80 std::vector<byte>(txt->txt, txt->txt + txt->length));
81 EXPECT_EQ(1, txt->record_start);
82
83 struct ares_txt_ext* txt2 = txt->next;
84 ASSERT_NE(nullptr, txt2);
85 EXPECT_EQ(std::vector<byte>(expected2a.data(), expected2a.data() + expected2a.size()),
86 std::vector<byte>(txt2->txt, txt2->txt + txt2->length));
87 EXPECT_EQ(1, txt2->record_start);
88
89 struct ares_txt_ext* txt3 = txt2->next;
90 ASSERT_NE(nullptr, txt3);
91 EXPECT_EQ(std::vector<byte>(expected2b.data(), expected2b.data() + expected2b.size()),
92 std::vector<byte>(txt3->txt, txt3->txt + txt3->length));
93 EXPECT_EQ(nullptr, txt3->next);
94 EXPECT_EQ(0, txt3->record_start);
95 ares_free_data(txt);
96 }
97
TEST_F(LibraryTest,ParseTxtEmpty)98 TEST_F(LibraryTest, ParseTxtEmpty) {
99 DNSPacket pkt;
100 std::string expected1 = "";
101 pkt.set_qid(0x1234).set_response().set_aa()
102 .add_question(new DNSQuestion("example.com", T_TXT))
103 .add_answer(new DNSTxtRR("example.com", 100, {expected1}));
104 std::vector<byte> data = pkt.data();
105
106 ares_dns_record_t *dnsrec = NULL;
107 ares_dns_rr_t *rr = NULL;
108 EXPECT_EQ(ARES_SUCCESS, ares_dns_parse(data.data(), data.size(), 0, &dnsrec));
109 EXPECT_EQ(1, ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER));
110 rr = ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, 0);
111 ASSERT_NE(nullptr, rr);
112 EXPECT_EQ(ARES_REC_TYPE_TXT, ares_dns_rr_get_type(rr));
113
114 size_t txtdata_len;
115 const unsigned char *txtdata;
116
117 /* Using array methodology */
118 EXPECT_EQ(1, ares_dns_rr_get_abin_cnt(rr, ARES_RR_TXT_DATA));
119 txtdata = ares_dns_rr_get_abin(rr, ARES_RR_TXT_DATA, 0, &txtdata_len);
120 EXPECT_EQ(txtdata_len, 0);
121 EXPECT_NE(nullptr, txtdata);
122
123 /* Using combined methodology */
124 txtdata = ares_dns_rr_get_bin(rr, ARES_RR_TXT_DATA, &txtdata_len);
125 EXPECT_EQ(txtdata_len, 0);
126 EXPECT_NE(nullptr, txtdata);
127
128 ares_dns_record_destroy(dnsrec); dnsrec = NULL;
129 }
130
TEST_F(LibraryTest,ParseTxtMalformedReply1)131 TEST_F(LibraryTest, ParseTxtMalformedReply1) {
132 std::vector<byte> data = {
133 0x12, 0x34, // qid
134 0x84, // response + query + AA + not-TC + not-RD
135 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError
136 0x00, 0x01, // num questions
137 0x00, 0x01, // num answer RRs
138 0x00, 0x00, // num authority RRs
139 0x00, 0x00, // num additional RRs
140 // Question
141 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e',
142 0x03, 'c', 'o', 'm',
143 0x00,
144 0x00, 0x10, // type TXT
145 0x00, 0x01, // class IN
146 // Answer 1
147 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e',
148 0x03, 'c', 'o', 'm',
149 0x00,
150 0x00, 0x10, // RR type
151 0x00, 0x01, // class IN
152 0x01, 0x02, 0x03, 0x04, // TTL
153 0x00, 0x03, // rdata length
154 0x12, 'a', 'b', // invalid length
155 };
156
157 struct ares_txt_reply* txt = nullptr;
158 EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), (int)data.size(), &txt));
159 ASSERT_EQ(nullptr, txt);
160 }
161
TEST_F(LibraryTest,ParseTxtMalformedReply2)162 TEST_F(LibraryTest, ParseTxtMalformedReply2) {
163 std::vector<byte> data = {
164 0x12, 0x34, // qid
165 0x84, // response + query + AA + not-TC + not-RD
166 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError
167 0x00, 0x01, // num questions
168 0x00, 0x01, // num answer RRs
169 0x00, 0x00, // num authority RRs
170 0x00, 0x00, // num additional RRs
171 // Question
172 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e',
173 0x03, 'c', 'o', 'm',
174 0x00,
175 0x00, 0x10, // type TXT
176 0x00, 0x01, // class IN
177 // Answer 1
178 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e',
179 0x03, 'c', 'o', 'm',
180 0x00,
181 0x00, 0x10, // RR type
182 // truncated
183 };
184
185 struct ares_txt_reply* txt = nullptr;
186 EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), (int)data.size(), &txt));
187 ASSERT_EQ(nullptr, txt);
188 }
189
TEST_F(LibraryTest,ParseTxtMalformedReply3)190 TEST_F(LibraryTest, ParseTxtMalformedReply3) {
191 std::vector<byte> data = {
192 0x12, 0x34, // qid
193 0x84, // response + query + AA + not-TC + not-RD
194 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError
195 0x00, 0x01, // num questions
196 0x00, 0x01, // num answer RRs
197 0x00, 0x00, // num authority RRs
198 0x00, 0x00, // num additional RRs
199 // Question
200 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e',
201 0x03, 'c', 'o', 'm',
202 0x00,
203 0x00, 0x10, // type TXT
204 0x00, 0x01, // class IN
205 // Answer 1
206 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e',
207 0x03, 'c', 'o', 'm',
208 0x00,
209 0x00, 0x10, // RR type
210 0x00, 0x01, // class IN
211 0x01, 0x02, 0x03, 0x04, // TTL
212 0x00, 0x13, // rdata length INVALID
213 0x02, 'a', 'b',
214 };
215
216 struct ares_txt_reply* txt = nullptr;
217 EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), (int)data.size(), &txt));
218 ASSERT_EQ(nullptr, txt);
219 }
220
TEST_F(LibraryTest,ParseTxtMalformedReply4)221 TEST_F(LibraryTest, ParseTxtMalformedReply4) {
222 std::vector<byte> data = {
223 0x12, 0x34, // qid
224 0x84, // response + query + AA + not-TC + not-RD
225 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError
226 0x00, 0x01, // num questions
227 0x00, 0x01, // num answer RRs
228 0x00, 0x00, // num authority RRs
229 0x00, 0x00, // num additional RRs
230 // Question
231 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e',
232 0x03, 'c', 'o', 'm',
233 0x00,
234 0x00, 0x10, // type TXT
235 0x00, // TRUNCATED
236 };
237
238 struct ares_txt_reply* txt = nullptr;
239 EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), (int)data.size(), &txt));
240 ASSERT_EQ(nullptr, txt);
241 }
242
TEST_F(LibraryTest,ParseTxtReplyErrors)243 TEST_F(LibraryTest, ParseTxtReplyErrors) {
244 DNSPacket pkt;
245 std::string expected1 = "txt1.example.com";
246 std::string expected2a = "txt2a";
247 std::string expected2b = "txt2b";
248 pkt.set_qid(0x1234).set_response().set_aa()
249 .add_question(new DNSQuestion("example.com", T_TXT))
250 .add_answer(new DNSTxtRR("example.com", 100, {expected1}))
251 .add_answer(new DNSTxtRR("example.com", 100, {expected1}))
252 .add_answer(new DNSTxtRR("example.com", 100, {expected2a, expected2b}));
253 std::vector<byte> data = pkt.data();
254 struct ares_txt_reply* txt = nullptr;
255 struct ares_txt_ext* txt_ext = nullptr;
256
257 // No question.
258 pkt.questions_.clear();
259 data = pkt.data();
260 txt = nullptr;
261 EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), (int)data.size(), &txt));
262 EXPECT_EQ(nullptr, txt);
263 pkt.add_question(new DNSQuestion("example.com", T_TXT));
264
265 #ifdef DISABLED
266 // Question != answer
267 pkt.questions_.clear();
268 pkt.add_question(new DNSQuestion("Axample.com", T_TXT));
269 data = pkt.data();
270 EXPECT_EQ(ARES_ENODATA, ares_parse_txt_reply(data.data(), (int)data.size(), &txt));
271 pkt.questions_.clear();
272 pkt.add_question(new DNSQuestion("example.com", T_TXT));
273 #endif
274
275 // Two questions.
276 pkt.add_question(new DNSQuestion("example.com", T_TXT));
277 data = pkt.data();
278 txt = nullptr;
279 EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), (int)data.size(), &txt));
280 EXPECT_EQ(nullptr, txt);
281 pkt.questions_.clear();
282 pkt.add_question(new DNSQuestion("example.com", T_TXT));
283
284 // No answer.
285 pkt.answers_.clear();
286 data = pkt.data();
287 txt = nullptr;
288 EXPECT_EQ(ARES_ENODATA, ares_parse_txt_reply(data.data(), (int)data.size(), &txt));
289 EXPECT_EQ(nullptr, txt);
290 pkt.add_answer(new DNSTxtRR("example.com", 100, {expected1}));
291
292 // Truncated packets.
293 for (size_t len = 1; len < data.size(); len++) {
294 txt = nullptr;
295 EXPECT_NE(ARES_SUCCESS, ares_parse_txt_reply(data.data(), (int)len, &txt));
296 EXPECT_EQ(nullptr, txt);
297 }
298
299 // Negative Length
300 EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply(data.data(), -1, &txt));
301 EXPECT_EQ(ARES_EBADRESP, ares_parse_txt_reply_ext(data.data(), -1, &txt_ext));
302 }
303
TEST_F(LibraryTest,ParseTxtReplyAllocFail)304 TEST_F(LibraryTest, ParseTxtReplyAllocFail) {
305 DNSPacket pkt;
306 std::string expected1 = "txt1.example.com";
307 std::string expected2a = "txt2a";
308 std::string expected2b = "txt2b";
309 pkt.set_qid(0x1234).set_response().set_aa()
310 .add_question(new DNSQuestion("example.com", T_TXT))
311 .add_answer(new DNSCnameRR("example.com", 300, "c.example.com"))
312 .add_answer(new DNSTxtRR("c.example.com", 100, {expected1}))
313 .add_answer(new DNSTxtRR("c.example.com", 100, {expected1}))
314 .add_answer(new DNSTxtRR("c.example.com", 100, {expected2a, expected2b}));
315 std::vector<byte> data = pkt.data();
316 struct ares_txt_reply* txt = nullptr;
317
318 for (int ii = 1; ii <= 13; ii++) {
319 ClearFails();
320 SetAllocFail(ii);
321 EXPECT_EQ(ARES_ENOMEM, ares_parse_txt_reply(data.data(), (int)data.size(), &txt)) << ii;
322 }
323 }
324
325
326 } // namespace test
327 } // namespace ares
328