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