]>
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
): d_isQuery ( isQuery
)
60 memset (& d
, 0 , sizeof ( d
));
63 const string
& DNSPacket :: getString ()
71 ComboAddress
DNSPacket :: getRemote () const
76 uint16_t DNSPacket :: getRemotePort () const
78 return d_remote
. sin4
. sin_port
;
81 DNSPacket :: DNSPacket ( const DNSPacket
& orig
) :
82 d_anyLocal ( orig
. d_anyLocal
),
84 qdomain ( orig
. qdomain
),
85 qdomainwild ( orig
. qdomainwild
),
86 qdomainzone ( orig
. qdomainzone
),
90 d_remote ( orig
. d_remote
),
91 d_tsig_algo ( orig
. d_tsig_algo
),
93 d_ednsRawPacketSizeLimit ( orig
. d_ednsRawPacketSizeLimit
),
97 d_dnssecOk ( orig
. d_dnssecOk
),
98 d_havetsig ( orig
. d_havetsig
),
100 d_tsigsecret ( orig
. d_tsigsecret
),
101 d_tsigkeyname ( orig
. d_tsigkeyname
),
102 d_tsigprevious ( orig
. d_tsigprevious
),
104 d_rawpacket ( orig
. d_rawpacket
),
106 d_maxreplylen ( orig
. d_maxreplylen
),
107 d_socket ( orig
. d_socket
),
109 d_ednsrcode ( orig
. d_ednsrcode
),
110 d_ednsversion ( orig
. d_ednsversion
),
112 d_wrapped ( orig
. d_wrapped
),
113 d_compress ( orig
. d_compress
),
114 d_tsigtimersonly ( orig
. d_tsigtimersonly
),
115 d_wantsnsid ( orig
. d_wantsnsid
),
116 d_haveednssubnet ( orig
. d_haveednssubnet
),
117 d_haveednssection ( orig
. d_haveednssection
),
119 d_isQuery ( orig
. d_isQuery
)
121 DLOG ( g_log
<< "DNSPacket copy constructor called!" << endl
);
124 void DNSPacket :: setRcode ( int v
)
129 void DNSPacket :: setAnswer ( bool b
)
132 d_rawpacket
. assign ( 12 ,( char ) 0 );
133 memset (( void *)& d
, 0 , sizeof ( d
));
139 void DNSPacket :: setA ( bool b
)
144 void DNSPacket :: setID ( uint16_t id
)
149 void DNSPacket :: setRA ( bool b
)
154 void DNSPacket :: setRD ( bool b
)
159 void DNSPacket :: setOpcode ( uint16_t opcode
)
164 void DNSPacket :: clearRecords ()
170 void DNSPacket :: addRecord ( const DNSZoneRecord
& rr
)
172 // this removes duplicates from the packet.
173 // in case we are not compressing for AXFR, no such checking is performed!
176 std :: string ser
= const_cast < DNSZoneRecord
&>( rr
). dr
. d_content
-> serialize ( rr
. dr
. d_name
);
177 auto hash
= boost :: hash
< std :: pair
< DNSName
, std :: string
> >()({ rr
. dr
. d_name
, ser
});
178 if ( d_dedup
. count ( hash
)) { // might be a dup
179 for ( auto i
= d_rrs
. begin (); i
!= d_rrs
. end ();++ i
) {
180 if ( rr
. dr
== i
-> dr
) // XXX SUPER SLOW
184 d_dedup
. insert ( hash
);
190 vector
< DNSZoneRecord
*> DNSPacket :: getAPRecords ()
192 vector
< DNSZoneRecord
*> arrs
;
194 for ( vector
< DNSZoneRecord
>:: iterator i
= d_rrs
. begin ();
198 if ( i
-> dr
. d_place
!= DNSResourceRecord :: ADDITIONAL
&&
199 ( i
-> dr
. d_type
== QType :: MX
||
200 i
-> dr
. d_type
== QType :: NS
||
201 i
-> dr
. d_type
== QType :: SRV
))
209 vector
< DNSZoneRecord
*> DNSPacket :: getAnswerRecords ()
211 vector
< DNSZoneRecord
*> arrs
;
213 for ( vector
< DNSZoneRecord
>:: iterator i
= d_rrs
. begin ();
217 if ( i
-> dr
. d_place
!= DNSResourceRecord :: ADDITIONAL
)
224 void DNSPacket :: setCompress ( bool compress
)
227 d_rawpacket
. reserve ( 65000 );
231 bool DNSPacket :: couldBeCached ()
233 return ! d_wantsnsid
&& qclass
== QClass :: IN
&& ! d_havetsig
;
236 unsigned int DNSPacket :: getMinTTL ()
238 unsigned int minttl
= UINT_MAX
;
239 for ( const DNSZoneRecord
& rr
: d_rrs
) {
240 if ( rr
. dr
. d_ttl
< minttl
)
241 minttl
= rr
. dr
. d_ttl
;
247 bool DNSPacket :: isEmpty ()
249 return ( d_rrs
. empty ());
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.
255 void DNSPacket :: wrapup ()
262 vector
< DNSZoneRecord
>:: iterator pos
;
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
267 stable_sort ( d_rrs
. begin (), d_rrs
. end (), []( const DNSZoneRecord
& a
, const DNSZoneRecord
& b
) {
268 return a
. dr
. d_place
< b
. dr
. d_place
;
270 static bool mustNotShuffle
= :: arg (). mustDo ( "no-shuffle" );
272 if (! d_tcp
&& ! mustNotShuffle
) {
277 vector
< uint8_t > packet
;
278 DNSPacketWriter
pw ( packet
, qdomain
, qtype
. getCode (), qclass
);
280 pw
. getHeader ()-> rcode
= d
. rcode
;
281 pw
. getHeader ()-> opcode
= d
. opcode
;
282 pw
. getHeader ()-> aa
= d
. aa
;
283 pw
. getHeader ()-> ra
= d
. ra
;
284 pw
. getHeader ()-> qr
= d
. qr
;
285 pw
. getHeader ()-> id
= d
. id
;
286 pw
. getHeader ()-> rd
= d
. rd
;
287 pw
. getHeader ()-> tc
= d
. tc
;
289 DNSPacketWriter :: optvect_t opts
;
291 /* optsize is expected to hold an upper bound of data that will be
292 added after actual record data - i.e. OPT, TSIG, perhaps one day
293 XPF. Because of the way `pw` incrementally writes the packet, we
294 cannot easily 'go back' and remove a few records. So, to prevent
295 going over our maximum size, we keep our (potential) extra data
298 This means that sometimes we'll send TC even if we'd end up with
299 a few bytes to spare, but so be it.
303 if ( d_haveednssection
|| d_dnssecOk
) {
304 /* root label (1), type (2), class (2), ttl (4) + rdlen (2) */
309 const static string mode_server_id
=:: arg ()[ "server-id" ];
310 if ( mode_server_id
!= "disabled" ) {
311 opts
. push_back ( make_pair ( EDNSOptionCode :: NSID
, mode_server_id
));
312 optsize
+= EDNS_OPTION_CODE_SIZE
+ EDNS_OPTION_LENGTH_SIZE
+ mode_server_id
. size ();
316 if ( d_haveednssubnet
)
318 // this is an upper bound
319 optsize
+= EDNS_OPTION_CODE_SIZE
+ EDNS_OPTION_LENGTH_SIZE
+ 2 + 1 + 1 ; // code+len+family+src len+scope len
320 optsize
+= d_eso
. source
. isIpv4 () ? 4 : 16 ;
323 if ( d_trc
. d_algoName
. countLabels ())
325 // TSIG is not OPT, but we count it in optsize anyway
326 optsize
+= d_trc
. d_algoName
. wirelength () + 3 + 1 + 2 ; // algo + time + fudge + maclen
327 optsize
+= EVP_MAX_MD_SIZE
+ 2 + 2 + 2 + 0 ; // mac + origid + ercode + otherdatalen + no other data
329 static_assert ( EVP_MAX_MD_SIZE
<= 64 , "EVP_MAX_MD_SIZE is overly huge on this system, please check" );
332 if (! d_rrs
. empty () || ! opts
. empty () || d_haveednssubnet
|| d_haveednssection
) {
334 uint8_t maxScopeMask
= 0 ;
335 for ( pos
= d_rrs
. begin (); pos
< d_rrs
. end (); ++ pos
) {
336 // cerr<<"during wrapup, content=["<<pos->content<<"]"<<endl;
337 maxScopeMask
= max ( maxScopeMask
, pos
-> scopeMask
);
339 pw
. startRecord ( pos
-> dr
. d_name
, pos
-> dr
. d_type
, pos
-> dr
. d_ttl
, pos
-> dr
. d_class
, pos
-> dr
. d_place
);
340 pos
-> dr
. d_content
-> toPacket ( pw
);
341 if ( pw
. size () + optsize
> ( d_tcp
? 65535 : getMaxReplyLen ())) {
344 pw
. getHeader ()-> tc
= 1 ;
349 // if(!pw.getHeader()->tc) // protect against double commit from addSignature
351 if (! d_rrs
. empty ()) pw
. commit ();
355 if ( d_haveednssubnet
) {
356 EDNSSubnetOpts eso
= d_eso
;
357 eso
. scope
= Netmask ( eso
. source
. getNetwork (), maxScopeMask
);
359 string opt
= makeEDNSSubnetOptsString ( eso
);
360 opts
. push_back ( make_pair ( 8 , opt
)); // 'EDNS SUBNET'
363 if (! opts
. empty () || d_haveednssection
|| d_dnssecOk
)
365 pw
. addOpt ( s_udpTruncationThreshold
, d_ednsrcode
, d_dnssecOk
? EDNSOpts :: DNSSECOK
: 0 , opts
);
369 catch ( std :: exception
& e
) {
370 g_log
<< Logger :: Warning
<< "Exception: " << e
. what ()<< endl
;
375 if ( d_trc
. d_algoName
. countLabels ())
376 addTSIG ( pw
, d_trc
, d_tsigkeyname
, d_tsigsecret
, d_tsigprevious
, d_tsigtimersonly
);
378 d_rawpacket
. assign (( char *)& packet
[ 0 ], packet
. size ()); // XXX we could do this natively on a vector..
380 // copy RR counts so they can be read later
381 d
. qdcount
= pw
. getHeader ()-> qdcount
;
382 d
. ancount
= pw
. getHeader ()-> ancount
;
383 d
. nscount
= pw
. getHeader ()-> nscount
;
384 d
. arcount
= pw
. getHeader ()-> arcount
;
387 void DNSPacket :: setQuestion ( int op
, const DNSName
& qd
, int newqtype
)
389 memset (& d
, 0 , sizeof ( d
));
390 d
. id
= dns_random ( 0xffff );
391 d
. rd
= d
. tc
= d
. aa
= false ;
393 d
. qdcount
= 1 ; // is htons'ed later on
394 d
. ancount
= d
. arcount
= d
. nscount
= 0 ;
400 /** convenience function for creating a reply packet from a question packet. Do not forget to delete it after use! */
401 DNSPacket
* DNSPacket :: replyPacket () const
403 DNSPacket
* r
= new DNSPacket ( false );
404 r
-> setSocket ( d_socket
);
405 r
-> d_anyLocal
= d_anyLocal
;
406 r
-> setRemote (& d_remote
);
407 r
-> setAnswer ( true ); // this implies the allocation of the header
408 r
-> setA ( true ); // and we are authoritative
409 r
-> setRA ( 0 ); // no recursion available
410 r
-> setRD ( d
. rd
); // if you wanted to recurse, answer will say you wanted it
412 r
-> setOpcode ( d
. opcode
);
417 r
-> qdomain
= qdomain
;
420 r
-> d_maxreplylen
= d_maxreplylen
;
421 r
-> d_wantsnsid
= d_wantsnsid
;
422 r
-> d_dnssecOk
= d_dnssecOk
;
424 r
-> d_haveednssubnet
= d_haveednssubnet
;
425 r
-> d_haveednssection
= d_haveednssection
;
426 r
-> d_ednsversion
= 0 ;
429 if ( d_tsigkeyname
. countLabels ()) {
430 r
-> d_tsigkeyname
= d_tsigkeyname
;
431 r
-> d_tsigprevious
= d_tsigprevious
;
433 r
-> d_tsigsecret
= d_tsigsecret
;
434 r
-> d_tsigtimersonly
= d_tsigtimersonly
;
436 r
-> d_havetsig
= d_havetsig
;
440 void DNSPacket :: spoofQuestion ( const DNSPacket
* qd
)
442 d_wrapped
= true ; // if we do this, don't later on wrapup
445 string :: size_type i
= sizeof ( d
);
448 labellen
= qd
-> d_rawpacket
[ i
];
451 d_rawpacket
. replace ( i
, labellen
, qd
-> d_rawpacket
, i
, labellen
);
456 int DNSPacket :: noparse ( const char * mesg
, size_t length
)
458 d_rawpacket
. assign ( mesg
, length
);
460 g_log
<< Logger :: Debug
<< "Ignoring packet: too short (" << length
<< " < 12) from "
461 << d_remote
. toStringWithPort ()<< endl
;
466 memcpy (( void *)& d
,( const void *) d_rawpacket
. c_str (), 12 );
470 void DNSPacket :: setTSIGDetails ( const TSIGRecordContent
& tr
, const DNSName
& keyname
, const string
& secret
, const string
& previous
, bool timersonly
)
473 d_trc
. d_origID
= ((( d
. id
& 0xFF )<< 8 ) | (( d
. id
& 0xFF00 )>> 8 ));
474 d_tsigkeyname
= keyname
;
475 d_tsigsecret
= secret
;
476 d_tsigprevious
= previous
;
477 d_tsigtimersonly
= timersonly
;
480 bool DNSPacket :: getTSIGDetails ( TSIGRecordContent
* trc
, DNSName
* keyname
, uint16_t * tsigPosOut
) const
482 MOADNSParser
mdp ( d_isQuery
, d_rawpacket
);
483 uint16_t tsigPos
= mdp
. getTSIGPos ();
488 for ( MOADNSParser :: answers_t :: const_iterator i
= mdp
. d_answers
. begin (); i
!= mdp
. d_answers
. end (); ++ i
) {
489 if ( i
-> first
. d_type
== QType :: TSIG
&& i
-> first
. d_class
== QType :: ANY
) {
490 // cast can fail, f.e. if d_content is an UnknownRecordContent.
491 shared_ptr
< TSIGRecordContent
> content
= std :: dynamic_pointer_cast
< TSIGRecordContent
>( i
-> first
. d_content
);
493 g_log
<< Logger :: Error
<< "TSIG record has no or invalid content (invalid packet)" << endl
;
497 * keyname
= i
-> first
. d_name
;
505 * tsigPosOut
= tsigPos
;
511 bool DNSPacket :: getTKEYRecord ( TKEYRecordContent
* tr
, DNSName
* keyname
) const
513 MOADNSParser
mdp ( d_isQuery
, d_rawpacket
);
516 for ( MOADNSParser :: answers_t :: const_iterator i
= mdp
. d_answers
. begin (); i
!= mdp
. d_answers
. end (); ++ i
) {
518 g_log
<< Logger :: Error
<< "More than one TKEY record found in query" << endl
;
522 if ( i
-> first
. d_type
== QType :: TKEY
) {
523 // cast can fail, f.e. if d_content is an UnknownRecordContent.
524 shared_ptr
< TKEYRecordContent
> content
= std :: dynamic_pointer_cast
< TKEYRecordContent
>( i
-> first
. d_content
);
526 g_log
<< Logger :: Error
<< "TKEY record has no or invalid content (invalid packet)" << endl
;
530 * keyname
= i
-> first
. d_name
;
538 /** This function takes data from the network, possibly received with recvfrom, and parses
539 it into our class. Results of calling this function multiple times on one packet are
540 unknown. Returns -1 if the packet cannot be parsed.
542 int DNSPacket :: parse ( const char * mesg
, size_t length
)
545 d_rawpacket
. assign ( mesg
, length
);
548 g_log
<< Logger :: Debug
<< "Ignoring packet: too short from "
549 << getRemote () << endl
;
553 MOADNSParser
mdp ( d_isQuery
, d_rawpacket
);
556 // ANY OPTION WHICH *MIGHT* BE SET DOWN BELOW SHOULD BE CLEARED FIRST!
560 d_havetsig
= mdp
. getTSIGPos ();
561 d_haveednssubnet
= false ;
562 d_haveednssection
= false ;
564 if ( getEDNSOpts ( mdp
, & edo
)) {
565 d_haveednssection
= true ;
567 "Values lower than 512 MUST be treated as equal to 512."
569 d_ednsRawPacketSizeLimit
= edo
. d_packetsize
;
570 d_maxreplylen
= std :: min ( std :: max ( static_cast < uint16_t >( 512 ), edo
. d_packetsize
), s_udpTruncationThreshold
);
571 // cerr<<edo.d_extFlags<<endl;
572 if ( edo
. d_extFlags
& EDNSOpts :: DNSSECOK
)
575 for ( vector
< pair
< uint16_t , string
> >:: const_iterator iter
= edo
. d_options
. begin ();
576 iter
!= edo
. d_options
. end ();
578 if ( iter
-> first
== EDNSOptionCode :: NSID
) {
581 else if ( s_doEDNSSubnetProcessing
&& ( iter
-> first
== EDNSOptionCode :: ECS
)) { // 'EDNS SUBNET'
582 if ( getEDNSSubnetOptsFromString ( iter
-> second
, & d_eso
)) {
583 //cerr<<"Parsed, source: "<<d_eso.source.toString()<<", scope: "<<d_eso.scope.toString()<<", family = "<<d_eso.scope.getNetwork().sin4.sin_family<<endl;
584 d_haveednssubnet
= true ;
588 // cerr<<"Have an option #"<<iter->first<<": "<<makeHexDump(iter->second)<<endl;
591 d_ednsversion
= edo
. d_version
;
592 d_ednsrcode
= edo
. d_extRCode
;
596 d_ednsRawPacketSizeLimit
=- 1 ;
599 memcpy (( void *)& d
,( const void *) d_rawpacket
. c_str (), 12 );
601 // if(!qdomain.empty()) // strip dot
602 // boost::erase_tail(qdomain, 1);
604 if (! ntohs ( d
. qdcount
)) {
606 g_log
<< Logger :: Warning
<< "No question section in packet from " << getRemote () << ", error=" << RCode :: to_s ( d
. rcode
)<< endl
;
614 d_trc
= TSIGRecordContent ();
618 catch ( std :: exception
& e
) {
622 unsigned int DNSPacket :: getMaxReplyLen ()
624 return d_maxreplylen
;
627 void DNSPacket :: setMaxReplyLen ( int bytes
)
632 //! Use this to set where this packet was received from or should be sent to
633 void DNSPacket :: setRemote ( const ComboAddress
* s
)
638 bool DNSPacket :: hasEDNSSubnet () const
640 return d_haveednssubnet
;
643 bool DNSPacket :: hasEDNS ()
645 return d_haveednssection
;
648 Netmask
DNSPacket :: getRealRemote () const
652 return Netmask ( d_remote
);
655 void DNSPacket :: setSocket ( Utility :: sock_t sock
)
660 void DNSPacket :: commitD ()
662 d_rawpacket
. replace ( 0 , 12 ,( char *)& d
, 12 ); // copy in d
665 bool DNSPacket :: checkForCorrectTSIG ( UeberBackend
* B
, DNSName
* keyname
, string
* secret
, TSIGRecordContent
* trc
) const
669 if (! this -> getTSIGDetails ( trc
, keyname
, & tsigPos
)) {
675 tt
. algo
= trc
-> d_algoName
;
676 if ( tt
. algo
== DNSName ( "hmac-md5.sig-alg.reg.int" ))
677 tt
. algo
= DNSName ( "hmac-md5" );
680 if ( tt
. algo
!= DNSName ( "gss-tsig" )) {
681 if (! B
-> getTSIGKey (* keyname
, & tt
. algo
, & secret64
)) {
682 g_log
<< Logger :: Error
<< "Packet for domain '" << this -> qdomain
<< "' denied: can't find TSIG key with name '" <<* keyname
<< "' and algorithm '" << tt
. algo
<< "'" << endl
;
685 B64Decode ( secret64
, * secret
);
692 result
= validateTSIG ( d_rawpacket
, tsigPos
, tt
, * trc
, "" , trc
-> d_mac
, false );
694 catch ( const std :: runtime_error
& err
) {
695 g_log
<< Logger :: Error
<< "Packet for '" << this -> qdomain
<< "' denied: " << err
. what ()<< endl
;
702 const DNSName
& DNSPacket :: getTSIGKeyname () const {
703 return d_tsigkeyname
;