35 G_ASSERT(
id < 0xffffU ) ;
36 q( (
id>>8U)&0xff ) ; q(
id&0xff ) ;
39 q( 0x00 ) ; q( 0x01 ) ;
40 q( 0x00 ) ; q( 0x00 ) ;
41 q( 0x00 ) ; q( 0x00 ) ;
42 q( 0x00 ) ; q( 0x00 ) ;
47 q( 0x00 ) ; q( 0x01 ) ;
50void GNet::DnsMessageRequest::q(
const std::string & domain ,
char sep )
54 for(
const auto & part : parts )
61void GNet::DnsMessageRequest::q(
const std::string & data )
63 if( data.size() > 63U )
throw DnsMessage::Error(
"overflow") ;
64 q(
static_cast<unsigned int>(data.size()) ) ;
65 m_data.append( data ) ;
68void GNet::DnsMessageRequest::q(
int n )
70 q(
static_cast<unsigned int>(n) ) ;
73void GNet::DnsMessageRequest::q(
unsigned int n )
75 m_data.append( 1U ,
static_cast<char>(n) ) ;
80 return m_data.data() ;
85 return m_data.size() ;
90GNet::DnsMessage::DnsMessage()
97 throw Error(
"truncated response" ) ;
107 return &m_buffer[0] ;
112 return m_buffer.size() ;
128 std::vector<Address> list ;
129 for(
unsigned int i = QDCOUNT() ; i < (QDCOUNT()+ANCOUNT()) ; i++ )
131 list.push_back( rrAddress(i) ) ;
138 char c = m_buffer.at(i) ;
139 return static_cast<unsigned char>(c) ;
144 return byte(i) * 256U + byte(i+1U) ;
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 ) ;
161 return !!( byte(2U) & 0x80 ) ;
166 return (
byte(2U) & 0x78 ) >> 3U ;
171 return !!( byte(2U) & 0x04 ) ;
176 return !!( byte(2U) & 0x02 ) ;
181 return !!( byte(2U) & 0x01 ) ;
186 return !!( byte(3U) & 0x80 ) ;
191 return (
byte(3U) & 0x70 ) >> 4 ;
196 return byte(3U) & 0x0f ;
222 result.reject( rcode ) ;
226void GNet::DnsMessage::reject(
unsigned int rcode )
228 if( m_buffer.size() < 10U )
229 throw std::out_of_range(
"dns message buffer too small" ) ;
231 unsigned char * buffer =
reinterpret_cast<unsigned char*
>(&m_buffer[0]) ;
232 buffer[2U] |= 0x80U ;
233 buffer[3U] &= 0xf0U ; buffer[3U] |= ( rcode & 0x0fU ) ;
234 buffer[6U] = 0U ; buffer[7U] = 0U ;
235 buffer[8U] = 0U ; buffer[9U] = 0U ;
238 unsigned int new_size = 12U ;
239 for(
unsigned int i = 0U ; i < QDCOUNT() ; i++ )
240 new_size += Question(*
this,new_size).size() ;
241 m_buffer.resize( new_size ) ;
246 if( record_index >= QDCOUNT() )
throw Error(
"invalid record number" ) ;
247 unsigned int offset = 12U ;
248 for(
unsigned int i = 0U ; i < record_index ; i++ )
255 if( record_index < QDCOUNT() )
throw Error(
"invalid rr number" ) ;
256 unsigned int offset = 12U ;
257 for(
unsigned int i = 0U ; i < record_index ; i++ )
262 offset +=
RR(*
this,offset).
size() ;
264 return RR( *
this , offset ) ;
269 return rr(record_index).
address() ;
295 unsigned int offset = offset_in ;
298 unsigned int n = msg.
byte( offset ) ;
299 if( ( n & 0xC0 ) == 0xC0 )
300 return offset - offset_in + 2U ;
301 else if( ( n & 0xC0 ) != 0 )
302 throw GNet::DnsMessage::Error(
"unknown label type" ) ;
308 return offset - offset_in + 1U ;
313 unsigned int offset = offset_in ;
314 std::vector<std::string> name ;
317 unsigned int n = msg.
byte( offset ) ;
318 if( ( n & 0xC0 ) == 0xC0 )
320 unsigned int m = msg.
byte(offset+1U) ;
321 offset = (n&0x3F)*256U + m ;
323 else if( ( n & 0xC0 ) != 0 )
325 throw GNet::DnsMessage::Error(
"unknown label type" ) ;
334 throw GNet::DnsMessage::Error(
"name overflow" ) ;
336 name.push_back( msg.
span(offset+1U,offset+n+1U) ) ;
357 m_type = msg.
word( offset ) ; offset += 2U ;
358 m_class = msg.
word( offset ) ; offset += 2U ;
360 m_rdata_size = msg.
word( offset ) ; offset += 2U ;
362 m_rdata_offset = offset ;
363 m_size = offset - m_offset + m_rdata_size ;
366 throw DnsMessage::Error(
"invalid rr class" ) ;
389std::string GNet::DnsMessageRR::rdata_dname(
unsigned int rdata_offset )
const
394std::string GNet::DnsMessageRR::rdata_dname(
unsigned int * rdata_offset_p )
const
401std::string GNet::DnsMessageRR::rdata_span(
unsigned int rdata_begin )
const
403 return rdata_span( rdata_begin , rdata_size() ) ;
406std::string GNet::DnsMessageRR::rdata_span(
unsigned int rdata_begin ,
unsigned int rdata_end )
const
408 return m_msg.span( m_rdata_offset + rdata_begin , m_rdata_offset + rdata_end ) ;
411unsigned int GNet::DnsMessageRR::rdata_offset()
const
413 return m_rdata_offset ;
416unsigned int GNet::DnsMessageRR::rdata_size()
const
418 return m_rdata_size ;
421unsigned int GNet::DnsMessageRR::rdata_byte(
unsigned int i )
const
423 return m_msg.byte( m_rdata_offset + i ) ;
426unsigned int GNet::DnsMessageRR::rdata_word(
unsigned int i )
const
428 return m_msg.word( m_rdata_offset + i ) ;
433 std::ostringstream ss ;
434 if( isa(
"A") && rdata_size() == 4U )
436 ss << rdata_byte(0U) <<
"." << rdata_byte(1U) <<
"." << rdata_byte(2U) <<
"." << rdata_byte(3U) <<
":0" ;
438 else if( isa(
"AAAA") && rdata_size() == 16U )
440 const char * sep =
"" ;
441 for(
unsigned int i = 0 ; i < 8U ; i++ , sep =
":" )
442 ss << sep << std::hex << rdata_word(i*2U) ;
447 throw DnsMessage::Error(
"not an address" ) ;
458 namespace DnsMessageRecordTypeImp
463 const char * second ;
465 constexpr std::array<Pair,23U> map = {{
495 namespace imp = DnsMessageRecordTypeImp ;
496 for(
const auto & item : imp::map )
498 if( type_name == item.second )
501 throw DnsMessage::Error(
"invalid rr type name" ) ;
506 namespace imp = DnsMessageRecordTypeImp ;
507 for(
const auto & item : imp::map )
509 if( item.first == type_value )
512 throw DnsMessage::Error(
"invalid rr type value" ) ;
The GNet::Address class encapsulates a TCP/UDP transport address.
static Address parse(const std::string &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.
static std::string read(const DnsMessage &msg, unsigned int)
Returns the decompressed name, made up of the labels with dots inbetween.
Represents DNS question record.
DnsMessageQuestion(const DnsMessage &, unsigned int offset)
Constructor.
std::string qname() const
Returns the subject of the question.
unsigned int size() const
Returns the record size.
Represents DNS response record.
unsigned int type() const
Returns the type value().
DnsMessageRR(const DnsMessage &, unsigned int offset)
Constructor.
Address address() const
Returns the Address if isa(A) or isa(AAAA).
unsigned int size() const
Returns the size.
bool isa(const std::string &) const
Returns true if the type() has the given name().
std::string name() const
Returns the NAME.
static std::string name(unsigned int type_value)
Returns the type name for the given type value.
static unsigned int value(const std::string &type_name)
Returns the type value for the given type name.
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 treated as a RR record.
unsigned int ANCOUNT() const
Returns the header ANCOUNT field, ie.
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).
unsigned int Z() const
Returns the header Z value (zero).
DnsMessage(const std::vector< char > &buffer)
Constructor.
unsigned int QDCOUNT() const
Returns the header QDCOUNT field, ie.
std::size_t n() const
Returns the raw data size.
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).
const char * p() const
Returns the raw data.
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.
static std::string join(const std::string &sep, const StringArray &strings)
Concatenates an array of strings with separators.
static void splitIntoFields(const std::string &in, StringArray &out, string_view ws, char escape='\0', bool remove_escapes=true)
Splits the string into fields.
std::vector< std::string > StringArray
A std::vector of std::strings.
std::string hostname()
Returns the hostname.
Overload discriminator for Address::parse()
A std::pair-like structure used in GNet::DnsMessage, needed for gcc 4.2.1.