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