]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnspacket.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include <sys/types.h>
32 #include <boost/tokenizer.hpp>
33 #include <boost/functional/hash.hpp>
34 #include <boost/algorithm/string.hpp>
35 #include <openssl/hmac.h>
38 #include "dnsseckeeper.hh"
40 #include "dnsbackend.hh"
41 #include "ednsoptions.hh"
42 #include "pdnsexception.hh"
43 #include "dnspacket.hh"
45 #include "arguments.hh"
46 #include "dnswriter.hh"
47 #include "dnsparser.hh"
48 #include "dnsrecords.hh"
49 #include "dnssecinfra.hh"
51 #include "ednssubnet.hh"
52 #include "gss_context.hh"
53 #include "dns_random.hh"
55 bool DNSPacket :: s_doEDNSSubnetProcessing
;
56 uint16_t DNSPacket :: s_udpTruncationThreshold
;
58 DNSPacket :: DNSPacket ( bool isQuery
)
64 d_haveednssubnet
= false ;
68 memset (& d
, 0 , sizeof ( d
));
70 d_tsig_algo
= TSIG_MD5
;
74 d_tsigtimersonly
= false ;
75 d_haveednssection
= false ;
79 const string
& DNSPacket :: getString ()
87 ComboAddress
DNSPacket :: getRemote () const
92 uint16_t DNSPacket :: getRemotePort () const
94 return d_remote
. sin4
. sin_port
;
97 DNSPacket :: DNSPacket ( const DNSPacket
& orig
) :
98 d_socket ( orig
. d_socket
),
99 d_remote ( orig
. d_remote
),
101 d_compress ( orig
. d_compress
),
105 qdomain ( orig
. qdomain
),
106 qdomainwild ( orig
. qdomainwild
),
107 qdomainzone ( orig
. qdomainzone
),
108 d_maxreplylen ( orig
. d_maxreplylen
),
109 d_wantsnsid ( orig
. d_wantsnsid
),
110 d_anyLocal ( orig
. d_anyLocal
),
112 d_haveednssubnet ( orig
. d_haveednssubnet
),
113 d_haveednssection ( orig
. d_haveednssection
),
114 d_ednsversion ( orig
. d_ednsversion
),
115 d_ednsrcode ( orig
. d_ednsrcode
),
116 d_dnssecOk ( orig
. d_dnssecOk
),
119 d_tsigkeyname ( orig
. d_tsigkeyname
),
120 d_tsigprevious ( orig
. d_tsigprevious
),
121 d_tsigtimersonly ( orig
. d_tsigtimersonly
),
123 d_tsigsecret ( orig
. d_tsigsecret
),
124 d_ednsRawPacketSizeLimit ( orig
. d_ednsRawPacketSizeLimit
),
125 d_havetsig ( orig
. d_havetsig
),
126 d_wrapped ( orig
. d_wrapped
),
128 d_rawpacket ( orig
. d_rawpacket
),
129 d_tsig_algo ( orig
. d_tsig_algo
),
132 d_isQuery ( orig
. d_isQuery
),
135 DLOG ( g_log
<< "DNSPacket copy constructor called!" << endl
);
138 void DNSPacket :: setRcode ( int v
)
143 void DNSPacket :: setAnswer ( bool b
)
146 d_rawpacket
. assign ( 12 ,( char ) 0 );
147 memset (( void *)& d
, 0 , sizeof ( d
));
153 void DNSPacket :: setA ( bool b
)
158 void DNSPacket :: setID ( uint16_t id
)
163 void DNSPacket :: setRA ( bool b
)
168 void DNSPacket :: setRD ( bool b
)
173 void DNSPacket :: setOpcode ( uint16_t opcode
)
178 void DNSPacket :: clearRecords ()
184 void DNSPacket :: addRecord ( const DNSZoneRecord
& rr
)
186 // this removes duplicates from the packet.
187 // in case we are not compressing for AXFR, no such checking is performed!
190 std :: string ser
= const_cast < DNSZoneRecord
&>( rr
). dr
. d_content
-> serialize ( rr
. dr
. d_name
);
191 auto hash
= boost :: hash
< std :: pair
< DNSName
, std :: string
> >()({ rr
. dr
. d_name
, ser
});
192 if ( d_dedup
. count ( hash
)) { // might be a dup
193 for ( auto i
= d_rrs
. begin (); i
!= d_rrs
. end ();++ i
) {
194 if ( rr
. dr
== i
-> dr
) // XXX SUPER SLOW
198 d_dedup
. insert ( hash
);
204 vector
< DNSZoneRecord
*> DNSPacket :: getAPRecords ()
206 vector
< DNSZoneRecord
*> arrs
;
208 for ( vector
< DNSZoneRecord
>:: iterator i
= d_rrs
. begin ();
212 if ( i
-> dr
. d_place
!= DNSResourceRecord :: ADDITIONAL
&&
213 ( i
-> dr
. d_type
== QType :: MX
||
214 i
-> dr
. d_type
== QType :: NS
||
215 i
-> dr
. d_type
== QType :: SRV
))
223 vector
< DNSZoneRecord
*> DNSPacket :: getAnswerRecords ()
225 vector
< DNSZoneRecord
*> arrs
;
227 for ( vector
< DNSZoneRecord
>:: iterator i
= d_rrs
. begin ();
231 if ( i
-> dr
. d_place
!= DNSResourceRecord :: ADDITIONAL
)
238 void DNSPacket :: setCompress ( bool compress
)
241 d_rawpacket
. reserve ( 65000 );
245 bool DNSPacket :: couldBeCached ()
247 return ! d_wantsnsid
&& qclass
== QClass :: IN
&& ! d_havetsig
;
250 unsigned int DNSPacket :: getMinTTL ()
252 unsigned int minttl
= UINT_MAX
;
253 for ( const DNSZoneRecord
& rr
: d_rrs
) {
254 if ( rr
. dr
. d_ttl
< minttl
)
255 minttl
= rr
. dr
. d_ttl
;
261 bool DNSPacket :: isEmpty ()
263 return ( d_rrs
. empty ());
266 /** Must be called before attempting to access getData(). This function stuffs all resource
267 * records found in rrs into the data buffer. It also frees resource records queued for us.
269 void DNSPacket :: wrapup ()
276 vector
< DNSZoneRecord
>:: iterator pos
;
278 // we now need to order rrs so that the different sections come at the right place
279 // we want a stable sort, based on the d_place field
281 stable_sort ( d_rrs
. begin (), d_rrs
. end (), []( const DNSZoneRecord
& a
, const DNSZoneRecord
& b
) {
282 return a
. dr
. d_place
< b
. dr
. d_place
;
284 static bool mustNotShuffle
= :: arg (). mustDo ( "no-shuffle" );
286 if (! d_tcp
&& ! mustNotShuffle
) {
291 vector
< uint8_t > packet
;
292 DNSPacketWriter
pw ( packet
, qdomain
, qtype
. getCode (), qclass
);
294 pw
. getHeader ()-> rcode
= d
. rcode
;
295 pw
. getHeader ()-> opcode
= d
. opcode
;
296 pw
. getHeader ()-> aa
= d
. aa
;
297 pw
. getHeader ()-> ra
= d
. ra
;
298 pw
. getHeader ()-> qr
= d
. qr
;
299 pw
. getHeader ()-> id
= d
. id
;
300 pw
. getHeader ()-> rd
= d
. rd
;
301 pw
. getHeader ()-> tc
= d
. tc
;
303 DNSPacketWriter :: optvect_t opts
;
305 /* optsize is expected to hold an upper bound of data that will be
306 added after actual record data - i.e. OPT, TSIG, perhaps one day
307 XPF. Because of the way `pw` incrementally writes the packet, we
308 cannot easily 'go back' and remove a few records. So, to prevent
309 going over our maximum size, we keep our (potential) extra data
312 This means that sometimes we'll send TC even if we'd end up with
313 a few bytes to spare, but so be it.
317 if ( d_haveednssection
|| d_dnssecOk
) {
318 /* root label (1), type (2), class (2), ttl (4) + rdlen (2) */
323 const static string mode_server_id
=:: arg ()[ "server-id" ];
324 if ( mode_server_id
!= "disabled" ) {
325 opts
. push_back ( make_pair ( EDNSOptionCode :: NSID
, mode_server_id
));
326 optsize
+= EDNS_OPTION_CODE_SIZE
+ EDNS_OPTION_LENGTH_SIZE
+ mode_server_id
. size ();
330 if ( d_haveednssubnet
)
332 // this is an upper bound
333 optsize
+= EDNS_OPTION_CODE_SIZE
+ EDNS_OPTION_LENGTH_SIZE
+ 2 + 1 + 1 ; // code+len+family+src len+scope len
334 optsize
+= d_eso
. source
. isIpv4 () ? 4 : 16 ;
337 if ( d_trc
. d_algoName
. countLabels ())
339 // TSIG is not OPT, but we count it in optsize anyway
340 optsize
+= d_trc
. d_algoName
. wirelength () + 3 + 1 + 2 ; // algo + time + fudge + maclen
341 optsize
+= EVP_MAX_MD_SIZE
+ 2 + 2 + 2 + 0 ; // mac + origid + ercode + otherdatalen + no other data
343 static_assert ( EVP_MAX_MD_SIZE
<= 64 , "EVP_MAX_MD_SIZE is overly huge on this system, please check" );
346 if (! d_rrs
. empty () || ! opts
. empty () || d_haveednssubnet
|| d_haveednssection
) {
348 uint8_t maxScopeMask
= 0 ;
349 for ( pos
= d_rrs
. begin (); pos
< d_rrs
. end (); ++ pos
) {
350 // cerr<<"during wrapup, content=["<<pos->content<<"]"<<endl;
351 maxScopeMask
= max ( maxScopeMask
, pos
-> scopeMask
);
353 pw
. startRecord ( pos
-> dr
. d_name
, pos
-> dr
. d_type
, pos
-> dr
. d_ttl
, pos
-> dr
. d_class
, pos
-> dr
. d_place
);
354 pos
-> dr
. d_content
-> toPacket ( pw
);
355 if ( pw
. size () + optsize
> ( d_tcp
? 65535 : getMaxReplyLen ())) {
357 if ( pos
-> dr
. d_place
== DNSResourceRecord :: ANSWER
|| pos
-> dr
. d_place
== DNSResourceRecord :: AUTHORITY
) {
359 pw
. getHeader ()-> tc
= 1 ;
365 // if(!pw.getHeader()->tc) // protect against double commit from addSignature
367 if (! d_rrs
. empty ()) pw
. commit ();
371 if ( d_haveednssubnet
) {
372 EDNSSubnetOpts eso
= d_eso
;
373 eso
. scope
= Netmask ( eso
. source
. getNetwork (), maxScopeMask
);
375 string opt
= makeEDNSSubnetOptsString ( eso
);
376 opts
. push_back ( make_pair ( 8 , opt
)); // 'EDNS SUBNET'
379 if (! opts
. empty () || d_haveednssection
|| d_dnssecOk
)
381 pw
. addOpt ( s_udpTruncationThreshold
, d_ednsrcode
, d_dnssecOk
? EDNSOpts :: DNSSECOK
: 0 , opts
);
385 catch ( std :: exception
& e
) {
386 g_log
<< Logger :: Warning
<< "Exception: " << e
. what ()<< endl
;
391 if ( d_trc
. d_algoName
. countLabels ())
392 addTSIG ( pw
, d_trc
, d_tsigkeyname
, d_tsigsecret
, d_tsigprevious
, d_tsigtimersonly
);
394 d_rawpacket
. assign (( char *)& packet
[ 0 ], packet
. size ()); // XXX we could do this natively on a vector..
396 // copy RR counts so they can be read later
397 d
. qdcount
= pw
. getHeader ()-> qdcount
;
398 d
. ancount
= pw
. getHeader ()-> ancount
;
399 d
. nscount
= pw
. getHeader ()-> nscount
;
400 d
. arcount
= pw
. getHeader ()-> arcount
;
403 void DNSPacket :: setQuestion ( int op
, const DNSName
& qd
, int newqtype
)
405 memset (& d
, 0 , sizeof ( d
));
406 d
. id
= dns_random ( 0xffff );
407 d
. rd
= d
. tc
= d
. aa
= false ;
409 d
. qdcount
= 1 ; // is htons'ed later on
410 d
. ancount
= d
. arcount
= d
. nscount
= 0 ;
416 /** convenience function for creating a reply packet from a question packet. Do not forget to delete it after use! */
417 DNSPacket
* DNSPacket :: replyPacket () const
419 DNSPacket
* r
= new DNSPacket ( false );
420 r
-> setSocket ( d_socket
);
421 r
-> d_anyLocal
= d_anyLocal
;
422 r
-> setRemote (& d_remote
);
423 r
-> setAnswer ( true ); // this implies the allocation of the header
424 r
-> setA ( true ); // and we are authoritative
425 r
-> setRA ( 0 ); // no recursion available
426 r
-> setRD ( d
. rd
); // if you wanted to recurse, answer will say you wanted it
428 r
-> setOpcode ( d
. opcode
);
433 r
-> qdomain
= qdomain
;
436 r
-> d_maxreplylen
= d_maxreplylen
;
437 r
-> d_wantsnsid
= d_wantsnsid
;
438 r
-> d_dnssecOk
= d_dnssecOk
;
440 r
-> d_haveednssubnet
= d_haveednssubnet
;
441 r
-> d_haveednssection
= d_haveednssection
;
442 r
-> d_ednsversion
= 0 ;
445 if ( d_tsigkeyname
. countLabels ()) {
446 r
-> d_tsigkeyname
= d_tsigkeyname
;
447 r
-> d_tsigprevious
= d_tsigprevious
;
449 r
-> d_tsigsecret
= d_tsigsecret
;
450 r
-> d_tsigtimersonly
= d_tsigtimersonly
;
452 r
-> d_havetsig
= d_havetsig
;
456 void DNSPacket :: spoofQuestion ( const DNSPacket
* qd
)
458 d_wrapped
= true ; // if we do this, don't later on wrapup
461 string :: size_type i
= sizeof ( d
);
464 labellen
= qd
-> d_rawpacket
[ i
];
467 d_rawpacket
. replace ( i
, labellen
, qd
-> d_rawpacket
, i
, labellen
);
472 int DNSPacket :: noparse ( const char * mesg
, size_t length
)
474 d_rawpacket
. assign ( mesg
, length
);
476 g_log
<< Logger :: Debug
<< "Ignoring packet: too short (" << length
<< " < 12) from "
477 << d_remote
. toStringWithPort ()<< endl
;
482 memcpy (( void *)& d
,( const void *) d_rawpacket
. c_str (), 12 );
486 void DNSPacket :: setTSIGDetails ( const TSIGRecordContent
& tr
, const DNSName
& keyname
, const string
& secret
, const string
& previous
, bool timersonly
)
489 d_trc
. d_origID
= ((( d
. id
& 0xFF )<< 8 ) | (( d
. id
& 0xFF00 )>> 8 ));
490 d_tsigkeyname
= keyname
;
491 d_tsigsecret
= secret
;
492 d_tsigprevious
= previous
;
493 d_tsigtimersonly
= timersonly
;
496 bool DNSPacket :: getTSIGDetails ( TSIGRecordContent
* trc
, DNSName
* keyname
, uint16_t * tsigPosOut
) const
498 MOADNSParser
mdp ( d_isQuery
, d_rawpacket
);
499 uint16_t tsigPos
= mdp
. getTSIGPos ();
504 for ( MOADNSParser :: answers_t :: const_iterator i
= mdp
. d_answers
. begin (); i
!= mdp
. d_answers
. end (); ++ i
) {
505 if ( i
-> first
. d_type
== QType :: TSIG
&& i
-> first
. d_class
== QType :: ANY
) {
506 // cast can fail, f.e. if d_content is an UnknownRecordContent.
507 shared_ptr
< TSIGRecordContent
> content
= std :: dynamic_pointer_cast
< TSIGRecordContent
>( i
-> first
. d_content
);
509 g_log
<< Logger :: Error
<< "TSIG record has no or invalid content (invalid packet)" << endl
;
513 * keyname
= i
-> first
. d_name
;
521 * tsigPosOut
= tsigPos
;
527 bool DNSPacket :: getTKEYRecord ( TKEYRecordContent
* tr
, DNSName
* keyname
) const
529 MOADNSParser
mdp ( d_isQuery
, d_rawpacket
);
532 for ( MOADNSParser :: answers_t :: const_iterator i
= mdp
. d_answers
. begin (); i
!= mdp
. d_answers
. end (); ++ i
) {
534 g_log
<< Logger :: Error
<< "More than one TKEY record found in query" << endl
;
538 if ( i
-> first
. d_type
== QType :: TKEY
) {
539 // cast can fail, f.e. if d_content is an UnknownRecordContent.
540 shared_ptr
< TKEYRecordContent
> content
= std :: dynamic_pointer_cast
< TKEYRecordContent
>( i
-> first
. d_content
);
542 g_log
<< Logger :: Error
<< "TKEY record has no or invalid content (invalid packet)" << endl
;
546 * keyname
= i
-> first
. d_name
;
554 /** This function takes data from the network, possibly received with recvfrom, and parses
555 it into our class. Results of calling this function multiple times on one packet are
556 unknown. Returns -1 if the packet cannot be parsed.
558 int DNSPacket :: parse ( const char * mesg
, size_t length
)
561 d_rawpacket
. assign ( mesg
, length
);
564 g_log
<< Logger :: Debug
<< "Ignoring packet: too short from "
565 << getRemote () << endl
;
569 MOADNSParser
mdp ( d_isQuery
, d_rawpacket
);
572 // ANY OPTION WHICH *MIGHT* BE SET DOWN BELOW SHOULD BE CLEARED FIRST!
576 d_havetsig
= mdp
. getTSIGPos ();
577 d_haveednssubnet
= false ;
578 d_haveednssection
= false ;
580 if ( getEDNSOpts ( mdp
, & edo
)) {
581 d_haveednssection
= true ;
583 "Values lower than 512 MUST be treated as equal to 512."
585 d_ednsRawPacketSizeLimit
= edo
. d_packetsize
;
586 d_maxreplylen
= std :: min ( std :: max ( static_cast < uint16_t >( 512 ), edo
. d_packetsize
), s_udpTruncationThreshold
);
587 // cerr<<edo.d_extFlags<<endl;
588 if ( edo
. d_extFlags
& EDNSOpts :: DNSSECOK
)
591 for ( vector
< pair
< uint16_t , string
> >:: const_iterator iter
= edo
. d_options
. begin ();
592 iter
!= edo
. d_options
. end ();
594 if ( iter
-> first
== EDNSOptionCode :: NSID
) {
597 else if ( s_doEDNSSubnetProcessing
&& ( iter
-> first
== EDNSOptionCode :: ECS
)) { // 'EDNS SUBNET'
598 if ( getEDNSSubnetOptsFromString ( iter
-> second
, & d_eso
)) {
599 //cerr<<"Parsed, source: "<<d_eso.source.toString()<<", scope: "<<d_eso.scope.toString()<<", family = "<<d_eso.scope.getNetwork().sin4.sin_family<<endl;
600 d_haveednssubnet
= true ;
604 // cerr<<"Have an option #"<<iter->first<<": "<<makeHexDump(iter->second)<<endl;
607 d_ednsversion
= edo
. d_version
;
608 d_ednsrcode
= edo
. d_extRCode
;
612 d_ednsRawPacketSizeLimit
=- 1 ;
615 memcpy (( void *)& d
,( const void *) d_rawpacket
. c_str (), 12 );
617 // if(!qdomain.empty()) // strip dot
618 // boost::erase_tail(qdomain, 1);
620 if (! ntohs ( d
. qdcount
)) {
622 g_log
<< Logger :: Warning
<< "No question section in packet from " << getRemote () << ", error=" << RCode :: to_s ( d
. rcode
)<< endl
;
630 d_trc
= TSIGRecordContent ();
634 catch ( std :: exception
& e
) {
638 unsigned int DNSPacket :: getMaxReplyLen ()
640 return d_maxreplylen
;
643 void DNSPacket :: setMaxReplyLen ( int bytes
)
648 //! Use this to set where this packet was received from or should be sent to
649 void DNSPacket :: setRemote ( const ComboAddress
* s
)
654 bool DNSPacket :: hasEDNSSubnet () const
656 return d_haveednssubnet
;
659 bool DNSPacket :: hasEDNS ()
661 return d_haveednssection
;
664 Netmask
DNSPacket :: getRealRemote () const
668 return Netmask ( d_remote
);
671 void DNSPacket :: setSocket ( Utility :: sock_t sock
)
676 void DNSPacket :: commitD ()
678 d_rawpacket
. replace ( 0 , 12 ,( char *)& d
, 12 ); // copy in d
681 bool DNSPacket :: checkForCorrectTSIG ( UeberBackend
* B
, DNSName
* keyname
, string
* secret
, TSIGRecordContent
* trc
) const
685 if (! this -> getTSIGDetails ( trc
, keyname
, & tsigPos
)) {
691 tt
. algo
= trc
-> d_algoName
;
692 if ( tt
. algo
== DNSName ( "hmac-md5.sig-alg.reg.int" ))
693 tt
. algo
= DNSName ( "hmac-md5" );
696 if ( tt
. algo
!= DNSName ( "gss-tsig" )) {
697 if (! B
-> getTSIGKey (* keyname
, & tt
. algo
, & secret64
)) {
698 g_log
<< Logger :: Error
<< "Packet for domain '" << this -> qdomain
<< "' denied: can't find TSIG key with name '" <<* keyname
<< "' and algorithm '" << tt
. algo
<< "'" << endl
;
701 B64Decode ( secret64
, * secret
);
708 result
= validateTSIG ( d_rawpacket
, tsigPos
, tt
, * trc
, "" , trc
-> d_mac
, false );
710 catch ( const std :: runtime_error
& err
) {
711 g_log
<< Logger :: Error
<< "Packet for '" << this -> qdomain
<< "' denied: " << err
. what ()<< endl
;
718 const DNSName
& DNSPacket :: getTSIGKeyname () const {
719 return d_tsigkeyname
;