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