]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsparser.hh
Merge pull request #5523 from rubenk/fix-typos-in-logmessage
[thirdparty/pdns.git] / pdns / dnsparser.hh
CommitLineData
4192ca66 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 */
ff6a1e7b
BH
22#ifndef DNSPARSER_HH
23#define DNSPARSER_HH
24
25#include <map>
26#include <sstream>
27#include <stdexcept>
ff6a1e7b
BH
28#include <iostream>
29#include <vector>
30#include <errno.h>
5a57d2ea 31// #include <netinet/in.h>
5716fab3 32#include "misc.hh"
dd7da6cd 33
9a450843
BH
34#include <boost/tuple/tuple.hpp>
35#include <boost/tuple/tuple_comparison.hpp>
5a57d2ea 36#include "dns.hh"
ea634573 37#include "dnswriter.hh"
d926c0da
KM
38#include "dnsname.hh"
39#include "pdnsexception.hh"
bff744a8
BH
40
41/** DNS records have three representations:
42 1) in the packet
43 2) parsed in a class, ready for use
44 3) in the zone
45
46 We should implement bidirectional transitions between 1&2 and 2&3.
47 Currently we have: 1 -> 2
48 2 -> 3
49
50 We can add: 2 -> 1 easily by reversing the packetwriter
51 And we might be able to reverse 2 -> 3 as well
52*/
53
10f4eea8 54#include "namespaces.hh"
61b26744 55#include "namespaces.hh"
7b1469bb
BH
56
57class MOADNSException : public runtime_error
58{
59public:
60 MOADNSException(const string& str) : runtime_error(str)
61 {}
62};
ff6a1e7b 63
ff6a1e7b
BH
64
65class MOADNSParser;
66
67class PacketReader
68{
69public:
092f210a 70 PacketReader(const vector<uint8_t>& content)
eef10ff2
PD
71 : d_pos(0), d_startrecordpos(0), d_content(content)
72 {
a683e8bd
RG
73 if(content.size() > std::numeric_limits<uint16_t>::max())
74 throw std::out_of_range("packet too large");
75
76 d_recordlen = (uint16_t) content.size();
745bf26e 77 not_used = 0;
eef10ff2 78 }
ff6a1e7b 79
092f210a
BH
80 uint32_t get32BitInt();
81 uint16_t get16BitInt();
bff744a8 82 uint8_t get8BitInt();
341930bb
BH
83
84 void xfr48BitInt(uint64_t& val);
bff744a8
BH
85
86 void xfr32BitInt(uint32_t& val)
87 {
88 val=get32BitInt();
89 }
90
cbf0e7f3
BH
91 void xfrIP(uint32_t& val)
92 {
93 xfr32BitInt(val);
79a9e9ad 94 val=htonl(val);
cbf0e7f3
BH
95 }
96
b9b28916
AT
97 void xfrIP6(std::string &val) {
98 xfrBlob(val, 16);
99 }
100
8bf26468
BH
101 void xfrTime(uint32_t& val)
102 {
103 xfr32BitInt(val);
104 }
105
106
bff744a8
BH
107 void xfr16BitInt(uint16_t& val)
108 {
109 val=get16BitInt();
110 }
111
8bf26468
BH
112 void xfrType(uint16_t& val)
113 {
114 xfr16BitInt(val);
115 }
116
117
8c1c9170
BH
118 void xfr8BitInt(uint8_t& val)
119 {
120 val=get8BitInt();
121 }
122
123
f21fc0aa 124 void xfrName(DNSName &name, bool compress=false, bool noDot=false)
bff744a8 125 {
143da54c 126 name=getName();
bff744a8
BH
127 }
128
84e1142d 129 void xfrText(string &text, bool multi=false, bool lenField=true)
bff744a8 130 {
84e1142d 131 text=getText(multi, lenField);
bff744a8
BH
132 }
133
948a927f
PL
134 void xfrUnquotedText(string &text, bool lenField){
135 text=getUnquotedText(lenField);
136 }
137
8c1c9170 138 void xfrBlob(string& blob);
2fe9d6f7 139 void xfrBlobNoSpaces(string& blob, int len);
06ffdc52 140 void xfrBlob(string& blob, int length);
e4090157 141 void xfrHexBlob(string& blob, bool keepReading=false);
8c1c9170 142
092f210a 143 static uint16_t get16BitInt(const vector<unsigned char>&content, uint16_t& pos);
bff744a8 144
ff6a1e7b 145 void getDnsrecordheader(struct dnsrecordheader &ah);
092f210a
BH
146 void copyRecord(vector<unsigned char>& dest, uint16_t len);
147 void copyRecord(unsigned char* dest, uint16_t len);
2ce12d79 148
8171ab83 149 DNSName getName();
84e1142d 150 string getText(bool multi, bool lenField);
948a927f 151 string getUnquotedText(bool lenField);
ff6a1e7b 152
092f210a 153 uint16_t d_pos;
bff744a8 154
d476d7fb
AT
155 bool eof() { return true; };
156
ff6a1e7b 157private:
8c1c9170 158 uint16_t d_startrecordpos; // needed for getBlob later on
abc1d928 159 uint16_t d_recordlen; // ditto
b816d574 160 uint16_t not_used; // Aligns the whole class on 8-byte boundries
092f210a 161 const vector<uint8_t>& d_content;
ff6a1e7b
BH
162};
163
ea634573 164struct DNSRecord;
7fc69fd0 165
ff6a1e7b
BH
166class DNSRecordContent
167{
168public:
6177a176
RG
169 static std::shared_ptr<DNSRecordContent> mastermake(const DNSRecord &dr, PacketReader& pr);
170 static std::shared_ptr<DNSRecordContent> mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t opcode);
171 static std::shared_ptr<DNSRecordContent> mastermake(uint16_t qtype, uint16_t qclass, const string& zone);
a957f3ee 172 static std::unique_ptr<DNSRecordContent> makeunique(uint16_t qtype, uint16_t qclass, const string& content);
bff744a8 173
f21fc0aa 174 virtual std::string getZoneRepresentation(bool noDot=false) const = 0;
ff6a1e7b 175 virtual ~DNSRecordContent() {}
6c0670c3 176 virtual void toPacket(DNSPacketWriter& pw)=0;
675fa24c 177 virtual string serialize(const DNSName& qname, bool canonic=false, bool lowerCase=false) // it would rock if this were const, but it is too hard
ea634573
BH
178 {
179 vector<uint8_t> packet;
9fdc0834 180 DNSPacketWriter pw(packet, g_rootdnsname, 1);
9c92ad4b
BH
181 if(canonic)
182 pw.setCanonic(true);
183
7f5bf0ba
BH
184 if(lowerCase)
185 pw.setLowercase(true);
186
5a1f298f 187 pw.startRecord(qname, this->getType());
ea634573 188 this->toPacket(pw);
ea634573
BH
189
190 string record;
e636cab2 191 pw.getRecordPayload(record); // needs to be called before commit()
ea634573
BH
192 return record;
193 }
194
f18e430f 195 virtual bool operator==(const DNSRecordContent& rhs) const
196 {
197 return typeid(*this)==typeid(rhs) && this->getZoneRepresentation() == rhs.getZoneRepresentation();
198 }
199
561434a6 200 static shared_ptr<DNSRecordContent> unserialize(const DNSName& qname, uint16_t qtype, const string& serialized);
ff6a1e7b 201
2770fad0
BH
202 void doRecordCheck(const struct DNSRecord&){}
203
7fc69fd0 204 typedef DNSRecordContent* makerfunc_t(const struct DNSRecord& dr, PacketReader& pr);
6c0670c3
BH
205 typedef DNSRecordContent* zmakerfunc_t(const string& str);
206
207 static void regist(uint16_t cl, uint16_t ty, makerfunc_t* f, zmakerfunc_t* z, const char* name)
7fc69fd0 208 {
8a63d3ce 209 if(f)
49a06471 210 getTypemap()[make_pair(cl,ty)]=f;
8a63d3ce 211 if(z)
49a06471 212 getZmakermap()[make_pair(cl,ty)]=z;
8a63d3ce 213
108c321e
BH
214 getT2Namemap().insert(make_pair(make_pair(cl,ty), name));
215 getN2Typemap().insert(make_pair(name, make_pair(cl,ty)));
7fc69fd0
BH
216 }
217
ee1ada80
BH
218 static void unregist(uint16_t cl, uint16_t ty)
219 {
220 pair<uint16_t, uint16_t> key=make_pair(cl, ty);
221 getTypemap().erase(key);
222 getZmakermap().erase(key);
223 }
224
7fc69fd0
BH
225 static uint16_t TypeToNumber(const string& name)
226 {
e1469cfc 227 n2typemap_t::const_iterator iter = getN2Typemap().find(toUpper(name));
108c321e 228 if(iter != getN2Typemap().end())
274e6aae
BH
229 return iter->second.second;
230
f6209eaf 231 if(boost::starts_with(name, "TYPE") || boost::starts_with(name, "type"))
a683e8bd 232 return (uint16_t) pdns_stou(name.substr(4));
274e6aae 233
7fc69fd0 234 throw runtime_error("Unknown DNS type '"+name+"'");
7fc69fd0
BH
235 }
236
57e5f5f7 237 static const string NumberToType(uint16_t num, uint16_t classnum=1)
7fc69fd0 238 {
108c321e
BH
239 t2namemap_t::const_iterator iter = getT2Namemap().find(make_pair(classnum, num));
240 if(iter == getT2Namemap().end())
335da0ba
AT
241 return "TYPE" + std::to_string(num);
242 // throw runtime_error("Unknown DNS type with numerical id "+std::to_string(num));
274e6aae 243 return iter->second;
7fc69fd0
BH
244 }
245
5a1f298f 246 virtual uint16_t getType() const = 0;
7fc69fd0 247
ea634573 248protected:
092f210a 249 typedef std::map<std::pair<uint16_t, uint16_t>, makerfunc_t* > typemap_t;
6c0670c3 250 typedef std::map<std::pair<uint16_t, uint16_t>, zmakerfunc_t* > zmakermap_t;
108c321e
BH
251 typedef std::map<std::pair<uint16_t, uint16_t>, string > t2namemap_t;
252 typedef std::map<string, std::pair<uint16_t, uint16_t> > n2typemap_t;
49a06471 253 static typemap_t& getTypemap();
108c321e
BH
254 static t2namemap_t& getT2Namemap();
255 static n2typemap_t& getN2Typemap();
49a06471 256 static zmakermap_t& getZmakermap();
ff6a1e7b
BH
257};
258
259struct DNSRecord
260{
748fc8db
AT
261 DNSRecord() {
262 d_type = 0;
263 d_class = QClass::IN;
264 d_ttl = 0;
265 d_clen = 0;
266 d_place = DNSResourceRecord::ANSWER;
267 }
fbe23591 268 explicit DNSRecord(const DNSResourceRecord& rr);
f809c028 269 DNSName d_name;
249fb4c2 270 std::shared_ptr<DNSRecordContent> d_content;
092f210a
BH
271 uint16_t d_type;
272 uint16_t d_class;
273 uint32_t d_ttl;
274 uint16_t d_clen;
e693ff5a 275 DNSResourceRecord::Place d_place;
9a450843
BH
276
277 bool operator<(const DNSRecord& rhs) const
278 {
2dcd140a 279 if(tie(d_name, d_type, d_class, d_ttl) < tie(rhs.d_name, rhs.d_type, rhs.d_class, rhs.d_ttl))
2caf4671 280 return true;
281
2dcd140a 282 if(tie(d_name, d_type, d_class, d_ttl) != tie(rhs.d_name, rhs.d_type, rhs.d_class, rhs.d_ttl))
2caf4671 283 return false;
284
9a450843
BH
285 string lzrp, rzrp;
286 if(d_content)
5716fab3 287 lzrp=toLower(d_content->getZoneRepresentation());
9a450843 288 if(rhs.d_content)
5716fab3 289 rzrp=toLower(rhs.d_content->getZoneRepresentation());
9a450843 290
2caf4671 291 return lzrp < rzrp;
9a450843
BH
292 }
293
23721d33 294 // this orders in canonical order and keeps the SOA record on top
295 static bool prettyCompare(const DNSRecord& a, const DNSRecord& b)
296 {
297 auto aType = (a.d_type == QType::SOA) ? 0 : a.d_type;
298 auto bType = (b.d_type == QType::SOA) ? 0 : b.d_type;
299
300 if(a.d_name.canonCompare(b.d_name))
301 return true;
302 if(b.d_name.canonCompare(a.d_name))
303 return false;
304
305 if(tie(aType, a.d_class, a.d_ttl) < tie(bType, b.d_class, b.d_ttl))
306 return true;
307
308 if(tie(aType, a.d_class, a.d_ttl) != tie(bType, b.d_class, b.d_ttl))
309 return false;
310
311 string lzrp, rzrp;
312 if(a.d_content)
313 lzrp=toLower(a.d_content->getZoneRepresentation());
314 if(b.d_content)
315 rzrp=toLower(b.d_content->getZoneRepresentation());
316
317 return lzrp < rzrp;
318 }
319
320
9a450843
BH
321 bool operator==(const DNSRecord& rhs) const
322 {
90ba52e0 323 if(d_type != rhs.d_type || d_class != rhs.d_class || d_name != rhs.d_name)
324 return false;
325
f18e430f 326 return *d_content == *rhs.d_content;
9a450843 327 }
ff6a1e7b
BH
328};
329
90ba52e0 330struct DNSZoneRecord
331{
7fdee6fc 332 int domain_id{-1};
333 uint8_t scopeMask{0};
334 int signttl{0};
90ba52e0 335 DNSName wildcardname;
7fdee6fc 336 bool auth{true};
90ba52e0 337 DNSRecord dr;
338};
339
340
6c0670c3 341//! This class can be used to parse incoming packets, and is copyable
57e5f5f7 342class MOADNSParser : public boost::noncopyable
ff6a1e7b
BH
343{
344public:
6c0670c3 345 //! Parse from a string
27c0050c 346 MOADNSParser(bool query, const string& buffer) : d_tsigPos(0)
ff6a1e7b 347 {
27c0050c 348 init(query, buffer.c_str(), (unsigned int)buffer.size());
ff6a1e7b
BH
349 }
350
6c0670c3 351 //! Parse from a pointer and length
27c0050c 352 MOADNSParser(bool query, const char *packet, unsigned int len) : d_tsigPos(0)
ff6a1e7b 353 {
27c0050c 354 init(query, packet, len);
ff6a1e7b 355 }
6c0670c3 356
561434a6 357 DNSName d_qname;
092f210a 358 uint16_t d_qclass, d_qtype;
e2ab3f63 359 //uint8_t d_rcode;
46443f87 360 dnsheader d_header;
ff6a1e7b
BH
361
362 typedef vector<pair<DNSRecord, uint16_t > > answers_t;
6c0670c3 363
b88526ce 364 //! All answers contained in this packet (everything *but* the question section)
ff6a1e7b
BH
365 answers_t d_answers;
366
367 shared_ptr<PacketReader> getPacketReader(uint16_t offset)
368 {
369 shared_ptr<PacketReader> pr(new PacketReader(d_content));
370 pr->d_pos=offset;
371 return pr;
372 }
6c0670c3 373
60a1c204 374 uint16_t getTSIGPos() const
57e5f5f7
BH
375 {
376 return d_tsigPos;
377 }
ff6a1e7b
BH
378private:
379 void getDnsrecordheader(struct dnsrecordheader &ah);
27c0050c 380 void init(bool query, const char *packet, unsigned int len);
ff6a1e7b 381 vector<uint8_t> d_content;
57e5f5f7 382 uint16_t d_tsigPos;
ff6a1e7b
BH
383};
384
7127879f 385string simpleCompress(const string& label, const string& root="");
886e2cf2 386void ageDNSPacket(char* packet, size_t length, uint32_t seconds);
2c73e580 387void ageDNSPacket(std::string& packet, uint32_t seconds);
153d5065 388void editDNSPacketTTL(char* packet, size_t length, std::function<uint32_t(uint8_t, uint16_t, uint16_t, uint32_t)> visitor);
0766890a 389uint32_t getDNSPacketMinTTL(const char* packet, size_t length);
55baa1f2
RG
390uint32_t getDNSPacketLength(const char* packet, size_t length);
391uint16_t getRecordsOfTypeCount(const char* packet, size_t length, uint8_t section, uint16_t type);
a1d0d0e6 392
393template<typename T>
394std::shared_ptr<T> getRR(const DNSRecord& dr)
395{
396 return std::dynamic_pointer_cast<T>(dr.d_content);
397}
398
ff6a1e7b 399#endif