]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsparser.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.
22 #include "dnsparser.hh"
23 #include "dnswriter.hh"
24 #include <boost/algorithm/string.hpp>
25 #include <boost/format.hpp>
27 #include "namespaces.hh"
29 class UnknownRecordContent
: public DNSRecordContent
32 UnknownRecordContent ( const DNSRecord
& dr
, PacketReader
& pr
)
35 pr
. copyRecord ( d_record
, dr
. d_clen
);
38 UnknownRecordContent ( const string
& zone
)
42 stringtok ( parts
, zone
);
43 if ( parts
. size ()!= 3 && !( parts
. size ()== 2 && equals ( parts
[ 1 ], "0" )) )
44 throw MOADNSException ( "Unknown record was stored incorrectly, need 3 fields, got " + std :: to_string ( parts
. size ())+ ": " + zone
);
45 const string
& relevant
=( parts
. size () > 2 ) ? parts
[ 2 ] : "" ;
46 unsigned int total
= pdns_stou ( parts
[ 1 ]);
47 if ( relevant
. size ()!= 2 * total
)
48 throw MOADNSException (( boost :: format ( "invalid unknown record length for label %s: size not equal to length field (%d != %d)" ) % d_dr
. d_name
. toString () % relevant
. size () % ( 2 * total
)). str ());
51 for ( unsigned int n
= 0 ; n
< total
; ++ n
) {
53 sscanf ( relevant
. c_str ()+ 2 * n
, "%02x" , & c
);
54 out
. append ( 1 , ( char ) c
);
57 d_record
. insert ( d_record
. end (), out
. begin (), out
. end ());
60 string
getZoneRepresentation ( bool noDot
) const override
63 str
<< " \\ # " <<( unsigned int ) d_record
. size ()<< " " ;
65 for ( size_t n
= 0 ; n
< d_record
. size (); ++ n
) {
66 snprintf ( hex
, sizeof ( hex
)- 1 , "%02x" , d_record
. at ( n
));
72 void toPacket ( DNSPacketWriter
& pw
) override
74 pw
. xfrBlob ( string ( d_record
. begin (), d_record
. end ()));
77 uint16_t getType () const override
83 vector
< uint8_t > d_record
;
86 shared_ptr
< DNSRecordContent
> DNSRecordContent :: unserialize ( const DNSName
& qname
, uint16_t qtype
, const string
& serialized
)
89 memset (& dnsheader
, 0 , sizeof ( dnsheader
));
90 dnsheader
. qdcount
= htons ( 1 );
91 dnsheader
. ancount
= htons ( 1 );
93 vector
< uint8_t > packet
; // build pseudo packet
95 /* will look like: dnsheader, 5 bytes, encoded qname, dns record header, serialized data */
97 string encoded
= qname
. toDNSString ();
99 packet
. resize ( sizeof ( dnsheader
) + 5 + encoded
. size () + sizeof ( struct dnsrecordheader
) + serialized
. size ());
103 memcpy (& packet
[ 0 ], & dnsheader
, sizeof ( dnsheader
)); pos
+= sizeof ( dnsheader
);
105 char tmp
[ 6 ]= "\x0" "\x0\x1" "\x0\x1" ; // root question for ns_t_a
106 memcpy (& packet
[ pos
], & tmp
, 5 ); pos
+= 5 ;
108 memcpy (& packet
[ pos
], encoded
. c_str (), encoded
. size ()); pos
+=( uint16_t ) encoded
. size ();
110 struct dnsrecordheader drh
;
111 drh
. d_type
= htons ( qtype
);
112 drh
. d_class
= htons ( 1 );
114 drh
. d_clen
= htons ( serialized
. size ());
116 memcpy (& packet
[ pos
], & drh
, sizeof ( drh
)); pos
+= sizeof ( drh
);
117 memcpy (& packet
[ pos
], serialized
. c_str (), serialized
. size ()); pos
+=( uint16_t ) serialized
. size ();
119 MOADNSParser
mdp ( false , ( char *)&* packet
. begin (), ( unsigned int ) packet
. size ());
120 shared_ptr
< DNSRecordContent
> ret
= mdp
. d_answers
. begin ()-> first
. d_content
;
124 DNSRecordContent
* DNSRecordContent :: mastermake ( const DNSRecord
& dr
,
127 uint16_t searchclass
= ( dr
. d_type
== QType :: OPT
) ? 1 : dr
. d_class
; // class is invalid for OPT
129 typemap_t :: const_iterator i
= getTypemap (). find ( make_pair ( searchclass
, dr
. d_type
));
130 if ( i
== getTypemap (). end () || ! i
-> second
) {
131 return new UnknownRecordContent ( dr
, pr
);
134 return i
-> second ( dr
, pr
);
137 DNSRecordContent
* DNSRecordContent :: mastermake ( uint16_t qtype
, uint16_t qclass
,
138 const string
& content
)
140 zmakermap_t :: const_iterator i
= getZmakermap (). find ( make_pair ( qclass
, qtype
));
141 if ( i
== getZmakermap (). end ()) {
142 return new UnknownRecordContent ( content
);
145 return i
-> second ( content
);
148 std :: unique_ptr
< DNSRecordContent
> DNSRecordContent :: makeunique ( uint16_t qtype
, uint16_t qclass
,
149 const string
& content
)
151 zmakermap_t :: const_iterator i
= getZmakermap (). find ( make_pair ( qclass
, qtype
));
152 if ( i
== getZmakermap (). end ()) {
153 return std :: unique_ptr
< DNSRecordContent
>( new UnknownRecordContent ( content
));
156 return std :: unique_ptr
< DNSRecordContent
>( i
-> second ( content
));
160 DNSRecordContent
* DNSRecordContent :: mastermake ( const DNSRecord
& dr
, PacketReader
& pr
, uint16_t oc
) {
161 // For opcode UPDATE and where the DNSRecord is an answer record, we don't care about content, because this is
162 // not used within the prerequisite section of RFC2136, so - we can simply use unknownrecordcontent.
163 // For section 3.2.3, we do need content so we need to get it properly. But only for the correct Qclasses.
164 if ( oc
== Opcode :: Update
&& dr
. d_place
== DNSResourceRecord :: ANSWER
&& dr
. d_class
!= 1 )
165 return new UnknownRecordContent ( dr
, pr
);
167 uint16_t searchclass
= ( dr
. d_type
== QType :: OPT
) ? 1 : dr
. d_class
; // class is invalid for OPT
169 typemap_t :: const_iterator i
= getTypemap (). find ( make_pair ( searchclass
, dr
. d_type
));
170 if ( i
== getTypemap (). end () || ! i
-> second
) {
171 return new UnknownRecordContent ( dr
, pr
);
174 return i
-> second ( dr
, pr
);
178 DNSRecordContent :: typemap_t
& DNSRecordContent :: getTypemap ()
180 static DNSRecordContent :: typemap_t typemap
;
184 DNSRecordContent :: n2typemap_t
& DNSRecordContent :: getN2Typemap ()
186 static DNSRecordContent :: n2typemap_t n2typemap
;
190 DNSRecordContent :: t2namemap_t
& DNSRecordContent :: getT2Namemap ()
192 static DNSRecordContent :: t2namemap_t t2namemap
;
197 DNSRecordContent :: zmakermap_t
& DNSRecordContent :: getZmakermap ()
199 static DNSRecordContent :: zmakermap_t zmakermap
;
203 DNSRecord :: DNSRecord ( const DNSResourceRecord
& rr
)
206 d_type
= rr
. qtype
. getCode ();
209 d_place
= rr
. d_place
;
211 d_content
= std :: shared_ptr
< DNSRecordContent
>( DNSRecordContent :: mastermake ( d_type
, rr
. qclass
, rr
. content
));
214 void MOADNSParser :: init ( bool query
, const char * packet
, unsigned int len
)
216 if ( len
< sizeof ( dnsheader
))
217 throw MOADNSException ( "Packet shorter than minimal header" );
219 memcpy (& d_header
, packet
, sizeof ( dnsheader
));
221 if ( d_header
. opcode
!= Opcode :: Query
&& d_header
. opcode
!= Opcode :: Notify
&& d_header
. opcode
!= Opcode :: Update
)
222 throw MOADNSException ( "Can't parse non-query packet with opcode=" + std :: to_string ( d_header
. opcode
));
224 d_header
. qdcount
= ntohs ( d_header
. qdcount
);
225 d_header
. ancount
= ntohs ( d_header
. ancount
);
226 d_header
. nscount
= ntohs ( d_header
. nscount
);
227 d_header
. arcount
= ntohs ( d_header
. arcount
);
229 if ( query
&& ( d_header
. qdcount
> 1 ))
230 throw MOADNSException ( "Query with QD > 1 (" + std :: to_string ( d_header
. qdcount
)+ ")" );
232 uint16_t contentlen
= len
- sizeof ( dnsheader
);
234 d_content
. resize ( contentlen
);
235 copy ( packet
+ sizeof ( dnsheader
), packet
+ len
, d_content
. begin ());
239 PacketReader
pr ( d_content
);
240 bool validPacket
= false ;
242 d_qtype
= d_qclass
= 0 ; // sometimes replies come in with no question, don't present garbage then
244 for ( n
= 0 ; n
< d_header
. qdcount
; ++ n
) {
245 d_qname
= pr
. getName ();
246 d_qtype
= pr
. get16BitInt ();
247 d_qclass
= pr
. get16BitInt ();
250 struct dnsrecordheader ah
;
251 vector
< unsigned char > record
;
253 d_answers
. reserve (( unsigned int )( d_header
. ancount
+ d_header
. nscount
+ d_header
. arcount
));
254 for ( n
= 0 ; n
< ( unsigned int )( d_header
. ancount
+ d_header
. nscount
+ d_header
. arcount
); ++ n
) {
257 if ( n
< d_header
. ancount
)
258 dr
. d_place
= DNSResourceRecord :: ANSWER
;
259 else if ( n
< d_header
. ancount
+ d_header
. nscount
)
260 dr
. d_place
= DNSResourceRecord :: AUTHORITY
;
262 dr
. d_place
= DNSResourceRecord :: ADDITIONAL
;
264 unsigned int recordStartPos
= pr
. d_pos
;
266 DNSName name
= pr
. getName ();
268 pr
. getDnsrecordheader ( ah
);
271 dr
. d_class
= ah
. d_class
;
276 if ( query
&& ( dr
. d_place
== DNSResourceRecord :: ANSWER
|| dr
. d_place
== DNSResourceRecord :: AUTHORITY
|| ( dr
. d_type
!= QType :: OPT
&& dr
. d_type
!= QType :: TSIG
&& dr
. d_type
!= QType :: SIG
&& dr
. d_type
!= QType :: TKEY
) || (( dr
. d_type
== QType :: TSIG
|| dr
. d_type
== QType :: SIG
|| dr
. d_type
== QType :: TKEY
) && dr
. d_class
!= QClass :: ANY
))) {
277 // cerr<<"discarding RR, query is "<<query<<", place is "<<dr.d_place<<", type is "<<dr.d_type<<", class is "<<dr.d_class<<endl;
278 dr
. d_content
= std :: shared_ptr
< DNSRecordContent
>( new UnknownRecordContent ( dr
, pr
));
281 // cerr<<"parsing RR, query is "<<query<<", place is "<<dr.d_place<<", type is "<<dr.d_type<<", class is "<<dr.d_class<<endl;
282 dr
. d_content
= std :: shared_ptr
< DNSRecordContent
>( DNSRecordContent :: mastermake ( dr
, pr
, d_header
. opcode
));
285 d_answers
. push_back ( make_pair ( dr
, pr
. d_pos
));
287 if ( dr
. d_type
== QType :: TSIG
&& dr
. d_class
== QClass :: ANY
) {
288 if ( dr
. d_place
!= DNSResourceRecord :: ADDITIONAL
|| n
!= ( unsigned int )( d_header
. ancount
+ d_header
. nscount
+ d_header
. arcount
) - 1 ) {
289 throw MOADNSException ( "Packet (" + d_qname
. toString ()+ "|#" + std :: to_string ( d_qtype
)+ ") has a TSIG record in an invalid position." );
291 d_tsigPos
= recordStartPos
+ sizeof ( struct dnsheader
);
296 if ( pr
. d_pos
!= contentlen
) {
297 throw MOADNSException ( "Packet (" + d_qname
+ "|#" + std :: to_string ( d_qtype
)+ ") has trailing garbage (" + std :: to_string ( pr
. d_pos
) + " < " +
298 std :: to_string ( contentlen
) + ")" );
302 catch ( std :: out_of_range
& re
) {
303 if ( validPacket
&& d_header
. tc
) { // don't sweat it over truncated packets, but do adjust an, ns and arcount
304 if ( n
< d_header
. ancount
) {
305 d_header
. ancount
= n
; d_header
. nscount
= d_header
. arcount
= 0 ;
307 else if ( n
< d_header
. ancount
+ d_header
. nscount
) {
308 d_header
. nscount
= n
- d_header
. ancount
; d_header
. arcount
= 0 ;
311 d_header
. arcount
= n
- d_header
. ancount
- d_header
. nscount
;
315 throw MOADNSException ( "Error parsing packet of " + std :: to_string ( len
)+ " bytes (rd=" +
316 std :: to_string ( d_header
. rd
)+
317 "), out of bounds: " + string ( re
. what ()));
323 void PacketReader :: getDnsrecordheader ( struct dnsrecordheader
& ah
)
326 unsigned char * p
= reinterpret_cast < unsigned char *>(& ah
);
328 for ( n
= 0 ; n
< sizeof ( dnsrecordheader
); ++ n
)
329 p
[ n
]= d_content
. at ( d_pos
++);
331 ah
. d_type
= ntohs ( ah
. d_type
);
332 ah
. d_class
= ntohs ( ah
. d_class
);
333 ah
. d_clen
= ntohs ( ah
. d_clen
);
334 ah
. d_ttl
= ntohl ( ah
. d_ttl
);
336 d_startrecordpos
= d_pos
; // needed for getBlob later on
337 d_recordlen
= ah
. d_clen
;
341 void PacketReader :: copyRecord ( vector
< unsigned char >& dest
, uint16_t len
)
347 for ( uint16_t n
= 0 ; n
< len
;++ n
) {
348 dest
. at ( n
)= d_content
. at ( d_pos
++);
352 void PacketReader :: copyRecord ( unsigned char * dest
, uint16_t len
)
354 if ( d_pos
+ len
> d_content
. size ())
355 throw std :: out_of_range ( "Attempt to copy outside of packet" );
357 memcpy ( dest
, & d_content
. at ( d_pos
), len
);
361 void PacketReader :: xfr48BitInt ( uint64_t & ret
)
364 ret
+= d_content
. at ( d_pos
++);
366 ret
+= d_content
. at ( d_pos
++);
368 ret
+= d_content
. at ( d_pos
++);
370 ret
+= d_content
. at ( d_pos
++);
372 ret
+= d_content
. at ( d_pos
++);
374 ret
+= d_content
. at ( d_pos
++);
377 uint32_t PacketReader :: get32BitInt ()
380 ret
+= d_content
. at ( d_pos
++);
382 ret
+= d_content
. at ( d_pos
++);
384 ret
+= d_content
. at ( d_pos
++);
386 ret
+= d_content
. at ( d_pos
++);
392 uint16_t PacketReader :: get16BitInt ()
394 return get16BitInt ( d_content
, d_pos
);
397 uint16_t PacketReader :: get16BitInt ( const vector
< unsigned char >& content
, uint16_t & pos
)
400 ret
+= content
. at ( pos
++);
402 ret
+= content
. at ( pos
++);
407 uint8_t PacketReader :: get8BitInt ()
409 return d_content
. at ( d_pos
++);
412 DNSName
PacketReader :: getName ()
414 unsigned int consumed
;
416 DNSName
dn (( const char *) d_content
. data () - 12 , d_content
. size () + 12 , d_pos
+ sizeof ( dnsheader
), true /* uncompress */ , 0 /* qtype */ , 0 /* qclass */ , & consumed
, sizeof ( dnsheader
));
418 // the -12 fakery is because we don't have the header in 'd_content', but we do need to get
419 // the internal offsets to work
423 catch ( std :: range_error
& re
)
425 throw std :: out_of_range ( string ( "dnsname issue: " )+ re
. what ());
430 throw std :: out_of_range ( "dnsname issue" );
432 throw PDNSException ( "PacketReader::getName(): name is empty" );
435 static string
txtEscape ( const string
& name
)
440 for ( string :: const_iterator i
= name
. begin (); i
!= name
. end ();++ i
) {
441 if (( unsigned char ) * i
> 127 || ( unsigned char ) * i
< 32 ) {
442 snprintf ( ebuf
, sizeof ( ebuf
), " \\ %03u" , ( unsigned char )* i
);
445 else if (* i
== '"' || * i
== ' \\ ' ){
455 // exceptions thrown here do not result in logging in the main pdns auth server - just so you know!
456 string
PacketReader :: getText ( bool multi
, bool lenField
)
460 while ( d_pos
< d_startrecordpos
+ d_recordlen
) {
466 labellen
= d_content
. at ( d_pos
++);
468 labellen
= d_recordlen
- ( d_pos
- d_startrecordpos
);
471 if ( labellen
) { // no need to do anything for an empty string
472 string
val (& d_content
. at ( d_pos
), & d_content
. at ( d_pos
+ labellen
- 1 )+ 1 );
473 ret
. append ( txtEscape ( val
)); // the end is one beyond the packet
484 string
PacketReader :: getUnquotedText ( bool lenField
)
488 stop_at
= ( uint8_t ) d_content
. at ( d_pos
) + d_pos
+ 1 ;
490 stop_at
= d_recordlen
;
496 string
ret (& d_content
. at ( d_pos
), & d_content
. at ( stop_at
));
501 void PacketReader :: xfrBlob ( string
& blob
)
504 if ( d_recordlen
&& !( d_pos
== ( d_startrecordpos
+ d_recordlen
)))
505 blob
. assign (& d_content
. at ( d_pos
), & d_content
. at ( d_startrecordpos
+ d_recordlen
- 1 ) + 1 );
509 d_pos
= d_startrecordpos
+ d_recordlen
;
513 throw std :: out_of_range ( "xfrBlob out of range" );
516 void PacketReader :: xfrBlobNoSpaces ( string
& blob
, int length
) {
517 xfrBlob ( blob
, length
);
520 void PacketReader :: xfrBlob ( string
& blob
, int length
)
523 blob
. assign (& d_content
. at ( d_pos
), & d_content
. at ( d_pos
+ length
- 1 ) + 1 );
532 void PacketReader :: xfrHexBlob ( string
& blob
, bool keepReading
)
537 //FIXME400 remove this method completely
538 string
simpleCompress ( const string
& elabel
, const string
& root
)
541 // FIXME400: this relies on the semi-canonical escaped output from getName
542 if ( strchr ( label
. c_str (), ' \\ ' )) {
543 boost :: replace_all ( label
, " \\ ." , "." );
544 boost :: replace_all ( label
, " \\ 032" , " " );
545 boost :: replace_all ( label
, " \\\\ " , " \\ " );
547 typedef vector
< pair
< unsigned int , unsigned int > > parts_t
;
549 vstringtok ( parts
, label
, "." );
551 ret
. reserve ( label
. size ()+ 4 );
552 for ( parts_t :: const_iterator i
= parts
. begin (); i
!= parts
. end (); ++ i
) {
553 if (! root
. empty () && ! strncasecmp ( root
. c_str (), label
. c_str () + i
-> first
, 1 + label
. length () - i
-> first
)) { // also match trailing 0, hence '1 +'
554 const unsigned char rootptr
[ 2 ]={ 0xc0 , 0x11 };
555 ret
. append (( const char *) rootptr
, 2 );
558 ret
. append ( 1 , ( char )( i
-> second
- i
-> first
));
559 ret
. append ( label
. c_str () + i
-> first
, i
-> second
- i
-> first
);
561 ret
. append ( 1 , ( char ) 0 );
566 /** Simple DNSPacketMangler. Ritual is: get a pointer into the packet and moveOffset() to beyond your needs
567 * If you survive that, feel free to read from the pointer */
568 class DNSPacketMangler
571 explicit DNSPacketMangler ( std :: string
& packet
)
572 : d_packet (( char *) packet
. c_str ()), d_length ( packet
. length ()), d_notyouroffset ( 12 ), d_offset ( d_notyouroffset
)
574 DNSPacketMangler ( char * packet
, size_t length
)
575 : d_packet ( packet
), d_length ( length
), d_notyouroffset ( 12 ), d_offset ( d_notyouroffset
)
581 while (( len
= get8BitInt ())) {
582 if ( len
>= 0xc0 ) { // extended label
589 void skipBytes ( uint16_t bytes
)
593 uint32_t get32BitInt ()
595 const char * p
= d_packet
+ d_offset
;
598 memcpy (& ret
, ( void *) p
, sizeof ( ret
));
601 uint16_t get16BitInt ()
603 const char * p
= d_packet
+ d_offset
;
606 memcpy (& ret
, ( void *) p
, sizeof ( ret
));
612 const char * p
= d_packet
+ d_offset
;
619 int toskip
= get16BitInt ();
622 void decreaseAndSkip32BitInt ( uint32_t decrease
)
624 const char * p
= d_packet
+ d_offset
;
628 memcpy (& tmp
, ( void *) p
, sizeof ( tmp
));
632 memcpy ( d_packet
+ d_offset
- 4 , ( const char *)& tmp
, sizeof ( tmp
));
634 uint32_t getOffset () const
639 void moveOffset ( uint16_t by
)
641 d_notyouroffset
+= by
;
642 if ( d_notyouroffset
> d_length
)
643 throw std :: out_of_range ( "dns packet out of range: " + std :: to_string ( d_notyouroffset
) + " > "
644 + std :: to_string ( d_length
) );
649 uint32_t d_notyouroffset
; // only 'moveOffset' can touch this
650 const uint32_t & d_offset
; // look.. but don't touch
654 // method of operation: silently fail if it doesn't work - we're only trying to be nice, don't fall over on it
655 void ageDNSPacket ( char * packet
, size_t length
, uint32_t seconds
)
657 if ( length
< sizeof ( dnsheader
))
662 memcpy (( void *)& dh
, ( const dnsheader
*) packet
, sizeof ( dh
));
663 uint64_t numrecords
= ntohs ( dh
. ancount
) + ntohs ( dh
. nscount
) + ntohs ( dh
. arcount
);
664 DNSPacketMangler
dpm ( packet
, length
);
667 for ( n
= 0 ; n
< ntohs ( dh
. qdcount
) ; ++ n
) {
672 // cerr<<"Skipped "<<n<<" questions, now parsing "<<numrecords<<" records"<<endl;
673 for ( n
= 0 ; n
< numrecords
; ++ n
) {
676 uint16_t dnstype
= dpm
. get16BitInt ();
680 if ( dnstype
== QType :: OPT
) // not aging that one with a stick
683 dpm
. decreaseAndSkip32BitInt ( seconds
);
693 void ageDNSPacket ( std :: string
& packet
, uint32_t seconds
)
695 ageDNSPacket (( char *) packet
. c_str (), packet
. length (), seconds
);
698 uint32_t getDNSPacketMinTTL ( const char * packet
, size_t length
)
700 uint32_t result
= std :: numeric_limits
< uint32_t >:: max ();
701 if ( length
< sizeof ( dnsheader
)) {
706 const dnsheader
* dh
= ( const dnsheader
*) packet
;
707 DNSPacketMangler
dpm ( const_cast < char *>( packet
), length
);
709 const uint16_t qdcount
= ntohs ( dh
-> qdcount
);
710 for ( size_t n
= 0 ; n
< qdcount
; ++ n
) {
715 const size_t numrecords
= ntohs ( dh
-> ancount
) + ntohs ( dh
-> nscount
) + ntohs ( dh
-> arcount
);
716 for ( size_t n
= 0 ; n
< numrecords
; ++ n
) {
718 const uint16_t dnstype
= dpm
. get16BitInt ();
722 if ( dnstype
== QType :: OPT
)
725 const uint32_t ttl
= dpm
. get32BitInt ();
738 uint32_t getDNSPacketLength ( const char * packet
, size_t length
)
740 uint32_t result
= length
;
741 if ( length
< sizeof ( dnsheader
)) {
746 const dnsheader
* dh
= ( const dnsheader
*) packet
;
747 DNSPacketMangler
dpm ( const_cast < char *>( packet
), length
);
749 const uint16_t qdcount
= ntohs ( dh
-> qdcount
);
750 for ( size_t n
= 0 ; n
< qdcount
; ++ n
) {
755 const size_t numrecords
= ntohs ( dh
-> ancount
) + ntohs ( dh
-> nscount
) + ntohs ( dh
-> arcount
);
756 for ( size_t n
= 0 ; n
< numrecords
; ++ n
) {
758 /* type (2), class (2) and ttl (4) */
762 result
= dpm
. getOffset ();
770 uint16_t getRecordsOfTypeCount ( const char * packet
, size_t length
, uint8_t section
, uint16_t type
)
773 if ( length
< sizeof ( dnsheader
)) {
778 const dnsheader
* dh
= ( const dnsheader
*) packet
;
779 DNSPacketMangler
dpm ( const_cast < char *>( packet
), length
);
781 const uint16_t qdcount
= ntohs ( dh
-> qdcount
);
782 for ( size_t n
= 0 ; n
< qdcount
; ++ n
) {
785 uint16_t dnstype
= dpm
. get16BitInt ();
786 if ( dnstype
== type
) {
796 const uint16_t ancount
= ntohs ( dh
-> ancount
);
797 for ( size_t n
= 0 ; n
< ancount
; ++ n
) {
800 uint16_t dnstype
= dpm
. get16BitInt ();
801 if ( dnstype
== type
) {
814 const uint16_t nscount
= ntohs ( dh
-> nscount
);
815 for ( size_t n
= 0 ; n
< nscount
; ++ n
) {
818 uint16_t dnstype
= dpm
. get16BitInt ();
819 if ( dnstype
== type
) {
832 const uint16_t arcount
= ntohs ( dh
-> arcount
);
833 for ( size_t n
= 0 ; n
< arcount
; ++ n
) {
836 uint16_t dnstype
= dpm
. get16BitInt ();
837 if ( dnstype
== type
) {