ares-test-parse-a.cc (14829B)
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, ParseAReplyOK) { 36 DNSPacket pkt; 37 pkt.set_qid(0x1234).set_response().set_aa() 38 .add_question(new DNSQuestion("example.com", T_A)) 39 .add_answer(new DNSARR("example.com", 0x01020304, {2,3,4,5})) 40 .add_answer(new DNSAaaaRR("example.com", 0x01020304, {0,0,0,0,0,0,0,0,0,0,0,0,2,3,4,5})); 41 std::vector<byte> data = { 42 0x12, 0x34, // qid 43 0x84, // response + query + AA + not-TC + not-RD 44 0x00, // not-RA + not-Z + not-AD + not-CD + rc=NoError 45 0x00, 0x01, // num questions 46 0x00, 0x02, // num answer RRs 47 0x00, 0x00, // num authority RRs 48 0x00, 0x00, // num additional RRs 49 // Question 50 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 51 0x03, 'c', 'o', 'm', 52 0x00, 53 0x00, 0x01, // type A 54 0x00, 0x01, // class IN 55 // Answer 1 56 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 57 0x03, 'c', 'o', 'm', 58 0x00, 59 0x00, 0x01, // RR type 60 0x00, 0x01, // class IN 61 0x01, 0x02, 0x03, 0x04, // TTL 62 0x00, 0x04, // rdata length 63 0x02, 0x03, 0x04, 0x05, 64 // Answer 2 65 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 66 0x03, 'c', 'o', 'm', 67 0x00, 68 0x00, 0x1c, // RR type 69 0x00, 0x01, // class IN 70 0x01, 0x02, 0x03, 0x04, // TTL 71 0x00, 0x10, // rdata length 72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x04, 0x05, 73 }; 74 EXPECT_EQ(data, pkt.data()); 75 struct hostent *host = nullptr; 76 struct ares_addrttl info[5]; 77 int count = 5; 78 EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), (int)data.size(), 79 &host, info, &count)); 80 EXPECT_EQ(1, count); 81 EXPECT_EQ(0x01020304, info[0].ttl); 82 unsigned long expected_addr = htonl(0x02030405); 83 EXPECT_EQ(expected_addr, info[0].ipaddr.s_addr); 84 EXPECT_EQ("2.3.4.5", AddressToString(&(info[0].ipaddr), 4)); 85 ASSERT_NE(nullptr, host); 86 std::stringstream ss; 87 ss << HostEnt(host); 88 EXPECT_EQ("{'example.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); 89 ares_free_hostent(host); 90 91 // Repeat without providing a hostent 92 EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), (int)data.size(), 93 nullptr, info, &count)); 94 EXPECT_EQ(1, count); 95 EXPECT_EQ(0x01020304, info[0].ttl); 96 EXPECT_EQ(expected_addr, info[0].ipaddr.s_addr); 97 EXPECT_EQ("2.3.4.5", AddressToString(&(info[0].ipaddr), 4)); 98 } 99 100 TEST_F(LibraryTest, ParseMalformedAReply) { 101 std::vector<byte> data = { 102 0x12, 0x34, // [0:2) qid 103 0x84, // [2] response + query + AA + not-TC + not-RD 104 0x00, // [3] not-RA + not-Z + not-AD + not-CD + rc=NoError 105 0x00, 0x01, // [4:6) num questions 106 0x00, 0x02, // [6:8) num answer RRs 107 0x00, 0x00, // [8:10) num authority RRs 108 0x00, 0x00, // [10:12) num additional RRs 109 // Question 110 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', // [12:20) 111 0x03, 'c', 'o', 'm', // [20,24) 112 0x00, // [24] 113 0x00, 0x01, // [25:26) type A 114 0x00, 0x01, // [27:29) class IN 115 // Answer 1 116 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', // [29:37) 117 0x03, 'c', 'o', 'm', // [37:41) 118 0x00, // [41] 119 0x00, 0x01, // [42:44) RR type 120 0x00, 0x01, // [44:46) class IN 121 0x01, 0x02, 0x03, 0x04, // [46:50) TTL 122 0x00, 0x04, // [50:52) rdata length 123 0x02, 0x03, 0x04, 0x05, // [52,56) 124 }; 125 struct hostent *host = nullptr; 126 struct ares_addrttl info[2]; 127 int count = 2; 128 129 // Invalid RR-len. 130 std::vector<byte> invalid_rrlen(data); 131 invalid_rrlen[51] = 180; 132 EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(invalid_rrlen.data(), (int)invalid_rrlen.size(), 133 &host, info, &count)); 134 135 // Truncate mid-question. 136 EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), 26, 137 &host, info, &count)); 138 139 // Truncate mid-answer. 140 EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), 42, 141 &host, info, &count)); 142 143 // Negative length 144 EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), -1, 145 &host, info, &count)); 146 } 147 148 TEST_F(LibraryTest, ParseAReplyNoData) { 149 DNSPacket pkt; 150 pkt.set_qid(0x1234).set_response().set_aa() 151 .add_question(new DNSQuestion("example.com", T_A)); 152 std::vector<byte> data = pkt.data(); 153 struct hostent *host = nullptr; 154 struct ares_addrttl info[2]; 155 int count = 2; 156 EXPECT_EQ(ARES_ENODATA, ares_parse_a_reply(data.data(), (int)data.size(), 157 &host, info, &count)); 158 EXPECT_EQ(0, count); 159 EXPECT_EQ(nullptr, host); 160 161 // Again but with a CNAME. 162 pkt.add_answer(new DNSCnameRR("example.com", 200, "c.example.com")); 163 data = pkt.data(); 164 // Expect success as per https://github.com/c-ares/c-ares/commit/2c63440127feed70ccefb148b8f938a2df6c15f8 165 EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), (int)data.size(), 166 &host, info, &count)); 167 EXPECT_EQ(0, count); 168 EXPECT_NE(nullptr, host); 169 std::stringstream ss; 170 ss << HostEnt(host); 171 EXPECT_EQ("{'c.example.com' aliases=[example.com] addrs=[]}", ss.str()); 172 ares_free_hostent(host); 173 } 174 175 TEST_F(LibraryTest, ParseAReplyVariantA) { 176 DNSPacket pkt; 177 pkt.set_qid(6366).set_rd().set_ra() 178 .add_question(new DNSQuestion("mit.edu", T_A)) 179 .add_answer(new DNSARR("mit.edu", 52, {18,7,22,69})) 180 .add_auth(new DNSNsRR("mit.edu", 292, "W20NS.mit.edu")) 181 .add_auth(new DNSNsRR("mit.edu", 292, "BITSY.mit.edu")) 182 .add_auth(new DNSNsRR("mit.edu", 292, "STRAWB.mit.edu")) 183 .add_additional(new DNSARR("STRAWB.mit.edu", 292, {18,71,0,151})); 184 struct hostent *host = nullptr; 185 struct ares_addrttl info[2]; 186 int count = 2; 187 std::vector<byte> data = pkt.data(); 188 EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), (int)data.size(), 189 &host, info, &count)); 190 EXPECT_EQ(1, count); 191 EXPECT_EQ("18.7.22.69", AddressToString(&(info[0].ipaddr), 4)); 192 EXPECT_EQ(52, info[0].ttl); 193 ares_free_hostent(host); 194 } 195 196 TEST_F(LibraryTest, ParseAReplyJustCname) { 197 DNSPacket pkt; 198 pkt.set_qid(6366).set_rd().set_ra() 199 .add_question(new DNSQuestion("mit.edu", T_A)) 200 .add_answer(new DNSCnameRR("mit.edu", 52, "other.mit.edu")); 201 struct hostent *host = nullptr; 202 struct ares_addrttl info[2]; 203 int count = 2; 204 std::vector<byte> data = pkt.data(); 205 EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), (int)data.size(), 206 &host, info, &count)); 207 EXPECT_EQ(0, count); 208 ASSERT_NE(nullptr, host); 209 std::stringstream ss; 210 ss << HostEnt(host); 211 EXPECT_EQ("{'other.mit.edu' aliases=[mit.edu] addrs=[]}", ss.str()); 212 ares_free_hostent(host); 213 } 214 215 TEST_F(LibraryTest, ParseAReplyVariantCname) { 216 DNSPacket pkt; 217 pkt.set_qid(6366).set_rd().set_ra() 218 .add_question(new DNSQuestion("query.example.com", T_A)) 219 .add_answer(new DNSCnameRR("query.example.com", 200, "redirect.query.example.com")) 220 .add_answer(new DNSARR("redirect.query.example.com", 300, {129,97,123,22})) 221 .add_auth(new DNSNsRR("example.com", 218, "aa.ns1.example.com")) 222 .add_auth(new DNSNsRR("example.com", 218, "ns2.example.com")) 223 .add_auth(new DNSNsRR("example.com", 218, "ns3.example.com")) 224 .add_auth(new DNSNsRR("example.com", 218, "ns4.example.com")) 225 .add_additional(new DNSARR("aa.ns1.example.com", 218, {129,97,1,1})) 226 .add_additional(new DNSARR("ns2.example.com", 218, {129,97,1,2})) 227 .add_additional(new DNSARR("ns3.example.com", 218, {129,97,1,3})) 228 .add_additional(new DNSARR("ns4.example.com", 218, {129,97,1,4})); 229 struct hostent *host = nullptr; 230 struct ares_addrttl info[2]; 231 int count = 2; 232 std::vector<byte> data = pkt.data(); 233 EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), (int)data.size(), 234 &host, info, &count)); 235 EXPECT_EQ(1, count); 236 EXPECT_EQ("129.97.123.22", AddressToString(&(info[0].ipaddr), 4)); 237 // TTL is reduced to match CNAME's. 238 EXPECT_EQ(200, info[0].ttl); 239 ares_free_hostent(host); 240 241 // Repeat parsing without places to put the results. 242 count = 0; 243 EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), (int)data.size(), 244 nullptr, info, &count)); 245 } 246 247 TEST_F(LibraryTest, ParseAReplyVariantCnameChain) { 248 DNSPacket pkt; 249 pkt.set_qid(6366).set_rd().set_ra() 250 .add_question(new DNSQuestion("c1.localhost", T_A)) 251 .add_answer(new DNSCnameRR("c1.localhost", 604800, "c2.localhost")) 252 .add_answer(new DNSCnameRR("c2.localhost", 604800, "c3.localhost")) 253 .add_answer(new DNSCnameRR("c3.localhost", 604800, "c4.localhost")) 254 .add_answer(new DNSARR("c4.localhost", 604800, {8,8,8,8})) 255 .add_auth(new DNSNsRR("localhost", 604800, "localhost")) 256 .add_additional(new DNSARR("localhost", 604800, {127,0,0,1})) 257 .add_additional(new DNSAaaaRR("localhost", 604800, 258 {0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 259 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})); 260 struct hostent *host = nullptr; 261 struct ares_addrttl info[2]; 262 int count = 2; 263 std::vector<byte> data = pkt.data(); 264 EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), (int)data.size(), 265 &host, info, &count)); 266 EXPECT_EQ(1, count); 267 EXPECT_EQ("8.8.8.8", AddressToString(&(info[0].ipaddr), 4)); 268 EXPECT_EQ(604800, info[0].ttl); 269 ares_free_hostent(host); 270 } 271 272 TEST_F(LibraryTest, ParseAReplyErrors) { 273 DNSPacket pkt; 274 pkt.set_qid(0x1234).set_response().set_aa() 275 .add_question(new DNSQuestion("example.com", T_A)) 276 .add_answer(new DNSARR("example.com", 100, {0x02, 0x03, 0x04, 0x05})); 277 std::vector<byte> data; 278 279 struct hostent *host = nullptr; 280 struct ares_addrttl info[2]; 281 int count = 2; 282 283 // No question. 284 pkt.questions_.clear(); 285 data = pkt.data(); 286 EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), (int)data.size(), 287 &host, info, &count)); 288 EXPECT_EQ(nullptr, host); 289 pkt.add_question(new DNSQuestion("example.com", T_A)); 290 291 // Question != answer, this is ok as of Issue #683 292 pkt.questions_.clear(); 293 pkt.add_question(new DNSQuestion("Axample.com", T_A)); 294 data = pkt.data(); 295 EXPECT_EQ(ARES_SUCCESS, ares_parse_a_reply(data.data(), (int)data.size(), 296 &host, info, &count)); 297 ASSERT_NE(nullptr, host); 298 std::stringstream ss; 299 ss << HostEnt(host); 300 EXPECT_EQ("{'axample.com' aliases=[] addrs=[2.3.4.5]}", ss.str()); 301 ares_free_hostent(host); 302 host = nullptr; 303 304 pkt.questions_.clear(); 305 pkt.add_question(new DNSQuestion("example.com", T_A)); 306 307 #ifdef DISABLED 308 // Not a response. 309 pkt.set_response(false); 310 data = pkt.data(); 311 EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), (int)data.size(), 312 &host, info, &count)); 313 EXPECT_EQ(nullptr, host); 314 pkt.set_response(true); 315 316 // Bad return code. 317 pkt.set_rcode(FORMERR); 318 data = pkt.data(); 319 EXPECT_EQ(ARES_ENODATA, ares_parse_a_reply(data.data(), (int)data.size(), 320 &host, info, &count)); 321 EXPECT_EQ(nullptr, host); 322 pkt.set_rcode(NOERROR); 323 #endif 324 325 // Two questions 326 pkt.add_question(new DNSQuestion("example.com", T_A)); 327 data = pkt.data(); 328 EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), (int)data.size(), 329 &host, info, &count)); 330 EXPECT_EQ(nullptr, host); 331 pkt.questions_.clear(); 332 pkt.add_question(new DNSQuestion("example.com", T_A)); 333 334 // Wrong sort of answer. 335 pkt.answers_.clear(); 336 pkt.add_answer(new DNSMxRR("example.com", 100, 100, "mx1.example.com")); 337 data = pkt.data(); 338 EXPECT_EQ(ARES_ENODATA, ares_parse_a_reply(data.data(), (int)data.size(), 339 &host, info, &count)); 340 EXPECT_EQ(nullptr, host); 341 pkt.answers_.clear(); 342 pkt.add_answer(new DNSARR("example.com", 100, {0x02, 0x03, 0x04, 0x05})); 343 344 // No answer. 345 pkt.answers_.clear(); 346 data = pkt.data(); 347 EXPECT_EQ(ARES_ENODATA, ares_parse_a_reply(data.data(), (int)data.size(), 348 &host, info, &count)); 349 EXPECT_EQ(nullptr, host); 350 pkt.add_answer(new DNSARR("example.com", 100, {0x02, 0x03, 0x04, 0x05})); 351 352 // Truncated packets. 353 data = pkt.data(); 354 for (size_t len = 1; len < data.size(); len++) { 355 EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), (int)len, 356 &host, info, &count)); 357 EXPECT_EQ(nullptr, host); 358 EXPECT_EQ(ARES_EBADRESP, ares_parse_a_reply(data.data(), (int)len, 359 nullptr, info, &count)); 360 } 361 } 362 363 TEST_F(LibraryTest, ParseAReplyAllocFail) { 364 DNSPacket pkt; 365 pkt.set_qid(0x1234).set_response().set_aa() 366 .add_question(new DNSQuestion("example.com", T_A)) 367 .add_answer(new DNSCnameRR("example.com", 300, "c.example.com")) 368 .add_answer(new DNSARR("c.example.com", 500, {0x02, 0x03, 0x04, 0x05})); 369 std::vector<byte> data = pkt.data(); 370 371 struct hostent *host = nullptr; 372 struct ares_addrttl info[2]; 373 int count = 2; 374 375 for (int ii = 1; ii <= 8; ii++) { 376 ClearFails(); 377 SetAllocFail(ii); 378 EXPECT_EQ(ARES_ENOMEM, ares_parse_a_reply(data.data(), (int)data.size(), 379 &host, info, &count)) << ii; 380 EXPECT_EQ(nullptr, host); 381 } 382 } 383 384 } // namespace test 385 } // namespace ares