tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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