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