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