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