]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsparser.cc
nit
[thirdparty/pdns.git] / pdns / dnsparser.cc
CommitLineData
4192ca66
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
93e4cb97 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 23#include "dnsparser.hh"
6c0670c3 24#include "dnswriter.hh"
ff6a1e7b 25#include <boost/lexical_cast.hpp>
4cf74e6f 26#include <boost/algorithm/string.hpp>
5dba9d25 27#include <boost/format.hpp>
ff6a1e7b 28
61b26744 29#include "namespaces.hh"
ff6a1e7b
BH
30
31class UnknownRecordContent : public DNSRecordContent
32{
33public:
7fc69fd0 34 UnknownRecordContent(const DNSRecord& dr, PacketReader& pr)
ea634573 35 : DNSRecordContent(dr.d_type), d_dr(dr)
ff6a1e7b 36 {
7fc69fd0 37 pr.copyRecord(d_record, dr.d_clen);
ff6a1e7b
BH
38 }
39
ea634573 40 UnknownRecordContent(const string& zone) : DNSRecordContent(0)
6c0670c3 41 {
95a61c6f
AT
42 // parse the input
43 vector<string> parts;
44 stringtok(parts, zone);
45 if(parts.size()!=3 && !(parts.size()==2 && equals(parts[1],"0")) )
46 throw MOADNSException("Unknown record was stored incorrectly, need 3 fields, got "+lexical_cast<string>(parts.size())+": "+zone );
47 const string& relevant=(parts.size() > 2) ? parts[2] : "";
48 unsigned int total=atoi(parts[1].c_str());
49 if(relevant.size()!=2*total)
50 throw MOADNSException((boost::format("invalid unknown record length for label %s: size not equal to length field (%d != %d)") % d_dr.d_label.c_str() % relevant.size() % (2*total)).str());
51 string out;
52 out.reserve(total+1);
53 for(unsigned int n=0; n < total; ++n) {
54 int c;
55 sscanf(relevant.c_str()+2*n, "%02x", &c);
56 out.append(1, (char)c);
57 }
58
59 d_record.insert(d_record.end(), out.begin(), out.end());
6c0670c3
BH
60 }
61
ff6a1e7b
BH
62 string getZoneRepresentation() const
63 {
64 ostringstream str;
705f31ae 65 str<<"\\# "<<(unsigned int)d_record.size()<<" ";
ff6a1e7b
BH
66 char hex[4];
67 for(size_t n=0; n<d_record.size(); ++n) {
68 snprintf(hex,sizeof(hex)-1, "%02x", d_record.at(n));
69 str << hex;
70 }
ff6a1e7b
BH
71 return str.str();
72 }
73
6c0670c3
BH
74 void toPacket(DNSPacketWriter& pw)
75 {
95a61c6f 76 pw.xfrBlob(string(d_record.begin(),d_record.end()));
6c0670c3 77 }
ff6a1e7b 78private:
6c0670c3
BH
79 DNSRecord d_dr;
80 vector<uint8_t> d_record;
ff6a1e7b
BH
81};
82
9bd9588f 83static const string EncodeDNSLabel(const string& input)
ea634573 84{
9bd9588f
BH
85 if(input.length() == 1 && input[0]=='.') // otherwise we encode .. (long story)
86 return string (1, 0);
87
213f6de6
BH
88 labelparts_t parts;
89 bool unescapedSomething = labeltokUnescape(parts, input);
90 string ret;
9bd9588f 91
213f6de6
BH
92 if(!unescapedSomething) {
93 for(labelparts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) {
9bd9588f
BH
94 ret.append(1, i->second - i->first);
95 ret.append(input.c_str() + i->first, i->second - i->first);
213f6de6
BH
96 }
97
98 } else {
99 for(labelparts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) {
9bd9588f
BH
100 string part(input.c_str() + i->first, i->second - i->first);
101 boost::replace_all(part, "\\\\", "\\");
102 boost::replace_all(part, "\\.", ".");
213f6de6
BH
103
104 ret.append(1, part.length());
105 ret.append(part);
106 }
107 }
108 ret.append(1, 0);
9bd9588f
BH
109 return ret;
110}
ff6a1e7b 111
213f6de6 112
ea634573
BH
113shared_ptr<DNSRecordContent> DNSRecordContent::unserialize(const string& qname, uint16_t qtype, const string& serialized)
114{
115 dnsheader dnsheader;
116 memset(&dnsheader, 0, sizeof(dnsheader));
117 dnsheader.qdcount=htons(1);
118 dnsheader.ancount=htons(1);
119
120 vector<uint8_t> packet; // build pseudo packet
678ce973
BH
121
122 /* will look like: dnsheader, 5 bytes, encoded qname, dns record header, serialized data */
ea634573
BH
123
124 string encoded=EncodeDNSLabel(qname);
678ce973
BH
125
126 packet.resize(sizeof(dnsheader) + 5 + encoded.size() + sizeof(struct dnsrecordheader) + serialized.size());
127
128 uint16_t pos=0;
129
130 memcpy(&packet[0], &dnsheader, sizeof(dnsheader)); pos+=sizeof(dnsheader);
131
132 char tmp[6]="\x0" "\x0\x1" "\x0\x1"; // root question for ns_t_a
133 memcpy(&packet[pos], &tmp, 5); pos+=5;
134
705f31ae 135 memcpy(&packet[pos], encoded.c_str(), encoded.size()); pos+=(uint16_t)encoded.size();
ea634573
BH
136
137 struct dnsrecordheader drh;
138 drh.d_type=htons(qtype);
139 drh.d_class=htons(1);
140 drh.d_ttl=0;
141 drh.d_clen=htons(serialized.size());
142
678ce973 143 memcpy(&packet[pos], &drh, sizeof(drh)); pos+=sizeof(drh);
705f31ae 144 memcpy(&packet[pos], serialized.c_str(), serialized.size()); pos+=(uint16_t)serialized.size();
ea634573 145
705f31ae 146 MOADNSParser mdp((char*)&*packet.begin(), (unsigned int)packet.size());
ea634573
BH
147 shared_ptr<DNSRecordContent> ret= mdp.d_answers.begin()->first.d_content;
148 ret->header.d_type=ret->d_qtype;
149 ret->label=mdp.d_answers.begin()->first.d_label;
150 ret->header.d_ttl=mdp.d_answers.begin()->first.d_ttl;
151 return ret;
152}
ff6a1e7b 153
7fc69fd0 154DNSRecordContent* DNSRecordContent::mastermake(const DNSRecord &dr,
232f0877 155 PacketReader& pr)
ff6a1e7b 156{
7f7b8d55
BH
157 uint16_t searchclass = (dr.d_type == QType::OPT) ? 1 : dr.d_class; // class is invalid for OPT
158
159 typemap_t::const_iterator i=getTypemap().find(make_pair(searchclass, dr.d_type));
49a06471 160 if(i==getTypemap().end() || !i->second) {
7fc69fd0 161 return new UnknownRecordContent(dr, pr);
ff6a1e7b 162 }
945a9ad4 163
7fc69fd0 164 return i->second(dr, pr);
ff6a1e7b
BH
165}
166
6c0670c3 167DNSRecordContent* DNSRecordContent::mastermake(uint16_t qtype, uint16_t qclass,
232f0877 168 const string& content)
6c0670c3 169{
49a06471
BH
170 zmakermap_t::const_iterator i=getZmakermap().find(make_pair(qclass, qtype));
171 if(i==getZmakermap().end()) {
6c0670c3
BH
172 return new UnknownRecordContent(content);
173 }
174
175 return i->second(content);
176}
177
7945d472
RA
178DNSRecordContent* DNSRecordContent::mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t oc) {
179 // For opcode UPDATE and where the DNSRecord is an answer record, we don't care about content, because this is
180 // not used within the prerequisite section of RFC2136, so - we can simply use unknownrecordcontent.
181 // For section 3.2.3, we do need content so we need to get it properly. But only for the correct Qclasses.
182 if (oc == Opcode::Update && dr.d_place == DNSRecord::Answer && dr.d_class != 1)
183 return new UnknownRecordContent(dr, pr);
914353ca 184
7945d472
RA
185 uint16_t searchclass = (dr.d_type == QType::OPT) ? 1 : dr.d_class; // class is invalid for OPT
186
187 typemap_t::const_iterator i=getTypemap().find(make_pair(searchclass, dr.d_type));
188 if(i==getTypemap().end() || !i->second) {
189 return new UnknownRecordContent(dr, pr);
190 }
191
192 return i->second(dr, pr);
193}
194
195
49a06471
BH
196DNSRecordContent::typemap_t& DNSRecordContent::getTypemap()
197{
198 static DNSRecordContent::typemap_t typemap;
199 return typemap;
200}
201
108c321e 202DNSRecordContent::n2typemap_t& DNSRecordContent::getN2Typemap()
49a06471 203{
93e4cb97
BH
204 static DNSRecordContent::n2typemap_t n2typemap;
205 return n2typemap;
49a06471
BH
206}
207
108c321e
BH
208DNSRecordContent::t2namemap_t& DNSRecordContent::getT2Namemap()
209{
93e4cb97
BH
210 static DNSRecordContent::t2namemap_t t2namemap;
211 return t2namemap;
108c321e
BH
212}
213
214
49a06471
BH
215DNSRecordContent::zmakermap_t& DNSRecordContent::getZmakermap()
216{
217 static DNSRecordContent::zmakermap_t zmakermap;
218 return zmakermap;
219}
220
ff6a1e7b
BH
221void MOADNSParser::init(const char *packet, unsigned int len)
222{
223 if(len < sizeof(dnsheader))
224 throw MOADNSException("Packet shorter than minimal header");
225
226 memcpy(&d_header, packet, sizeof(dnsheader));
227
7945d472 228 if(d_header.opcode != Opcode::Query && d_header.opcode != Opcode::Notify && d_header.opcode != Opcode::Update)
f27e6356
BH
229 throw MOADNSException("Can't parse non-query packet with opcode="+ lexical_cast<string>(d_header.opcode));
230
ff6a1e7b
BH
231 d_header.qdcount=ntohs(d_header.qdcount);
232 d_header.ancount=ntohs(d_header.ancount);
233 d_header.nscount=ntohs(d_header.nscount);
234 d_header.arcount=ntohs(d_header.arcount);
235
092f210a 236 uint16_t contentlen=len-sizeof(dnsheader);
ff6a1e7b
BH
237
238 d_content.resize(contentlen);
239 copy(packet+sizeof(dnsheader), packet+len, d_content.begin());
240
629eaf49 241 unsigned int n=0;
ff6a1e7b
BH
242
243 PacketReader pr(d_content);
7b1469bb 244 bool validPacket=false;
512c8492 245 try {
00bf10d3
BH
246 d_qtype = d_qclass = 0; // sometimes replies come in with no question, don't present garbage then
247
40207e64
BH
248 for(n=0;n < d_header.qdcount; ++n) {
249 d_qname=pr.getLabel();
250 d_qtype=pr.get16BitInt();
251 d_qclass=pr.get16BitInt();
252 }
253
512c8492
BH
254 struct dnsrecordheader ah;
255 vector<unsigned char> record;
7b1469bb 256 validPacket=true;
c4ac5865 257 for(n=0;n < (unsigned int)(d_header.ancount + d_header.nscount + d_header.arcount); ++n) {
512c8492
BH
258 DNSRecord dr;
259
260 if(n < d_header.ancount)
4957a608 261 dr.d_place=DNSRecord::Answer;
512c8492 262 else if(n < d_header.ancount + d_header.nscount)
4957a608 263 dr.d_place=DNSRecord::Nameserver;
512c8492 264 else
4957a608 265 dr.d_place=DNSRecord::Additional;
512c8492 266
57e5f5f7
BH
267 unsigned int recordStartPos=pr.d_pos;
268
512c8492
BH
269 string label=pr.getLabel();
270
271 pr.getDnsrecordheader(ah);
272 dr.d_ttl=ah.d_ttl;
273 dr.d_type=ah.d_type;
274 dr.d_class=ah.d_class;
275
276 dr.d_label=label;
277 dr.d_clen=ah.d_clen;
7b1469bb 278
dd7da6cd 279 dr.d_content=std::shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(dr, pr, d_header.opcode));
bc9b5203 280 d_answers.push_back(make_pair(dr, pr.d_pos));
57e5f5f7
BH
281
282 if(dr.d_type == QType::TSIG && dr.d_class == 0xff)
4957a608 283 d_tsigPos = recordStartPos + sizeof(struct dnsheader);
512c8492 284 }
e5986c84
BH
285
286#if 0
512c8492 287 if(pr.d_pos!=contentlen) {
29a14b24 288 throw MOADNSException("Packet ("+d_qname+"|#"+lexical_cast<string>(d_qtype)+") has trailing garbage ("+ lexical_cast<string>(pr.d_pos) + " < " +
232f0877 289 lexical_cast<string>(contentlen) + ")");
ff6a1e7b 290 }
e5986c84 291#endif
512c8492 292 }
10f4eea8 293 catch(std::out_of_range &re) {
629eaf49
BH
294 if(validPacket && d_header.tc) { // don't sweat it over truncated packets, but do adjust an, ns and arcount
295 if(n < d_header.ancount) {
4957a608 296 d_header.ancount=n; d_header.nscount = d_header.arcount = 0;
629eaf49
BH
297 }
298 else if(n < d_header.ancount + d_header.nscount) {
4957a608 299 d_header.nscount = n - d_header.ancount; d_header.arcount=0;
629eaf49
BH
300 }
301 else {
4957a608 302 d_header.arcount = n - d_header.ancount - d_header.nscount;
629eaf49
BH
303 }
304 }
305 else {
7b1469bb 306 throw MOADNSException("Error parsing packet of "+lexical_cast<string>(len)+" bytes (rd="+
232f0877
CH
307 lexical_cast<string>(d_header.rd)+
308 "), out of bounds: "+string(re.what()));
629eaf49 309 }
ff6a1e7b 310 }
ff6a1e7b
BH
311}
312
10321a98 313
ff6a1e7b
BH
314void PacketReader::getDnsrecordheader(struct dnsrecordheader &ah)
315{
316 unsigned int n;
317 unsigned char *p=reinterpret_cast<unsigned char*>(&ah);
318
319 for(n=0; n < sizeof(dnsrecordheader); ++n)
320 p[n]=d_content.at(d_pos++);
321
322 ah.d_type=ntohs(ah.d_type);
323 ah.d_class=ntohs(ah.d_class);
324 ah.d_clen=ntohs(ah.d_clen);
325 ah.d_ttl=ntohl(ah.d_ttl);
8c1c9170
BH
326
327 d_startrecordpos=d_pos; // needed for getBlob later on
328 d_recordlen=ah.d_clen;
ff6a1e7b
BH
329}
330
331
092f210a 332void PacketReader::copyRecord(vector<unsigned char>& dest, uint16_t len)
ff6a1e7b
BH
333{
334 dest.resize(len);
bff744a8
BH
335 if(!len)
336 return;
337
092f210a 338 for(uint16_t n=0;n<len;++n) {
ff6a1e7b
BH
339 dest.at(n)=d_content.at(d_pos++);
340 }
341}
342
092f210a 343void PacketReader::copyRecord(unsigned char* dest, uint16_t len)
ff6a1e7b
BH
344{
345 if(d_pos + len > d_content.size())
10f4eea8 346 throw std::out_of_range("Attempt to copy outside of packet");
ff6a1e7b 347
bff744a8 348 memcpy(dest, &d_content.at(d_pos), len);
ff6a1e7b
BH
349 d_pos+=len;
350}
351
341930bb
BH
352void PacketReader::xfr48BitInt(uint64_t& ret)
353{
354 ret=0;
355 ret+=d_content.at(d_pos++);
356 ret<<=8;
357 ret+=d_content.at(d_pos++);
358 ret<<=8;
359 ret+=d_content.at(d_pos++);
360 ret<<=8;
361 ret+=d_content.at(d_pos++);
362 ret<<=8;
363 ret+=d_content.at(d_pos++);
364 ret<<=8;
365 ret+=d_content.at(d_pos++);
366}
ff6a1e7b 367
092f210a 368uint32_t PacketReader::get32BitInt()
ff6a1e7b 369{
092f210a 370 uint32_t ret=0;
ff6a1e7b
BH
371 ret+=d_content.at(d_pos++);
372 ret<<=8;
373 ret+=d_content.at(d_pos++);
374 ret<<=8;
375 ret+=d_content.at(d_pos++);
376 ret<<=8;
377 ret+=d_content.at(d_pos++);
378
379 return ret;
380}
381
382
092f210a 383uint16_t PacketReader::get16BitInt()
ff6a1e7b
BH
384{
385 return get16BitInt(d_content, d_pos);
386}
387
092f210a 388uint16_t PacketReader::get16BitInt(const vector<unsigned char>&content, uint16_t& pos)
ff6a1e7b 389{
092f210a 390 uint16_t ret=0;
ff6a1e7b
BH
391 ret+=content.at(pos++);
392 ret<<=8;
393 ret+=content.at(pos++);
394
395 return ret;
396}
397
49a06471 398uint8_t PacketReader::get8BitInt()
ff6a1e7b
BH
399{
400 return d_content.at(d_pos++);
401}
402
d926c0da 403string PacketReader::getLabel()
ff6a1e7b 404{
d926c0da
KM
405 unsigned int consumed;
406 vector<uint8_t> content(d_content);
407 content.insert(content.begin(), sizeof(dnsheader), 0);
408
409 string ret = DNSName((const char*) content.data(), content.size(), d_pos + sizeof(dnsheader), true /* uncompress */, 0 /* qtype */, 0 /* qclass */, &consumed).toString();
410
411 d_pos+=consumed;
1ab67463 412 return ret;
ff6a1e7b
BH
413}
414
ef6a78d5
BH
415static string txtEscape(const string &name)
416{
417 string ret;
5dba9d25 418 char ebuf[5];
ef6a78d5 419
5dba9d25 420 for(string::const_iterator i=name.begin();i!=name.end();++i) {
837f4b49 421 if((unsigned char) *i > 127 || (unsigned char) *i < 32) {
5dba9d25
PD
422 snprintf(ebuf, sizeof(ebuf), "\\%03u", (unsigned char)*i);
423 ret += ebuf;
424 }
66b40966 425 else if(*i=='"' || *i=='\\'){
ef6a78d5
BH
426 ret += '\\';
427 ret += *i;
428 }
429 else
430 ret += *i;
5dba9d25 431 }
ef6a78d5
BH
432 return ret;
433}
434
435// exceptions thrown here do not result in logging in the main pdns auth server - just so you know!
436string PacketReader::getText(bool multi)
9d9c52ef
BH
437{
438 string ret;
439 ret.reserve(40);
ef6a78d5
BH
440 while(d_pos < d_startrecordpos + d_recordlen ) {
441 if(!ret.empty()) {
442 ret.append(1,' ');
443 }
444 unsigned char labellen=d_content.at(d_pos++);
445
446 ret.append(1,'"');
950f78df
BH
447 if(labellen) { // no need to do anything for an empty string
448 string val(&d_content.at(d_pos), &d_content.at(d_pos+labellen-1)+1);
449 ret.append(txtEscape(val)); // the end is one beyond the packet
450 }
ef6a78d5
BH
451 ret.append(1,'"');
452 d_pos+=labellen;
453 if(!multi)
454 break;
455 }
9d9c52ef 456
9d9c52ef
BH
457 return ret;
458}
ff6a1e7b 459
ef6a78d5 460
8c1c9170 461void PacketReader::xfrBlob(string& blob)
2bc83940 462try
8c1c9170 463{
e2c162d3 464 if(d_recordlen && !(d_pos == (d_startrecordpos + d_recordlen)))
7f7b8d55
BH
465 blob.assign(&d_content.at(d_pos), &d_content.at(d_startrecordpos + d_recordlen - 1 ) + 1);
466 else
467 blob.clear();
8c1c9170
BH
468
469 d_pos = d_startrecordpos + d_recordlen;
470}
2bc83940 471catch(...)
472{
473 throw std::out_of_range("xfrBlob out of range");
474}
59a0f653 475
2fe9d6f7
AT
476void PacketReader::xfrBlobNoSpaces(string& blob, int length) {
477 xfrBlob(blob, length);
478}
479
06ffdc52
BH
480void PacketReader::xfrBlob(string& blob, int length)
481{
2617464d 482 if(length) {
0407751c 483 blob.assign(&d_content.at(d_pos), &d_content.at(d_pos + length - 1 ) + 1 );
2617464d
BH
484
485 d_pos += length;
486 }
487 else
488 blob.clear();
06ffdc52
BH
489}
490
491
e4090157 492void PacketReader::xfrHexBlob(string& blob, bool keepReading)
59a0f653
BH
493{
494 xfrBlob(blob);
495}
b8e0f341 496
27ff60a3 497string simpleCompress(const string& elabel, const string& root)
b8e0f341 498{
27ff60a3 499 string label=elabel;
d926c0da 500 // FIXME: this relies on the semi-canonical escaped output from getLabel
83b746fd 501 if(strchr(label.c_str(), '\\')) {
502 boost::replace_all(label, "\\.", ".");
503 boost::replace_all(label, "\\032", " ");
504 boost::replace_all(label, "\\\\", "\\");
505 }
b8e0f341
BH
506 typedef vector<pair<unsigned int, unsigned int> > parts_t;
507 parts_t parts;
508 vstringtok(parts, label, ".");
509 string ret;
510 ret.reserve(label.size()+4);
511 for(parts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) {
05a38bfa 512 if(!root.empty() && !strncasecmp(root.c_str(), label.c_str() + i->first, 1 + label.length() - i->first)) { // also match trailing 0, hence '1 +'
015db425
PD
513 const unsigned char rootptr[2]={0xc0,0x11};
514 ret.append((const char *) rootptr, 2);
7127879f
BH
515 return ret;
516 }
b8e0f341
BH
517 ret.append(1, (char)(i->second - i->first));
518 ret.append(label.c_str() + i->first, i->second - i->first);
519 }
520 ret.append(1, (char)0);
521 return ret;
522}
523
7127879f 524
b8e0f341
BH
525void simpleExpandTo(const string& label, unsigned int frompos, string& ret)
526{
527 unsigned int labellen=0;
53edfc45 528 while((labellen=(unsigned char)label.at(frompos++))) {
b8e0f341
BH
529 ret.append(label.c_str()+frompos, labellen);
530 ret.append(1,'.');
531 frompos+=labellen;
532 }
533}
2c73e580
BH
534
535/** Simple DNSPacketMangler. Ritual is: get a pointer into the packet and moveOffset() to beyond your needs
536 * If you survive that, feel free to read from the pointer */
537class DNSPacketMangler
538{
539public:
540 explicit DNSPacketMangler(std::string& packet)
541 : d_packet(packet), d_notyouroffset(12), d_offset(d_notyouroffset)
542 {}
543
544 void skipLabel()
545 {
546 uint8_t len;
547 while((len=get8BitInt())) {
548 if(len >= 0xc0) { // extended label
232f0877
CH
549 get8BitInt();
550 return;
2c73e580
BH
551 }
552 skipBytes(len);
553 }
554 }
555 void skipBytes(uint16_t bytes)
556 {
557 moveOffset(bytes);
558 }
559 uint16_t get16BitInt()
560 {
561 const char* p = d_packet.c_str() + d_offset;
562 moveOffset(2);
563 uint16_t ret;
564 memcpy(&ret, (void*)p, 2);
565 return ntohs(ret);
566 }
567
568 uint8_t get8BitInt()
569 {
570 const char* p = d_packet.c_str() + d_offset;
571 moveOffset(1);
572 return *p;
573 }
574
575 void skipRData()
576 {
577 int toskip = get16BitInt();
578 moveOffset(toskip);
579 }
580 void decreaseAndSkip32BitInt(uint32_t decrease)
581 {
582 const char *p = (const char*)d_packet.c_str() + d_offset;
583 moveOffset(4);
584
585 uint32_t tmp;
586 memcpy(&tmp, (void*) p, sizeof(tmp));
587 tmp = ntohl(tmp);
588 tmp-=decrease;
589 tmp = htonl(tmp);
590 d_packet.replace(d_offset-4, sizeof(tmp), (const char*)&tmp, sizeof(tmp));
591 }
592private:
593 void moveOffset(uint16_t by)
594 {
595 d_notyouroffset += by;
596 if(d_notyouroffset > d_packet.length())
10f4eea8 597 throw std::out_of_range("dns packet out of range: "+lexical_cast<string>(d_notyouroffset) +" > "
2c73e580
BH
598 + lexical_cast<string>(d_packet.length()) );
599 }
600 std::string& d_packet;
601
602 uint32_t d_notyouroffset; // only 'moveOffset' can touch this
603 const uint32_t& d_offset; // look.. but don't touch
604
605};
606
607// method of operation: silently fail if it doesn't work - we're only trying to be nice, don't fall over on it
608void ageDNSPacket(std::string& packet, uint32_t seconds)
609{
44b67752 610 if(packet.length() < sizeof(dnsheader))
2c73e580
BH
611 return;
612 try
613 {
44b67752
BH
614 dnsheader dh;
615 memcpy((void*)&dh, (const dnsheader*)packet.c_str(), sizeof(dh));
616 int numrecords = ntohs(dh.ancount) + ntohs(dh.nscount) + ntohs(dh.arcount);
2c73e580
BH
617 DNSPacketMangler dpm(packet);
618
619 int n;
44b67752 620 for(n=0; n < ntohs(dh.qdcount) ; ++n) {
2c73e580
BH
621 dpm.skipLabel();
622 dpm.skipBytes(4); // qtype, qclass
623 }
624 // cerr<<"Skipped "<<n<<" questions, now parsing "<<numrecords<<" records"<<endl;
625 for(n=0; n < numrecords; ++n) {
626 dpm.skipLabel();
627
628 uint16_t dnstype = dpm.get16BitInt();
88a754aa 629 /* uint16_t dnsclass = */ dpm.get16BitInt();
2c73e580
BH
630
631 if(dnstype == QType::OPT) // not aging that one with a stick
232f0877 632 break;
2c73e580
BH
633
634 dpm.decreaseAndSkip32BitInt(seconds);
635 dpm.skipRData();
636 }
637 }
638 catch(...)
639 {
640 return;
641 }
642}