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