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