]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnspacket.cc
Merge branch 'rfc2136' of https://github.com/mind04/pdns into rfc2136
[thirdparty/pdns.git] / pdns / dnspacket.cc
1 /*
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2001 - 2011 PowerDNS.COM BV
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
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "utility.hh"
20 #include <cstdio>
21 #include <cstdlib>
22 #include <sys/types.h>
23 #include <iostream>
24 #include <string>
25 #include <errno.h>
26 #include <boost/tokenizer.hpp>
27 #include <boost/algorithm/string.hpp>
28 #include <algorithm>
29 #include <boost/foreach.hpp>
30 #include "dnsseckeeper.hh"
31 #include "dns.hh"
32 #include "dnsbackend.hh"
33 #include "ahuexception.hh"
34 #include "dnspacket.hh"
35 #include "logger.hh"
36 #include "arguments.hh"
37 #include "dnswriter.hh"
38 #include "dnsparser.hh"
39 #include "dnsrecords.hh"
40 #include "dnssecinfra.hh"
41 #include "base64.hh"
42 #include "ednssubnet.hh"
43
44 bool DNSPacket::s_doEDNSSubnetProcessing;
45 std::vector<int> DNSPacket::s_ednssubnetcodes;
46 uint16_t DNSPacket::s_udpTruncationThreshold;
47
48 DNSPacket::DNSPacket()
49 {
50 d_wrapped=false;
51 d_compress=true;
52 d_tcp=false;
53 d_wantsnsid=false;
54 d_haveednssubnet = false;
55 d_dnssecOk=false;
56 }
57
58 const string& DNSPacket::getString()
59 {
60 if(!d_wrapped)
61 wrapup();
62
63 return d_rawpacket;
64 }
65
66 string DNSPacket::getRemote() const
67 {
68 return d_remote.toString();
69 }
70
71 uint16_t DNSPacket::getRemotePort() const
72 {
73 return d_remote.sin4.sin_port;
74 }
75
76 DNSPacket::DNSPacket(const DNSPacket &orig)
77 {
78 DLOG(L<<"DNSPacket copy constructor called!"<<endl);
79 d_socket=orig.d_socket;
80 d_remote=orig.d_remote;
81 d_qlen=orig.d_qlen;
82 d_dt=orig.d_dt;
83 d_compress=orig.d_compress;
84 d_tcp=orig.d_tcp;
85 qtype=orig.qtype;
86 qclass=orig.qclass;
87 qdomain=orig.qdomain;
88 d_maxreplylen = orig.d_maxreplylen;
89 d_ednsping = orig.d_ednsping;
90 d_wantsnsid = orig.d_wantsnsid;
91 d_anyLocal = orig.d_anyLocal;
92 d_eso = orig.d_eso;
93 d_haveednssubnet = orig.d_haveednssubnet;
94 d_haveednssection = orig.d_haveednssection;
95 d_ednssubnetcode = orig.d_ednssubnetcode;
96 d_dnssecOk = orig.d_dnssecOk;
97 d_rrs=orig.d_rrs;
98
99 d_tsigkeyname = orig.d_tsigkeyname;
100 d_tsigprevious = orig.d_tsigprevious;
101 d_tsigtimersonly = orig.d_tsigtimersonly;
102 d_trc = orig.d_trc;
103 d_tsigsecret = orig.d_tsigsecret;
104
105 d_havetsig = orig.d_havetsig;
106 d_wrapped=orig.d_wrapped;
107
108 d_rawpacket=orig.d_rawpacket;
109 d=orig.d;
110 }
111
112 void DNSPacket::setRcode(int v)
113 {
114 d.rcode=v;
115 }
116
117 void DNSPacket::setAnswer(bool b)
118 {
119 if(b) {
120 d_rawpacket.assign(12,(char)0);
121 memset((void *)&d,0,sizeof(d));
122
123 d.qr=b;
124 }
125 }
126
127 void DNSPacket::setA(bool b)
128 {
129 d.aa=b;
130 }
131
132 void DNSPacket::setID(uint16_t id)
133 {
134 d.id=id;
135 }
136
137 void DNSPacket::setRA(bool b)
138 {
139 d.ra=b;
140 }
141
142 void DNSPacket::setRD(bool b)
143 {
144 d.rd=b;
145 }
146
147 void DNSPacket::setOpcode(uint16_t opcode)
148 {
149 d.opcode=opcode;
150 }
151
152
153 void DNSPacket::clearRecords()
154 {
155 d_rrs.clear();
156 }
157
158 void DNSPacket::addRecord(const DNSResourceRecord &rr)
159 {
160 // this removes duplicates from the packet in case we are not compressing
161 // for AXFR, no such checking is performed!
162 if(d_compress)
163 for(vector<DNSResourceRecord>::const_iterator i=d_rrs.begin();i!=d_rrs.end();++i)
164 if(rr.qname==i->qname && rr.qtype==i->qtype && rr.content==i->content) {
165 if(rr.qtype.getCode()!=QType::MX && rr.qtype.getCode()!=QType::SRV)
166 return;
167 if(rr.priority==i->priority)
168 return;
169 }
170
171 d_rrs.push_back(rr);
172 }
173
174
175
176 static int rrcomp(const DNSResourceRecord &A, const DNSResourceRecord &B)
177 {
178 if(A.d_place < B.d_place)
179 return 1;
180
181 return 0;
182 }
183
184 vector<DNSResourceRecord*> DNSPacket::getAPRecords()
185 {
186 vector<DNSResourceRecord*> arrs;
187
188 for(vector<DNSResourceRecord>::iterator i=d_rrs.begin();
189 i!=d_rrs.end();
190 ++i)
191 {
192 if(i->d_place!=DNSResourceRecord::ADDITIONAL &&
193 (i->qtype.getCode()==QType::MX ||
194 i->qtype.getCode()==QType::NS ||
195 i->qtype.getCode()==QType::SRV))
196 {
197 arrs.push_back(&*i);
198 }
199 }
200
201 return arrs;
202
203 }
204
205 vector<DNSResourceRecord*> DNSPacket::getAnswerRecords()
206 {
207 vector<DNSResourceRecord*> arrs;
208
209 for(vector<DNSResourceRecord>::iterator i=d_rrs.begin();
210 i!=d_rrs.end();
211 ++i)
212 {
213 if(i->d_place!=DNSResourceRecord::ADDITIONAL)
214 arrs.push_back(&*i);
215 }
216 return arrs;
217 }
218
219
220 void DNSPacket::setCompress(bool compress)
221 {
222 d_compress=compress;
223 d_rawpacket.reserve(65000);
224 d_rrs.reserve(200);
225 }
226
227 bool DNSPacket::couldBeCached()
228 {
229 return d_ednsping.empty() && !d_wantsnsid && qclass==QClass::IN;
230 }
231
232 unsigned int DNSPacket::getMinTTL()
233 {
234 unsigned int minttl = UINT_MAX;
235 BOOST_FOREACH(DNSResourceRecord rr, d_rrs) {
236 if (rr.ttl < minttl)
237 minttl = rr.ttl;
238 }
239
240 return minttl;
241 }
242
243 bool DNSPacket::isEmpty()
244 {
245 return (d_rrs.empty());
246 }
247
248 /** Must be called before attempting to access getData(). This function stuffs all resource
249 * records found in rrs into the data buffer. It also frees resource records queued for us.
250 */
251 void DNSPacket::wrapup()
252 {
253 if(d_wrapped) {
254 return;
255 }
256
257 DNSResourceRecord rr;
258 vector<DNSResourceRecord>::iterator pos;
259
260 // we now need to order rrs so that the different sections come at the right place
261 // we want a stable sort, based on the d_place field
262
263 stable_sort(d_rrs.begin(),d_rrs.end(), rrcomp);
264 static bool mustNotShuffle = ::arg().mustDo("no-shuffle");
265
266 if(!d_tcp && !mustNotShuffle) {
267 shuffle(d_rrs);
268 }
269 d_wrapped=true;
270
271 vector<uint8_t> packet;
272 DNSPacketWriter pw(packet, qdomain, qtype.getCode(), qclass);
273
274 pw.getHeader()->rcode=d.rcode;
275 pw.getHeader()->opcode = d.opcode;
276 pw.getHeader()->aa=d.aa;
277 pw.getHeader()->ra=d.ra;
278 pw.getHeader()->qr=d.qr;
279 pw.getHeader()->id=d.id;
280 pw.getHeader()->rd=d.rd;
281 pw.getHeader()->tc=d.tc;
282
283 DNSPacketWriter::optvect_t opts;
284 if(d_wantsnsid) {
285 opts.push_back(make_pair(3, ::arg()["server-id"]));
286 }
287
288 if(!d_ednsping.empty()) {
289 opts.push_back(make_pair(4, d_ednsping));
290 }
291
292
293 if(!d_rrs.empty() || !opts.empty() || d_haveednssubnet || d_haveednssection) {
294 try {
295 uint8_t maxScopeMask=0;
296 for(pos=d_rrs.begin(); pos < d_rrs.end(); ++pos) {
297 maxScopeMask = max(maxScopeMask, pos->scopeMask);
298 // this needs to deal with the 'prio' mismatch:
299 if(pos->qtype.getCode()==QType::MX || pos->qtype.getCode() == QType::SRV) {
300 pos->content = lexical_cast<string>(pos->priority) + " " + pos->content;
301 }
302
303 if(!pos->content.empty() && pos->qtype.getCode()==QType::TXT && pos->content[0]!='"') {
304 pos->content="\""+pos->content+"\"";
305 }
306 if(pos->content.empty()) // empty contents confuse the MOADNS setup
307 pos->content=".";
308
309 pw.startRecord(pos->qname, pos->qtype.getCode(), pos->ttl, pos->qclass, (DNSPacketWriter::Place)pos->d_place);
310 shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(pos->qtype.getCode(), 1, pos->content));
311 drc->toPacket(pw);
312 if(pw.size() + 20U > (d_tcp ? 65535 : getMaxReplyLen())) { // 20 = room for EDNS0
313 pw.rollback();
314 if(pos->d_place == DNSResourceRecord::ANSWER || pos->d_place == DNSResourceRecord::AUTHORITY) {
315 pw.getHeader()->tc=1;
316 }
317 goto noCommit;
318 }
319 }
320
321 // if(!pw.getHeader()->tc) // protect against double commit from addSignature
322
323 if(!d_rrs.empty()) pw.commit();
324
325 noCommit:;
326
327 if(d_haveednssubnet) {
328 string makeEDNSSubnetOptsString(const EDNSSubnetOpts& eso);
329 EDNSSubnetOpts eso = d_eso;
330 eso.scope = Netmask(eso.source.getNetwork(), maxScopeMask);
331
332 string opt = makeEDNSSubnetOptsString(eso);
333 opts.push_back(make_pair(d_ednssubnetcode, opt)); // 'EDNS SUBNET'
334 }
335
336 if(!opts.empty() || d_haveednssection || d_dnssecOk)
337 {
338 pw.addOpt(s_udpTruncationThreshold, 0, d_dnssecOk ? EDNSOpts::DNSSECOK : 0, opts);
339 pw.commit();
340 }
341 }
342 catch(std::exception& e) {
343 L<<Logger::Warning<<"Exception: "<<e.what()<<endl;
344 throw;
345 }
346 }
347
348 if(!d_trc.d_algoName.empty())
349 addTSIG(pw, &d_trc, d_tsigkeyname, d_tsigsecret, d_tsigprevious, d_tsigtimersonly);
350
351 d_rawpacket.assign((char*)&packet[0], packet.size());
352 }
353
354 void DNSPacket::setQuestion(int op, const string &qd, int newqtype)
355 {
356 memset(&d,0,sizeof(d));
357 d.id=Utility::random();
358 d.rd=d.tc=d.aa=false;
359 d.qr=false;
360 d.qdcount=1; // is htons'ed later on
361 d.ancount=d.arcount=d.nscount=0;
362 d.opcode=op;
363 qdomain=qd;
364 qtype=newqtype;
365 }
366
367 /** convenience function for creating a reply packet from a question packet. Do not forget to delete it after use! */
368 DNSPacket *DNSPacket::replyPacket() const
369 {
370 DNSPacket *r=new DNSPacket;
371 r->setSocket(d_socket);
372 r->d_anyLocal=d_anyLocal;
373 r->setRemote(&d_remote);
374 r->setAnswer(true); // this implies the allocation of the header
375 r->setA(true); // and we are authoritative
376 r->setRA(0); // no recursion available
377 r->setRD(d.rd); // if you wanted to recurse, answer will say you wanted it
378 r->setID(d.id);
379 r->setOpcode(d.opcode);
380
381 r->d_dt=d_dt;
382 r->d.qdcount=1;
383 r->d_tcp = d_tcp;
384 r->qdomain = qdomain;
385 r->qtype = qtype;
386 r->qclass = qclass;
387 r->d_maxreplylen = d_maxreplylen;
388 r->d_ednsping = d_ednsping;
389 r->d_wantsnsid = d_wantsnsid;
390 r->d_dnssecOk = d_dnssecOk;
391 r->d_eso = d_eso;
392 r->d_haveednssubnet = d_haveednssubnet;
393 r->d_haveednssection = d_haveednssection;
394 r->d_ednssubnetcode = d_ednssubnetcode;
395
396 if(!d_tsigkeyname.empty()) {
397 r->d_tsigkeyname = d_tsigkeyname;
398 r->d_tsigprevious = d_tsigprevious;
399 r->d_trc = d_trc;
400 r->d_tsigsecret = d_tsigsecret;
401 r->d_tsigtimersonly = d_tsigtimersonly;
402 }
403 r->d_havetsig = d_havetsig;
404 return r;
405 }
406
407 void DNSPacket::spoofQuestion(const DNSPacket *qd)
408 {
409 d_wrapped=true; // if we do this, don't later on wrapup
410
411 int labellen;
412 string::size_type i=sizeof(d);
413
414 for(;;) {
415 labellen = qd->d_rawpacket[i];
416 if(!labellen) break;
417 i++;
418 d_rawpacket.replace(i, labellen, qd->d_rawpacket, i, labellen);
419 i = i + labellen;
420 }
421 }
422
423 int DNSPacket::noparse(const char *mesg, int length)
424 {
425 d_rawpacket.assign(mesg,length);
426 if(length < 12) {
427 L << Logger::Warning << "Ignoring packet: too short from "
428 << getRemote() << endl;
429 return -1;
430 }
431 d_wantsnsid=false;
432 d_ednsping.clear();
433 d_maxreplylen=512;
434 memcpy((void *)&d,(const void *)d_rawpacket.c_str(),12);
435 return 0;
436 }
437
438 void DNSPacket::setTSIGDetails(const TSIGRecordContent& tr, const string& keyname, const string& secret, const string& previous, bool timersonly)
439 {
440 d_trc=tr;
441 d_tsigkeyname = keyname;
442 d_tsigsecret = secret;
443 d_tsigprevious = previous;
444 d_tsigtimersonly=timersonly;
445 }
446
447 bool DNSPacket::getTSIGDetails(TSIGRecordContent* trc, string* keyname, string* message) const
448 {
449 MOADNSParser mdp(d_rawpacket);
450
451 if(!mdp.getTSIGPos())
452 return false;
453
454 bool gotit=false;
455 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
456 if(i->first.d_type == QType::TSIG) {
457 *trc = *boost::dynamic_pointer_cast<TSIGRecordContent>(i->first.d_content);
458
459 gotit=true;
460 *keyname = i->first.d_label;
461 if(!keyname->empty())
462 keyname->resize(keyname->size()-1); // drop the trailing dot
463 }
464 }
465 if(!gotit)
466 return false;
467 if(message)
468 *message = makeTSIGMessageFromTSIGPacket(d_rawpacket, mdp.getTSIGPos(), *keyname, *trc, d_tsigprevious, false); // if you change rawpacket to getString it breaks!
469
470 return true;
471 }
472
473 /** This function takes data from the network, possibly received with recvfrom, and parses
474 it into our class. Results of calling this function multiple times on one packet are
475 unknown. Returns -1 if the packet cannot be parsed.
476 */
477 int DNSPacket::parse(const char *mesg, int length)
478 try
479 {
480 d_rawpacket.assign(mesg,length);
481 d_wrapped=true;
482 if(length < 12) {
483 L << Logger::Warning << "Ignoring packet: too short from "
484 << getRemote() << endl;
485 return -1;
486 }
487
488 MOADNSParser mdp(d_rawpacket);
489 EDNSOpts edo;
490
491 // ANY OPTION WHICH *MIGHT* BE SET DOWN BELOW SHOULD BE CLEARED FIRST!
492
493 d_wantsnsid=false;
494 d_dnssecOk=false;
495 d_ednsping.clear();
496 d_havetsig = mdp.getTSIGPos();
497 d_haveednssubnet = false;
498 d_haveednssection = false;
499
500
501 if(getEDNSOpts(mdp, &edo)) {
502 d_haveednssection=true;
503 d_maxreplylen=std::min(edo.d_packetsize, s_udpTruncationThreshold);
504 // cerr<<edo.d_Z<<endl;
505 if(edo.d_Z & EDNSOpts::DNSSECOK)
506 d_dnssecOk=true;
507
508 for(vector<pair<uint16_t, string> >::const_iterator iter = edo.d_options.begin();
509 iter != edo.d_options.end();
510 ++iter) {
511 if(iter->first == 3) {// 'EDNS NSID'
512 d_wantsnsid=1;
513 }
514 else if(iter->first == 5) {// 'EDNS PING'
515 d_ednsping = iter->second;
516 }
517 else if(s_doEDNSSubnetProcessing && (iter->first == 8 || std::find(s_ednssubnetcodes.begin(), s_ednssubnetcodes.end(), iter->first) != s_ednssubnetcodes.end())) { // 'EDNS SUBNET'
518 if(getEDNSSubnetOptsFromString(iter->second, &d_eso)) {
519 //cerr<<"Parsed, source: "<<d_eso.source.toString()<<", scope: "<<d_eso.scope.toString()<<", family = "<<d_eso.scope.getNetwork().sin4.sin_family<<endl;
520 d_haveednssubnet=true;
521 d_ednssubnetcode=iter->first;
522 }
523 }
524 else {
525 // cerr<<"Have an option #"<<iter->first<<": "<<makeHexDump(iter->second)<<endl;
526 }
527 }
528 }
529 else {
530 d_maxreplylen=512;
531 }
532
533 memcpy((void *)&d,(const void *)d_rawpacket.c_str(),12);
534 qdomain=mdp.d_qname;
535 if(!qdomain.empty()) // strip dot
536 boost::erase_tail(qdomain, 1);
537
538 if(!ntohs(d.qdcount)) {
539 if(!d_tcp) {
540 L << Logger::Warning << "No question section in packet from " << getRemote() <<", rcode="<<(int)d.rcode<<endl;
541 return -1;
542 }
543 }
544
545 qtype=mdp.d_qtype;
546 qclass=mdp.d_qclass;
547 return 0;
548 }
549 catch(std::exception& e) {
550 return -1;
551 }
552
553 unsigned int DNSPacket::getMaxReplyLen()
554 {
555 return d_maxreplylen;
556 }
557
558 void DNSPacket::setMaxReplyLen(int bytes)
559 {
560 d_maxreplylen=bytes;
561 }
562
563 //! Use this to set where this packet was received from or should be sent to
564 void DNSPacket::setRemote(const ComboAddress *s)
565 {
566 d_remote=*s;
567 }
568
569 bool DNSPacket::hasEDNSSubnet()
570 {
571 return d_haveednssubnet;
572 }
573
574 bool DNSPacket::hasEDNS()
575 {
576 return d_haveednssection;
577 }
578
579 Netmask DNSPacket::getRealRemote() const
580 {
581 if(d_haveednssubnet)
582 return d_eso.source;
583 return Netmask(d_remote);
584 }
585
586 void DNSPacket::setSocket(Utility::sock_t sock)
587 {
588 d_socket=sock;
589 }
590
591 void DNSPacket::commitD()
592 {
593 d_rawpacket.replace(0,12,(char *)&d,12); // copy in d
594 }
595
596 bool checkForCorrectTSIG(const DNSPacket* q, DNSBackend* B, string* keyname, string* secret, TSIGRecordContent* trc)
597 {
598 string message;
599
600 q->getTSIGDetails(trc, keyname, &message);
601 uint64_t now = time(0);
602 if(abs(trc->d_time - now) > trc->d_fudge) {
603 L<<Logger::Error<<"Packet for '"<<q->qdomain<<"' denied: TSIG (key '"<<*keyname<<"') time delta "<< abs(trc->d_time - now)<<" > 'fudge' "<<trc->d_fudge<<endl;
604 return false;
605 }
606
607 string secret64;
608
609 if(!B->getTSIGKey(*keyname, &trc->d_algoName, &secret64)) {
610 L<<Logger::Error<<"Packet for domain '"<<q->qdomain<<"' denied: can't find TSIG key with name '"<<*keyname<<"' and algorithm '"<<trc->d_algoName<<"'"<<endl;
611 return false;
612 }
613
614 if (trc->d_algoName == "hmac-md5")
615 trc->d_algoName += ".sig-alg.reg.int.";
616
617 if (trc->d_algoName != "hmac-md5.sig-alg.reg.int.") {
618 L<<Logger::Error<<"Unsupported TSIG HMAC algorithm " << trc->d_algoName << endl;
619 return false;
620 }
621
622 B64Decode(secret64, *secret);
623 bool result=calculateMD5HMAC(*secret, message) == trc->d_mac;
624 if(!result) {
625 L<<Logger::Error<<"Packet for domain '"<<q->qdomain<<"' denied: TSIG signature mismatch using '"<<*keyname<<"' and algorithm '"<<trc->d_algoName<<"'"<<endl;
626 }
627 return result;
628 }