]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsparser.cc
speed up storage of NS records
[thirdparty/pdns.git] / pdns / dnsparser.cc
CommitLineData
4192ca66
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
f27e6356 3 Copyright (C) 2005 - 2006 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
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
06bd9ccf 16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
4192ca66
BH
17*/
18
ff6a1e7b 19#include "dnsparser.hh"
6c0670c3 20#include "dnswriter.hh"
ff6a1e7b
BH
21#include <boost/lexical_cast.hpp>
22
23using namespace boost;
24
25class UnknownRecordContent : public DNSRecordContent
26{
27public:
7fc69fd0 28 UnknownRecordContent(const DNSRecord& dr, PacketReader& pr)
ea634573 29 : DNSRecordContent(dr.d_type), d_dr(dr)
ff6a1e7b 30 {
7fc69fd0 31 pr.copyRecord(d_record, dr.d_clen);
ff6a1e7b
BH
32 }
33
ea634573 34 UnknownRecordContent(const string& zone) : DNSRecordContent(0)
6c0670c3
BH
35 {
36 d_record.insert(d_record.end(), zone.begin(), zone.end());
37 }
38
ff6a1e7b
BH
39 string getZoneRepresentation() const
40 {
41 ostringstream str;
705f31ae 42 str<<"\\# "<<(unsigned int)d_record.size()<<" ";
ff6a1e7b
BH
43 char hex[4];
44 for(size_t n=0; n<d_record.size(); ++n) {
45 snprintf(hex,sizeof(hex)-1, "%02x", d_record.at(n));
46 str << hex;
47 }
ff6a1e7b
BH
48 return str.str();
49 }
50
6c0670c3
BH
51 void toPacket(DNSPacketWriter& pw)
52 {
d0b471d3 53 string tmp((char*)&*d_record.begin(), d_record.size());
6c0670c3
BH
54 vector<string> parts;
55 stringtok(parts, tmp);
cc835f89 56 if(parts.size()!=3)
a9af3782 57 throw MOADNSException("Unknown record was stored incorrectly, need 3 fields, got "+lexical_cast<string>(parts.size())+": "+tmp );
6c0670c3
BH
58 const string& relevant=parts[2];
59 unsigned int total=atoi(parts[1].c_str());
60 if(relevant.size()!=2*total)
61 throw runtime_error("invalid unknown record");
62 string out;
cc835f89 63 out.reserve(total+1);
6c0670c3
BH
64 for(unsigned int n=0; n < total; ++n) {
65 int c;
66 sscanf(relevant.c_str()+2*n, "%02x", &c);
67 out.append(1, (char)c);
68 }
69 pw.xfrBlob(out);
70 }
ff6a1e7b 71private:
6c0670c3
BH
72 DNSRecord d_dr;
73 vector<uint8_t> d_record;
ff6a1e7b
BH
74};
75
ea634573
BH
76static const string EncodeDNSLabel(const string& input)
77{
78 typedef vector<string> parts_t;
79 parts_t parts;
80 stringtok(parts,input,".");
81 string ret;
82 for(parts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) {
83 ret.append(1,(char)i->length());
84 ret.append(*i);
85 }
86 ret.append(1,(char)0);
87 return ret;
88}
ff6a1e7b 89
ea634573
BH
90shared_ptr<DNSRecordContent> DNSRecordContent::unserialize(const string& qname, uint16_t qtype, const string& serialized)
91{
92 dnsheader dnsheader;
93 memset(&dnsheader, 0, sizeof(dnsheader));
94 dnsheader.qdcount=htons(1);
95 dnsheader.ancount=htons(1);
96
97 vector<uint8_t> packet; // build pseudo packet
678ce973
BH
98
99 /* will look like: dnsheader, 5 bytes, encoded qname, dns record header, serialized data */
ea634573
BH
100
101 string encoded=EncodeDNSLabel(qname);
678ce973
BH
102
103 packet.resize(sizeof(dnsheader) + 5 + encoded.size() + sizeof(struct dnsrecordheader) + serialized.size());
104
105 uint16_t pos=0;
106
107 memcpy(&packet[0], &dnsheader, sizeof(dnsheader)); pos+=sizeof(dnsheader);
108
109 char tmp[6]="\x0" "\x0\x1" "\x0\x1"; // root question for ns_t_a
110 memcpy(&packet[pos], &tmp, 5); pos+=5;
111
705f31ae 112 memcpy(&packet[pos], encoded.c_str(), encoded.size()); pos+=(uint16_t)encoded.size();
ea634573
BH
113
114 struct dnsrecordheader drh;
115 drh.d_type=htons(qtype);
116 drh.d_class=htons(1);
117 drh.d_ttl=0;
118 drh.d_clen=htons(serialized.size());
119
678ce973 120 memcpy(&packet[pos], &drh, sizeof(drh)); pos+=sizeof(drh);
705f31ae 121 memcpy(&packet[pos], serialized.c_str(), serialized.size()); pos+=(uint16_t)serialized.size();
ea634573 122
705f31ae 123 MOADNSParser mdp((char*)&*packet.begin(), (unsigned int)packet.size());
ea634573
BH
124 shared_ptr<DNSRecordContent> ret= mdp.d_answers.begin()->first.d_content;
125 ret->header.d_type=ret->d_qtype;
126 ret->label=mdp.d_answers.begin()->first.d_label;
127 ret->header.d_ttl=mdp.d_answers.begin()->first.d_ttl;
128 return ret;
129}
ff6a1e7b 130
7fc69fd0 131DNSRecordContent* DNSRecordContent::mastermake(const DNSRecord &dr,
ff6a1e7b
BH
132 PacketReader& pr)
133{
49a06471
BH
134 typemap_t::const_iterator i=getTypemap().find(make_pair(dr.d_class, dr.d_type));
135 if(i==getTypemap().end() || !i->second) {
7fc69fd0 136 return new UnknownRecordContent(dr, pr);
ff6a1e7b 137 }
945a9ad4 138
7fc69fd0 139 return i->second(dr, pr);
ff6a1e7b
BH
140}
141
6c0670c3
BH
142DNSRecordContent* DNSRecordContent::mastermake(uint16_t qtype, uint16_t qclass,
143 const string& content)
144{
49a06471
BH
145 zmakermap_t::const_iterator i=getZmakermap().find(make_pair(qclass, qtype));
146 if(i==getZmakermap().end()) {
6c0670c3
BH
147 return new UnknownRecordContent(content);
148 }
149
150 return i->second(content);
151}
152
ff6a1e7b 153
49a06471
BH
154DNSRecordContent::typemap_t& DNSRecordContent::getTypemap()
155{
156 static DNSRecordContent::typemap_t typemap;
157 return typemap;
158}
159
160DNSRecordContent::namemap_t& DNSRecordContent::getNamemap()
161{
162 static DNSRecordContent::namemap_t namemap;
163 return namemap;
164}
165
166DNSRecordContent::zmakermap_t& DNSRecordContent::getZmakermap()
167{
168 static DNSRecordContent::zmakermap_t zmakermap;
169 return zmakermap;
170}
171
172
ff6a1e7b
BH
173
174void MOADNSParser::init(const char *packet, unsigned int len)
175{
176 if(len < sizeof(dnsheader))
177 throw MOADNSException("Packet shorter than minimal header");
178
179 memcpy(&d_header, packet, sizeof(dnsheader));
180
94dd1374 181 if(d_header.opcode!=0 && d_header.opcode != 4) // notification
f27e6356
BH
182 throw MOADNSException("Can't parse non-query packet with opcode="+ lexical_cast<string>(d_header.opcode));
183
ff6a1e7b
BH
184 d_header.qdcount=ntohs(d_header.qdcount);
185 d_header.ancount=ntohs(d_header.ancount);
186 d_header.nscount=ntohs(d_header.nscount);
187 d_header.arcount=ntohs(d_header.arcount);
188
092f210a 189 uint16_t contentlen=len-sizeof(dnsheader);
ff6a1e7b
BH
190
191 d_content.resize(contentlen);
192 copy(packet+sizeof(dnsheader), packet+len, d_content.begin());
193
629eaf49 194 unsigned int n=0;
ff6a1e7b
BH
195
196 PacketReader pr(d_content);
7b1469bb 197 bool validPacket=false;
512c8492 198 try {
40207e64
BH
199 for(n=0;n < d_header.qdcount; ++n) {
200 d_qname=pr.getLabel();
201 d_qtype=pr.get16BitInt();
202 d_qclass=pr.get16BitInt();
203 }
204
512c8492
BH
205 struct dnsrecordheader ah;
206 vector<unsigned char> record;
7b1469bb 207 validPacket=true;
512c8492 208 for(n=0;n < d_header.ancount + d_header.nscount + d_header.arcount; ++n) {
512c8492
BH
209 DNSRecord dr;
210
211 if(n < d_header.ancount)
212 dr.d_place=DNSRecord::Answer;
213 else if(n < d_header.ancount + d_header.nscount)
214 dr.d_place=DNSRecord::Nameserver;
215 else
216 dr.d_place=DNSRecord::Additional;
217
218 string label=pr.getLabel();
219
220 pr.getDnsrecordheader(ah);
221 dr.d_ttl=ah.d_ttl;
222 dr.d_type=ah.d_type;
223 dr.d_class=ah.d_class;
224
225 dr.d_label=label;
226 dr.d_clen=ah.d_clen;
7b1469bb 227
512c8492 228 dr.d_content=boost::shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(dr, pr));
bc9b5203 229 d_answers.push_back(make_pair(dr, pr.d_pos));
512c8492 230 }
e5986c84
BH
231
232#if 0
512c8492 233 if(pr.d_pos!=contentlen) {
29a14b24
BH
234 throw MOADNSException("Packet ("+d_qname+"|#"+lexical_cast<string>(d_qtype)+") has trailing garbage ("+ lexical_cast<string>(pr.d_pos) + " < " +
235 lexical_cast<string>(contentlen) + ")");
ff6a1e7b 236 }
e5986c84 237#endif
512c8492
BH
238 }
239 catch(out_of_range &re) {
629eaf49
BH
240 if(validPacket && d_header.tc) { // don't sweat it over truncated packets, but do adjust an, ns and arcount
241 if(n < d_header.ancount) {
242 d_header.ancount=n; d_header.nscount = d_header.arcount = 0;
243 }
244 else if(n < d_header.ancount + d_header.nscount) {
245 d_header.nscount = n - d_header.ancount; d_header.arcount=0;
246 }
247 else {
248 d_header.arcount = n - d_header.ancount - d_header.nscount;
249 }
250 }
251 else {
7b1469bb
BH
252 throw MOADNSException("Error parsing packet of "+lexical_cast<string>(len)+" bytes (rd="+
253 lexical_cast<string>(d_header.rd)+
254 "), out of bounds: "+string(re.what()));
629eaf49 255 }
ff6a1e7b 256 }
ff6a1e7b
BH
257}
258
10321a98
BH
259bool MOADNSParser::getEDNSOpts(EDNSOpts* eo)
260{
1335ee62 261 if(d_header.arcount && !d_answers.empty()) {
10321a98 262 eo->d_packetsize=d_answers.back().first.d_class;
705f31ae 263
009f9f55 264 EDNS0Record stuff;
8a63d3ce
BH
265 uint32_t ttl=ntohl(d_answers.back().first.d_ttl);
266 memcpy(&stuff, &ttl, sizeof(stuff));
267
268 eo->d_extRCode=stuff.extRCode;
269 eo->d_version=stuff.version;
270 eo->d_Z=stuff.Z;
271
272 return true;
10321a98
BH
273 }
274 else
275 return false;
276}
277
ff6a1e7b
BH
278void PacketReader::getDnsrecordheader(struct dnsrecordheader &ah)
279{
280 unsigned int n;
281 unsigned char *p=reinterpret_cast<unsigned char*>(&ah);
282
283 for(n=0; n < sizeof(dnsrecordheader); ++n)
284 p[n]=d_content.at(d_pos++);
285
286 ah.d_type=ntohs(ah.d_type);
287 ah.d_class=ntohs(ah.d_class);
288 ah.d_clen=ntohs(ah.d_clen);
289 ah.d_ttl=ntohl(ah.d_ttl);
8c1c9170
BH
290
291 d_startrecordpos=d_pos; // needed for getBlob later on
292 d_recordlen=ah.d_clen;
ff6a1e7b
BH
293}
294
295
092f210a 296void PacketReader::copyRecord(vector<unsigned char>& dest, uint16_t len)
ff6a1e7b
BH
297{
298 dest.resize(len);
bff744a8
BH
299 if(!len)
300 return;
301
092f210a 302 for(uint16_t n=0;n<len;++n) {
ff6a1e7b
BH
303 dest.at(n)=d_content.at(d_pos++);
304 }
305}
306
092f210a 307void PacketReader::copyRecord(unsigned char* dest, uint16_t len)
ff6a1e7b
BH
308{
309 if(d_pos + len > d_content.size())
310 throw MOADNSException("Attempt to copy outside of packet");
311
bff744a8 312 memcpy(dest, &d_content.at(d_pos), len);
ff6a1e7b
BH
313 d_pos+=len;
314}
315
316
092f210a 317uint32_t PacketReader::get32BitInt()
ff6a1e7b 318{
092f210a 319 uint32_t ret=0;
ff6a1e7b
BH
320 ret+=d_content.at(d_pos++);
321 ret<<=8;
322 ret+=d_content.at(d_pos++);
323 ret<<=8;
324 ret+=d_content.at(d_pos++);
325 ret<<=8;
326 ret+=d_content.at(d_pos++);
327
328 return ret;
329}
330
331
092f210a 332uint16_t PacketReader::get16BitInt()
ff6a1e7b
BH
333{
334 return get16BitInt(d_content, d_pos);
335}
336
092f210a 337uint16_t PacketReader::get16BitInt(const vector<unsigned char>&content, uint16_t& pos)
ff6a1e7b 338{
092f210a 339 uint16_t ret=0;
ff6a1e7b
BH
340 ret+=content.at(pos++);
341 ret<<=8;
342 ret+=content.at(pos++);
343
344 return ret;
345}
346
49a06471 347uint8_t PacketReader::get8BitInt()
ff6a1e7b
BH
348{
349 return d_content.at(d_pos++);
350}
351
352
353string PacketReader::getLabel(unsigned int recurs)
354{
1ab67463
BH
355 string ret;
356 ret.reserve(40);
357 getLabelFromContent(d_content, d_pos, ret, recurs++);
358 return ret;
ff6a1e7b
BH
359}
360
ef6a78d5
BH
361static string txtEscape(const string &name)
362{
363 string ret;
364
365 for(string::const_iterator i=name.begin();i!=name.end();++i)
366 if(*i=='"' || *i=='\\'){
367 ret += '\\';
368 ret += *i;
369 }
370 else
371 ret += *i;
372 return ret;
373}
374
375// exceptions thrown here do not result in logging in the main pdns auth server - just so you know!
376string PacketReader::getText(bool multi)
9d9c52ef
BH
377{
378 string ret;
379 ret.reserve(40);
ef6a78d5
BH
380 while(d_pos < d_startrecordpos + d_recordlen ) {
381 if(!ret.empty()) {
382 ret.append(1,' ');
383 }
384 unsigned char labellen=d_content.at(d_pos++);
385
386 ret.append(1,'"');
387 string val(&d_content.at(d_pos), &d_content.at(d_pos+labellen-1)+1);
388
389 ret.append(txtEscape(val)); // the end is one beyond the packet
390 ret.append(1,'"');
391 d_pos+=labellen;
392 if(!multi)
393 break;
394 }
9d9c52ef 395
9d9c52ef
BH
396 return ret;
397}
ff6a1e7b 398
ef6a78d5 399
49a06471 400void PacketReader::getLabelFromContent(const vector<uint8_t>& content, uint16_t& frompos, string& ret, int recurs)
ff6a1e7b
BH
401{
402 if(recurs > 10)
403 throw MOADNSException("Loop");
1ab67463 404
ff6a1e7b
BH
405 for(;;) {
406 unsigned char labellen=content.at(frompos++);
1ab67463 407
ff6a1e7b 408 if(!labellen) {
7738a23f
BH
409 if(ret.empty())
410 ret.append(1,'.');
ff6a1e7b
BH
411 break;
412 }
413 if((labellen & 0xc0) == 0xc0) {
092f210a 414 uint16_t offset=256*(labellen & ~0xc0) + (unsigned int)content.at(frompos++) - sizeof(dnsheader);
ff6a1e7b 415 // cout<<"This is an offset, need to go to: "<<offset<<endl;
1ab67463 416 return getLabelFromContent(content, offset, ret, ++recurs);
ff6a1e7b
BH
417 }
418 else {
38e655b6
BH
419 // XXX FIXME THIS MIGHT BE VERY SLOW!
420 ret.reserve(ret.size() + labellen + 2);
421 for(string::size_type n = 0 ; n < labellen; ++n, frompos++) {
422 if(content.at(frompos)=='.')
423 ret.append(1, '\\');
424 ret.append(1, content[frompos]);
425 }
7738a23f 426 ret.append(1,'.');
ff6a1e7b
BH
427 }
428 }
ff6a1e7b 429}
8c1c9170
BH
430
431void PacketReader::xfrBlob(string& blob)
432{
433 blob.assign(&d_content.at(d_pos), &d_content.at(d_startrecordpos + d_recordlen - 1 ) + 1);
434
435 d_pos = d_startrecordpos + d_recordlen;
436}
59a0f653
BH
437
438void PacketReader::xfrHexBlob(string& blob)
439{
440 xfrBlob(blob);
441}
b8e0f341 442
7127879f 443string simpleCompress(const string& label, const string& root)
b8e0f341
BH
444{
445 typedef vector<pair<unsigned int, unsigned int> > parts_t;
446 parts_t parts;
447 vstringtok(parts, label, ".");
448 string ret;
449 ret.reserve(label.size()+4);
450 for(parts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) {
7127879f
BH
451 if(!root.empty() && !strncasecmp(root.c_str(), label.c_str() + i->first, label.length() - i->first)) {
452 const char rootptr[2]={0xc0,0x11};
453 ret.append(rootptr, 2);
454 return ret;
455 }
b8e0f341
BH
456 ret.append(1, (char)(i->second - i->first));
457 ret.append(label.c_str() + i->first, i->second - i->first);
458 }
459 ret.append(1, (char)0);
460 return ret;
461}
462
7127879f 463
b8e0f341
BH
464void simpleExpandTo(const string& label, unsigned int frompos, string& ret)
465{
466 unsigned int labellen=0;
467 while((labellen=label.at(frompos++))) {
468 ret.append(label.c_str()+frompos, labellen);
469 ret.append(1,'.');
470 frompos+=labellen;
471 }
472}