]>
Commit | Line | Data |
---|---|---|
4192ca66 BH |
1 | /* |
2 | PowerDNS Versatile Database Driven Nameserver | |
7f5bf0ba | 3 | Copyright (C) 2005 - 2011 PowerDNS.COM BV |
4192ca66 BH |
4 | |
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License version 2 as | |
7 | published by the Free Software Foundation | |
8 | ||
f782fe38 MH |
9 | Additionally, the license of this program contains a special |
10 | exception which allows to distribute the program in binary form when | |
11 | it is linked against OpenSSL. | |
12 | ||
4192ca66 BH |
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 | |
06bd9ccf | 20 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
4192ca66 BH |
21 | */ |
22 | ||
ff6a1e7b BH |
23 | #ifndef DNSPARSER_HH |
24 | #define DNSPARSER_HH | |
25 | ||
26 | #include <map> | |
27 | #include <sstream> | |
28 | #include <stdexcept> | |
ff6a1e7b BH |
29 | #include <iostream> |
30 | #include <vector> | |
31 | #include <errno.h> | |
5a57d2ea | 32 | // #include <netinet/in.h> |
5716fab3 | 33 | #include "misc.hh" |
ff6a1e7b | 34 | #include <boost/shared_ptr.hpp> |
7fc69fd0 | 35 | #include <boost/lexical_cast.hpp> |
9a450843 BH |
36 | #include <boost/tuple/tuple.hpp> |
37 | #include <boost/tuple/tuple_comparison.hpp> | |
5a57d2ea | 38 | #include "dns.hh" |
ea634573 | 39 | #include "dnswriter.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 | |
57 | class MOADNSException : public runtime_error | |
58 | { | |
59 | public: | |
60 | MOADNSException(const string& str) : runtime_error(str) | |
61 | {} | |
62 | }; | |
ff6a1e7b | 63 | |
ff6a1e7b BH |
64 | |
65 | class MOADNSParser; | |
66 | ||
67 | class PacketReader | |
68 | { | |
69 | public: | |
092f210a | 70 | PacketReader(const vector<uint8_t>& content) |
eef10ff2 PD |
71 | : d_pos(0), d_startrecordpos(0), d_content(content) |
72 | { | |
73 | d_recordlen = content.size(); | |
74 | } | |
ff6a1e7b | 75 | |
092f210a BH |
76 | uint32_t get32BitInt(); |
77 | uint16_t get16BitInt(); | |
bff744a8 | 78 | uint8_t get8BitInt(); |
341930bb BH |
79 | |
80 | void xfr48BitInt(uint64_t& val); | |
bff744a8 BH |
81 | |
82 | void xfr32BitInt(uint32_t& val) | |
83 | { | |
84 | val=get32BitInt(); | |
85 | } | |
86 | ||
cbf0e7f3 BH |
87 | void xfrIP(uint32_t& val) |
88 | { | |
89 | xfr32BitInt(val); | |
79a9e9ad | 90 | val=htonl(val); |
cbf0e7f3 BH |
91 | } |
92 | ||
b9b28916 AT |
93 | void xfrIP6(std::string &val) { |
94 | xfrBlob(val, 16); | |
95 | } | |
96 | ||
8bf26468 BH |
97 | void xfrTime(uint32_t& val) |
98 | { | |
99 | xfr32BitInt(val); | |
100 | } | |
101 | ||
102 | ||
bff744a8 BH |
103 | void xfr16BitInt(uint16_t& val) |
104 | { | |
105 | val=get16BitInt(); | |
106 | } | |
107 | ||
8bf26468 BH |
108 | void xfrType(uint16_t& val) |
109 | { | |
110 | xfr16BitInt(val); | |
111 | } | |
112 | ||
113 | ||
8c1c9170 BH |
114 | void xfr8BitInt(uint8_t& val) |
115 | { | |
116 | val=get8BitInt(); | |
117 | } | |
118 | ||
119 | ||
bca6643b | 120 | void xfrLabel(string &label, bool compress=false) |
bff744a8 BH |
121 | { |
122 | label=getLabel(); | |
123 | } | |
124 | ||
ef6a78d5 | 125 | void xfrText(string &text, bool multi=false) |
bff744a8 | 126 | { |
ef6a78d5 | 127 | text=getText(multi); |
bff744a8 BH |
128 | } |
129 | ||
8c1c9170 | 130 | void xfrBlob(string& blob); |
06ffdc52 | 131 | void xfrBlob(string& blob, int length); |
e4090157 | 132 | void xfrHexBlob(string& blob, bool keepReading=false); |
8c1c9170 | 133 | |
092f210a BH |
134 | static uint16_t get16BitInt(const vector<unsigned char>&content, uint16_t& pos); |
135 | static void getLabelFromContent(const vector<uint8_t>& content, uint16_t& frompos, string& ret, int recurs); | |
bff744a8 | 136 | |
ff6a1e7b | 137 | void getDnsrecordheader(struct dnsrecordheader &ah); |
092f210a BH |
138 | void copyRecord(vector<unsigned char>& dest, uint16_t len); |
139 | void copyRecord(unsigned char* dest, uint16_t len); | |
2ce12d79 | 140 | |
ff6a1e7b | 141 | string getLabel(unsigned int recurs=0); |
ef6a78d5 | 142 | string getText(bool multi); |
ff6a1e7b | 143 | |
092f210a | 144 | uint16_t d_pos; |
bff744a8 | 145 | |
ff6a1e7b | 146 | private: |
8c1c9170 | 147 | uint16_t d_startrecordpos; // needed for getBlob later on |
abc1d928 | 148 | uint16_t d_recordlen; // ditto |
092f210a | 149 | const vector<uint8_t>& d_content; |
ff6a1e7b BH |
150 | }; |
151 | ||
ea634573 | 152 | struct DNSRecord; |
7fc69fd0 | 153 | |
ff6a1e7b BH |
154 | class DNSRecordContent |
155 | { | |
156 | public: | |
7fc69fd0 | 157 | static DNSRecordContent* mastermake(const DNSRecord &dr, PacketReader& pr); |
7945d472 | 158 | static DNSRecordContent* mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t opcode); |
6c0670c3 | 159 | static DNSRecordContent* mastermake(uint16_t qtype, uint16_t qclass, const string& zone); |
bff744a8 | 160 | |
ff6a1e7b | 161 | virtual std::string getZoneRepresentation() const = 0; |
ff6a1e7b | 162 | virtual ~DNSRecordContent() {} |
6c0670c3 | 163 | virtual void toPacket(DNSPacketWriter& pw)=0; |
7f5bf0ba | 164 | virtual string serialize(const string& qname, bool canonic=false, bool lowerCase=false) // it would rock if this were const, but it is too hard |
ea634573 BH |
165 | { |
166 | vector<uint8_t> packet; | |
7127879f BH |
167 | string empty; |
168 | DNSPacketWriter pw(packet, empty, 1); | |
9c92ad4b BH |
169 | if(canonic) |
170 | pw.setCanonic(true); | |
171 | ||
7f5bf0ba BH |
172 | if(lowerCase) |
173 | pw.setLowercase(true); | |
174 | ||
ea634573 BH |
175 | pw.startRecord(qname, d_qtype); |
176 | this->toPacket(pw); | |
177 | pw.commit(); | |
178 | ||
179 | string record; | |
180 | pw.getRecords(record); | |
181 | return record; | |
182 | } | |
183 | ||
184 | static shared_ptr<DNSRecordContent> unserialize(const string& qname, uint16_t qtype, const string& serialized); | |
ff6a1e7b | 185 | |
2770fad0 BH |
186 | void doRecordCheck(const struct DNSRecord&){} |
187 | ||
ff6a1e7b BH |
188 | std::string label; |
189 | struct dnsrecordheader header; | |
7fc69fd0 BH |
190 | |
191 | typedef DNSRecordContent* makerfunc_t(const struct DNSRecord& dr, PacketReader& pr); | |
6c0670c3 BH |
192 | typedef DNSRecordContent* zmakerfunc_t(const string& str); |
193 | ||
194 | static void regist(uint16_t cl, uint16_t ty, makerfunc_t* f, zmakerfunc_t* z, const char* name) | |
7fc69fd0 | 195 | { |
8a63d3ce | 196 | if(f) |
49a06471 | 197 | getTypemap()[make_pair(cl,ty)]=f; |
8a63d3ce | 198 | if(z) |
49a06471 | 199 | getZmakermap()[make_pair(cl,ty)]=z; |
8a63d3ce | 200 | |
108c321e BH |
201 | getT2Namemap().insert(make_pair(make_pair(cl,ty), name)); |
202 | getN2Typemap().insert(make_pair(name, make_pair(cl,ty))); | |
7fc69fd0 BH |
203 | } |
204 | ||
ee1ada80 BH |
205 | static void unregist(uint16_t cl, uint16_t ty) |
206 | { | |
207 | pair<uint16_t, uint16_t> key=make_pair(cl, ty); | |
208 | getTypemap().erase(key); | |
209 | getZmakermap().erase(key); | |
210 | } | |
211 | ||
7fc69fd0 BH |
212 | static uint16_t TypeToNumber(const string& name) |
213 | { | |
e1469cfc | 214 | n2typemap_t::const_iterator iter = getN2Typemap().find(toUpper(name)); |
108c321e | 215 | if(iter != getN2Typemap().end()) |
274e6aae BH |
216 | return iter->second.second; |
217 | ||
218 | if(boost::starts_with(name, "TYPE")) | |
219 | return atoi(name.c_str()+4); | |
220 | ||
7fc69fd0 | 221 | throw runtime_error("Unknown DNS type '"+name+"'"); |
7fc69fd0 BH |
222 | } |
223 | ||
57e5f5f7 | 224 | static const string NumberToType(uint16_t num, uint16_t classnum=1) |
7fc69fd0 | 225 | { |
108c321e BH |
226 | t2namemap_t::const_iterator iter = getT2Namemap().find(make_pair(classnum, num)); |
227 | if(iter == getT2Namemap().end()) | |
274e6aae | 228 | return "TYPE" + lexical_cast<string>(num); |
a640a9d4 | 229 | // throw runtime_error("Unknown DNS type with numerical id "+lexical_cast<string>(num)); |
274e6aae | 230 | return iter->second; |
7fc69fd0 BH |
231 | } |
232 | ||
ea634573 BH |
233 | explicit DNSRecordContent(uint16_t type) : d_qtype(type) |
234 | {} | |
9c92ad4b BH |
235 | |
236 | ||
237 | DNSRecordContent& operator=(const DNSRecordContent& orig) | |
238 | { | |
239 | const_cast<uint16_t&>(d_qtype) = orig.d_qtype; // **COUGH** | |
240 | label = orig.label; | |
241 | header = orig.header; | |
242 | return *this; | |
243 | } | |
244 | ||
245 | ||
ea634573 | 246 | const uint16_t d_qtype; |
7fc69fd0 | 247 | |
ea634573 | 248 | protected: |
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 | ||
259 | struct DNSRecord | |
260 | { | |
261 | std::string d_label; | |
092f210a BH |
262 | uint16_t d_type; |
263 | uint16_t d_class; | |
264 | uint32_t d_ttl; | |
265 | uint16_t d_clen; | |
6c0670c3 | 266 | enum {Answer=1, Nameserver, Additional} d_place; |
ff6a1e7b | 267 | boost::shared_ptr<DNSRecordContent> d_content; |
9a450843 BH |
268 | |
269 | bool operator<(const DNSRecord& rhs) const | |
270 | { | |
271 | string lzrp, rzrp; | |
272 | if(d_content) | |
5716fab3 | 273 | lzrp=toLower(d_content->getZoneRepresentation()); |
9a450843 | 274 | if(rhs.d_content) |
5716fab3 | 275 | rzrp=toLower(rhs.d_content->getZoneRepresentation()); |
9a450843 | 276 | |
5716fab3 BH |
277 | string llabel=toLower(d_label); |
278 | string rlabel=toLower(rhs.d_label); | |
279 | ||
9a450843 | 280 | return |
5716fab3 BH |
281 | tie(llabel, d_type, d_class, lzrp) < |
282 | tie(rlabel, rhs.d_type, rhs.d_class, rzrp); | |
9a450843 BH |
283 | } |
284 | ||
285 | bool operator==(const DNSRecord& rhs) const | |
286 | { | |
287 | string lzrp, rzrp; | |
288 | if(d_content) | |
5716fab3 | 289 | lzrp=toLower(d_content->getZoneRepresentation()); |
9a450843 | 290 | if(rhs.d_content) |
5716fab3 BH |
291 | rzrp=toLower(rhs.d_content->getZoneRepresentation()); |
292 | ||
293 | string llabel=toLower(d_label); | |
294 | string rlabel=toLower(rhs.d_label); | |
9a450843 BH |
295 | |
296 | return | |
5716fab3 BH |
297 | tie(llabel, d_type, d_class, lzrp) == |
298 | tie(rlabel, rhs.d_type, rhs.d_class, rzrp); | |
9a450843 | 299 | } |
ff6a1e7b BH |
300 | }; |
301 | ||
6c0670c3 | 302 | //! This class can be used to parse incoming packets, and is copyable |
57e5f5f7 | 303 | class MOADNSParser : public boost::noncopyable |
ff6a1e7b BH |
304 | { |
305 | public: | |
6c0670c3 | 306 | //! Parse from a string |
57e5f5f7 | 307 | MOADNSParser(const string& buffer) : d_tsigPos(0) |
ff6a1e7b | 308 | { |
705f31ae | 309 | init(buffer.c_str(), (unsigned int)buffer.size()); |
ff6a1e7b BH |
310 | } |
311 | ||
6c0670c3 | 312 | //! Parse from a pointer and length |
57e5f5f7 | 313 | MOADNSParser(const char *packet, unsigned int len) : d_tsigPos(0) |
ff6a1e7b BH |
314 | { |
315 | init(packet, len); | |
316 | } | |
6c0670c3 | 317 | |
ff6a1e7b BH |
318 | dnsheader d_header; |
319 | string d_qname; | |
092f210a | 320 | uint16_t d_qclass, d_qtype; |
e2ab3f63 | 321 | //uint8_t d_rcode; |
ff6a1e7b BH |
322 | |
323 | typedef vector<pair<DNSRecord, uint16_t > > answers_t; | |
6c0670c3 BH |
324 | |
325 | //! All answers contained in this packet | |
ff6a1e7b BH |
326 | answers_t d_answers; |
327 | ||
328 | shared_ptr<PacketReader> getPacketReader(uint16_t offset) | |
329 | { | |
330 | shared_ptr<PacketReader> pr(new PacketReader(d_content)); | |
331 | pr->d_pos=offset; | |
332 | return pr; | |
333 | } | |
6c0670c3 | 334 | |
57e5f5f7 BH |
335 | uint16_t getTSIGPos() |
336 | { | |
337 | return d_tsigPos; | |
338 | } | |
ff6a1e7b BH |
339 | private: |
340 | void getDnsrecordheader(struct dnsrecordheader &ah); | |
341 | void init(const char *packet, unsigned int len); | |
342 | vector<uint8_t> d_content; | |
57e5f5f7 | 343 | uint16_t d_tsigPos; |
ff6a1e7b BH |
344 | }; |
345 | ||
7127879f | 346 | string simpleCompress(const string& label, const string& root=""); |
b8e0f341 | 347 | void simpleExpandTo(const string& label, unsigned int frompos, string& ret); |
2c73e580 | 348 | void ageDNSPacket(std::string& packet, uint32_t seconds); |
ff6a1e7b | 349 | #endif |