36 G_ASSERT(
id < 0xffffU ) ;
51void GNet::DnsMessageRequest::addDomainName(
const std::string & domain ,
char sep )
53 std::string_view domain_sv( domain ) ;
58 addLabel( std::string_view() ) ;
61void GNet::DnsMessageRequest::addLabel( std::string_view data )
63 if( data.size() > 63U )
throw DnsMessage::Error(
"overflow") ;
64 addByte(
static_cast<unsigned int>(data.size()) ) ;
66 m_data.append( data.data() , data.size() ) ;
69void GNet::DnsMessageRequest::addWord(
unsigned int n )
71 addByte( (n >> 8) & 0xFFU ) ;
72 addByte( (n >> 0) & 0xFFU ) ;
75void GNet::DnsMessageRequest::addByte(
unsigned int n )
77 m_data.append( 1U ,
static_cast<char>(
static_cast<unsigned char>(n)) ) ;
82 return m_data.data() ;
87 return m_data.size() ;
92GNet::DnsMessage::DnsMessage()
107 return m_buffer.size() >= 12U && !TC() ;
112 return m_buffer.data() ;
117 return m_buffer.size() ;
130 return { r.
p() , r.
n() } ;
135 std::vector<Address> list ;
136 for(
unsigned int i = QDCOUNT() ; i < (QDCOUNT()+ANCOUNT()) ; i++ )
138 list.push_back( rrAddress(i) ) ;
145 if( i > m_buffer.size() )
146 throw Error(
"invalid offset: " + std::to_string(i) +
"/" + std::to_string(m_buffer.size()) ) ;
147 char c = m_buffer.at( i ) ;
148 return static_cast<unsigned char>(c) ;
153 return byte(i) * 256U + byte(i+1U) ;
158 if( begin >= m_buffer.size() || end > m_buffer.size() || begin > end )
159 throw Error(
"invalid span" ) ;
160 return { m_buffer.begin()+begin , m_buffer.begin()+end } ;
170 return !!( byte(2U) & 0x80 ) ;
175 return (
byte(2U) & 0x78 ) >> 3U ;
180 return !!( byte(2U) & 0x04 ) ;
185 return !!( byte(2U) & 0x02 ) ;
191 return !!( byte(2U) & 0x01 ) ;
198 return !!( byte(3U) & 0x80 ) ;
205 return (
byte(3U) & 0x70 ) >> 4 ;
211 return byte(3U) & 0x0f ;
241 result.convertToResponse( rcode ,
false ) ;
245void GNet::DnsMessage::convertToResponse(
unsigned int rcode ,
bool authoritative )
247 if( m_buffer.size() < 10U || QDCOUNT() == 0U || OPCODE() != 0U )
248 throw Error(
"cannot convert" ) ;
251 unsigned char * buffer =
reinterpret_cast<unsigned char*
>( m_buffer.data() ) ;
252 buffer[2U] |= 0x80U ;
253 if( authoritative ) buffer[2U] |= 0x04U ;
254 buffer[3U] &= 0xf0U ; buffer[3U] |= ( rcode & 0x0fU ) ;
255 buffer[6U] = 0U ; buffer[7U] = 0U ;
256 buffer[8U] = 0U ; buffer[9U] = 0U ;
257 buffer[10U] = 0U ; buffer[11U] = 0U ;
260 unsigned int new_size = 12U ;
261 for(
unsigned int i = 0U ; i < QDCOUNT() ; i++ )
262 new_size += Question(*
this,new_size).size() ;
265 m_buffer.resize( new_size ) ;
268void GNet::DnsMessage::addWord(
unsigned int n )
270 addByte( (n >> 8) & 0xFFU ) ;
271 addByte( (n >> 0) & 0xFFU ) ;
274void GNet::DnsMessage::addByte(
unsigned int n )
276 m_buffer.push_back(
static_cast<char>(
static_cast<unsigned char>(n)) ) ;
281 if( record_index >= QDCOUNT() )
282 throw Error(
"invalid record number" ) ;
284 unsigned int offset = 12U ;
285 for(
unsigned int i = 0U ; i < record_index ; i++ )
287 return { *this , offset } ;
292 if( record_index < QDCOUNT() )
293 throw Error(
"invalid rr number" ) ;
295 unsigned int offset = 12U ;
296 for(
unsigned int i = 0U ; i < record_index ; i++ )
301 offset +=
RR(*
this,offset).
size() ;
303 return { *this , offset } ;
308 return rr(record_index).
address() ;
317 m_qtype = msg.
word( offset + qname_size ) ;
318 m_qclass = msg.
word( offset + qname_size + 2U ) ;
319 m_size = qname_size + 2U + 2U ;
348 unsigned int offset = offset_in ;
351 unsigned int n = msg.
byte( offset ) ;
352 if( ( n & 0xC0 ) == 0xC0 )
353 return offset - offset_in + 2U ;
354 else if( ( n & 0xC0 ) != 0 )
355 throw DnsMessage::Error(
"unknown label type" ) ;
361 return offset - offset_in + 1U ;
366 unsigned int offset = offset_in ;
370 unsigned int n = msg.
byte( offset ) ;
371 if( ( n & 0xC0U ) == 0xC0U )
373 unsigned int m = msg.
byte(offset+1U) ;
374 offset = (n&0x3FU)*256U + m ;
375 if( offset > offset_in )
376 throw DnsMessage::Error(
"invalid label" ) ;
378 else if( ( n & 0xC0U ) != 0U )
380 throw DnsMessage::Error(
"unknown label type" ) ;
389 throw DnsMessage::Error(
"name overflow" ) ;
391 result.append( result.empty()?0U:1U ,
'.' ) ;
392 result.append( msg.
span(offset+1U,offset+n+1U) ) ;
414 m_size =
offset - m_offset + m_rdata_size ;
417 throw DnsMessage::Error(
"invalid rr class" ) ;
451std::string GNet::DnsMessageRR::rdataDname(
unsigned int rdata_offset )
const
457std::string GNet::DnsMessageRR::rdataDname(
unsigned int * rdata_offset_p )
const
466std::string GNet::DnsMessageRR::rdataSpan(
unsigned int rdata_begin )
const
468 return rdataSpan( rdata_begin , rdataSize() ) ;
472std::string GNet::DnsMessageRR::rdataSpan(
unsigned int rdata_begin ,
unsigned int rdata_end )
const
474 return m_msg.span( m_rdata_offset + rdata_begin , m_rdata_offset + rdata_end ) ;
478unsigned int GNet::DnsMessageRR::rdataOffset()
const
480 return m_rdata_offset ;
484unsigned int GNet::DnsMessageRR::rdataSize()
const
486 return m_rdata_size ;
489unsigned int GNet::DnsMessageRR::rdataByte(
unsigned int i )
const
491 return m_msg.byte( m_rdata_offset + i ) ;
494unsigned int GNet::DnsMessageRR::rdataWord(
unsigned int i )
const
496 return m_msg.word( m_rdata_offset + i ) ;
502 return addressImp( port , ok ) ;
508 auto a = addressImp( port , ok ) ;
510 throw DnsMessage::Error(
"not an address" ) ;
514GNet::Address GNet::DnsMessageRR::addressImp(
unsigned int port ,
bool & ok )
const
516 std::ostringstream ss ;
517 if( isa(
"A") && rdataSize() == 4U )
519 ss << rdataByte(0U) <<
"." << rdataByte(1U) <<
"." << rdataByte(2U) <<
"." << rdataByte(3U) <<
":" << port ;
521 else if( isa(
"AAAA") && rdataSize() == 16U )
523 const char * sep =
"" ;
524 for(
unsigned int i = 0 ; i < 8U ; i++ , sep =
":" )
525 ss << sep << std::hex << rdataWord(i*2U) ;
529 return ok ?
Address::parse( ss.str() , Address::NotLocal() ) : Address::defaultAddress() ;
536 namespace DnsMessageRecordTypeImp
541 const char * second ;
543 constexpr std::array<Pair,23U> map = {{
573 namespace imp = DnsMessageRecordTypeImp ;
574 for(
const auto & item : imp::map )
584 unsigned int v = value( type_name , std::nothrow ) ;
586 throw DnsMessage::Error(
"invalid rr type name" ) ;
592 namespace imp = DnsMessageRecordTypeImp ;
593 for(
const auto & item : imp::map )
595 if( item.first == type_value )
598 throw DnsMessage::Error(
"invalid rr type value" ) ;
The GNet::Address class encapsulates a TCP/UDP transport address.
static bool validString(std::string_view display_string, std::string *reason=nullptr)
Returns true if the transport-address display string is valid.
static Address parse(std::string_view display_string)
Factory function for any address family.
const sockaddr * address() const
Returns the sockaddr address.
static unsigned int size(const DnsMessage &msg, unsigned int)
Returns the size of the compressed name at the given offset.
static std::string read(const DnsMessage &msg, unsigned int)
Returns the decompressed domain name at the given offset, made up of the labels with dots inbetween.
Represents DNS question record.
DnsMessageQuestion(const DnsMessage &, unsigned int offset)
Constructor.
unsigned int qtype() const
Returns the question QTYPE value.
std::string qname() const
Returns the question domain name (QNAME).
unsigned int size() const
Returns the record size.
unsigned int qclass() const
Returns the question QCLASS value.
unsigned int offset() const
Calls rdataOffset().
Represents DNS response record.
unsigned int type() const
Returns the RR TYPE value().
unsigned int class_() const
Returns the RR CLASS value().
DnsMessageRR(const DnsMessage &, unsigned int offset)
Constructor from DnsMessage data.
unsigned int size() const
Returns the size of the RR.
Address address(unsigned int port=0U) const
Returns the Address if isa(A) or isa(AAAA).
bool isa(std::string_view) const noexcept
Returns true if the type() has the given name().
std::string name() const
Returns the RR NAME.
static unsigned int value(std::string_view type_name)
Returns the type value for the given type name.
static std::string name(unsigned int type_value)
Returns the type name for the given type value.
Represents a DNS query message.
std::size_t n() const
Returns message size.
const char * p() const
Returns a pointer to the message data.
DnsMessageRequest(const std::string &type, const std::string &hostname, unsigned int id=0U)
Constructor.
A DNS message parser, with static factory functions for message composition.
Address rrAddress(unsigned int n) const
Returns the address in the n'th record.
unsigned int ANCOUNT() const
Returns the header ANCOUNT field, ie.
const char * p() const noexcept
Returns the raw data.
Question question(unsigned int n) const
Returns the n'th record as a Question record.
unsigned int RCODE() const
Returns the header RCODE.
bool QR() const
Returns the header QR (query/response).
bool valid() const
Returns true if the message data is big enough for a header and its TC() flag is false.
unsigned int Z() const
Returns the header Z value (zero).
DnsMessage(const std::vector< char > &buffer)
Constructor. Check with valid().
unsigned int QDCOUNT() const
Returns the header QDCOUNT field, ie.
unsigned int NSCOUNT() const
Returns the header NSCOUNT field, ie.
unsigned int ARCOUNT() const
Returns the header ARCOUNT field, ie.
bool AA() const
Returns the header AA flag (authorative).
unsigned int OPCODE() const
Returns the header OPCODE.
static DnsMessage rejection(const DnsMessage &request, unsigned int rcode)
Factory function for a failure response based on the given request message.
bool TC() const
Returns the header TC flag (truncated).
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).
std::string span(unsigned int begin, unsigned int end) const
Returns the data in the given half-open byte range.
unsigned int byte(unsigned int byte_index) const
Returns byte at the given offset.
std::vector< Address > addresses() const
Returns the Answer addresses.
bool RD() const
Returns the header RD (recursion desired).
static DnsMessage empty()
Factory function for an unusable object.
unsigned int ID() const
Returns the header ID.
bool RA() const
Returns the header RA (recursion available).
RR rr(unsigned int n) const
Returns the n'th record as a RR record.
unsigned int word(unsigned int byte_index) const
Returns word at the given byte offset.
std::size_t n() const noexcept
Returns the raw data size.
static bool match(std::string_view, std::string_view) noexcept
Returns true if the two strings are the same.
A zero-copy string field iterator where the field separators are short fixed strings.
std::string hostname()
Returns the hostname.