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 #ifndef mozilla_net_DNSPacket_h__
6 #define mozilla_net_DNSPacket_h__
7 
8 #include "mozilla/Maybe.h"
9 #include "mozilla/Result.h"
10 #include "pk11pub.h"
11 #include "ScopedNSSTypes.h"
12 #include "nsClassHashtable.h"
13 #include "nsIDNSService.h"
14 #include "DNS.h"
15 #include "DNSByTypeRecord.h"
16 
17 namespace mozilla {
18 namespace net {
19 
20 class DOHresp {
21  public:
22   nsresult Add(uint32_t TTL, unsigned char const* dns, unsigned int index,
23                uint16_t len, bool aLocalAllowed);
24   nsTArray<NetAddr> mAddresses;
25   uint32_t mTtl = 0;
26 };
27 
28 // the values map to RFC1035 type identifiers
29 enum TrrType {
30   TRRTYPE_A = 1,
31   TRRTYPE_NS = 2,
32   TRRTYPE_CNAME = 5,
33   TRRTYPE_AAAA = 28,
34   TRRTYPE_OPT = 41,
35   TRRTYPE_TXT = 16,
36   TRRTYPE_HTTPSSVC = nsIDNSService::RESOLVE_TYPE_HTTPSSVC,  // 65
37 };
38 
39 enum class DNSPacketStatus : uint8_t {
40   Unknown = 0,
41   Success,
42   KeyNotAvailable,
43   KeyNotUsable,
44   EncodeError,
45   EncryptError,
46   DecodeError,
47   DecryptError,
48 };
49 
50 class DNSPacket {
51  public:
52   DNSPacket() = default;
53   virtual ~DNSPacket() = default;
54 
55   Result<uint8_t, nsresult> GetRCode() const;
56 
57   // Called in order to feed data into the buffer.
58   nsresult OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aInputStream,
59                            uint64_t aOffset, const uint32_t aCount);
60 
61   // Encodes the name request into a buffer that represents a DNS packet
62   virtual nsresult EncodeRequest(nsCString& aBody, const nsACString& aHost,
63                                  uint16_t aType, bool aDisableECS);
64 
65   // Decodes the DNS response and extracts the responses, additional records,
66   // etc. XXX: This should probably be refactored to reduce the number of
67   // output parameters and have a common format for different record types.
68   virtual nsresult Decode(
69       nsCString& aHost, enum TrrType aType, nsCString& aCname,
70       bool aAllowRFC1918, DOHresp& aResp, TypeRecordResultType& aTypeResult,
71       nsClassHashtable<nsCStringHashKey, DOHresp>& aAdditionalRecords,
72       uint32_t& aTTL);
73 
PacketStatus()74   DNSPacketStatus PacketStatus() const { return mStatus; }
75 
76  protected:
77   // Never accept larger DOH responses than this as that would indicate
78   // something is wrong. Typical ones are much smaller.
79   static const unsigned int MAX_SIZE = 3200;
80 
81   nsresult PassQName(unsigned int& index, const unsigned char* aBuffer);
82   nsresult GetQname(nsACString& aQname, unsigned int& aIndex,
83                     const unsigned char* aBuffer);
84   nsresult ParseSvcParam(unsigned int svcbIndex, uint16_t key,
85                          SvcFieldValue& field, uint16_t length,
86                          const unsigned char* aBuffer);
87   nsresult DecodeInternal(
88       nsCString& aHost, enum TrrType aType, nsCString& aCname,
89       bool aAllowRFC1918, DOHresp& aResp, TypeRecordResultType& aTypeResult,
90       nsClassHashtable<nsCStringHashKey, DOHresp>& aAdditionalRecords,
91       uint32_t& aTTL, const unsigned char* aBuffer, uint32_t aLen);
92 
SetDNSPacketStatus(DNSPacketStatus aStatus)93   void SetDNSPacketStatus(DNSPacketStatus aStatus) {
94     if (mStatus == DNSPacketStatus::Unknown ||
95         mStatus == DNSPacketStatus::Success) {
96       mStatus = aStatus;
97     }
98   }
99 
100   // The response buffer.
101   unsigned char mResponse[MAX_SIZE]{};
102   unsigned int mBodySize = 0;
103   DNSPacketStatus mStatus = DNSPacketStatus::Unknown;
104 };
105 
106 class ODoHDNSPacket final : public DNSPacket {
107  public:
108   ODoHDNSPacket() = default;
109   virtual ~ODoHDNSPacket();
110 
111   static bool ParseODoHConfigs(Span<const uint8_t> aData,
112                                nsTArray<ObliviousDoHConfig>& aOut);
113 
114   virtual nsresult EncodeRequest(nsCString& aBody, const nsACString& aHost,
115                                  uint16_t aType, bool aDisableECS) override;
116 
117   virtual nsresult Decode(
118       nsCString& aHost, enum TrrType aType, nsCString& aCname,
119       bool aAllowRFC1918, DOHresp& aResp, TypeRecordResultType& aTypeResult,
120       nsClassHashtable<nsCStringHashKey, DOHresp>& aAdditionalRecords,
121       uint32_t& aTTL) override;
122 
123  protected:
124   bool EncryptDNSQuery(const nsACString& aQuery, uint16_t aPaddingLen,
125                        const ObliviousDoHConfig& aConfig,
126                        ObliviousDoHMessage& aOut);
127   bool DecryptDNSResponse();
128 
129   HpkeContext* mContext = nullptr;
130   UniqueSECItem mPlainQuery;
131   // This struct indicates the range of decrypted responses stored in mResponse.
132   struct DecryptedResponseRange {
133     uint16_t mStart = 0;
134     uint16_t mLength = 0;
135   };
136   Maybe<DecryptedResponseRange> mDecryptedResponseRange;
137 };
138 
139 }  // namespace net
140 }  // namespace mozilla
141 
142 #endif  // mozilla_net_DNSPacket_h__
143