ares-test-parse-txt.cc (11548B)
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 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 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 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 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 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 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 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 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 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