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