]>
Commit | Line | Data |
---|---|---|
12c86877 | 1 | /* |
12471842 PL |
2 | * This file is part of PowerDNS or dnsdist. |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
e8c59f2d | 22 | #pragma once |
1258abe0 | 23 | #include <sys/types.h> |
809fe23f | 24 | #include "iputils.hh" |
af7d3ea6 | 25 | #include "ednssubnet.hh" |
37063755 | 26 | #include "ednscookies.hh" |
3d92919d | 27 | #include <optional> |
55b524a0 | 28 | #include <unordered_set> |
12c86877 BH |
29 | #include <sys/socket.h> |
30 | #include <netinet/in.h> | |
31 | #include <sys/time.h> | |
1258abe0 BH |
32 | #include <unistd.h> |
33 | #include <arpa/inet.h> | |
34 | ||
12c86877 | 35 | #include <iostream> |
f28cf17b | 36 | #include <optional> |
12c86877 | 37 | #include <string> |
12c86877 BH |
38 | #include <vector> |
39 | #include "qtype.hh" | |
40 | #include "dns.hh" | |
41 | #include "misc.hh" | |
42 | #include "utility.hh" | |
43 | #include "logger.hh" | |
5c409fa2 | 44 | #include "pdnsexception.hh" |
78bcb858 | 45 | #include "dnsrecords.hh" |
12c86877 | 46 | |
3971cf53 | 47 | class UeberBackend; |
e0d84497 | 48 | class DNSSECKeeper; |
34b37bbb | 49 | |
90ba52e0 | 50 | |
12c86877 BH |
51 | //! This class represents DNS packets, either received or to be sent. |
52 | class DNSPacket | |
53 | { | |
54 | public: | |
27c0050c | 55 | DNSPacket(bool isQuery); |
f238ce64 OM |
56 | DNSPacket(const DNSPacket &orig) = default; |
57 | DNSPacket & operator=(const DNSPacket &) = default; | |
12c86877 | 58 | |
a683e8bd RG |
59 | int noparse(const char *mesg, size_t len); //!< just suck the data inward |
60 | int parse(const char *mesg, size_t len); //!< parse a raw UDP or TCP packet and suck the data inward | |
1f07a63f | 61 | const string& getString(bool throwsOnTruncation=false); //!< for serialization - just passes the whole packet. If throwsOnTruncation is set, an exception will be raised if the records are too large to fit inside a single DNS payload, instead of setting the TC bit |
12c86877 | 62 | |
34b37bbb | 63 | // address & socket manipulation |
4172a5b2 | 64 | void setRemote(const ComboAddress*, std::optional<ComboAddress> = std::nullopt); |
b9b4da23 | 65 | ComboAddress getRemote() const; |
4172a5b2 | 66 | ComboAddress getInnerRemote() const; // for proxy protocol |
af7d3ea6 | 67 | Netmask getRealRemote() const; |
b9b4da23 | 68 | ComboAddress getLocal() const |
88c1bc50 BH |
69 | { |
70 | ComboAddress ca; | |
71 | socklen_t len=sizeof(ca); | |
72 | getsockname(d_socket, (sockaddr*)&ca, &len); | |
b9b4da23 | 73 | return ca; |
88c1bc50 | 74 | } |
092f210a | 75 | uint16_t getRemotePort() const; |
2b6f1436 | 76 | |
4172a5b2 PD |
77 | string getRemoteString() const; |
78 | string getRemoteStringWithPort() const; | |
79 | ||
2b6f1436 | 80 | boost::optional<ComboAddress> d_anyLocal; |
12c86877 | 81 | |
34b37bbb BH |
82 | Utility::sock_t getSocket() const |
83 | { | |
84 | return d_socket; | |
85 | } | |
b8e0f341 | 86 | void setSocket(Utility::sock_t sock); |
34b37bbb | 87 | |
34b37bbb BH |
88 | // these manipulate 'd' |
89 | void setA(bool); //!< make this packet authoritative - manipulates 'd' | |
90 | void setID(uint16_t); //!< set the DNS id of this packet - manipulates 'd' | |
91 | void setRA(bool); //!< set the Recursion Available flag - manipulates 'd' | |
92 | void setRD(bool); //!< set the Recursion Desired flag - manipulates 'd' | |
93 | void setAnswer(bool); //!< Make this packet an answer - clears the 'stringbuffer' first, if passed 'true', does nothing otherwise, manipulates 'd' | |
12c86877 | 94 | |
34b37bbb BH |
95 | void setOpcode(uint16_t); //!< set the Opcode of this packet - manipulates 'd' |
96 | void setRcode(int v); //!< set the Rcode of this packet - manipulates 'd' | |
97 | ||
98 | void clearRecords(); //!< when building a packet, wipe all previously added records (clears 'rrs') | |
77235722 | 99 | |
90ba52e0 | 100 | /** Add a DNSZoneRecord to this packet. A DNSPacket (as does a DNS Packet) has 4 kinds of resource records. Questions, |
12c86877 | 101 | Answers, Authority and Additional. See RFC 1034 and 1035 for details. You can specify where a record needs to go in the |
90ba52e0 | 102 | DNSZoneRecord d_place field */ |
9bbcf03a | 103 | void addRecord(DNSZoneRecord&&); // adds to 'rrs' |
34b37bbb | 104 | |
c2f3be9d | 105 | void setQuestion(int op, const DNSName &qdomain, int qtype); // wipes 'd', sets a random id, creates start of packet (domain, type, class etc) |
34b37bbb BH |
106 | |
107 | DTime d_dt; //!< the time this packet was created. replyPacket() copies this in for you, so d_dt becomes the time spent processing the question+answer | |
1f07a63f | 108 | void wrapup(bool throwsOnTruncation=false); // writes out queued rrs, and generates the binary packet. also shuffles. also rectifies dnsheader 'd', and copies it to the stringbuffer. If throwsOnTruncation is set, an exception will be raised if the records are too large to fit inside a single DNS payload, instead of setting the TC bit |
c2826d2e | 109 | void spoofQuestion(const DNSPacket& qd); //!< paste in the exact right case of the question. Useful for PacketCache |
b35ea8ec | 110 | unsigned int getMinTTL(); //!< returns lowest TTL of any record in the packet |
9951e2d0 | 111 | bool isEmpty(); //!< returns true if there are no rrs in the packet |
34b37bbb | 112 | |
90ba52e0 | 113 | vector<DNSZoneRecord*> getAPRecords(); //!< get a vector with DNSZoneRecords that need additional processing |
114 | vector<DNSZoneRecord*> getAnswerRecords(); //!< get a vector with DNSZoneRecords that are answers | |
bdbee377 | 115 | vector<DNSZoneRecord*> getServiceRecords(); //!< Get a vector with all Service-style (SVCB) records |
34b37bbb BH |
116 | void setCompress(bool compress); |
117 | ||
c2826d2e | 118 | std::unique_ptr<DNSPacket> replyPacket() const; //!< convenience function that creates a virgin answer packet to this question |
34b37bbb | 119 | |
b8e0f341 | 120 | void commitD(); //!< copies 'd' into the stringbuffer |
78bcb858 | 121 | unsigned int getMaxReplyLen(); //!< retrieve the maximum length of the packet we should send in response |
80397312 | 122 | void setMaxReplyLen(int bytes); //!< set the max reply len (used when retrieving from the packet cache, and this changed) |
7f7b8d55 | 123 | |
c2826d2e | 124 | bool couldBeCached() const; //!< returns 0 if this query should bypass the packet cache |
02980dc2 | 125 | bool hasEDNSSubnet() const; |
c2826d2e | 126 | bool hasEDNS() const; |
37063755 PL |
127 | bool hasEDNSCookie() const; |
128 | bool hasWellFormedEDNSCookie() const; | |
38118dcb | 129 | bool hasValidEDNSCookie() const; |
298fabc3 AT |
130 | uint8_t getEDNSVersion() const { return d_ednsversion; }; |
131 | void setEDNSRcode(uint16_t extRCode) | |
132 | { | |
133 | // WARNING: this is really 12 bits | |
134 | d_ednsrcode=extRCode; | |
135 | }; | |
136 | uint8_t getEDNSRCode() const { return d_ednsrcode; }; | |
bf269e28 RG |
137 | uint32_t getHash() const { return d_hash; }; |
138 | void setHash(uint32_t hash) { d_hash = hash; }; | |
139 | ||
34b37bbb | 140 | //////// DATA ! |
12c86877 | 141 | |
c2f3be9d PD |
142 | DNSName qdomain; //!< qname of the question 4 - unsure how this is used |
143 | DNSName qdomainwild; //!< wildcard matched by qname, used by LuaPolicyEngine | |
144 | DNSName qdomainzone; //!< zone name for the answer (as reflected in SOA for negative responses), used by LuaPolicyEngine | |
921d0747 | 145 | string d_peer_principal; |
1a5ac5d7 AT |
146 | const DNSName& getTSIGKeyname() const; |
147 | ||
921d0747 PL |
148 | struct dnsheader d; //!< dnsheader at the start of the databuffer 12 |
149 | ||
921d0747 PL |
150 | TSIGRecordContent d_trc; //72 |
151 | ||
152 | ComboAddress d_remote; //28 | |
034768b4 | 153 | std::optional<ComboAddress> d_inner_remote; // the 'outer' remote is the IP on the physical packet header. The 'inner' remote lives one layer deeper, in the PROXY header. |
eace2c24 | 154 | TSIGHashEnum d_tsig_algo{TSIG_MD5}; //4 |
921d0747 | 155 | |
f93ad391 | 156 | int d_ednsRawPacketSizeLimit{-1}; // only used for Lua record |
eace2c24 RG |
157 | uint16_t qclass{QClass::IN}; //!< class of the question - should always be INternet 2 |
158 | QType qtype; //!< type of the question 2 | |
159 | ||
160 | bool d_tcp{false}; | |
161 | bool d_dnssecOk{false}; | |
162 | bool d_havetsig{false}; | |
78bcb858 | 163 | |
ea3816cf | 164 | bool getTSIGDetails(TSIGRecordContent* tr, DNSName* keyname, uint16_t* tsigPos=nullptr) const; |
675fa24c PD |
165 | void setTSIGDetails(const TSIGRecordContent& tr, const DNSName& keyname, const string& secret, const string& previous, bool timersonly=false); |
166 | bool getTKEYRecord(TKEYRecordContent* tr, DNSName* keyname) const; | |
4429ed62 | 167 | |
90ba52e0 | 168 | vector<DNSZoneRecord>& getRRS() { return d_rrs; } |
ea3816cf RG |
169 | bool checkForCorrectTSIG(UeberBackend* B, DNSName* keyname, string* secret, TSIGRecordContent* trc) const; |
170 | ||
779b8a25 | 171 | static uint16_t s_udpTruncationThreshold; |
eace2c24 | 172 | static bool s_doEDNSSubnetProcessing; |
37063755 PL |
173 | static bool s_doEDNSCookieProcessing; |
174 | static string s_EDNSCookieKey; | |
50e2abc0 | 175 | EDNSSubnetOpts d_eso; |
15e39ee4 OM |
176 | |
177 | #ifdef ENABLE_GSS_TSIG | |
dd0ef5ed | 178 | void cleanupGSS(int rcode); |
15e39ee4 | 179 | #endif |
eace2c24 | 180 | |
12c86877 | 181 | private: |
34b37bbb BH |
182 | void pasteQ(const char *question, int length); //!< set the question of this packet, useful for crafting replies |
183 | ||
78bcb858 | 184 | string d_tsigsecret; |
675fa24c | 185 | DNSName d_tsigkeyname; |
78bcb858 | 186 | string d_tsigprevious; |
78bcb858 | 187 | |
90ba52e0 | 188 | vector<DNSZoneRecord> d_rrs; // 8 |
9d40dd1f | 189 | std::unordered_set<size_t> d_dedup; |
921d0747 | 190 | string d_rawpacket; // this is where everything lives 8 |
37063755 | 191 | EDNSCookiesOpt d_eco; |
921d0747 | 192 | |
eace2c24 RG |
193 | int d_maxreplylen{0}; |
194 | int d_socket{-1}; // 4 | |
bf269e28 | 195 | uint32_t d_hash{0}; |
eace2c24 RG |
196 | // WARNING! This is really 12 bits |
197 | uint16_t d_ednsrcode{0}; | |
198 | uint8_t d_ednsversion{0}; | |
199 | ||
200 | bool d_wrapped{false}; // 1 | |
201 | bool d_compress{true}; // 1 | |
202 | bool d_tsigtimersonly{false}; | |
203 | bool d_wantsnsid{false}; | |
204 | bool d_haveednssubnet{false}; | |
37063755 | 205 | bool d_haveednscookie{false}; |
29992caa | 206 | bool d_ednscookievalid{false}; |
eace2c24 | 207 | bool d_haveednssection{false}; |
27c0050c | 208 | bool d_isQuery; |
12c86877 | 209 | }; |