DNSPacket.cpp (34450B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "DNSPacket.h" 6 7 #include "DNS.h" 8 #include "mozilla/StaticPrefs_network.h" 9 // Put DNSLogging.h at the end to avoid LOG being overwritten by other headers. 10 #include "DNSLogging.h" 11 12 #include "nsIInputStream.h" 13 14 namespace mozilla { 15 namespace net { 16 17 static uint16_t get16bit(const unsigned char* aData, unsigned int index) { 18 return ((aData[index] << 8) | aData[index + 1]); 19 } 20 21 static uint32_t get32bit(const unsigned char* aData, unsigned int index) { 22 return (aData[index] << 24) | (aData[index + 1] << 16) | 23 (aData[index + 2] << 8) | aData[index + 3]; 24 } 25 26 // https://datatracker.ietf.org/doc/html/rfc8914#name-defined-extended-dns-errors 27 // This is a list of errors for which we should not fallback to Do53. 28 // These are normally explicit filtering performed by the recursive resolver. 29 bool hardFail(uint16_t code) { 30 const uint16_t noFallbackErrors[] = { 31 4, // Forged answer (malware filtering) 32 17, // Filtered 33 }; 34 35 for (const auto& err : noFallbackErrors) { 36 if (code == err) { 37 return true; 38 } 39 } 40 return false; 41 } 42 43 nsresult DNSPacket::FillBuffer( 44 std::function<int(unsigned char response[MAX_SIZE])>&& aPredicate) { 45 int response_length = aPredicate(mResponse); 46 if (response_length < 0) { 47 LOG(("FillBuffer response len < 0")); 48 mBodySize = 0; 49 mStatus = NS_ERROR_UNEXPECTED; 50 return mStatus; 51 } 52 53 mBodySize = response_length; 54 return NS_OK; 55 } 56 // static 57 nsresult DNSPacket::ParseSvcParam(unsigned int svcbIndex, uint16_t key, 58 SvcFieldValue& field, uint16_t length, 59 const unsigned char* aBuffer) { 60 switch (key) { 61 case SvcParamKeyMandatory: { 62 if (length % 2 != 0) { 63 // This key should encode a list of uint16_t 64 return NS_ERROR_UNEXPECTED; 65 } 66 while (length > 0) { 67 uint16_t mandatoryKey = get16bit(aBuffer, svcbIndex); 68 length -= 2; 69 svcbIndex += 2; 70 71 if (!IsValidSvcParamKey(mandatoryKey)) { 72 LOG(("The mandatory field includes a key we don't support %u", 73 mandatoryKey)); 74 return NS_ERROR_UNEXPECTED; 75 } 76 } 77 break; 78 } 79 case SvcParamKeyAlpn: { 80 field.mValue = AsVariant(SvcParamAlpn()); 81 auto& alpnArray = field.mValue.as<SvcParamAlpn>().mValue; 82 while (length > 0) { 83 uint8_t alpnIdLength = aBuffer[svcbIndex++]; 84 length -= 1; 85 if (alpnIdLength > length) { 86 return NS_ERROR_UNEXPECTED; 87 } 88 89 alpnArray.AppendElement( 90 nsCString((const char*)&aBuffer[svcbIndex], alpnIdLength)); 91 length -= alpnIdLength; 92 svcbIndex += alpnIdLength; 93 } 94 break; 95 } 96 case SvcParamKeyNoDefaultAlpn: { 97 if (length != 0) { 98 // This key should not contain a value 99 return NS_ERROR_UNEXPECTED; 100 } 101 field.mValue = AsVariant(SvcParamNoDefaultAlpn{}); 102 break; 103 } 104 case SvcParamKeyPort: { 105 if (length != 2) { 106 // This key should only encode a uint16_t 107 return NS_ERROR_UNEXPECTED; 108 } 109 field.mValue = 110 AsVariant(SvcParamPort{.mValue = get16bit(aBuffer, svcbIndex)}); 111 break; 112 } 113 case SvcParamKeyIpv4Hint: { 114 if (length % 4 != 0) { 115 // This key should only encode IPv4 addresses 116 return NS_ERROR_UNEXPECTED; 117 } 118 119 field.mValue = AsVariant(SvcParamIpv4Hint()); 120 auto& ipv4array = field.mValue.as<SvcParamIpv4Hint>().mValue; 121 while (length > 0) { 122 NetAddr addr; 123 addr.inet.family = AF_INET; 124 addr.inet.port = 0; 125 addr.inet.ip = ntohl(get32bit(aBuffer, svcbIndex)); 126 ipv4array.AppendElement(addr); 127 length -= 4; 128 svcbIndex += 4; 129 } 130 break; 131 } 132 case SvcParamKeyEchConfig: { 133 field.mValue = AsVariant(SvcParamEchConfig{ 134 .mValue = nsCString((const char*)(&aBuffer[svcbIndex]), length)}); 135 break; 136 } 137 case SvcParamKeyIpv6Hint: { 138 if (length % 16 != 0) { 139 // This key should only encode IPv6 addresses 140 return NS_ERROR_UNEXPECTED; 141 } 142 143 field.mValue = AsVariant(SvcParamIpv6Hint()); 144 auto& ipv6array = field.mValue.as<SvcParamIpv6Hint>().mValue; 145 while (length > 0) { 146 NetAddr addr; 147 addr.inet6.family = AF_INET6; 148 addr.inet6.port = 0; // unknown 149 addr.inet6.flowinfo = 0; // unknown 150 addr.inet6.scope_id = 0; // unknown 151 for (int i = 0; i < 16; i++, svcbIndex++) { 152 addr.inet6.ip.u8[i] = aBuffer[svcbIndex]; 153 } 154 ipv6array.AppendElement(addr); 155 length -= 16; 156 // no need to increase svcbIndex - we did it in the for above. 157 } 158 break; 159 } 160 case SvcParamKeyODoHConfig: { 161 field.mValue = AsVariant(SvcParamODoHConfig{ 162 .mValue = nsCString((const char*)(&aBuffer[svcbIndex]), length)}); 163 break; 164 } 165 default: { 166 // Unespected type. We'll just ignore it. 167 return NS_OK; 168 break; 169 } 170 } 171 return NS_OK; 172 } 173 174 nsresult DNSPacket::PassQName(unsigned int& index, 175 const unsigned char* aBuffer) { 176 uint8_t length; 177 do { 178 if (mBodySize < (index + 1)) { 179 LOG(("TRR: PassQName:%d fail at index %d\n", __LINE__, index)); 180 return NS_ERROR_ILLEGAL_VALUE; 181 } 182 length = static_cast<uint8_t>(aBuffer[index]); 183 if ((length & 0xc0) == 0xc0) { 184 // name pointer, advance over it and be done 185 if (mBodySize < (index + 2)) { 186 return NS_ERROR_ILLEGAL_VALUE; 187 } 188 index += 2; 189 break; 190 } 191 if (length & 0xc0) { 192 LOG(("TRR: illegal label length byte (%x) at index %d\n", length, index)); 193 return NS_ERROR_ILLEGAL_VALUE; 194 } 195 // pass label 196 if (mBodySize < (index + 1 + length)) { 197 LOG(("TRR: PassQName:%d fail at index %d\n", __LINE__, index)); 198 return NS_ERROR_ILLEGAL_VALUE; 199 } 200 index += 1 + length; 201 } while (length); 202 return NS_OK; 203 } 204 205 // GetQname: retrieves the qname (stores in 'aQname') and stores the index 206 // after qname was parsed into the 'aIndex'. 207 // static 208 nsresult DNSPacket::GetQname(nsACString& aQname, unsigned int& aIndex, 209 const unsigned char* aBuffer, 210 unsigned int aBodySize) { 211 uint8_t clength = 0; 212 unsigned int cindex = aIndex; 213 unsigned int loop = 128; // a valid DNS name can never loop this much 214 unsigned int endindex = 0; // index position after this data 215 do { 216 if (cindex >= aBodySize) { 217 LOG(("TRR: bad Qname packet\n")); 218 return NS_ERROR_ILLEGAL_VALUE; 219 } 220 clength = static_cast<uint8_t>(aBuffer[cindex]); 221 if ((clength & 0xc0) == 0xc0) { 222 // name pointer, get the new offset (14 bits) 223 if ((cindex + 1) >= aBodySize) { 224 return NS_ERROR_ILLEGAL_VALUE; 225 } 226 // extract the new index position for the next label 227 uint16_t newpos = (clength & 0x3f) << 8 | aBuffer[cindex + 1]; 228 if (!endindex) { 229 // only update on the first "jump" 230 endindex = cindex + 2; 231 } 232 cindex = newpos; 233 continue; 234 } 235 if (clength & 0xc0) { 236 // any of those bits set individually is an error 237 LOG(("TRR: bad Qname packet\n")); 238 return NS_ERROR_ILLEGAL_VALUE; 239 } 240 241 cindex++; 242 243 if (clength) { 244 if (!aQname.IsEmpty()) { 245 aQname.Append("."); 246 } 247 if ((cindex + clength) > aBodySize) { 248 return NS_ERROR_ILLEGAL_VALUE; 249 } 250 aQname.Append((const char*)(&aBuffer[cindex]), clength); 251 cindex += clength; // skip label 252 } 253 } while (clength && --loop); 254 255 if (!loop) { 256 LOG(("DNSPacket::DohDecode pointer loop error\n")); 257 return NS_ERROR_ILLEGAL_VALUE; 258 } 259 if (!endindex) { 260 // there was no "jump" 261 endindex = cindex; 262 } 263 aIndex = endindex; 264 return NS_OK; 265 } 266 267 nsresult DOHresp::Add(uint32_t TTL, unsigned char const* dns, 268 unsigned int index, uint16_t len, bool aLocalAllowed) { 269 NetAddr addr; 270 if (4 == len) { 271 // IPv4 272 addr.inet.family = AF_INET; 273 addr.inet.port = 0; // unknown 274 addr.inet.ip = ntohl(get32bit(dns, index)); 275 } else if (16 == len) { 276 // IPv6 277 addr.inet6.family = AF_INET6; 278 addr.inet6.port = 0; // unknown 279 addr.inet6.flowinfo = 0; // unknown 280 addr.inet6.scope_id = 0; // unknown 281 for (int i = 0; i < 16; i++, index++) { 282 addr.inet6.ip.u8[i] = dns[index]; 283 } 284 } else { 285 return NS_ERROR_UNEXPECTED; 286 } 287 288 if (addr.IsIPAddrLocal() && !aLocalAllowed) { 289 return NS_ERROR_FAILURE; 290 } 291 292 // While the DNS packet might return individual TTLs for each address, 293 // we can only return one value in the AddrInfo class so pick the 294 // lowest number. 295 if (mTtl < TTL) { 296 mTtl = TTL; 297 } 298 299 if (LOG_ENABLED()) { 300 char buf[128]; 301 addr.ToStringBuffer(buf, sizeof(buf)); 302 LOG(("DOHresp:Add %s\n", buf)); 303 } 304 mAddresses.AppendElement(addr); 305 return NS_OK; 306 } 307 308 nsresult DNSPacket::OnDataAvailable(nsIRequest* aRequest, 309 nsIInputStream* aInputStream, 310 uint64_t aOffset, const uint32_t aCount) { 311 if (aCount + mBodySize > MAX_SIZE) { 312 LOG(("DNSPacket::OnDataAvailable:%d fail\n", __LINE__)); 313 return NS_ERROR_FAILURE; 314 } 315 uint32_t count; 316 nsresult rv = 317 aInputStream->Read((char*)mResponse + mBodySize, aCount, &count); 318 if (NS_FAILED(rv)) { 319 return rv; 320 } 321 MOZ_ASSERT(count == aCount); 322 mBodySize += aCount; 323 return NS_OK; 324 } 325 326 const uint8_t kDNS_CLASS_IN = 1; 327 328 // static 329 nsresult DNSPacket::EncodeHost(nsCString& aBody, const nsACString& aHost) { 330 // The input host name should be converted to a sequence of labels, where 331 // each label consists of a length octet followed by that number of 332 // octets. The domain name terminates with the zero length octet for the 333 // null label of the root. 334 335 int32_t index = 0; 336 int32_t offset = 0; 337 do { 338 bool dotFound = false; 339 int32_t labelLength; 340 index = aHost.FindChar('.', offset); 341 if (kNotFound != index) { 342 dotFound = true; 343 labelLength = index - offset; 344 } else { 345 labelLength = aHost.Length() - offset; 346 } 347 if (labelLength > 63) { 348 // too long label! 349 return NS_ERROR_ILLEGAL_VALUE; 350 } 351 if (labelLength > 0) { 352 aBody += static_cast<unsigned char>(labelLength); 353 nsDependentCSubstring label = Substring(aHost, offset, labelLength); 354 aBody.Append(label); 355 } 356 if (!dotFound) { 357 aBody += '\0'; // terminate with a final zero 358 break; 359 } 360 offset += labelLength + 1; // move over label and dot 361 } while (true); 362 363 return NS_OK; 364 } 365 366 nsresult DNSPacket::EncodeRequest(nsCString& aBody, const nsACString& aHost, 367 uint16_t aType, bool aDisableECS) { 368 aBody.Truncate(); 369 // Header 370 aBody += '\0'; 371 aBody += '\0'; // 16 bit id 372 aBody += 0x01; // |QR| Opcode |AA|TC|RD| Set the RD bit 373 aBody += '\0'; // |RA| Z | RCODE | 374 aBody += '\0'; 375 aBody += 1; // QDCOUNT (number of entries in the question section) 376 aBody += '\0'; 377 aBody += '\0'; // ANCOUNT 378 aBody += '\0'; 379 aBody += '\0'; // NSCOUNT 380 381 char additionalRecords = 382 (aDisableECS || StaticPrefs::network_trr_padding()) ? 1 : 0; 383 aBody += '\0'; // ARCOUNT 384 aBody += additionalRecords; // ARCOUNT low byte for EDNS(0) 385 386 // Question 387 388 nsresult rv = EncodeHost(aBody, aHost); 389 if (NS_FAILED(rv)) { 390 return rv; 391 } 392 393 // Followed by 16 bit QTYPE and 16 bit QCLASS 394 aBody += static_cast<uint8_t>(aType >> 8); // upper 8 bit TYPE 395 aBody += static_cast<uint8_t>(aType); 396 aBody += '\0'; // upper 8 bit CLASS 397 aBody += kDNS_CLASS_IN; // IN - "the Internet" 398 399 if (additionalRecords) { 400 // EDNS(0) is RFC 6891, ECS is RFC 7871 401 aBody += '\0'; // NAME | domain name | MUST be 0 (root domain) | 402 aBody += '\0'; 403 aBody += 41; // TYPE | u_int16_t | OPT (41) | 404 aBody += 16; // CLASS | u_int16_t | requestor's UDP payload size | 405 aBody += 406 '\0'; // advertise 4K (high-byte: 16 | low-byte: 0), ignored by DoH 407 aBody += '\0'; // TTL | u_int32_t | extended RCODE and flags | 408 aBody += '\0'; 409 aBody += '\0'; 410 aBody += '\0'; 411 412 // calculate padding length 413 unsigned int paddingLen = 0; 414 unsigned int rdlen = 0; 415 bool padding = StaticPrefs::network_trr_padding(); 416 if (padding) { 417 // always add padding specified in rfc 7830 when this config is enabled 418 // to allow the reponse to be padded as well 419 420 // two bytes RDLEN, 4 bytes padding header 421 unsigned int packetLen = aBody.Length() + 2 + 4; 422 if (aDisableECS) { 423 // 8 bytes for disabling ecs 424 packetLen += 8; 425 } 426 427 // clamp the padding length, because the padding extension only allows up 428 // to 2^16 - 1 bytes padding and adding too much padding wastes resources 429 uint32_t padTo = std::clamp<uint32_t>( 430 StaticPrefs::network_trr_padding_length(), 0, 1024); 431 432 // Calculate number of padding bytes. The second '%'-operator is necessary 433 // because we prefer to add 0 bytes padding rather than padTo bytes 434 if (padTo > 0) { 435 paddingLen = (padTo - (packetLen % padTo)) % padTo; 436 } 437 // padding header + padding length 438 rdlen += 4 + paddingLen; 439 } 440 if (aDisableECS) { 441 rdlen += 8; 442 } 443 444 // RDLEN | u_int16_t | length of all RDATA | 445 aBody += (char)((rdlen >> 8) & 0xff); // upper 8 bit RDLEN 446 aBody += (char)(rdlen & 0xff); 447 448 // RDATA | octet stream | {attribute,value} pairs | 449 // The RDATA is just the ECS option setting zero subnet prefix 450 451 if (aDisableECS) { 452 aBody += '\0'; // upper 8 bit OPTION-CODE ECS 453 aBody += 8; // OPTION-CODE, 2 octets, for ECS is 8 454 455 aBody += '\0'; // upper 8 bit OPTION-LENGTH 456 aBody += 4; // OPTION-LENGTH, 2 octets, contains the length of the 457 // payload after OPTION-LENGTH 458 aBody += '\0'; // upper 8 bit FAMILY. IANA Address Family Numbers 459 // registry, not the AF_* constants! 460 aBody += 1; // FAMILY (Ipv4), 2 octets 461 462 aBody += '\0'; // SOURCE PREFIX-LENGTH | SCOPE PREFIX-LENGTH | 463 aBody += '\0'; 464 465 // ADDRESS, minimum number of octets == nothing because zero bits 466 } 467 468 if (padding) { 469 aBody += '\0'; // upper 8 bit option OPTION-CODE PADDING 470 aBody += 12; // OPTION-CODE, 2 octets, for PADDING is 12 471 472 // OPTION-LENGTH, 2 octets 473 aBody += (char)((paddingLen >> 8) & 0xff); 474 aBody += (char)(paddingLen & 0xff); 475 for (unsigned int i = 0; i < paddingLen; i++) { 476 aBody += '\0'; 477 } 478 } 479 } 480 481 return NS_OK; 482 } 483 484 // static 485 nsresult DNSPacket::ParseHTTPS(uint16_t aRDLen, struct SVCB& aParsed, 486 unsigned int aIndex, 487 const unsigned char* aBuffer, 488 unsigned int aBodySize, 489 const nsACString& aOriginHost) { 490 int32_t lastSvcParamKey = -1; 491 nsresult rv = NS_OK; 492 unsigned int svcbIndex = aIndex; 493 CheckedInt<uint16_t> available = aRDLen; 494 495 // Should have at least 2 bytes for the priority and one for the 496 // qname length. 497 if (available.value() < 3) { 498 return NS_ERROR_UNEXPECTED; 499 } 500 501 aParsed.mSvcFieldPriority = get16bit(aBuffer, svcbIndex); 502 svcbIndex += 2; 503 504 rv = GetQname(aParsed.mSvcDomainName, svcbIndex, aBuffer, aBodySize); 505 if (NS_FAILED(rv)) { 506 return rv; 507 } 508 509 if (aParsed.mSvcDomainName.IsEmpty()) { 510 if (aParsed.mSvcFieldPriority == 0) { 511 // For AliasMode SVCB RRs, a TargetName of "." indicates that 512 // the service is not available or does not exist. 513 return NS_OK; 514 } 515 516 // For ServiceMode SVCB RRs, if TargetName has the value ".", 517 // then the owner name of this record MUST be used as 518 // the effective TargetName. 519 // When the qname is port prefix name, we need to use the 520 // original host name as TargetName. 521 aParsed.mSvcDomainName = aOriginHost; 522 } 523 524 available -= (svcbIndex - aIndex); 525 if (!available.isValid()) { 526 return NS_ERROR_UNEXPECTED; 527 } 528 while (available.value() >= 4) { 529 // Every SvcFieldValues must have at least 4 bytes for the 530 // SvcParamKey (2 bytes) and length of SvcParamValue (2 bytes) 531 // If the length ever goes above the available data, meaning if 532 // available ever underflows, then that is an error. 533 struct SvcFieldValue value; 534 uint16_t key = get16bit(aBuffer, svcbIndex); 535 svcbIndex += 2; 536 537 // 2.2 Clients MUST consider an RR malformed if SvcParamKeys are 538 // not in strictly increasing numeric order. 539 if (key <= lastSvcParamKey) { 540 LOG(("SvcParamKeys not in increasing order")); 541 return NS_ERROR_UNEXPECTED; 542 } 543 lastSvcParamKey = key; 544 545 uint16_t len = get16bit(aBuffer, svcbIndex); 546 svcbIndex += 2; 547 548 available -= 4 + len; 549 if (!available.isValid()) { 550 return NS_ERROR_UNEXPECTED; 551 } 552 553 rv = ParseSvcParam(svcbIndex, key, value, len, aBuffer); 554 if (NS_FAILED(rv)) { 555 return rv; 556 } 557 svcbIndex += len; 558 559 // If this is an unknown key, we will simply ignore it. 560 // We also don't need to record SvcParamKeyMandatory 561 if (key == SvcParamKeyMandatory || !IsValidSvcParamKey(key)) { 562 continue; 563 } 564 565 if (value.mValue.is<SvcParamIpv4Hint>() || 566 value.mValue.is<SvcParamIpv6Hint>()) { 567 aParsed.mHasIPHints = true; 568 } 569 if (value.mValue.is<SvcParamEchConfig>()) { 570 aParsed.mHasEchConfig = true; 571 aParsed.mEchConfig = value.mValue.as<SvcParamEchConfig>().mValue; 572 } 573 if (value.mValue.is<SvcParamODoHConfig>()) { 574 aParsed.mODoHConfig = value.mValue.as<SvcParamODoHConfig>().mValue; 575 } 576 aParsed.mSvcFieldValue.AppendElement(value); 577 } 578 579 return NS_OK; 580 } 581 582 Result<uint8_t, nsresult> DNSPacket::GetRCode() const { 583 if (mBodySize < 12) { 584 LOG(("DNSPacket::GetRCode - packet too small")); 585 return Err(NS_ERROR_ILLEGAL_VALUE); 586 } 587 588 return mResponse[3] & 0x0F; 589 } 590 591 Result<bool, nsresult> DNSPacket::RecursionAvailable() const { 592 if (mBodySize < 12) { 593 LOG(("DNSPacket::GetRCode - packet too small")); 594 return Err(NS_ERROR_ILLEGAL_VALUE); 595 } 596 597 return mResponse[3] & 0x80; 598 } 599 600 nsresult DNSPacket::DecodeInternal( 601 nsCString& aHost, enum TrrType aType, nsCString& aCname, bool aAllowRFC1918, 602 DOHresp& aResp, TypeRecordResultType& aTypeResult, 603 nsClassHashtable<nsCStringHashKey, DOHresp>& aAdditionalRecords, 604 uint32_t& aTTL, const unsigned char* aBuffer, uint32_t aLen) { 605 // The response has a 12 byte header followed by the question (returned) 606 // and then the answer. The answer section itself contains the name, type 607 // and class again and THEN the record data. 608 609 // www.example.com response: 610 // header: 611 // abcd 8180 0001 0001 0000 0000 612 // the question: 613 // 0377 7777 0765 7861 6d70 6c65 0363 6f6d 0000 0100 01 614 // the answer: 615 // 03 7777 7707 6578 616d 706c 6503 636f 6d00 0001 0001 616 // 0000 0080 0004 5db8 d822 617 618 unsigned int index = 12; 619 uint8_t length; 620 nsAutoCString host; 621 nsresult rv; 622 uint16_t extendedError = UINT16_MAX; 623 624 LOG(("doh decode %s %d bytes\n", aHost.get(), aLen)); 625 626 aCname.Truncate(); 627 628 if (aLen < 12) { 629 LOG(("TRR bad incoming DOH, eject!\n")); 630 return NS_ERROR_ILLEGAL_VALUE; 631 } 632 633 if (!mNativePacket && (aBuffer[0] || aBuffer[1])) { 634 LOG(("Packet ID is unexpectedly non-zero")); 635 return NS_ERROR_ILLEGAL_VALUE; 636 } 637 638 uint8_t rcode = mResponse[3] & 0x0F; 639 LOG(("TRR Decode %s RCODE %d\n", PromiseFlatCString(aHost).get(), rcode)); 640 641 uint16_t questionRecords = get16bit(aBuffer, 4); // qdcount 642 // iterate over the single(?) host name in question 643 while (questionRecords) { 644 do { 645 if (aLen < (index + 1)) { 646 LOG(("TRR Decode 1 index: %u size: %u", index, aLen)); 647 return NS_ERROR_ILLEGAL_VALUE; 648 } 649 length = static_cast<uint8_t>(aBuffer[index]); 650 if (length) { 651 if (host.Length()) { 652 host.Append("."); 653 } 654 if (aLen < (index + 1 + length)) { 655 LOG(("TRR Decode 2 index: %u size: %u len: %u", index, aLen, length)); 656 return NS_ERROR_ILLEGAL_VALUE; 657 } 658 host.Append(((char*)aBuffer) + index + 1, length); 659 } 660 index += 1 + length; // skip length byte + label 661 } while (length); 662 if (aLen < (index + 4)) { 663 LOG(("TRR Decode 3 index: %u size: %u", index, aLen)); 664 return NS_ERROR_ILLEGAL_VALUE; 665 } 666 index += 4; // skip question's type, class 667 questionRecords--; 668 } 669 670 // Figure out the number of answer records from ANCOUNT 671 uint16_t answerRecords = get16bit(aBuffer, 6); 672 673 LOG(("TRR Decode: %d answer records (%u bytes body) %s index=%u\n", 674 answerRecords, aLen, host.get(), index)); 675 676 while (answerRecords) { 677 nsAutoCString qname; 678 rv = GetQname(qname, index, aBuffer, mBodySize); 679 if (NS_FAILED(rv)) { 680 return rv; 681 } 682 // 16 bit TYPE 683 if (aLen < (index + 2)) { 684 LOG(("TRR: Dohdecode:%d fail at index %d\n", __LINE__, index + 2)); 685 return NS_ERROR_ILLEGAL_VALUE; 686 } 687 uint16_t TYPE = get16bit(aBuffer, index); 688 689 index += 2; 690 691 // 16 bit class 692 if (aLen < (index + 2)) { 693 LOG(("TRR: Dohdecode:%d fail at index %d\n", __LINE__, index + 2)); 694 return NS_ERROR_ILLEGAL_VALUE; 695 } 696 uint16_t CLASS = get16bit(aBuffer, index); 697 if (kDNS_CLASS_IN != CLASS) { 698 LOG(("TRR bad CLASS (%u) at index %d\n", CLASS, index)); 699 return NS_ERROR_UNEXPECTED; 700 } 701 index += 2; 702 703 // 32 bit TTL (seconds) 704 if (aLen < (index + 4)) { 705 LOG(("TRR: Dohdecode:%d fail at index %d\n", __LINE__, index)); 706 return NS_ERROR_ILLEGAL_VALUE; 707 } 708 uint32_t TTL = get32bit(aBuffer, index); 709 index += 4; 710 711 // 16 bit RDLENGTH 712 if (aLen < (index + 2)) { 713 LOG(("TRR: Dohdecode:%d fail at index %d\n", __LINE__, index)); 714 return NS_ERROR_ILLEGAL_VALUE; 715 } 716 uint16_t RDLENGTH = get16bit(aBuffer, index); 717 index += 2; 718 719 if (aLen < (index + RDLENGTH)) { 720 LOG(("TRR: Dohdecode:%d fail RDLENGTH=%d at index %d\n", __LINE__, 721 RDLENGTH, index)); 722 return NS_ERROR_ILLEGAL_VALUE; 723 } 724 725 if ((TYPE != TRRTYPE_CNAME) && (TYPE != TRRTYPE_HTTPSSVC) && 726 (TYPE != static_cast<uint16_t>(aType))) { 727 // Not the same type as was asked for nor CNAME 728 LOG(("TRR: Dohdecode:%d asked for type %d got %d\n", __LINE__, aType, 729 TYPE)); 730 index += RDLENGTH; 731 answerRecords--; 732 continue; 733 } 734 735 // We check if the qname is a case-insensitive match for the host or the 736 // FQDN version of the host 737 bool responseMatchesQuestion = 738 (qname.Length() == aHost.Length() || 739 (aHost.Length() == qname.Length() + 1 && aHost.Last() == '.')) && 740 StringBeginsWith(aHost, qname, nsCaseInsensitiveCStringComparator); 741 742 if (responseMatchesQuestion) { 743 // RDATA 744 // - A (TYPE 1): 4 bytes 745 // - AAAA (TYPE 28): 16 bytes 746 // - NS (TYPE 2): N bytes 747 748 switch (TYPE) { 749 case TRRTYPE_A: 750 if (RDLENGTH != 4) { 751 LOG(("TRR bad length for A (%u)\n", RDLENGTH)); 752 return NS_ERROR_UNEXPECTED; 753 } 754 rv = aResp.Add(TTL, aBuffer, index, RDLENGTH, aAllowRFC1918); 755 if (NS_FAILED(rv)) { 756 LOG( 757 ("TRR:DohDecode failed: local IP addresses or unknown IP " 758 "family\n")); 759 return rv; 760 } 761 break; 762 case TRRTYPE_AAAA: 763 if (RDLENGTH != 16) { 764 LOG(("TRR bad length for AAAA (%u)\n", RDLENGTH)); 765 return NS_ERROR_UNEXPECTED; 766 } 767 rv = aResp.Add(TTL, aBuffer, index, RDLENGTH, aAllowRFC1918); 768 if (NS_FAILED(rv)) { 769 LOG(("TRR got unique/local IPv6 address!\n")); 770 return rv; 771 } 772 break; 773 774 case TRRTYPE_NS: 775 break; 776 case TRRTYPE_CNAME: 777 if (aCname.IsEmpty()) { 778 nsAutoCString qname; 779 unsigned int qnameindex = index; 780 rv = GetQname(qname, qnameindex, aBuffer, mBodySize); 781 if (NS_FAILED(rv)) { 782 return rv; 783 } 784 if (!qname.IsEmpty()) { 785 ToLowerCase(qname); 786 aCname = qname; 787 LOG(("DNSPacket::DohDecode CNAME host %s => %s\n", host.get(), 788 aCname.get())); 789 } else { 790 LOG(("DNSPacket::DohDecode empty CNAME for host %s!\n", 791 host.get())); 792 } 793 } else { 794 LOG(("DNSPacket::DohDecode CNAME - ignoring another entry\n")); 795 } 796 break; 797 case TRRTYPE_TXT: { 798 // TXT record RRDATA sections are a series of character-strings 799 // each character string is a length byte followed by that many data 800 // bytes 801 nsAutoCString txt; 802 unsigned int txtIndex = index; 803 uint16_t available = RDLENGTH; 804 805 while (available > 0) { 806 uint8_t characterStringLen = aBuffer[txtIndex++]; 807 available--; 808 if (characterStringLen > available) { 809 LOG(("DNSPacket::DohDecode MALFORMED TXT RECORD\n")); 810 break; 811 } 812 txt.Append((const char*)(&aBuffer[txtIndex]), characterStringLen); 813 txtIndex += characterStringLen; 814 available -= characterStringLen; 815 } 816 817 if (!aTypeResult.is<TypeRecordTxt>()) { 818 aTypeResult = AsVariant(CopyableTArray<nsCString>()); 819 } 820 821 { 822 auto& results = aTypeResult.as<TypeRecordTxt>(); 823 results.AppendElement(txt); 824 } 825 if (aTTL > TTL) { 826 aTTL = TTL; 827 } 828 LOG(("DNSPacket::DohDecode TXT host %s => %s\n", host.get(), 829 txt.get())); 830 831 break; 832 } 833 case TRRTYPE_HTTPSSVC: { 834 struct SVCB parsed; 835 836 if (aType != TRRTYPE_HTTPSSVC) { 837 // Ignore the entry that we just parsed if we didn't ask for it. 838 break; 839 } 840 841 rv = ParseHTTPS(RDLENGTH, parsed, index, aBuffer, mBodySize, 842 mOriginHost ? *mOriginHost : qname); 843 if (NS_FAILED(rv)) { 844 return rv; 845 } 846 847 if (parsed.mSvcDomainName.IsEmpty() && 848 parsed.mSvcFieldPriority == 0) { 849 // For AliasMode SVCB RRs, a TargetName of "." indicates that the 850 // service is not available or does not exist. 851 continue; 852 } 853 854 // Check for AliasForm 855 if (aCname.IsEmpty() && parsed.mSvcFieldPriority == 0) { 856 // Alias form SvcDomainName must not have the "." value (empty) 857 if (parsed.mSvcDomainName.IsEmpty()) { 858 return NS_ERROR_UNEXPECTED; 859 } 860 aCname = parsed.mSvcDomainName; 861 // If aliasForm is present, Service form must be ignored. 862 aTypeResult = mozilla::AsVariant(Nothing()); 863 ToLowerCase(aCname); 864 LOG(("DNSPacket::DohDecode HTTPSSVC AliasForm host %s => %s\n", 865 host.get(), aCname.get())); 866 break; 867 } 868 869 aTTL = TTL; 870 871 if (!aTypeResult.is<TypeRecordHTTPSSVC>()) { 872 aTypeResult = mozilla::AsVariant(CopyableTArray<SVCB>()); 873 } 874 { 875 auto& results = aTypeResult.as<TypeRecordHTTPSSVC>(); 876 results.AppendElement(parsed); 877 } 878 879 break; 880 } 881 default: 882 // skip unknown record types 883 LOG(("TRR unsupported TYPE (%u) RDLENGTH %u\n", TYPE, RDLENGTH)); 884 break; 885 } 886 } else { 887 LOG(("TRR asked for %s data but got %s\n", aHost.get(), qname.get())); 888 } 889 890 index += RDLENGTH; 891 LOG(("done with record type %u len %u index now %u of %u\n", TYPE, RDLENGTH, 892 index, aLen)); 893 answerRecords--; 894 } 895 896 // NSCOUNT 897 uint16_t nsRecords = get16bit(aBuffer, 8); 898 LOG(("TRR Decode: %d ns records (%u bytes body)\n", nsRecords, aLen)); 899 while (nsRecords) { 900 rv = PassQName(index, aBuffer); 901 if (NS_FAILED(rv)) { 902 return rv; 903 } 904 905 if (aLen < (index + 8)) { 906 return NS_ERROR_ILLEGAL_VALUE; 907 } 908 index += 2; // type 909 index += 2; // class 910 index += 4; // ttl 911 912 // 16 bit RDLENGTH 913 if (aLen < (index + 2)) { 914 return NS_ERROR_ILLEGAL_VALUE; 915 } 916 uint16_t RDLENGTH = get16bit(aBuffer, index); 917 index += 2; 918 if (aLen < (index + RDLENGTH)) { 919 return NS_ERROR_ILLEGAL_VALUE; 920 } 921 index += RDLENGTH; 922 LOG(("done with nsRecord now %u of %u\n", index, aLen)); 923 nsRecords--; 924 } 925 926 // additional resource records 927 uint16_t arRecords = get16bit(aBuffer, 10); 928 LOG(("TRR Decode: %d additional resource records (%u bytes body)\n", 929 arRecords, aLen)); 930 931 while (arRecords) { 932 nsAutoCString qname; 933 rv = GetQname(qname, index, aBuffer, mBodySize); 934 if (NS_FAILED(rv)) { 935 LOG(("Bad qname for additional record")); 936 return rv; 937 } 938 939 if (aLen < (index + 8)) { 940 return NS_ERROR_ILLEGAL_VALUE; 941 } 942 uint16_t type = get16bit(aBuffer, index); 943 index += 2; 944 // The next two bytes encode class 945 // (or udpPayloadSize when type is TRRTYPE_OPT) 946 uint16_t cls = get16bit(aBuffer, index); 947 index += 2; 948 // The next 4 bytes encode TTL 949 // (or extRCode + ednsVersion + flags when type is TRRTYPE_OPT) 950 uint32_t ttl = get32bit(aBuffer, index); 951 index += 4; 952 // cls and ttl are unused when type is TRRTYPE_OPT 953 954 // 16 bit RDLENGTH 955 if (aLen < (index + 2)) { 956 LOG(("Record too small")); 957 return NS_ERROR_ILLEGAL_VALUE; 958 } 959 960 uint16_t rdlength = get16bit(aBuffer, index); 961 index += 2; 962 if (aLen < (index + rdlength)) { 963 LOG(("rdlength too big")); 964 return NS_ERROR_ILLEGAL_VALUE; 965 } 966 967 auto parseRecord = [&]() { 968 LOG(("Parsing additional record type: %u", type)); 969 auto* entry = aAdditionalRecords.GetOrInsertNew(qname); 970 971 switch (type) { 972 case TRRTYPE_A: 973 if (kDNS_CLASS_IN != cls) { 974 LOG(("NOT IN - returning")); 975 return; 976 } 977 if (rdlength != 4) { 978 LOG(("TRR bad length for A (%u)\n", rdlength)); 979 return; 980 } 981 rv = entry->Add(ttl, aBuffer, index, rdlength, aAllowRFC1918); 982 if (NS_FAILED(rv)) { 983 LOG( 984 ("TRR:DohDecode failed: local IP addresses or unknown IP " 985 "family\n")); 986 return; 987 } 988 break; 989 case TRRTYPE_AAAA: 990 if (kDNS_CLASS_IN != cls) { 991 LOG(("NOT IN - returning")); 992 return; 993 } 994 if (rdlength != 16) { 995 LOG(("TRR bad length for AAAA (%u)\n", rdlength)); 996 return; 997 } 998 rv = entry->Add(ttl, aBuffer, index, rdlength, aAllowRFC1918); 999 if (NS_FAILED(rv)) { 1000 LOG(("TRR got unique/local IPv6 address!\n")); 1001 return; 1002 } 1003 break; 1004 case TRRTYPE_OPT: { // OPT 1005 LOG(("Parsing opt rdlen: %u", rdlength)); 1006 unsigned int offset = 0; 1007 while (offset + 2 <= rdlength) { 1008 uint16_t optCode = get16bit(aBuffer, index + offset); 1009 LOG(("optCode: %u", optCode)); 1010 offset += 2; 1011 if (offset + 2 > rdlength) { 1012 break; 1013 } 1014 uint16_t optLen = get16bit(aBuffer, index + offset); 1015 LOG(("optLen: %u", optLen)); 1016 offset += 2; 1017 if (offset + optLen > rdlength) { 1018 LOG(("offset: %u, optLen: %u, rdlen: %u", offset, optLen, 1019 rdlength)); 1020 break; 1021 } 1022 1023 LOG(("OPT: code: %u len:%u", optCode, optLen)); 1024 1025 if (optCode != 15) { 1026 offset += optLen; 1027 continue; 1028 } 1029 1030 // optCode == 15; Extended DNS error 1031 1032 if (offset + 2 > rdlength || optLen < 2) { 1033 break; 1034 } 1035 extendedError = get16bit(aBuffer, index + offset); 1036 1037 LOG(("Extended error code: %u message: %s", extendedError, 1038 nsAutoCString((char*)aBuffer + index + offset + 2, optLen - 2) 1039 .get())); 1040 offset += optLen; 1041 } 1042 break; 1043 } 1044 default: 1045 break; 1046 } 1047 }; 1048 1049 parseRecord(); 1050 1051 index += rdlength; 1052 LOG(("done with additional rr now %u of %u\n", index, aLen)); 1053 arRecords--; 1054 } 1055 1056 if (index != aLen) { 1057 LOG(("DohDecode failed to parse entire response body, %u out of %u bytes\n", 1058 index, aLen)); 1059 // failed to parse 100%, do not continue 1060 return NS_ERROR_ILLEGAL_VALUE; 1061 } 1062 1063 if (aType == TRRTYPE_NS && rcode != 0) { 1064 return NS_ERROR_UNKNOWN_HOST; 1065 } 1066 1067 if ((aType != TRRTYPE_NS) && aCname.IsEmpty() && aResp.mAddresses.IsEmpty() && 1068 aTypeResult.is<TypeRecordEmpty>()) { 1069 // no entries were stored! 1070 LOG(("TRR: No entries were stored!\n")); 1071 1072 if (extendedError != UINT16_MAX && 1073 StaticPrefs::network_trr_hard_fail_on_extended_error() && 1074 hardFail(extendedError)) { 1075 return NS_ERROR_DEFINITIVE_UNKNOWN_HOST; 1076 } 1077 return NS_ERROR_UNKNOWN_HOST; 1078 } 1079 1080 // https://tools.ietf.org/html/draft-ietf-dnsop-svcb-httpssvc-03#page-14 1081 // If one or more SVCB records of ServiceForm SvcRecordType are returned for 1082 // HOST, clients should select the highest-priority option with acceptable 1083 // parameters. 1084 if (aTypeResult.is<TypeRecordHTTPSSVC>()) { 1085 auto& results = aTypeResult.as<TypeRecordHTTPSSVC>(); 1086 results.Sort(); 1087 } 1088 1089 return NS_OK; 1090 } 1091 1092 // 1093 // DohDecode() collects the TTL and the IP addresses in the response 1094 // 1095 nsresult DNSPacket::Decode( 1096 nsCString& aHost, enum TrrType aType, nsCString& aCname, bool aAllowRFC1918, 1097 DOHresp& aResp, TypeRecordResultType& aTypeResult, 1098 nsClassHashtable<nsCStringHashKey, DOHresp>& aAdditionalRecords, 1099 uint32_t& aTTL) { 1100 nsresult rv = 1101 DecodeInternal(aHost, aType, aCname, aAllowRFC1918, aResp, aTypeResult, 1102 aAdditionalRecords, aTTL, mResponse, mBodySize); 1103 mStatus = rv; 1104 return rv; 1105 } 1106 1107 } // namespace net 1108 } // namespace mozilla