]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnspacket.cc
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2001 - 2011 PowerDNS.COM BV
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation
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.
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
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <sys/types.h>
26 #include <boost/tokenizer.hpp>
27 #include <boost/algorithm/string.hpp>
29 #include <boost/foreach.hpp>
30 #include "dnsseckeeper.hh"
32 #include "dnsbackend.hh"
33 #include "ahuexception.hh"
34 #include "dnspacket.hh"
36 #include "arguments.hh"
37 #include "dnswriter.hh"
38 #include "dnsparser.hh"
39 #include "dnsrecords.hh"
40 #include "dnssecinfra.hh"
42 #include "ednssubnet.hh"
44 bool DNSPacket :: s_doEDNSSubnetProcessing
;
45 std :: vector
< int > DNSPacket :: s_ednssubnetcodes
;
46 uint16_t DNSPacket :: s_udpTruncationThreshold
;
48 DNSPacket :: DNSPacket ()
54 d_haveednssubnet
= false ;
58 const string
& DNSPacket :: getString ()
66 string
DNSPacket :: getRemote () const
68 return d_remote
. toString ();
71 uint16_t DNSPacket :: getRemotePort () const
73 return d_remote
. sin4
. sin_port
;
76 DNSPacket :: DNSPacket ( const DNSPacket
& orig
)
78 DLOG ( L
<< "DNSPacket copy constructor called!" << endl
);
79 d_socket
= orig
. d_socket
;
80 d_remote
= orig
. d_remote
;
83 d_compress
= orig
. d_compress
;
88 d_maxreplylen
= orig
. d_maxreplylen
;
89 d_ednsping
= orig
. d_ednsping
;
90 d_wantsnsid
= orig
. d_wantsnsid
;
91 d_anyLocal
= orig
. d_anyLocal
;
93 d_haveednssubnet
= orig
. d_haveednssubnet
;
94 d_haveednssection
= orig
. d_haveednssection
;
95 d_ednssubnetcode
= orig
. d_ednssubnetcode
;
96 d_dnssecOk
= orig
. d_dnssecOk
;
99 d_tsigkeyname
= orig
. d_tsigkeyname
;
100 d_tsigprevious
= orig
. d_tsigprevious
;
101 d_tsigtimersonly
= orig
. d_tsigtimersonly
;
103 d_tsigsecret
= orig
. d_tsigsecret
;
105 d_havetsig
= orig
. d_havetsig
;
106 d_wrapped
= orig
. d_wrapped
;
108 d_rawpacket
= orig
. d_rawpacket
;
112 void DNSPacket :: setRcode ( int v
)
117 void DNSPacket :: setAnswer ( bool b
)
120 d_rawpacket
. assign ( 12 ,( char ) 0 );
121 memset (( void *)& d
, 0 , sizeof ( d
));
127 void DNSPacket :: setA ( bool b
)
132 void DNSPacket :: setID ( uint16_t id
)
137 void DNSPacket :: setRA ( bool b
)
142 void DNSPacket :: setRD ( bool b
)
147 void DNSPacket :: setOpcode ( uint16_t opcode
)
153 void DNSPacket :: clearRecords ()
158 void DNSPacket :: addRecord ( const DNSResourceRecord
& rr
)
160 // this removes duplicates from the packet in case we are not compressing
161 // for AXFR, no such checking is performed!
163 for ( vector
< DNSResourceRecord
>:: const_iterator i
= d_rrs
. begin (); i
!= d_rrs
. end ();++ i
)
164 if ( rr
. qname
== i
-> qname
&& rr
. qtype
== i
-> qtype
&& rr
. content
== i
-> content
) {
165 if ( rr
. qtype
. getCode ()!= QType :: MX
&& rr
. qtype
. getCode ()!= QType :: SRV
)
167 if ( rr
. priority
== i
-> priority
)
176 static int rrcomp ( const DNSResourceRecord
& A
, const DNSResourceRecord
& B
)
178 if ( A
. d_place
< B
. d_place
)
184 vector
< DNSResourceRecord
*> DNSPacket :: getAPRecords ()
186 vector
< DNSResourceRecord
*> arrs
;
188 for ( vector
< DNSResourceRecord
>:: iterator i
= d_rrs
. begin ();
192 if ( i
-> d_place
!= DNSResourceRecord :: ADDITIONAL
&&
193 ( i
-> qtype
. getCode ()== QType :: MX
||
194 i
-> qtype
. getCode ()== QType :: NS
||
195 i
-> qtype
. getCode ()== QType :: SRV
))
205 vector
< DNSResourceRecord
*> DNSPacket :: getAnswerRecords ()
207 vector
< DNSResourceRecord
*> arrs
;
209 for ( vector
< DNSResourceRecord
>:: iterator i
= d_rrs
. begin ();
213 if ( i
-> d_place
!= DNSResourceRecord :: ADDITIONAL
)
220 void DNSPacket :: setCompress ( bool compress
)
223 d_rawpacket
. reserve ( 65000 );
227 bool DNSPacket :: couldBeCached ()
229 return d_ednsping
. empty () && ! d_wantsnsid
&& qclass
== QClass :: IN
;
232 unsigned int DNSPacket :: getMinTTL ()
234 unsigned int minttl
= UINT_MAX
;
235 BOOST_FOREACH ( DNSResourceRecord rr
, d_rrs
) {
243 bool DNSPacket :: isEmpty ()
245 return ( d_rrs
. empty ());
248 /** Must be called before attempting to access getData(). This function stuffs all resource
249 * records found in rrs into the data buffer. It also frees resource records queued for us.
251 void DNSPacket :: wrapup ()
257 DNSResourceRecord rr
;
258 vector
< DNSResourceRecord
>:: iterator pos
;
260 // we now need to order rrs so that the different sections come at the right place
261 // we want a stable sort, based on the d_place field
263 stable_sort ( d_rrs
. begin (), d_rrs
. end (), rrcomp
);
264 static bool mustNotShuffle
= :: arg (). mustDo ( "no-shuffle" );
266 if (! d_tcp
&& ! mustNotShuffle
) {
271 vector
< uint8_t > packet
;
272 DNSPacketWriter
pw ( packet
, qdomain
, qtype
. getCode (), qclass
);
274 pw
. getHeader ()-> rcode
= d
. rcode
;
275 pw
. getHeader ()-> opcode
= d
. opcode
;
276 pw
. getHeader ()-> aa
= d
. aa
;
277 pw
. getHeader ()-> ra
= d
. ra
;
278 pw
. getHeader ()-> qr
= d
. qr
;
279 pw
. getHeader ()-> id
= d
. id
;
280 pw
. getHeader ()-> rd
= d
. rd
;
281 pw
. getHeader ()-> tc
= d
. tc
;
283 DNSPacketWriter :: optvect_t opts
;
285 opts
. push_back ( make_pair ( 3 , :: arg ()[ "server-id" ]));
288 if (! d_ednsping
. empty ()) {
289 opts
. push_back ( make_pair ( 4 , d_ednsping
));
293 if (! d_rrs
. empty () || ! opts
. empty () || d_haveednssubnet
|| d_haveednssection
) {
295 uint8_t maxScopeMask
= 0 ;
296 for ( pos
= d_rrs
. begin (); pos
< d_rrs
. end (); ++ pos
) {
297 maxScopeMask
= max ( maxScopeMask
, pos
-> scopeMask
);
298 // this needs to deal with the 'prio' mismatch:
299 if ( pos
-> qtype
. getCode ()== QType :: MX
|| pos
-> qtype
. getCode () == QType :: SRV
) {
300 pos
-> content
= lexical_cast
< string
>( pos
-> priority
) + " " + pos
-> content
;
303 if (! pos
-> content
. empty () && pos
-> qtype
. getCode ()== QType :: TXT
&& pos
-> content
[ 0 ]!= '"' ) {
304 pos
-> content
= " \" " + pos
-> content
+ " \" " ;
306 if ( pos
-> content
. empty ()) // empty contents confuse the MOADNS setup
309 pw
. startRecord ( pos
-> qname
, pos
-> qtype
. getCode (), pos
-> ttl
, pos
-> qclass
, ( DNSPacketWriter :: Place
) pos
-> d_place
);
310 shared_ptr
< DNSRecordContent
> drc ( DNSRecordContent :: mastermake ( pos
-> qtype
. getCode (), 1 , pos
-> content
));
312 if ( pw
. size () + 20U > ( d_tcp
? 65535 : getMaxReplyLen ())) { // 20 = room for EDNS0
314 if ( pos
-> d_place
== DNSResourceRecord :: ANSWER
|| pos
-> d_place
== DNSResourceRecord :: AUTHORITY
) {
315 pw
. getHeader ()-> tc
= 1 ;
321 // if(!pw.getHeader()->tc) // protect against double commit from addSignature
323 if (! d_rrs
. empty ()) pw
. commit ();
327 if ( d_haveednssubnet
) {
328 string
makeEDNSSubnetOptsString ( const EDNSSubnetOpts
& eso
);
329 EDNSSubnetOpts eso
= d_eso
;
330 eso
. scope
= Netmask ( eso
. source
. getNetwork (), maxScopeMask
);
332 string opt
= makeEDNSSubnetOptsString ( eso
);
333 opts
. push_back ( make_pair ( d_ednssubnetcode
, opt
)); // 'EDNS SUBNET'
336 if (! opts
. empty () || d_haveednssection
|| d_dnssecOk
)
338 pw
. addOpt ( s_udpTruncationThreshold
, 0 , d_dnssecOk
? EDNSOpts :: DNSSECOK
: 0 , opts
);
342 catch ( std :: exception
& e
) {
343 L
<< Logger :: Warning
<< "Exception: " << e
. what ()<< endl
;
348 if (! d_trc
. d_algoName
. empty ())
349 addTSIG ( pw
, & d_trc
, d_tsigkeyname
, d_tsigsecret
, d_tsigprevious
, d_tsigtimersonly
);
351 d_rawpacket
. assign (( char *)& packet
[ 0 ], packet
. size ());
354 void DNSPacket :: setQuestion ( int op
, const string
& qd
, int newqtype
)
356 memset (& d
, 0 , sizeof ( d
));
357 d
. id
= Utility :: random ();
358 d
. rd
= d
. tc
= d
. aa
= false ;
360 d
. qdcount
= 1 ; // is htons'ed later on
361 d
. ancount
= d
. arcount
= d
. nscount
= 0 ;
367 /** convenience function for creating a reply packet from a question packet. Do not forget to delete it after use! */
368 DNSPacket
* DNSPacket :: replyPacket () const
370 DNSPacket
* r
= new DNSPacket
;
371 r
-> setSocket ( d_socket
);
372 r
-> d_anyLocal
= d_anyLocal
;
373 r
-> setRemote (& d_remote
);
374 r
-> setAnswer ( true ); // this implies the allocation of the header
375 r
-> setA ( true ); // and we are authoritative
376 r
-> setRA ( 0 ); // no recursion available
377 r
-> setRD ( d
. rd
); // if you wanted to recurse, answer will say you wanted it
379 r
-> setOpcode ( d
. opcode
);
384 r
-> qdomain
= qdomain
;
387 r
-> d_maxreplylen
= d_maxreplylen
;
388 r
-> d_ednsping
= d_ednsping
;
389 r
-> d_wantsnsid
= d_wantsnsid
;
390 r
-> d_dnssecOk
= d_dnssecOk
;
392 r
-> d_haveednssubnet
= d_haveednssubnet
;
393 r
-> d_haveednssection
= d_haveednssection
;
394 r
-> d_ednssubnetcode
= d_ednssubnetcode
;
396 if (! d_tsigkeyname
. empty ()) {
397 r
-> d_tsigkeyname
= d_tsigkeyname
;
398 r
-> d_tsigprevious
= d_tsigprevious
;
400 r
-> d_tsigsecret
= d_tsigsecret
;
401 r
-> d_tsigtimersonly
= d_tsigtimersonly
;
403 r
-> d_havetsig
= d_havetsig
;
407 void DNSPacket :: spoofQuestion ( const DNSPacket
* qd
)
409 d_wrapped
= true ; // if we do this, don't later on wrapup
412 string :: size_type i
= sizeof ( d
);
415 labellen
= qd
-> d_rawpacket
[ i
];
418 d_rawpacket
. replace ( i
, labellen
, qd
-> d_rawpacket
, i
, labellen
);
423 int DNSPacket :: noparse ( const char * mesg
, int length
)
425 d_rawpacket
. assign ( mesg
, length
);
427 L
<< Logger :: Warning
<< "Ignoring packet: too short from "
428 << getRemote () << endl
;
434 memcpy (( void *)& d
,( const void *) d_rawpacket
. c_str (), 12 );
438 void DNSPacket :: setTSIGDetails ( const TSIGRecordContent
& tr
, const string
& keyname
, const string
& secret
, const string
& previous
, bool timersonly
)
441 d_tsigkeyname
= keyname
;
442 d_tsigsecret
= secret
;
443 d_tsigprevious
= previous
;
444 d_tsigtimersonly
= timersonly
;
447 bool DNSPacket :: getTSIGDetails ( TSIGRecordContent
* trc
, string
* keyname
, string
* message
) const
449 MOADNSParser
mdp ( d_rawpacket
);
451 if (! mdp
. getTSIGPos ())
455 for ( MOADNSParser :: answers_t :: const_iterator i
= mdp
. d_answers
. begin (); i
!= mdp
. d_answers
. end (); ++ i
) {
456 if ( i
-> first
. d_type
== QType :: TSIG
) {
457 * trc
= * boost :: dynamic_pointer_cast
< TSIGRecordContent
>( i
-> first
. d_content
);
460 * keyname
= i
-> first
. d_label
;
461 if (! keyname
-> empty ())
462 keyname
-> resize ( keyname
-> size ()- 1 ); // drop the trailing dot
468 * message
= makeTSIGMessageFromTSIGPacket ( d_rawpacket
, mdp
. getTSIGPos (), * keyname
, * trc
, d_tsigprevious
, false ); // if you change rawpacket to getString it breaks!
473 /** This function takes data from the network, possibly received with recvfrom, and parses
474 it into our class. Results of calling this function multiple times on one packet are
475 unknown. Returns -1 if the packet cannot be parsed.
477 int DNSPacket :: parse ( const char * mesg
, int length
)
480 d_rawpacket
. assign ( mesg
, length
);
483 L
<< Logger :: Warning
<< "Ignoring packet: too short from "
484 << getRemote () << endl
;
488 MOADNSParser
mdp ( d_rawpacket
);
491 // ANY OPTION WHICH *MIGHT* BE SET DOWN BELOW SHOULD BE CLEARED FIRST!
496 d_havetsig
= mdp
. getTSIGPos ();
497 d_haveednssubnet
= false ;
498 d_haveednssection
= false ;
501 if ( getEDNSOpts ( mdp
, & edo
)) {
502 d_haveednssection
= true ;
503 d_maxreplylen
= std :: min ( edo
. d_packetsize
, s_udpTruncationThreshold
);
504 // cerr<<edo.d_Z<<endl;
505 if ( edo
. d_Z
& EDNSOpts :: DNSSECOK
)
508 for ( vector
< pair
< uint16_t , string
> >:: const_iterator iter
= edo
. d_options
. begin ();
509 iter
!= edo
. d_options
. end ();
511 if ( iter
-> first
== 3 ) { // 'EDNS NSID'
514 else if ( iter
-> first
== 5 ) { // 'EDNS PING'
515 d_ednsping
= iter
-> second
;
517 else if ( s_doEDNSSubnetProcessing
&& ( iter
-> first
== 8 || std :: find ( s_ednssubnetcodes
. begin (), s_ednssubnetcodes
. end (), iter
-> first
) != s_ednssubnetcodes
. end ())) { // 'EDNS SUBNET'
518 if ( getEDNSSubnetOptsFromString ( iter
-> second
, & d_eso
)) {
519 //cerr<<"Parsed, source: "<<d_eso.source.toString()<<", scope: "<<d_eso.scope.toString()<<", family = "<<d_eso.scope.getNetwork().sin4.sin_family<<endl;
520 d_haveednssubnet
= true ;
521 d_ednssubnetcode
= iter
-> first
;
525 // cerr<<"Have an option #"<<iter->first<<": "<<makeHexDump(iter->second)<<endl;
533 memcpy (( void *)& d
,( const void *) d_rawpacket
. c_str (), 12 );
535 if (! qdomain
. empty ()) // strip dot
536 boost :: erase_tail ( qdomain
, 1 );
538 if (! ntohs ( d
. qdcount
)) {
540 L
<< Logger :: Warning
<< "No question section in packet from " << getRemote () << ", rcode=" <<( int ) d
. rcode
<< endl
;
549 catch ( std :: exception
& e
) {
553 unsigned int DNSPacket :: getMaxReplyLen ()
555 return d_maxreplylen
;
558 void DNSPacket :: setMaxReplyLen ( int bytes
)
563 //! Use this to set where this packet was received from or should be sent to
564 void DNSPacket :: setRemote ( const ComboAddress
* s
)
569 bool DNSPacket :: hasEDNSSubnet ()
571 return d_haveednssubnet
;
574 bool DNSPacket :: hasEDNS ()
576 return d_haveednssection
;
579 Netmask
DNSPacket :: getRealRemote () const
583 return Netmask ( d_remote
);
586 void DNSPacket :: setSocket ( Utility :: sock_t sock
)
591 void DNSPacket :: commitD ()
593 d_rawpacket
. replace ( 0 , 12 ,( char *)& d
, 12 ); // copy in d
596 bool checkForCorrectTSIG ( const DNSPacket
* q
, DNSBackend
* B
, string
* keyname
, string
* secret
, TSIGRecordContent
* trc
)
600 q
-> getTSIGDetails ( trc
, keyname
, & message
);
601 uint64_t now
= time ( 0 );
602 if ( abs ( trc
-> d_time
- now
) > trc
-> d_fudge
) {
603 L
<< Logger :: Error
<< "Packet for '" << q
-> qdomain
<< "' denied: TSIG (key '" <<* keyname
<< "') time delta " << abs ( trc
-> d_time
- now
)<< " > 'fudge' " << trc
-> d_fudge
<< endl
;
609 if (! B
-> getTSIGKey (* keyname
, & trc
-> d_algoName
, & secret64
)) {
610 L
<< Logger :: Error
<< "Packet for domain '" << q
-> qdomain
<< "' denied: can't find TSIG key with name '" <<* keyname
<< "' and algorithm '" << trc
-> d_algoName
<< "'" << endl
;
614 if ( trc
-> d_algoName
== "hmac-md5" )
615 trc
-> d_algoName
+= ".sig-alg.reg.int." ;
617 if ( trc
-> d_algoName
!= "hmac-md5.sig-alg.reg.int." ) {
618 L
<< Logger :: Error
<< "Unsupported TSIG HMAC algorithm " << trc
-> d_algoName
<< endl
;
622 B64Decode ( secret64
, * secret
);
623 bool result
= calculateMD5HMAC (* secret
, message
) == trc
-> d_mac
;
625 L
<< Logger :: Error
<< "Packet for domain '" << q
-> qdomain
<< "' denied: TSIG signature mismatch using '" <<* keyname
<< "' and algorithm '" << trc
-> d_algoName
<< "'" << endl
;