]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnspacket.cc
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2001 - 2015 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 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.
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.
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 St, Fifth Floor, Boston, MA 02110-1301 USA
29 #include <sys/types.h>
33 #include <boost/tokenizer.hpp>
34 #include <boost/algorithm/string.hpp>
36 #include <boost/foreach.hpp>
37 #include "dnsseckeeper.hh"
39 #include "dnsbackend.hh"
40 #include "pdnsexception.hh"
41 #include "dnspacket.hh"
43 #include "arguments.hh"
44 #include "dnswriter.hh"
45 #include "dnsparser.hh"
46 #include "dnsrecords.hh"
47 #include "dnssecinfra.hh"
49 #include "ednssubnet.hh"
50 #include "gss_context.hh"
52 bool DNSPacket :: s_doEDNSSubnetProcessing
;
53 uint16_t DNSPacket :: s_udpTruncationThreshold
;
55 DNSPacket :: DNSPacket ()
61 d_haveednssubnet
= false ;
65 const string
& DNSPacket :: getString ()
73 string
DNSPacket :: getRemote () const
75 return d_remote
. toString ();
78 uint16_t DNSPacket :: getRemotePort () const
80 return d_remote
. sin4
. sin_port
;
83 DNSPacket :: DNSPacket ( const DNSPacket
& orig
)
85 DLOG ( L
<< "DNSPacket copy constructor called!" << endl
);
86 d_socket
= orig
. d_socket
;
87 d_remote
= orig
. d_remote
;
90 d_compress
= orig
. d_compress
;
95 qdomainwild
= orig
. qdomainwild
;
96 qdomainzone
= orig
. qdomainzone
;
97 d_maxreplylen
= orig
. d_maxreplylen
;
98 d_ednsping
= orig
. d_ednsping
;
99 d_wantsnsid
= orig
. d_wantsnsid
;
100 d_anyLocal
= orig
. d_anyLocal
;
102 d_haveednssubnet
= orig
. d_haveednssubnet
;
103 d_haveednssection
= orig
. d_haveednssection
;
104 d_dnssecOk
= orig
. d_dnssecOk
;
107 d_tsigkeyname
= orig
. d_tsigkeyname
;
108 d_tsigprevious
= orig
. d_tsigprevious
;
109 d_tsigtimersonly
= orig
. d_tsigtimersonly
;
111 d_tsigsecret
= orig
. d_tsigsecret
;
113 d_havetsig
= orig
. d_havetsig
;
114 d_wrapped
= orig
. d_wrapped
;
116 d_rawpacket
= orig
. d_rawpacket
;
120 void DNSPacket :: setRcode ( int v
)
125 void DNSPacket :: setAnswer ( bool b
)
128 d_rawpacket
. assign ( 12 ,( char ) 0 );
129 memset (( void *)& d
, 0 , sizeof ( d
));
135 void DNSPacket :: setA ( bool b
)
140 void DNSPacket :: setID ( uint16_t id
)
145 void DNSPacket :: setRA ( bool b
)
150 void DNSPacket :: setRD ( bool b
)
155 void DNSPacket :: setOpcode ( uint16_t opcode
)
161 void DNSPacket :: clearRecords ()
166 void DNSPacket :: addRecord ( const DNSResourceRecord
& rr
)
168 // this removes duplicates from the packet in case we are not compressing
169 // for AXFR, no such checking is performed!
171 for ( vector
< DNSResourceRecord
>:: const_iterator i
= d_rrs
. begin (); i
!= d_rrs
. end ();++ i
)
172 if ( rr
. qname
== i
-> qname
&& rr
. qtype
== i
-> qtype
&& rr
. content
== i
-> content
) {
181 static int rrcomp ( const DNSResourceRecord
& A
, const DNSResourceRecord
& B
)
183 if ( A
. d_place
< B
. d_place
)
189 vector
< DNSResourceRecord
*> DNSPacket :: getAPRecords ()
191 vector
< DNSResourceRecord
*> arrs
;
193 for ( vector
< DNSResourceRecord
>:: iterator i
= d_rrs
. begin ();
197 if ( i
-> d_place
!= DNSResourceRecord :: ADDITIONAL
&&
198 ( i
-> qtype
. getCode ()== QType :: MX
||
199 i
-> qtype
. getCode ()== QType :: NS
||
200 i
-> qtype
. getCode ()== QType :: SRV
))
210 vector
< DNSResourceRecord
*> DNSPacket :: getAnswerRecords ()
212 vector
< DNSResourceRecord
*> arrs
;
214 for ( vector
< DNSResourceRecord
>:: iterator i
= d_rrs
. begin ();
218 if ( i
-> d_place
!= DNSResourceRecord :: ADDITIONAL
)
225 void DNSPacket :: setCompress ( bool compress
)
228 d_rawpacket
. reserve ( 65000 );
232 bool DNSPacket :: couldBeCached ()
234 return d_ednsping
. empty () && ! d_wantsnsid
&& qclass
== QClass :: IN
;
237 unsigned int DNSPacket :: getMinTTL ()
239 unsigned int minttl
= UINT_MAX
;
240 BOOST_FOREACH ( DNSResourceRecord rr
, d_rrs
) {
248 bool DNSPacket :: isEmpty ()
250 return ( d_rrs
. empty ());
253 /** Must be called before attempting to access getData(). This function stuffs all resource
254 * records found in rrs into the data buffer. It also frees resource records queued for us.
256 void DNSPacket :: wrapup ()
262 DNSResourceRecord rr
;
263 vector
< DNSResourceRecord
>:: iterator pos
;
265 // we now need to order rrs so that the different sections come at the right place
266 // we want a stable sort, based on the d_place field
268 stable_sort ( d_rrs
. begin (), d_rrs
. end (), rrcomp
);
269 static bool mustNotShuffle
= :: arg (). mustDo ( "no-shuffle" );
271 if (! d_tcp
&& ! mustNotShuffle
) {
276 vector
< uint8_t > packet
;
277 DNSPacketWriter
pw ( packet
, qdomain
, qtype
. getCode (), qclass
);
279 pw
. getHeader ()-> rcode
= d
. rcode
;
280 pw
. getHeader ()-> opcode
= d
. opcode
;
281 pw
. getHeader ()-> aa
= d
. aa
;
282 pw
. getHeader ()-> ra
= d
. ra
;
283 pw
. getHeader ()-> qr
= d
. qr
;
284 pw
. getHeader ()-> id
= d
. id
;
285 pw
. getHeader ()-> rd
= d
. rd
;
286 pw
. getHeader ()-> tc
= d
. tc
;
288 DNSPacketWriter :: optvect_t opts
;
290 const static string mode_server_id
=:: arg ()[ "server-id" ];
291 if ( mode_server_id
!= "disabled" ) {
292 opts
. push_back ( make_pair ( 3 , mode_server_id
));
296 if (! d_ednsping
. empty ()) {
297 opts
. push_back ( make_pair ( 4 , d_ednsping
));
301 if (! d_rrs
. empty () || ! opts
. empty () || d_haveednssubnet
|| d_haveednssection
) {
303 uint8_t maxScopeMask
= 0 ;
304 for ( pos
= d_rrs
. begin (); pos
< d_rrs
. end (); ++ pos
) {
305 maxScopeMask
= max ( maxScopeMask
, pos
-> scopeMask
);
307 if (! pos
-> content
. empty () && pos
-> qtype
. getCode ()== QType :: TXT
&& pos
-> content
[ 0 ]!= '"' ) {
308 pos
-> content
= " \" " + pos
-> content
+ " \" " ;
310 if ( pos
-> content
. empty ()) // empty contents confuse the MOADNS setup
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 (), pos
-> qclass
, pos
-> content
));
316 if ( pw
. size () + 20U > ( d_tcp
? 65535 : getMaxReplyLen ())) { // 20 = room for EDNS0
318 if ( pos
-> d_place
== DNSResourceRecord :: ANSWER
|| pos
-> d_place
== DNSResourceRecord :: AUTHORITY
) {
319 pw
. getHeader ()-> tc
= 1 ;
325 // if(!pw.getHeader()->tc) // protect against double commit from addSignature
327 if (! d_rrs
. empty ()) pw
. commit ();
331 if ( d_haveednssubnet
) {
332 string
makeEDNSSubnetOptsString ( const EDNSSubnetOpts
& eso
);
333 EDNSSubnetOpts eso
= d_eso
;
334 eso
. scope
= Netmask ( eso
. source
. getNetwork (), maxScopeMask
);
336 string opt
= makeEDNSSubnetOptsString ( eso
);
337 opts
. push_back ( make_pair ( 8 , opt
)); // 'EDNS SUBNET'
340 if (! opts
. empty () || d_haveednssection
|| d_dnssecOk
)
342 pw
. addOpt ( s_udpTruncationThreshold
, 0 , d_dnssecOk
? EDNSOpts :: DNSSECOK
: 0 , opts
);
346 catch ( std :: exception
& e
) {
347 L
<< Logger :: Warning
<< "Exception: " << e
. what ()<< endl
;
352 if ( d_trc
. d_algoName
. countLabels ())
353 addTSIG ( pw
, & d_trc
, d_tsigkeyname
, d_tsigsecret
, d_tsigprevious
, d_tsigtimersonly
);
355 d_rawpacket
. assign (( char *)& packet
[ 0 ], packet
. size ());
357 // copy RR counts so LPE can read them
358 d
. qdcount
= pw
. getHeader ()-> qdcount
;
359 d
. ancount
= pw
. getHeader ()-> ancount
;
360 d
. nscount
= pw
. getHeader ()-> nscount
;
361 d
. arcount
= pw
. getHeader ()-> arcount
;
364 void DNSPacket :: setQuestion ( int op
, const DNSName
& qd
, int newqtype
)
366 memset (& d
, 0 , sizeof ( d
));
367 d
. id
= Utility :: random ();
368 d
. rd
= d
. tc
= d
. aa
= false ;
370 d
. qdcount
= 1 ; // is htons'ed later on
371 d
. ancount
= d
. arcount
= d
. nscount
= 0 ;
377 /** convenience function for creating a reply packet from a question packet. Do not forget to delete it after use! */
378 DNSPacket
* DNSPacket :: replyPacket () const
380 DNSPacket
* r
= new DNSPacket
;
381 r
-> setSocket ( d_socket
);
382 r
-> d_anyLocal
= d_anyLocal
;
383 r
-> setRemote (& d_remote
);
384 r
-> setAnswer ( true ); // this implies the allocation of the header
385 r
-> setA ( true ); // and we are authoritative
386 r
-> setRA ( 0 ); // no recursion available
387 r
-> setRD ( d
. rd
); // if you wanted to recurse, answer will say you wanted it
389 r
-> setOpcode ( d
. opcode
);
394 r
-> qdomain
= qdomain
;
397 r
-> d_maxreplylen
= d_maxreplylen
;
398 r
-> d_ednsping
= d_ednsping
;
399 r
-> d_wantsnsid
= d_wantsnsid
;
400 r
-> d_dnssecOk
= d_dnssecOk
;
402 r
-> d_haveednssubnet
= d_haveednssubnet
;
403 r
-> d_haveednssection
= d_haveednssection
;
405 if ( d_tsigkeyname
. countLabels ()) {
406 r
-> d_tsigkeyname
= d_tsigkeyname
;
407 r
-> d_tsigprevious
= d_tsigprevious
;
409 r
-> d_tsigsecret
= d_tsigsecret
;
410 r
-> d_tsigtimersonly
= d_tsigtimersonly
;
412 r
-> d_havetsig
= d_havetsig
;
416 void DNSPacket :: spoofQuestion ( const DNSPacket
* qd
)
418 d_wrapped
= true ; // if we do this, don't later on wrapup
421 string :: size_type i
= sizeof ( d
);
424 labellen
= qd
-> d_rawpacket
[ i
];
427 d_rawpacket
. replace ( i
, labellen
, qd
-> d_rawpacket
, i
, labellen
);
432 int DNSPacket :: noparse ( const char * mesg
, int length
)
434 d_rawpacket
. assign ( mesg
, length
);
436 L
<< Logger :: Warning
<< "Ignoring packet: too short (" << length
<< " < 12) from "
437 << d_remote
. toStringWithPort ()<< endl
;
443 memcpy (( void *)& d
,( const void *) d_rawpacket
. c_str (), 12 );
447 void DNSPacket :: setTSIGDetails ( const TSIGRecordContent
& tr
, const DNSName
& keyname
, const string
& secret
, const string
& previous
, bool timersonly
)
450 d_tsigkeyname
= keyname
;
451 d_tsigsecret
= secret
;
452 d_tsigprevious
= previous
;
453 d_tsigtimersonly
= timersonly
;
456 bool DNSPacket :: getTSIGDetails ( TSIGRecordContent
* trc
, DNSName
* keyname
, string
* message
) const
458 MOADNSParser
mdp ( d_rawpacket
);
460 if (! mdp
. getTSIGPos ())
464 for ( MOADNSParser :: answers_t :: const_iterator i
= mdp
. d_answers
. begin (); i
!= mdp
. d_answers
. end (); ++ i
) {
465 if ( i
-> first
. d_type
== QType :: TSIG
) {
466 * trc
= * std :: dynamic_pointer_cast
< TSIGRecordContent
>( i
-> first
. d_content
);
469 * keyname
= i
-> first
. d_label
;
475 * message
= makeTSIGMessageFromTSIGPacket ( d_rawpacket
, mdp
. getTSIGPos (), * keyname
, * trc
, d_tsigprevious
, false ); // if you change rawpacket to getString it breaks!
480 bool DNSPacket :: getTKEYRecord ( TKEYRecordContent
* tr
, DNSName
* keyname
) const
482 MOADNSParser
mdp ( d_rawpacket
);
485 for ( MOADNSParser :: answers_t :: const_iterator i
= mdp
. d_answers
. begin (); i
!= mdp
. d_answers
. end (); ++ i
) {
487 L
<< Logger :: Error
<< "More than one TKEY record found in query" << endl
;
491 if ( i
-> first
. d_type
== QType :: TKEY
) {
492 * tr
= * std :: dynamic_pointer_cast
< TKEYRecordContent
>( i
-> first
. d_content
);
493 * keyname
= i
-> first
. d_label
;
501 /** This function takes data from the network, possibly received with recvfrom, and parses
502 it into our class. Results of calling this function multiple times on one packet are
503 unknown. Returns -1 if the packet cannot be parsed.
505 int DNSPacket :: parse ( const char * mesg
, int length
)
508 d_rawpacket
. assign ( mesg
, length
);
511 L
<< Logger :: Warning
<< "Ignoring packet: too short from "
512 << getRemote () << endl
;
516 MOADNSParser
mdp ( d_rawpacket
);
519 // ANY OPTION WHICH *MIGHT* BE SET DOWN BELOW SHOULD BE CLEARED FIRST!
524 d_havetsig
= mdp
. getTSIGPos ();
525 d_haveednssubnet
= false ;
526 d_haveednssection
= false ;
529 if ( getEDNSOpts ( mdp
, & edo
)) {
530 d_haveednssection
= true ;
531 d_maxreplylen
= std :: min ( edo
. d_packetsize
, s_udpTruncationThreshold
);
532 // cerr<<edo.d_Z<<endl;
533 if ( edo
. d_Z
& EDNSOpts :: DNSSECOK
)
536 for ( vector
< pair
< uint16_t , string
> >:: const_iterator iter
= edo
. d_options
. begin ();
537 iter
!= edo
. d_options
. end ();
539 if ( iter
-> first
== 3 ) { // 'EDNS NSID'
542 else if ( iter
-> first
== 5 ) { // 'EDNS PING'
543 d_ednsping
= iter
-> second
;
545 else if ( s_doEDNSSubnetProcessing
&& ( iter
-> first
== 8 )) { // 'EDNS SUBNET'
546 if ( getEDNSSubnetOptsFromString ( iter
-> second
, & d_eso
)) {
547 //cerr<<"Parsed, source: "<<d_eso.source.toString()<<", scope: "<<d_eso.scope.toString()<<", family = "<<d_eso.scope.getNetwork().sin4.sin_family<<endl;
548 d_haveednssubnet
= true ;
552 // cerr<<"Have an option #"<<iter->first<<": "<<makeHexDump(iter->second)<<endl;
560 memcpy (( void *)& d
,( const void *) d_rawpacket
. c_str (), 12 );
562 // if(!qdomain.empty()) // strip dot
563 // boost::erase_tail(qdomain, 1);
565 if (! ntohs ( d
. qdcount
)) {
567 L
<< Logger :: Warning
<< "No question section in packet from " << getRemote () << ", error=" << RCode :: to_s ( d
. rcode
)<< endl
;
576 catch ( std :: exception
& e
) {
580 unsigned int DNSPacket :: getMaxReplyLen ()
582 return d_maxreplylen
;
585 void DNSPacket :: setMaxReplyLen ( int bytes
)
590 //! Use this to set where this packet was received from or should be sent to
591 void DNSPacket :: setRemote ( const ComboAddress
* s
)
596 bool DNSPacket :: hasEDNSSubnet ()
598 return d_haveednssubnet
;
601 bool DNSPacket :: hasEDNS ()
603 return d_haveednssection
;
606 Netmask
DNSPacket :: getRealRemote () const
610 return Netmask ( d_remote
);
613 void DNSPacket :: setSocket ( Utility :: sock_t sock
)
618 void DNSPacket :: commitD ()
620 d_rawpacket
. replace ( 0 , 12 ,( char *)& d
, 12 ); // copy in d
623 bool checkForCorrectTSIG ( const DNSPacket
* q
, UeberBackend
* B
, DNSName
* keyname
, string
* secret
, TSIGRecordContent
* trc
)
627 q
-> getTSIGDetails ( trc
, keyname
, & message
);
628 int64_t now
= time ( 0 );
629 if ( abs (( int64_t ) trc
-> d_time
- now
) > trc
-> d_fudge
) {
630 L
<< Logger :: Error
<< "Packet for '" << q
-> qdomain
. toString ()<< "' denied: TSIG (key '" << keyname
-> toString ()<< "') time delta " << abs ( trc
-> d_time
- now
)<< " > 'fudge' " << trc
-> d_fudge
<< endl
;
634 DNSName algoName
= trc
-> d_algoName
; // FIXME
635 if ( algoName
== DNSName ( "hmac-md5.sig-alg.reg.int" ))
636 algoName
= DNSName ( "hmac-md5" );
638 if ( algoName
== "gss-tsig" ) {
639 if (! gss_verify_signature (* keyname
, message
, trc
-> d_mac
)) {
640 L
<< Logger :: Error
<< "Packet for domain '" << q
-> qdomain
<< "' denied: TSIG signature mismatch using '" <<* keyname
<< "' and algorithm '" << trc
-> d_algoName
<< "'" << endl
;
647 if (! B
-> getTSIGKey (* keyname
, & algoName
, & secret64
)) {
648 L
<< Logger :: Error
<< "Packet for domain '" << q
-> qdomain
. toString ()<< "' denied: can't find TSIG key with name '" << keyname
-> toString ()<< "' and algorithm '" << algoName
. toString ()<< "'" << endl
;
651 if ( trc
-> d_algoName
== DNSName ( "hmac-md5" ))
652 trc
-> d_algoName
+= DNSName ( "sig-alg.reg.int." );
655 if (! getTSIGHashEnum ( trc
-> d_algoName
, algo
)) {
656 L
<< Logger :: Error
<< "Unsupported TSIG HMAC algorithm " << trc
-> d_algoName
. toString () << endl
;
660 B64Decode ( secret64
, * secret
);
661 bool result
= calculateHMAC (* secret
, message
, algo
) == trc
-> d_mac
;
663 L
<< Logger :: Error
<< "Packet for domain '" << q
-> qdomain
. toString ()<< "' denied: TSIG signature mismatch using '" << keyname
-> toString ()<< "' and algorithm '" << trc
-> d_algoName
. toString ()<< "'" << endl
;