E-MailRelay

gdnsmessage.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2021 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
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.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gdnsmessage.cpp
19///
20
21#include "gdef.h"
22#include "gdnsmessage.h"
23#include "gassert.h"
24#include "gstr.h"
25#include "gstringview.h"
26#include <array>
27#include <vector>
28#include <iomanip>
29#include <sstream>
30#include <stdexcept>
31
32 GNet::DnsMessageRequest::DnsMessageRequest( const std::string & type , const std::string & hostname , unsigned int id )
33{
34 // header section
35 G_ASSERT( id < 0xffffU ) ;
36 q( (id>>8U)&0xff ) ; q( id&0xff ) ; // ID=id - arbitrary identifier to link query with response
37 q( 0x01 ) ; // flags - QR=0 (ie. query) and RD=1 (ie. recursion desired)
38 q( 0x00 ) ; // RA=0 (recursion available) and Z=0 (zero bits, but see RFC-2671) and RCODE=0 (response code)
39 q( 0x00 ) ; q( 0x01 ) ; // QDCOUNT=1 (ie. one question section)
40 q( 0x00 ) ; q( 0x00 ) ; // ANCOUNT=0 (ie. no answer sections)
41 q( 0x00 ) ; q( 0x00 ) ; // NSCOUNT=0 (ie. no authority sections)
42 q( 0x00 ) ; q( 0x00 ) ; // ARCOUNT=0 (ie. no additional sections)
43
44 // question section
45 q( hostname , '.' ) ; // QNAME
46 q( 0x00 ) ; q( DnsMessageRecordType::value(type) ) ; // eg. QTYPE=A
47 q( 0x00 ) ; q( 0x01 ) ; // QCLASS=IN(ternet)
48}
49
50 void GNet::DnsMessageRequest::q( const std::string & domain , char sep )
51{
52 G::StringArray parts ;
53 G::Str::splitIntoFields( domain , parts , {&sep,1U} ) ;
54 for( const auto & part : parts )
55 {
56 q( part ) ;
57 }
58 q( std::string() ) ;
59}
60
61 void GNet::DnsMessageRequest::q( const std::string & data )
62{
63 if( data.size() > 63U ) throw DnsMessage::Error("overflow") ;
64 q( static_cast<unsigned int>(data.size()) ) ;
65 m_data.append( data ) ;
66}
67
68 void GNet::DnsMessageRequest::q( int n )
69{
70 q( static_cast<unsigned int>(n) ) ;
71}
72
73 void GNet::DnsMessageRequest::q( unsigned int n )
74{
75 m_data.append( 1U , static_cast<char>(n) ) ;
76}
77
78 const char * GNet::DnsMessageRequest::p() const
79{
80 return m_data.data() ;
81}
82
83std::size_t GNet::DnsMessageRequest::n() const
84{
85 return m_data.size() ;
86}
87
88// ==
89
90GNet::DnsMessage::DnsMessage()
91= default;
92
93 GNet::DnsMessage::DnsMessage( const std::vector<char> & buffer ) :
94 m_buffer(buffer)
95{
96 if( TC() )
97 throw Error( "truncated response" ) ;
98}
99
100 GNet::DnsMessage::DnsMessage( const char * p , std::size_t n ) :
101 m_buffer(p,p+n)
102{
103}
104
105 const char * GNet::DnsMessage::p() const
106{
107 return &m_buffer[0] ;
108}
109
110std::size_t GNet::DnsMessage::n() const
111{
112 return m_buffer.size() ;
113}
114
115 GNet::DnsMessage GNet::DnsMessage::empty()
116{
117 return DnsMessage() ;
118}
119
120 GNet::DnsMessage GNet::DnsMessage::request( const std::string & type , const std::string & hostname , unsigned int id )
121{
122 DnsMessageRequest r( type , hostname , id ) ;
123 return DnsMessage( r.p() , r.n() ) ;
124}
125
126std::vector<GNet::Address> GNet::DnsMessage::addresses() const
127{
128 std::vector<Address> list ;
129 for( unsigned int i = QDCOUNT() ; i < (QDCOUNT()+ANCOUNT()) ; i++ )
130 {
131 list.push_back( rrAddress(i) ) ;
132 }
133 return list ;
134}
135
136 unsigned int GNet::DnsMessage::byte( unsigned int i ) const
137{
138 char c = m_buffer.at(i) ;
139 return static_cast<unsigned char>(c) ;
140}
141
142 unsigned int GNet::DnsMessage::word( unsigned int i ) const
143{
144 return byte(i) * 256U + byte(i+1U) ;
145}
146
147std::string GNet::DnsMessage::span( unsigned int begin , unsigned int end ) const
148{
149 if( begin >= m_buffer.size() || end > m_buffer.size() || begin > end )
150 throw Error( "span error" ) ;
151 return std::string( m_buffer.begin()+begin , m_buffer.begin()+end ) ;
152}
153
154 unsigned int GNet::DnsMessage::ID() const
155{
156 return word( 0U ) ;
157}
158
159 bool GNet::DnsMessage::QR() const
160{
161 return !!( byte(2U) & 0x80 ) ;
162}
163
164 unsigned int GNet::DnsMessage::OPCODE() const
165{
166 return ( byte(2U) & 0x78 ) >> 3U ;
167}
168
169 bool GNet::DnsMessage::AA() const
170{
171 return !!( byte(2U) & 0x04 ) ;
172}
173
174 bool GNet::DnsMessage::TC() const
175{
176 return !!( byte(2U) & 0x02 ) ;
177}
178
179 bool GNet::DnsMessage::RD() const
180{
181 return !!( byte(2U) & 0x01 ) ;
182}
183
184 bool GNet::DnsMessage::RA() const
185{
186 return !!( byte(3U) & 0x80 ) ;
187}
188
189 unsigned int GNet::DnsMessage::Z() const
190{
191 return ( byte(3U) & 0x70 ) >> 4 ;
192}
193
194 unsigned int GNet::DnsMessage::RCODE() const
195{
196 return byte(3U) & 0x0f ;
197}
198
199 unsigned int GNet::DnsMessage::QDCOUNT() const
200{
201 return word(4U) ;
202}
203
204 unsigned int GNet::DnsMessage::ANCOUNT() const
205{
206 return word(6U) ;
207}
208
209 unsigned int GNet::DnsMessage::NSCOUNT() const
210{
211 return word(8U) ;
212}
213
214 unsigned int GNet::DnsMessage::ARCOUNT() const
215{
216 return word(10U) ;
217}
218
219 GNet::DnsMessage GNet::DnsMessage::rejection( const DnsMessage & message , unsigned int rcode )
220{
221 DnsMessage result( message ) ;
222 result.reject( rcode ) ;
223 return result ;
224}
225
226 void GNet::DnsMessage::reject( unsigned int rcode )
227{
228 if( m_buffer.size() < 10U )
229 throw std::out_of_range( "dns message buffer too small" ) ;
230
231 unsigned char * buffer = reinterpret_cast<unsigned char*>(&m_buffer[0]) ;
232 buffer[2U] |= 0x80U ; // QR
233 buffer[3U] &= 0xf0U ; buffer[3U] |= ( rcode & 0x0fU ) ; // RCODE
234 buffer[6U] = 0U ; buffer[7U] = 0U ; // ANCOUNT
235 buffer[8U] = 0U ; buffer[9U] = 0U ; // NSCOUNT
236
237 // chop off RRs
238 unsigned int new_size = 12U ; // HEADER size
239 for( unsigned int i = 0U ; i < QDCOUNT() ; i++ )
240 new_size += Question(*this,new_size).size() ;
241 m_buffer.resize( new_size ) ;
242}
243
244 GNet::DnsMessageQuestion GNet::DnsMessage::question( unsigned int record_index ) const
245{
246 if( record_index >= QDCOUNT() ) throw Error( "invalid record number" ) ;
247 unsigned int offset = 12U ; // HEADER size
248 for( unsigned int i = 0U ; i < record_index ; i++ )
249 offset += Question(*this,offset).size() ;
250 return Question(*this,offset) ;
251}
252
253 GNet::DnsMessageRR GNet::DnsMessage::rr( unsigned int record_index ) const
254{
255 if( record_index < QDCOUNT() ) throw Error( "invalid rr number" ) ;
256 unsigned int offset = 12U ; // HEADER size
257 for( unsigned int i = 0U ; i < record_index ; i++ )
258 {
259 if( i < QDCOUNT() )
260 offset += Question(*this,offset).size() ;
261 else
262 offset += RR(*this,offset).size() ;
263 }
264 return RR( *this , offset ) ;
265}
266
267 GNet::Address GNet::DnsMessage::rrAddress( unsigned int record_index ) const
268{
269 return rr(record_index).address() ;
270}
271
272// ==
273
274 GNet::DnsMessageQuestion::DnsMessageQuestion( const DnsMessage & msg , unsigned int offset ) :
275 m_size(0U)
276{
277 m_qname = DnsMessageNameParser::read( msg , offset ) ;
278 m_size = DnsMessageNameParser::size( msg , offset ) + 2U + 2U ; // QNAME + QTYPE + QCLASS
279}
280
281 unsigned int GNet::DnsMessageQuestion::size() const
282{
283 return m_size ;
284}
285
286std::string GNet::DnsMessageQuestion::qname() const
287{
288 return m_qname ;
289}
290
291// ==
292
293 unsigned int GNet::DnsMessageNameParser::size( const DnsMessage & msg , unsigned int offset_in )
294{
295 unsigned int offset = offset_in ;
296 for(;;)
297 {
298 unsigned int n = msg.byte( offset ) ;
299 if( ( n & 0xC0 ) == 0xC0 ) // compression -- see RFC-1035 4.1.4
300 return offset - offset_in + 2U ;
301 else if( ( n & 0xC0 ) != 0 )
302 throw GNet::DnsMessage::Error( "unknown label type" ) ; // "reserved for future use"
303 else if( n == 0U )
304 break ;
305 else
306 offset += (n+1U) ;
307 }
308 return offset - offset_in + 1U ;
309}
310
311std::string GNet::DnsMessageNameParser::read( const DnsMessage & msg , unsigned int offset_in )
312{
313 unsigned int offset = offset_in ;
314 std::vector<std::string> name ;
315 for(;;)
316 {
317 unsigned int n = msg.byte( offset ) ;
318 if( ( n & 0xC0 ) == 0xC0 )
319 {
320 unsigned int m = msg.byte(offset+1U) ;
321 offset = (n&0x3F)*256U + m ;
322 }
323 else if( ( n & 0xC0 ) != 0 )
324 {
325 throw GNet::DnsMessage::Error( "unknown label type" ) ; // "reserved for future use"
326 }
327 else if( n == 0U )
328 {
329 break ;
330 }
331 else
332 {
333 if( n > 63U )
334 throw GNet::DnsMessage::Error( "name overflow" ) ;
335
336 name.push_back( msg.span(offset+1U,offset+n+1U) ) ;
337 offset += (n+1U) ;
338 }
339 }
340 return G::Str::join( "." , name ) ;
341}
342
343// ==
344
345 GNet::DnsMessageRR::DnsMessageRR( const DnsMessage & msg , unsigned int offset ) :
346 m_msg(msg) ,
347 m_offset(offset) ,
348 m_size(0U) ,
349 m_type(0U) ,
350 m_class(0U) ,
351 m_rdata_offset(0U) ,
352 m_rdata_size(0U)
353{
354 m_name = DnsMessageNameParser::read( msg , offset ) ; // NAME
355 offset += DnsMessageNameParser::size( msg , offset ) ;
356
357 m_type = msg.word( offset ) ; offset += 2U ; // TYPE
358 m_class = msg.word( offset ) ; offset += 2U ; // CLASS
359 offset += 4U ; // TTL
360 m_rdata_size = msg.word( offset ) ; offset += 2U ; // RDLENGTH
361
362 m_rdata_offset = offset ;
363 m_size = offset - m_offset + m_rdata_size ;
364
365 if( m_class != 1U ) // "IN" (internet)
366 throw DnsMessage::Error( "invalid rr class" ) ;
367}
368
369 unsigned int GNet::DnsMessageRR::type() const
370{
371 return m_type ;
372}
373
374 bool GNet::DnsMessageRR::isa( const std::string & type_name ) const
375{
376 return m_type == DnsMessageRecordType::value(type_name) ;
377}
378
379 unsigned int GNet::DnsMessageRR::size() const
380{
381 return m_size ;
382}
383
384std::string GNet::DnsMessageRR::name() const
385{
386 return m_name ;
387}
388
389std::string GNet::DnsMessageRR::rdata_dname( unsigned int rdata_offset ) const
390{
391 return DnsMessageNameParser::read( m_msg , m_rdata_offset + rdata_offset ) ;
392}
393
394std::string GNet::DnsMessageRR::rdata_dname( unsigned int * rdata_offset_p ) const
395{
396 std::string dname = DnsMessageNameParser::read( m_msg , m_rdata_offset + *rdata_offset_p ) ;
397 *rdata_offset_p += DnsMessageNameParser::size( m_msg , m_rdata_offset + *rdata_offset_p ) ;
398 return dname ;
399}
400
401std::string GNet::DnsMessageRR::rdata_span( unsigned int rdata_begin ) const
402{
403 return rdata_span( rdata_begin , rdata_size() ) ;
404}
405
406std::string GNet::DnsMessageRR::rdata_span( unsigned int rdata_begin , unsigned int rdata_end ) const
407{
408 return m_msg.span( m_rdata_offset + rdata_begin , m_rdata_offset + rdata_end ) ;
409}
410
411 unsigned int GNet::DnsMessageRR::rdata_offset() const
412{
413 return m_rdata_offset ;
414}
415
416 unsigned int GNet::DnsMessageRR::rdata_size() const
417{
418 return m_rdata_size ;
419}
420
421 unsigned int GNet::DnsMessageRR::rdata_byte( unsigned int i ) const
422{
423 return m_msg.byte( m_rdata_offset + i ) ;
424}
425
426 unsigned int GNet::DnsMessageRR::rdata_word( unsigned int i ) const
427{
428 return m_msg.word( m_rdata_offset + i ) ;
429}
430
431 GNet::Address GNet::DnsMessageRR::address() const
432{
433 std::ostringstream ss ;
434 if( isa("A") && rdata_size() == 4U )
435 {
436 ss << rdata_byte(0U) << "." << rdata_byte(1U) << "." << rdata_byte(2U) << "." << rdata_byte(3U) << ":0" ;
437 }
438 else if( isa("AAAA") && rdata_size() == 16U )
439 {
440 const char * sep = "" ;
441 for( unsigned int i = 0 ; i < 8U ; i++ , sep = ":" )
442 ss << sep << std::hex << rdata_word(i*2U) ;
443 ss << ".0" ;
444 }
445 else
446 {
447 throw DnsMessage::Error( "not an address" ) ;
448 }
449 return Address::parse( ss.str() , Address::NotLocal() ) ;
450}
451
452// ==
453
454 namespace GNet
455{
456 //| \namespace GNet::DnsMessageRecordTypeImp
457 /// A private implementation namespace for GNet::DnsMessage.
458 namespace DnsMessageRecordTypeImp
459 {
460 struct Pair /// A std::pair-like structure used in GNet::DnsMessage, needed for gcc 4.2.1
461 {
462 unsigned int first ;
463 const char * second ;
464 } ;
465 constexpr std::array<Pair,23U> map = {{
466 { 1 , "A" } , // a host address
467 { 2 , "NS" } , // an authoritative name server
468 { 3 , "MD" } , // a mail destination (Obsolete - use MX)
469 { 4 , "MF" } , // a mail forwarder (Obsolete - use MX)
470 { 5 , "CNAME" } , // the canonical name for an alias
471 { 6 , "SOA" } , // marks the start of a zone of authority
472 { 7 , "MB" } , // a mailbox domain name (EXPERIMENTAL)
473 { 8 , "MG" } , // a mail group member (EXPERIMENTAL)
474 { 9 , "MR" } , // a mail rename domain name (EXPERIMENTAL)
475 { 10 , "NULL_" } , // a null RR (EXPERIMENTAL)
476 { 11 , "WKS" } , // a well known service description
477 { 12 , "PTR" } , // a domain name pointer
478 { 13 , "HINFO" } , // host information
479 { 14 , "MINFO" } , // mailbox or mail list information
480 { 15 , "MX" } , // mail exchange
481 { 16 , "TXT" } , // text strings
482 { 28 , "AAAA" } , // IPv6 -- RFC-3596
483 { 33 , "SRV" } , // service pointer -- RFC-2782
484 { 41 , "OPT" } , // extended options -- EDNS0 -- RFC-2671
485 { 43 , "DS" } , // delegation signer -- DNSSEC -- RFC-4034
486 { 46 , "RRSIG" } , // resource record signature -- DNSSEC -- RFC-4034
487 { 47 , "NSEC" } , // next secure -- DNSSEC -- RFC-4034
488 { 48 , "DNSKEY" } // dns public key -- DNSSEC -- RFC-4034
489 }} ;
490 }
491}
492
493 unsigned int GNet::DnsMessageRecordType::value( const std::string & type_name )
494{
495 namespace imp = DnsMessageRecordTypeImp ;
496 for( const auto & item : imp::map )
497 {
498 if( type_name == item.second )
499 return item.first ;
500 }
501 throw DnsMessage::Error( "invalid rr type name" ) ;
502}
503
504std::string GNet::DnsMessageRecordType::name( unsigned int type_value )
505{
506 namespace imp = DnsMessageRecordTypeImp ;
507 for( const auto & item : imp::map )
508 {
509 if( item.first == type_value )
510 return item.second ;
511 }
512 throw DnsMessage::Error( "invalid rr type value" ) ;
513}
514
GNet::Address
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:53
GNet::Address::parse
static Address parse(const std::string &display_string)
Factory function for any address family.
Definition: gaddress.cpp:217
GNet::Address::address
const sockaddr * address() const
Returns the sockaddr address.
Definition: gaddress.cpp:434
GNet::DnsMessageNameParser::size
static unsigned int size(const DnsMessage &msg, unsigned int)
Returns the size of the compressed name.
Definition: gdnsmessage.cpp:293
GNet::DnsMessageNameParser::read
static std::string read(const DnsMessage &msg, unsigned int)
Returns the decompressed name, made up of the labels with dots inbetween.
Definition: gdnsmessage.cpp:311
GNet::DnsMessageQuestion
Represents DNS question record.
Definition: gdnsmessage.h:231
GNet::DnsMessageQuestion::DnsMessageQuestion
DnsMessageQuestion(const DnsMessage &, unsigned int offset)
Constructor.
Definition: gdnsmessage.cpp:274
GNet::DnsMessageQuestion::qname
std::string qname() const
Returns the subject of the question.
Definition: gdnsmessage.cpp:286
GNet::DnsMessageQuestion::size
unsigned int size() const
Returns the record size.
Definition: gdnsmessage.cpp:281
GNet::DnsMessageRR
Represents DNS response record.
Definition: gdnsmessage.h:181
GNet::DnsMessageRR::type
unsigned int type() const
Returns the type value().
Definition: gdnsmessage.cpp:369
GNet::DnsMessageRR::DnsMessageRR
DnsMessageRR(const DnsMessage &, unsigned int offset)
Constructor.
Definition: gdnsmessage.cpp:345
GNet::DnsMessageRR::address
Address address() const
Returns the Address if isa(A) or isa(AAAA).
Definition: gdnsmessage.cpp:431
GNet::DnsMessageRR::size
unsigned int size() const
Returns the size.
Definition: gdnsmessage.cpp:379
GNet::DnsMessageRR::isa
bool isa(const std::string &) const
Returns true if the type() has the given name().
Definition: gdnsmessage.cpp:374
GNet::DnsMessageRR::name
std::string name() const
Returns the NAME.
Definition: gdnsmessage.cpp:384
GNet::DnsMessageRecordType::name
static std::string name(unsigned int type_value)
Returns the type name for the given type value.
Definition: gdnsmessage.cpp:504
GNet::DnsMessageRecordType::value
static unsigned int value(const std::string &type_name)
Returns the type value for the given type name.
Definition: gdnsmessage.cpp:493
GNet::DnsMessageRequest
Represents a DNS query message.
Definition: gdnsmessage.h:269
GNet::DnsMessageRequest::n
std::size_t n() const
Returns message size.
Definition: gdnsmessage.cpp:83
GNet::DnsMessageRequest::p
const char * p() const
Returns a pointer to the message data.
Definition: gdnsmessage.cpp:78
GNet::DnsMessageRequest::DnsMessageRequest
DnsMessageRequest(const std::string &type, const std::string &hostname, unsigned int id=0U)
Constructor.
Definition: gdnsmessage.cpp:32
GNet::DnsMessage
A DNS message parser, with static factory functions for message composition.
Definition: gdnsmessage.h:52
GNet::DnsMessage::rrAddress
Address rrAddress(unsigned int n) const
Returns the address in the n'th record treated as a RR record.
Definition: gdnsmessage.cpp:267
GNet::DnsMessage::ANCOUNT
unsigned int ANCOUNT() const
Returns the header ANCOUNT field, ie.
Definition: gdnsmessage.cpp:204
GNet::DnsMessage::question
Question question(unsigned int n) const
Returns the n'th record as a Question record.
Definition: gdnsmessage.cpp:244
GNet::DnsMessage::RCODE
unsigned int RCODE() const
Returns the header RCODE.
Definition: gdnsmessage.cpp:194
GNet::DnsMessage::QR
bool QR() const
Returns the header QR (query/response).
Definition: gdnsmessage.cpp:159
GNet::DnsMessage::Z
unsigned int Z() const
Returns the header Z value (zero).
Definition: gdnsmessage.cpp:189
GNet::DnsMessage::DnsMessage
DnsMessage(const std::vector< char > &buffer)
Constructor.
Definition: gdnsmessage.cpp:93
GNet::DnsMessage::QDCOUNT
unsigned int QDCOUNT() const
Returns the header QDCOUNT field, ie.
Definition: gdnsmessage.cpp:199
GNet::DnsMessage::n
std::size_t n() const
Returns the raw data size.
Definition: gdnsmessage.cpp:110
GNet::DnsMessage::NSCOUNT
unsigned int NSCOUNT() const
Returns the header NSCOUNT field, ie.
Definition: gdnsmessage.cpp:209
GNet::DnsMessage::ARCOUNT
unsigned int ARCOUNT() const
Returns the header ARCOUNT field, ie.
Definition: gdnsmessage.cpp:214
GNet::DnsMessage::AA
bool AA() const
Returns the header AA flag (authorative).
Definition: gdnsmessage.cpp:169
GNet::DnsMessage::p
const char * p() const
Returns the raw data.
Definition: gdnsmessage.cpp:105
GNet::DnsMessage::OPCODE
unsigned int OPCODE() const
Returns the header OPCODE.
Definition: gdnsmessage.cpp:164
GNet::DnsMessage::rejection
static DnsMessage rejection(const DnsMessage &request, unsigned int rcode)
Factory function for a failure response based on the given request message.
Definition: gdnsmessage.cpp:219
GNet::DnsMessage::TC
bool TC() const
Returns the header TC flag (truncated).
Definition: gdnsmessage.cpp:174
GNet::DnsMessage::request
static DnsMessage request(const std::string &type, const std::string &hostname, unsigned int id=0U)
Factory function for a request message of the give type ("A", "AAAA", etc).
Definition: gdnsmessage.cpp:120
GNet::DnsMessage::span
std::string span(unsigned int begin, unsigned int end) const
Returns the data in the given half-open byte range.
Definition: gdnsmessage.cpp:147
GNet::DnsMessage::byte
unsigned int byte(unsigned int byte_index) const
Returns byte at the given offset.
Definition: gdnsmessage.cpp:136
GNet::DnsMessage::addresses
std::vector< Address > addresses() const
Returns the Answer addresses.
Definition: gdnsmessage.cpp:126
GNet::DnsMessage::RD
bool RD() const
Returns the header RD (recursion desired).
Definition: gdnsmessage.cpp:179
GNet::DnsMessage::empty
static DnsMessage empty()
Factory function for an unusable object.
Definition: gdnsmessage.cpp:115
GNet::DnsMessage::ID
unsigned int ID() const
Returns the header ID.
Definition: gdnsmessage.cpp:154
GNet::DnsMessage::RA
bool RA() const
Returns the header RA (recursion available).
Definition: gdnsmessage.cpp:184
GNet::DnsMessage::rr
RR rr(unsigned int n) const
Returns the n'th record as a RR record.
Definition: gdnsmessage.cpp:253
GNet::DnsMessage::word
unsigned int word(unsigned int byte_index) const
Returns word at the given byte offset.
Definition: gdnsmessage.cpp:142
G::Str::join
static std::string join(const std::string &sep, const StringArray &strings)
Concatenates an array of strings with separators.
Definition: gstr.cpp:1195
G::Str::splitIntoFields
static void splitIntoFields(const std::string &in, StringArray &out, string_view ws, char escape='\0', bool remove_escapes=true)
Splits the string into fields.
Definition: gstr.cpp:1146
gassert.h
gdnsmessage.h
gstr.h
gstringview.h
GNet
Network classes.
Definition: gdef.h:1115
G::StringArray
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstrings.h:31
G::hostname
std::string hostname()
Returns the hostname.
Definition: ghostname_unix.cpp:27
GNet::Address::NotLocal
Overload discriminator for Address::parse()
Definition: gaddress.h:113
GNet::DnsMessageRecordTypeImp::Pair
A std::pair-like structure used in GNet::DnsMessage, needed for gcc 4.2.1.
Definition: gdnsmessage.cpp:461