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