]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsparser.cc
Check TSIG signature on IXFR
[thirdparty/pdns.git] / pdns / dnsparser.cc
1 /*
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 */
22 #include "dnsparser.hh"
23 #include "dnswriter.hh"
24 #include <boost/algorithm/string.hpp>
25 #include <boost/format.hpp>
26
27 #include "namespaces.hh"
28
29 class UnknownRecordContent : public DNSRecordContent
30 {
31 public:
32 UnknownRecordContent(const DNSRecord& dr, PacketReader& pr)
33 : d_dr(dr)
34 {
35 pr.copyRecord(d_record, dr.d_clen);
36 }
37
38 UnknownRecordContent(const string& zone)
39 {
40 // parse the input
41 vector<string> parts;
42 stringtok(parts, zone);
43 if(parts.size()!=3 && !(parts.size()==2 && equals(parts[1],"0")) )
44 throw MOADNSException("Unknown record was stored incorrectly, need 3 fields, got "+std::to_string(parts.size())+": "+zone );
45 const string& relevant=(parts.size() > 2) ? parts[2] : "";
46 unsigned int total=pdns_stou(parts[1]);
47 if(relevant.size()!=2*total)
48 throw MOADNSException((boost::format("invalid unknown record length for label %s: size not equal to length field (%d != %d)") % d_dr.d_name.toString() % relevant.size() % (2*total)).str());
49 string out;
50 out.reserve(total+1);
51 for(unsigned int n=0; n < total; ++n) {
52 int c;
53 sscanf(relevant.c_str()+2*n, "%02x", &c);
54 out.append(1, (char)c);
55 }
56
57 d_record.insert(d_record.end(), out.begin(), out.end());
58 }
59
60 string getZoneRepresentation(bool noDot) const override
61 {
62 ostringstream str;
63 str<<"\\# "<<(unsigned int)d_record.size()<<" ";
64 char hex[4];
65 for(size_t n=0; n<d_record.size(); ++n) {
66 snprintf(hex,sizeof(hex)-1, "%02x", d_record.at(n));
67 str << hex;
68 }
69 return str.str();
70 }
71
72 void toPacket(DNSPacketWriter& pw) override
73 {
74 pw.xfrBlob(string(d_record.begin(),d_record.end()));
75 }
76
77 uint16_t getType() const override
78 {
79 return d_dr.d_type;
80 }
81 private:
82 DNSRecord d_dr;
83 vector<uint8_t> d_record;
84 };
85
86 shared_ptr<DNSRecordContent> DNSRecordContent::unserialize(const DNSName& qname, uint16_t qtype, const string& serialized)
87 {
88 dnsheader dnsheader;
89 memset(&dnsheader, 0, sizeof(dnsheader));
90 dnsheader.qdcount=htons(1);
91 dnsheader.ancount=htons(1);
92
93 vector<uint8_t> packet; // build pseudo packet
94
95 /* will look like: dnsheader, 5 bytes, encoded qname, dns record header, serialized data */
96
97 string encoded=qname.toDNSString();
98
99 packet.resize(sizeof(dnsheader) + 5 + encoded.size() + sizeof(struct dnsrecordheader) + serialized.size());
100
101 uint16_t pos=0;
102
103 memcpy(&packet[0], &dnsheader, sizeof(dnsheader)); pos+=sizeof(dnsheader);
104
105 char tmp[6]="\x0" "\x0\x1" "\x0\x1"; // root question for ns_t_a
106 memcpy(&packet[pos], &tmp, 5); pos+=5;
107
108 memcpy(&packet[pos], encoded.c_str(), encoded.size()); pos+=(uint16_t)encoded.size();
109
110 struct dnsrecordheader drh;
111 drh.d_type=htons(qtype);
112 drh.d_class=htons(1);
113 drh.d_ttl=0;
114 drh.d_clen=htons(serialized.size());
115
116 memcpy(&packet[pos], &drh, sizeof(drh)); pos+=sizeof(drh);
117 memcpy(&packet[pos], serialized.c_str(), serialized.size()); pos+=(uint16_t)serialized.size();
118
119 MOADNSParser mdp(false, (char*)&*packet.begin(), (unsigned int)packet.size());
120 shared_ptr<DNSRecordContent> ret= mdp.d_answers.begin()->first.d_content;
121 return ret;
122 }
123
124 DNSRecordContent* DNSRecordContent::mastermake(const DNSRecord &dr,
125 PacketReader& pr)
126 {
127 uint16_t searchclass = (dr.d_type == QType::OPT) ? 1 : dr.d_class; // class is invalid for OPT
128
129 typemap_t::const_iterator i=getTypemap().find(make_pair(searchclass, dr.d_type));
130 if(i==getTypemap().end() || !i->second) {
131 return new UnknownRecordContent(dr, pr);
132 }
133
134 return i->second(dr, pr);
135 }
136
137 DNSRecordContent* DNSRecordContent::mastermake(uint16_t qtype, uint16_t qclass,
138 const string& content)
139 {
140 zmakermap_t::const_iterator i=getZmakermap().find(make_pair(qclass, qtype));
141 if(i==getZmakermap().end()) {
142 return new UnknownRecordContent(content);
143 }
144
145 return i->second(content);
146 }
147
148 std::unique_ptr<DNSRecordContent> DNSRecordContent::makeunique(uint16_t qtype, uint16_t qclass,
149 const string& content)
150 {
151 zmakermap_t::const_iterator i=getZmakermap().find(make_pair(qclass, qtype));
152 if(i==getZmakermap().end()) {
153 return std::unique_ptr<DNSRecordContent>(new UnknownRecordContent(content));
154 }
155
156 return std::unique_ptr<DNSRecordContent>(i->second(content));
157 }
158
159
160 DNSRecordContent* DNSRecordContent::mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t oc) {
161 // For opcode UPDATE and where the DNSRecord is an answer record, we don't care about content, because this is
162 // not used within the prerequisite section of RFC2136, so - we can simply use unknownrecordcontent.
163 // For section 3.2.3, we do need content so we need to get it properly. But only for the correct Qclasses.
164 if (oc == Opcode::Update && dr.d_place == DNSResourceRecord::ANSWER && dr.d_class != 1)
165 return new UnknownRecordContent(dr, pr);
166
167 uint16_t searchclass = (dr.d_type == QType::OPT) ? 1 : dr.d_class; // class is invalid for OPT
168
169 typemap_t::const_iterator i=getTypemap().find(make_pair(searchclass, dr.d_type));
170 if(i==getTypemap().end() || !i->second) {
171 return new UnknownRecordContent(dr, pr);
172 }
173
174 return i->second(dr, pr);
175 }
176
177
178 DNSRecordContent::typemap_t& DNSRecordContent::getTypemap()
179 {
180 static DNSRecordContent::typemap_t typemap;
181 return typemap;
182 }
183
184 DNSRecordContent::n2typemap_t& DNSRecordContent::getN2Typemap()
185 {
186 static DNSRecordContent::n2typemap_t n2typemap;
187 return n2typemap;
188 }
189
190 DNSRecordContent::t2namemap_t& DNSRecordContent::getT2Namemap()
191 {
192 static DNSRecordContent::t2namemap_t t2namemap;
193 return t2namemap;
194 }
195
196
197 DNSRecordContent::zmakermap_t& DNSRecordContent::getZmakermap()
198 {
199 static DNSRecordContent::zmakermap_t zmakermap;
200 return zmakermap;
201 }
202
203 DNSRecord::DNSRecord(const DNSResourceRecord& rr)
204 {
205 d_name = rr.qname;
206 d_type = rr.qtype.getCode();
207 d_ttl = rr.ttl;
208 d_class = rr.qclass;
209 d_place = rr.d_place;
210 d_clen = 0;
211 d_content = std::shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(d_type, rr.qclass, rr.content));
212 }
213
214 void MOADNSParser::init(bool query, const char *packet, unsigned int len)
215 {
216 if(len < sizeof(dnsheader))
217 throw MOADNSException("Packet shorter than minimal header");
218
219 memcpy(&d_header, packet, sizeof(dnsheader));
220
221 if(d_header.opcode != Opcode::Query && d_header.opcode != Opcode::Notify && d_header.opcode != Opcode::Update)
222 throw MOADNSException("Can't parse non-query packet with opcode="+ std::to_string(d_header.opcode));
223
224 d_header.qdcount=ntohs(d_header.qdcount);
225 d_header.ancount=ntohs(d_header.ancount);
226 d_header.nscount=ntohs(d_header.nscount);
227 d_header.arcount=ntohs(d_header.arcount);
228
229 if (query && (d_header.qdcount > 1))
230 throw MOADNSException("Query with QD > 1 ("+std::to_string(d_header.qdcount)+")");
231
232 uint16_t contentlen=len-sizeof(dnsheader);
233
234 d_content.resize(contentlen);
235 copy(packet+sizeof(dnsheader), packet+len, d_content.begin());
236
237 unsigned int n=0;
238
239 PacketReader pr(d_content);
240 bool validPacket=false;
241 try {
242 d_qtype = d_qclass = 0; // sometimes replies come in with no question, don't present garbage then
243
244 for(n=0;n < d_header.qdcount; ++n) {
245 d_qname=pr.getName();
246 d_qtype=pr.get16BitInt();
247 d_qclass=pr.get16BitInt();
248 }
249
250 struct dnsrecordheader ah;
251 vector<unsigned char> record;
252 validPacket=true;
253 d_answers.reserve((unsigned int)(d_header.ancount + d_header.nscount + d_header.arcount));
254 for(n=0;n < (unsigned int)(d_header.ancount + d_header.nscount + d_header.arcount); ++n) {
255 DNSRecord dr;
256
257 if(n < d_header.ancount)
258 dr.d_place=DNSResourceRecord::ANSWER;
259 else if(n < d_header.ancount + d_header.nscount)
260 dr.d_place=DNSResourceRecord::AUTHORITY;
261 else
262 dr.d_place=DNSResourceRecord::ADDITIONAL;
263
264 unsigned int recordStartPos=pr.d_pos;
265
266 DNSName name=pr.getName();
267
268 pr.getDnsrecordheader(ah);
269 dr.d_ttl=ah.d_ttl;
270 dr.d_type=ah.d_type;
271 dr.d_class=ah.d_class;
272
273 dr.d_name=name;
274 dr.d_clen=ah.d_clen;
275
276 if (query && (dr.d_place == DNSResourceRecord::ANSWER || dr.d_place == DNSResourceRecord::AUTHORITY || (dr.d_type != QType::OPT && dr.d_type != QType::TSIG && dr.d_type != QType::SIG && dr.d_type != QType::TKEY) || ((dr.d_type == QType::TSIG || dr.d_type == QType::SIG || dr.d_type == QType::TKEY) && dr.d_class != QClass::ANY))) {
277 // cerr<<"discarding RR, query is "<<query<<", place is "<<dr.d_place<<", type is "<<dr.d_type<<", class is "<<dr.d_class<<endl;
278 dr.d_content=std::shared_ptr<DNSRecordContent>(new UnknownRecordContent(dr, pr));
279 }
280 else {
281 // cerr<<"parsing RR, query is "<<query<<", place is "<<dr.d_place<<", type is "<<dr.d_type<<", class is "<<dr.d_class<<endl;
282 dr.d_content=std::shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(dr, pr, d_header.opcode));
283 }
284
285 d_answers.push_back(make_pair(dr, pr.d_pos));
286
287 if(dr.d_type == QType::TSIG && dr.d_class == QClass::ANY) {
288 if(dr.d_place != DNSResourceRecord::ADDITIONAL || n != (unsigned int)(d_header.ancount + d_header.nscount + d_header.arcount) - 1) {
289 throw MOADNSException("Packet ("+d_qname.toString()+"|#"+std::to_string(d_qtype)+") has a TSIG record in an invalid position.");
290 }
291 d_tsigPos = recordStartPos + sizeof(struct dnsheader);
292 }
293 }
294
295 #if 0
296 if(pr.d_pos!=contentlen) {
297 throw MOADNSException("Packet ("+d_qname+"|#"+std::to_string(d_qtype)+") has trailing garbage ("+ std::to_string(pr.d_pos) + " < " +
298 std::to_string(contentlen) + ")");
299 }
300 #endif
301 }
302 catch(std::out_of_range &re) {
303 if(validPacket && d_header.tc) { // don't sweat it over truncated packets, but do adjust an, ns and arcount
304 if(n < d_header.ancount) {
305 d_header.ancount=n; d_header.nscount = d_header.arcount = 0;
306 }
307 else if(n < d_header.ancount + d_header.nscount) {
308 d_header.nscount = n - d_header.ancount; d_header.arcount=0;
309 }
310 else {
311 d_header.arcount = n - d_header.ancount - d_header.nscount;
312 }
313 }
314 else {
315 throw MOADNSException("Error parsing packet of "+std::to_string(len)+" bytes (rd="+
316 std::to_string(d_header.rd)+
317 "), out of bounds: "+string(re.what()));
318 }
319 }
320 }
321
322
323 void PacketReader::getDnsrecordheader(struct dnsrecordheader &ah)
324 {
325 unsigned int n;
326 unsigned char *p=reinterpret_cast<unsigned char*>(&ah);
327
328 for(n=0; n < sizeof(dnsrecordheader); ++n)
329 p[n]=d_content.at(d_pos++);
330
331 ah.d_type=ntohs(ah.d_type);
332 ah.d_class=ntohs(ah.d_class);
333 ah.d_clen=ntohs(ah.d_clen);
334 ah.d_ttl=ntohl(ah.d_ttl);
335
336 d_startrecordpos=d_pos; // needed for getBlob later on
337 d_recordlen=ah.d_clen;
338 }
339
340
341 void PacketReader::copyRecord(vector<unsigned char>& dest, uint16_t len)
342 {
343 dest.resize(len);
344 if(!len)
345 return;
346
347 for(uint16_t n=0;n<len;++n) {
348 dest.at(n)=d_content.at(d_pos++);
349 }
350 }
351
352 void PacketReader::copyRecord(unsigned char* dest, uint16_t len)
353 {
354 if(d_pos + len > d_content.size())
355 throw std::out_of_range("Attempt to copy outside of packet");
356
357 memcpy(dest, &d_content.at(d_pos), len);
358 d_pos+=len;
359 }
360
361 void PacketReader::xfr48BitInt(uint64_t& ret)
362 {
363 ret=0;
364 ret+=d_content.at(d_pos++);
365 ret<<=8;
366 ret+=d_content.at(d_pos++);
367 ret<<=8;
368 ret+=d_content.at(d_pos++);
369 ret<<=8;
370 ret+=d_content.at(d_pos++);
371 ret<<=8;
372 ret+=d_content.at(d_pos++);
373 ret<<=8;
374 ret+=d_content.at(d_pos++);
375 }
376
377 uint32_t PacketReader::get32BitInt()
378 {
379 uint32_t ret=0;
380 ret+=d_content.at(d_pos++);
381 ret<<=8;
382 ret+=d_content.at(d_pos++);
383 ret<<=8;
384 ret+=d_content.at(d_pos++);
385 ret<<=8;
386 ret+=d_content.at(d_pos++);
387
388 return ret;
389 }
390
391
392 uint16_t PacketReader::get16BitInt()
393 {
394 return get16BitInt(d_content, d_pos);
395 }
396
397 uint16_t PacketReader::get16BitInt(const vector<unsigned char>&content, uint16_t& pos)
398 {
399 uint16_t ret=0;
400 ret+=content.at(pos++);
401 ret<<=8;
402 ret+=content.at(pos++);
403
404 return ret;
405 }
406
407 uint8_t PacketReader::get8BitInt()
408 {
409 return d_content.at(d_pos++);
410 }
411
412 DNSName PacketReader::getName()
413 {
414 unsigned int consumed;
415 try {
416 DNSName dn((const char*) d_content.data() - 12, d_content.size() + 12, d_pos + sizeof(dnsheader), true /* uncompress */, 0 /* qtype */, 0 /* qclass */, &consumed, sizeof(dnsheader));
417
418 // the -12 fakery is because we don't have the header in 'd_content', but we do need to get
419 // the internal offsets to work
420 d_pos+=consumed;
421 return dn;
422 }
423 catch(std::range_error& re)
424 {
425 throw std::out_of_range(string("dnsname issue: ")+re.what());
426 }
427
428 catch(...)
429 {
430 throw std::out_of_range("dnsname issue");
431 }
432 throw PDNSException("PacketReader::getName(): name is empty");
433 }
434
435 static string txtEscape(const string &name)
436 {
437 string ret;
438 char ebuf[5];
439
440 for(string::const_iterator i=name.begin();i!=name.end();++i) {
441 if((unsigned char) *i > 127 || (unsigned char) *i < 32) {
442 snprintf(ebuf, sizeof(ebuf), "\\%03u", (unsigned char)*i);
443 ret += ebuf;
444 }
445 else if(*i=='"' || *i=='\\'){
446 ret += '\\';
447 ret += *i;
448 }
449 else
450 ret += *i;
451 }
452 return ret;
453 }
454
455 // exceptions thrown here do not result in logging in the main pdns auth server - just so you know!
456 string PacketReader::getText(bool multi, bool lenField)
457 {
458 string ret;
459 ret.reserve(40);
460 while(d_pos < d_startrecordpos + d_recordlen ) {
461 if(!ret.empty()) {
462 ret.append(1,' ');
463 }
464 uint16_t labellen;
465 if(lenField)
466 labellen=d_content.at(d_pos++);
467 else
468 labellen=d_recordlen - (d_pos - d_startrecordpos);
469
470 ret.append(1,'"');
471 if(labellen) { // no need to do anything for an empty string
472 string val(&d_content.at(d_pos), &d_content.at(d_pos+labellen-1)+1);
473 ret.append(txtEscape(val)); // the end is one beyond the packet
474 }
475 ret.append(1,'"');
476 d_pos+=labellen;
477 if(!multi)
478 break;
479 }
480
481 return ret;
482 }
483
484 string PacketReader::getUnquotedText(bool lenField)
485 {
486 int16_t stop_at;
487 if(lenField)
488 stop_at = (uint8_t)d_content.at(d_pos) + d_pos + 1;
489 else
490 stop_at = d_recordlen;
491
492 if(stop_at == d_pos)
493 return "";
494
495 d_pos++;
496 string ret(&d_content.at(d_pos), &d_content.at(stop_at));
497 d_pos = stop_at;
498 return ret;
499 }
500
501 void PacketReader::xfrBlob(string& blob)
502 try
503 {
504 if(d_recordlen && !(d_pos == (d_startrecordpos + d_recordlen)))
505 blob.assign(&d_content.at(d_pos), &d_content.at(d_startrecordpos + d_recordlen - 1 ) + 1);
506 else
507 blob.clear();
508
509 d_pos = d_startrecordpos + d_recordlen;
510 }
511 catch(...)
512 {
513 throw std::out_of_range("xfrBlob out of range");
514 }
515
516 void PacketReader::xfrBlobNoSpaces(string& blob, int length) {
517 xfrBlob(blob, length);
518 }
519
520 void PacketReader::xfrBlob(string& blob, int length)
521 {
522 if(length) {
523 blob.assign(&d_content.at(d_pos), &d_content.at(d_pos + length - 1 ) + 1 );
524
525 d_pos += length;
526 }
527 else
528 blob.clear();
529 }
530
531
532 void PacketReader::xfrHexBlob(string& blob, bool keepReading)
533 {
534 xfrBlob(blob);
535 }
536
537 //FIXME400 remove this method completely
538 string simpleCompress(const string& elabel, const string& root)
539 {
540 string label=elabel;
541 // FIXME400: this relies on the semi-canonical escaped output from getName
542 if(strchr(label.c_str(), '\\')) {
543 boost::replace_all(label, "\\.", ".");
544 boost::replace_all(label, "\\032", " ");
545 boost::replace_all(label, "\\\\", "\\");
546 }
547 typedef vector<pair<unsigned int, unsigned int> > parts_t;
548 parts_t parts;
549 vstringtok(parts, label, ".");
550 string ret;
551 ret.reserve(label.size()+4);
552 for(parts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) {
553 if(!root.empty() && !strncasecmp(root.c_str(), label.c_str() + i->first, 1 + label.length() - i->first)) { // also match trailing 0, hence '1 +'
554 const unsigned char rootptr[2]={0xc0,0x11};
555 ret.append((const char *) rootptr, 2);
556 return ret;
557 }
558 ret.append(1, (char)(i->second - i->first));
559 ret.append(label.c_str() + i->first, i->second - i->first);
560 }
561 ret.append(1, (char)0);
562 return ret;
563 }
564
565
566 /** Simple DNSPacketMangler. Ritual is: get a pointer into the packet and moveOffset() to beyond your needs
567 * If you survive that, feel free to read from the pointer */
568 class DNSPacketMangler
569 {
570 public:
571 explicit DNSPacketMangler(std::string& packet)
572 : d_packet((char*) packet.c_str()), d_length(packet.length()), d_notyouroffset(12), d_offset(d_notyouroffset)
573 {}
574 DNSPacketMangler(char* packet, size_t length)
575 : d_packet(packet), d_length(length), d_notyouroffset(12), d_offset(d_notyouroffset)
576 {}
577
578 void skipLabel()
579 {
580 uint8_t len;
581 while((len=get8BitInt())) {
582 if(len >= 0xc0) { // extended label
583 get8BitInt();
584 return;
585 }
586 skipBytes(len);
587 }
588 }
589 void skipBytes(uint16_t bytes)
590 {
591 moveOffset(bytes);
592 }
593 uint32_t get32BitInt()
594 {
595 const char* p = d_packet + d_offset;
596 moveOffset(4);
597 uint32_t ret;
598 memcpy(&ret, (void*)p, sizeof(ret));
599 return ntohl(ret);
600 }
601 uint16_t get16BitInt()
602 {
603 const char* p = d_packet + d_offset;
604 moveOffset(2);
605 uint16_t ret;
606 memcpy(&ret, (void*)p, sizeof(ret));
607 return ntohs(ret);
608 }
609
610 uint8_t get8BitInt()
611 {
612 const char* p = d_packet + d_offset;
613 moveOffset(1);
614 return *p;
615 }
616
617 void skipRData()
618 {
619 int toskip = get16BitInt();
620 moveOffset(toskip);
621 }
622 void decreaseAndSkip32BitInt(uint32_t decrease)
623 {
624 const char *p = d_packet + d_offset;
625 moveOffset(4);
626
627 uint32_t tmp;
628 memcpy(&tmp, (void*) p, sizeof(tmp));
629 tmp = ntohl(tmp);
630 tmp-=decrease;
631 tmp = htonl(tmp);
632 memcpy(d_packet + d_offset-4, (const char*)&tmp, sizeof(tmp));
633 }
634 uint32_t getOffset() const
635 {
636 return d_offset;
637 }
638 private:
639 void moveOffset(uint16_t by)
640 {
641 d_notyouroffset += by;
642 if(d_notyouroffset > d_length)
643 throw std::out_of_range("dns packet out of range: "+std::to_string(d_notyouroffset) +" > "
644 + std::to_string(d_length) );
645 }
646 char* d_packet;
647 size_t d_length;
648
649 uint32_t d_notyouroffset; // only 'moveOffset' can touch this
650 const uint32_t& d_offset; // look.. but don't touch
651
652 };
653
654 // method of operation: silently fail if it doesn't work - we're only trying to be nice, don't fall over on it
655 void ageDNSPacket(char* packet, size_t length, uint32_t seconds)
656 {
657 if(length < sizeof(dnsheader))
658 return;
659 try
660 {
661 dnsheader dh;
662 memcpy((void*)&dh, (const dnsheader*)packet, sizeof(dh));
663 uint64_t numrecords = ntohs(dh.ancount) + ntohs(dh.nscount) + ntohs(dh.arcount);
664 DNSPacketMangler dpm(packet, length);
665
666 uint64_t n;
667 for(n=0; n < ntohs(dh.qdcount) ; ++n) {
668 dpm.skipLabel();
669 /* type and class */
670 dpm.skipBytes(4);
671 }
672 // cerr<<"Skipped "<<n<<" questions, now parsing "<<numrecords<<" records"<<endl;
673 for(n=0; n < numrecords; ++n) {
674 dpm.skipLabel();
675
676 uint16_t dnstype = dpm.get16BitInt();
677 /* class */
678 dpm.skipBytes(2);
679
680 if(dnstype == QType::OPT) // not aging that one with a stick
681 break;
682
683 dpm.decreaseAndSkip32BitInt(seconds);
684 dpm.skipRData();
685 }
686 }
687 catch(...)
688 {
689 return;
690 }
691 }
692
693 void ageDNSPacket(std::string& packet, uint32_t seconds)
694 {
695 ageDNSPacket((char*)packet.c_str(), packet.length(), seconds);
696 }
697
698 uint32_t getDNSPacketMinTTL(const char* packet, size_t length)
699 {
700 uint32_t result = std::numeric_limits<uint32_t>::max();
701 if(length < sizeof(dnsheader)) {
702 return result;
703 }
704 try
705 {
706 const dnsheader* dh = (const dnsheader*) packet;
707 DNSPacketMangler dpm(const_cast<char*>(packet), length);
708
709 const uint16_t qdcount = ntohs(dh->qdcount);
710 for(size_t n = 0; n < qdcount; ++n) {
711 dpm.skipLabel();
712 /* type and class */
713 dpm.skipBytes(4);
714 }
715 const size_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount);
716 for(size_t n = 0; n < numrecords; ++n) {
717 dpm.skipLabel();
718 const uint16_t dnstype = dpm.get16BitInt();
719 /* class */
720 dpm.skipBytes(2);
721
722 if(dnstype == QType::OPT)
723 break;
724
725 const uint32_t ttl = dpm.get32BitInt();
726 if (result > ttl)
727 result = ttl;
728
729 dpm.skipRData();
730 }
731 }
732 catch(...)
733 {
734 }
735 return result;
736 }
737
738 uint32_t getDNSPacketLength(const char* packet, size_t length)
739 {
740 uint32_t result = length;
741 if(length < sizeof(dnsheader)) {
742 return result;
743 }
744 try
745 {
746 const dnsheader* dh = (const dnsheader*) packet;
747 DNSPacketMangler dpm(const_cast<char*>(packet), length);
748
749 const uint16_t qdcount = ntohs(dh->qdcount);
750 for(size_t n = 0; n < qdcount; ++n) {
751 dpm.skipLabel();
752 /* type and class */
753 dpm.skipBytes(4);
754 }
755 const size_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount);
756 for(size_t n = 0; n < numrecords; ++n) {
757 dpm.skipLabel();
758 /* type (2), class (2) and ttl (4) */
759 dpm.skipBytes(8);
760 dpm.skipRData();
761 }
762 result = dpm.getOffset();
763 }
764 catch(...)
765 {
766 }
767 return result;
768 }
769
770 uint16_t getRecordsOfTypeCount(const char* packet, size_t length, uint8_t section, uint16_t type)
771 {
772 uint16_t result = 0;
773 if(length < sizeof(dnsheader)) {
774 return result;
775 }
776 try
777 {
778 const dnsheader* dh = (const dnsheader*) packet;
779 DNSPacketMangler dpm(const_cast<char*>(packet), length);
780
781 const uint16_t qdcount = ntohs(dh->qdcount);
782 for(size_t n = 0; n < qdcount; ++n) {
783 dpm.skipLabel();
784 if (section == 0) {
785 uint16_t dnstype = dpm.get16BitInt();
786 if (dnstype == type) {
787 result++;
788 }
789 /* class */
790 dpm.skipBytes(2);
791 } else {
792 /* type and class */
793 dpm.skipBytes(4);
794 }
795 }
796 const uint16_t ancount = ntohs(dh->ancount);
797 for(size_t n = 0; n < ancount; ++n) {
798 dpm.skipLabel();
799 if (section == 1) {
800 uint16_t dnstype = dpm.get16BitInt();
801 if (dnstype == type) {
802 result++;
803 }
804 /* class */
805 dpm.skipBytes(2);
806 } else {
807 /* type and class */
808 dpm.skipBytes(4);
809 }
810 /* ttl */
811 dpm.skipBytes(4);
812 dpm.skipRData();
813 }
814 const uint16_t nscount = ntohs(dh->nscount);
815 for(size_t n = 0; n < nscount; ++n) {
816 dpm.skipLabel();
817 if (section == 2) {
818 uint16_t dnstype = dpm.get16BitInt();
819 if (dnstype == type) {
820 result++;
821 }
822 /* class */
823 dpm.skipBytes(2);
824 } else {
825 /* type and class */
826 dpm.skipBytes(4);
827 }
828 /* ttl */
829 dpm.skipBytes(4);
830 dpm.skipRData();
831 }
832 const uint16_t arcount = ntohs(dh->arcount);
833 for(size_t n = 0; n < arcount; ++n) {
834 dpm.skipLabel();
835 if (section == 3) {
836 uint16_t dnstype = dpm.get16BitInt();
837 if (dnstype == type) {
838 result++;
839 }
840 /* class */
841 dpm.skipBytes(2);
842 } else {
843 /* type and class */
844 dpm.skipBytes(4);
845 }
846 /* ttl */
847 dpm.skipBytes(4);
848 dpm.skipRData();
849 }
850 }
851 catch(...)
852 {
853 }
854 return result;
855 }