E-MailRelay

gdnsmessage.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 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.h
19///
20
21#ifndef G_NET_DNS_MESSAGE_H
22#define G_NET_DNS_MESSAGE_H
23
24#include "gdef.h"
25#include "gexception.h"
26#include "gaddress.h"
27#include "gstringview.h"
28#include <vector>
29#include <utility>
30#include <string>
31#include <map>
32#include <new>
33
34 namespace GNet
35{
36 class DnsMessage ;
37 class DnsMessageRR ;
38 class DnsMessageRecordType ;
39 class DnsMessageQuestion ;
40 class DnsMessageNameParser ;
41 class DnsMessageRequest ;
42 class DnsMessageRRData ;
43 class DnsMessageDumper ;
44 class DnsMessageBuilder ;
45}
46
47//| \class GNet::DnsMessage
48/// A DNS message parser, with static factory functions for message composition.
49/// A DnsMessage contains a Header and four sections: Question, Answer, Authority
50/// and Additional. The Question section contains Question records (DnsMessageQuestion)
51/// while the Answer, Authority and Additional sections contain RR records
52/// (DnsMessageRR). Each RR has a standard header followed by RDATA.
53/// \see RFC-1035
54///
55 class GNet::DnsMessage
56{
57 public:
58 G_EXCEPTION( Error , tx("dns message error") )
59 using Question = DnsMessageQuestion ;
60 using RR = DnsMessageRR ;
61
62 explicit DnsMessage( const std::vector<char> & buffer ) ;
63 ///< Constructor. Check with valid().
64
65 DnsMessage( const char * , std::size_t ) ;
66 ///< Constructor. Check with valid().
67
68 bool valid() const ;
69 ///< Returns true if the message data is big enough
70 ///< for a header and its TC() flag is false.
71
72 std::vector<Address> addresses() const ;
73 ///< Returns the Answer addresses.
74
75 unsigned int ID() const ;
76 ///< Returns the header ID.
77
78 bool QR() const ;
79 ///< Returns the header QR (query/response).
80
81 unsigned int OPCODE() const ;
82 ///< Returns the header OPCODE.
83
84 bool AA() const ;
85 ///< Returns the header AA flag (authorative).
86
87 bool TC() const ;
88 ///< Returns the header TC flag (truncated).
89
90 bool RD() const ;
91 ///< Returns the header RD (recursion desired).
92
93 bool RA() const ;
94 ///< Returns the header RA (recursion available).
95
96 unsigned int Z() const ;
97 ///< Returns the header Z value (zero).
98
99 unsigned int RCODE() const ;
100 ///< Returns the header RCODE.
101
102 unsigned int QDCOUNT() const ;
103 ///< Returns the header QDCOUNT field, ie. the number of
104 ///< records in the Question section.
105
106 unsigned int ANCOUNT() const ;
107 ///< Returns the header ANCOUNT field, ie. the number of
108 ///< RR records in the Answer section.
109
110 unsigned int NSCOUNT() const ;
111 ///< Returns the header NSCOUNT field, ie. the number of
112 ///< RR records in the Authority section.
113
114 unsigned int ARCOUNT() const ;
115 ///< Returns the header ARCOUNT field, ie. the number of
116 ///< RR records in the Additional section.
117
118 unsigned int recordCount() const ;
119 ///< Returns QDCOUNT()+ANCOUNT()+NSCOUNT()+ARCOUNT().
120
121 Question question( unsigned int n ) const ;
122 ///< Returns the n'th record as a Question record.
123 ///< Precondition: n < QDCOUNT()
124
125 RR rr( unsigned int n ) const ;
126 ///< Returns the n'th record as a RR record. The returned
127 ///< object retains a reference to this DnsMessage, so
128 ///< prefer rrAddress().
129 ///< Precondition: n >= QDCOUNT() && n < recordCount()
130
131 Address rrAddress( unsigned int n ) const ;
132 ///< Returns the address in the n'th record.
133 ///< Throws if not A or AAAA.
134 ///< Precondition: n >= QDCOUNT()
135
136 const char * p() const noexcept ;
137 ///< Returns the raw data.
138
139 std::size_t n() const noexcept ;
140 ///< Returns the raw data size.
141
142 unsigned int byte( unsigned int byte_index ) const ;
143 ///< Returns byte at the given offset.
144
145 unsigned int word( unsigned int byte_index ) const ;
146 ///< Returns word at the given byte offset.
147
148 std::string span( unsigned int begin , unsigned int end ) const ;
149 ///< Returns the data in the given half-open byte range.
150
151 static DnsMessage request( const std::string & type , const std::string & hostname , unsigned int id = 0U ) ;
152 ///< Factory function for a request message of the give type
153 ///< ("A", "AAAA", etc). The type name is interpreted by
154 ///< DnsMessageRecordType::value().
155
156 static DnsMessage rejection( const DnsMessage & request , unsigned int rcode ) ;
157 ///< Factory function for a failure response based on the given
158 ///< request message.
159
160 static DnsMessage response( const DnsMessage & request , const Address & address ) ;
161 ///< Factory function for an answer response based on the given
162 ///< request message.
163
164 static DnsMessage empty() ;
165 ///< Factory function for an unusable object. Most methods will
166 ///< throw, except n() will return zero.
167
168 private:
169 friend class DnsMessageDumper ;
170 DnsMessage() ;
171 friend class DnsMessageBuilder ;
172 void convertToResponse( unsigned int rcode , bool authoritative ) ;
173 void addByte( unsigned int ) ;
174 void addWord( unsigned int ) ;
175
176 private:
177 std::vector<char> m_buffer ;
178} ;
179
180//| \class GNet::DnsMessageRecordType
181/// A static class for mapping between a RR type name, such as "AAAA",
182/// and its corresponding numeric value.
183///
184 class GNet::DnsMessageRecordType
185{
186 public:
187 static unsigned int value( std::string_view type_name ) ;
188 ///< Returns the type value for the given type name.
189 ///< Throws on error.
190
191 static unsigned int value( std::string_view type_name , std::nothrow_t ) noexcept ;
192 ///< Returns the type value for the given type name,
193 ///< or zero on error.
194
195 static std::string name( unsigned int type_value ) ;
196 ///< Returns the type name for the given type value.
197
198 public:
199 DnsMessageRecordType() = delete ;
200} ;
201
202//| \class GNet::DnsMessageRRData
203/// A trivial mix-in base class that simplifies method names
204/// when accessing data from a DnsMessageRR derived class.
205///
206 class GNet::DnsMessageRRData
207{
208 public:
209 unsigned int byte( unsigned int offset ) const ;
210 ///< Calls rdataByte().
211
212 unsigned int word( unsigned int offset ) const ;
213 ///< Calls rdataWord().
214
215 std::string span( unsigned int begin , unsigned int end ) const ;
216 ///< Calls rdataSpan().
217
218 std::string span( unsigned int begin ) const ;
219 ///< Calls rdataSpan().
220
221 std::string dname( unsigned int rdata_offset ) const ;
222 ///< Calls rdataDname().
223
224 std::string dname( unsigned int * rdata_offset_inout_p ) const ;
225 ///< Calls rdataDname().
226
227 unsigned int offset() const ;
228 ///< Calls rdataOffset().
229
230 unsigned int size() const ;
231 ///< Calls rdataSize().
232
233 protected:
234 DnsMessageRRData() = default ;
235} ;
236
237//| \class GNet::DnsMessageRR
238/// Represents DNS response record.
239///
240 class GNet::DnsMessageRR : private DnsMessageRRData
241{
242 public:
243 using RR = DnsMessageRR ;
244
245 public:
246 DnsMessageRR( const DnsMessage & , unsigned int offset ) ;
247 ///< Constructor from DnsMessage data. Keeps the
248 ///< DnsMessage reference, which is then passed
249 ///< to copies.
250
251 bool isa( std::string_view ) const noexcept ;
252 ///< Returns true if the type() has the given name().
253
254 unsigned int type() const ;
255 ///< Returns the RR TYPE value().
256
257 unsigned int class_() const ;
258 ///< Returns the RR CLASS value().
259
260 unsigned int size() const ;
261 ///< Returns the size of the RR.
262
263 std::string name() const ;
264 ///< Returns the RR NAME.
265
266 Address address( unsigned int port = 0U ) const ;
267 ///< Returns the Address if isa(A) or isa(AAAA).
268 ///< Throws if not A or AAAA.
269
270 Address address( unsigned int port , std::nothrow_t ) const ;
271 ///< Returns the Address if isa(A) or isa(AAAA).
272 ///< Returns Address::defaultAddress() (with a zero
273 ///< port number) if not valid.
274
275 const DnsMessageRRData & rdata() const ;
276 ///< Provides access to the message RDATA.
277
278 public:
279 ~DnsMessageRR() = default ;
280 DnsMessageRR( const DnsMessageRR & ) = default ;
281 DnsMessageRR( DnsMessageRR && ) = default ;
282 DnsMessageRR & operator=( const DnsMessageRR & ) = delete ;
283 DnsMessageRR & operator=( DnsMessageRR && ) = delete ;
284
285 private:
286 friend class GNet::DnsMessageRRData ;
287 std::string rdataDname( unsigned int rdata_offset ) const ;
288 std::string rdataDname( unsigned int * rdata_offset_inout_p ) const ;
289 std::string rdataSpan( unsigned int begin ) const ;
290 std::string rdataSpan( unsigned int begin , unsigned int end ) const ;
291 unsigned int rdataOffset() const ;
292 unsigned int rdataSize() const ;
293 unsigned int rdataByte( unsigned int offset ) const ;
294 unsigned int rdataWord( unsigned int offset ) const ;
295 GNet::Address addressImp( unsigned int port , bool & ok ) const ;
296
297 private:
298 const DnsMessage & m_msg ; // NOLINT cppcoreguidelines-avoid-const-or-ref-data-members
299 unsigned int m_offset {0U} ;
300 unsigned int m_size {0U} ;
301 unsigned int m_type {0U} ;
302 unsigned int m_class {0U} ;
303 unsigned int m_rdata_offset {0U} ;
304 unsigned int m_rdata_size {0U} ;
305 std::string m_name ;
306} ;
307
308//| \class GNet::DnsMessageQuestion
309/// Represents DNS question record.
310///
311 class GNet::DnsMessageQuestion
312{
313 public:
314 DnsMessageQuestion( const DnsMessage & , unsigned int offset ) ;
315 ///< Constructor.
316
317 unsigned int size() const ;
318 ///< Returns the record size.
319
320 unsigned int qtype() const ;
321 ///< Returns the question QTYPE value.
322
323 unsigned int qclass() const ;
324 ///< Returns the question QCLASS value.
325
326 std::string qname() const ;
327 ///< Returns the question domain name (QNAME).
328
329 private:
330 unsigned int m_size {0U} ;
331 unsigned int m_qtype {0U} ;
332 unsigned int m_qclass {0U} ;
333 std::string m_qname ;
334} ;
335
336//| \class GNet::DnsMessageNameParser
337/// An implementation class used by GNet::DnsMessage to parse
338/// compressed domain names.
339///
340 class GNet::DnsMessageNameParser
341{
342 public:
343 static unsigned int size( const DnsMessage & msg , unsigned int ) ;
344 ///< Returns the size of the compressed name at the given offset.
345
346 static std::string read( const DnsMessage & msg , unsigned int ) ;
347 ///< Returns the decompressed domain name at the given offset,
348 ///< made up of the labels with dots inbetween.
349
350 public:
351 DnsMessageNameParser() = delete ;
352} ;
353
354//| \class GNet::DnsMessageRequest
355/// Represents a DNS query message.
356///
357 class GNet::DnsMessageRequest
358{
359 public:
360 using RR = DnsMessageRR ;
361
362 DnsMessageRequest( const std::string & type , const std::string & hostname , unsigned int id = 0U ) ;
363 ///< Constructor.
364
365 const char * p() const ;
366 ///< Returns a pointer to the message data.
367
368 std::size_t n() const ;
369 ///< Returns message size.
370
371 private:
372 void addDomainName( const std::string & domain , char sep ) ;
373 void addLabel( std::string_view ) ;
374 void addWord( unsigned int ) ;
375 void addByte( unsigned int ) ;
376
377 private:
378 std::string m_data ;
379} ;
380
381 inline
382 const GNet::DnsMessageRRData & GNet::DnsMessageRR::rdata() const
383{
384 return *this ;
385}
386
387 inline
388std::string GNet::DnsMessageRRData::dname( unsigned int offset ) const
389{
390 return static_cast<const DnsMessageRR *>(this)->rdataDname( offset ) ;
391}
392
393 inline
394std::string GNet::DnsMessageRRData::dname( unsigned int * offset_inout_p ) const
395{
396 return static_cast<const DnsMessageRR *>(this)->rdataDname( offset_inout_p ) ;
397}
398
399 inline
400std::string GNet::DnsMessageRRData::span( unsigned int begin ) const
401{
402 return static_cast<const DnsMessageRR *>(this)->rdataSpan( begin ) ;
403}
404
405 inline
406std::string GNet::DnsMessageRRData::span( unsigned int begin , unsigned int end ) const
407{
408 return static_cast<const DnsMessageRR *>(this)->rdataSpan( begin , end ) ;
409}
410
411 inline
412 unsigned int GNet::DnsMessageRRData::size() const
413{
414 return static_cast<const DnsMessageRR *>(this)->rdataSize() ;
415}
416
417 inline
418 unsigned int GNet::DnsMessageRRData::byte( unsigned int offset ) const
419{
420 return static_cast<const DnsMessageRR *>(this)->rdataByte( offset ) ;
421}
422
423 inline
424 unsigned int GNet::DnsMessageRRData::word( unsigned int offset ) const
425{
426 return static_cast<const DnsMessageRR *>(this)->rdataWord( offset ) ;
427}
428
429 inline
430 unsigned int GNet::DnsMessage::recordCount() const
431{
432 return QDCOUNT() + ANCOUNT() + NSCOUNT() + ARCOUNT() ;
433}
434
435#endif
GNet::Address
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:63
GNet::DnsMessageNameParser
An implementation class used by GNet::DnsMessage to parse compressed domain names.
Definition: gdnsmessage.h:341
GNet::DnsMessageNameParser::size
static unsigned int size(const DnsMessage &msg, unsigned int)
Returns the size of the compressed name at the given offset.
Definition: gdnsmessage.cpp:346
GNet::DnsMessageNameParser::read
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.
Definition: gdnsmessage.cpp:364
GNet::DnsMessageQuestion
Represents DNS question record.
Definition: gdnsmessage.h:312
GNet::DnsMessageQuestion::DnsMessageQuestion
DnsMessageQuestion(const DnsMessage &, unsigned int offset)
Constructor.
Definition: gdnsmessage.cpp:313
GNet::DnsMessageQuestion::qtype
unsigned int qtype() const
Returns the question QTYPE value.
Definition: gdnsmessage.cpp:332
GNet::DnsMessageQuestion::qname
std::string qname() const
Returns the question domain name (QNAME).
Definition: gdnsmessage.cpp:327
GNet::DnsMessageQuestion::size
unsigned int size() const
Returns the record size.
Definition: gdnsmessage.cpp:322
GNet::DnsMessageQuestion::qclass
unsigned int qclass() const
Returns the question QCLASS value.
Definition: gdnsmessage.cpp:338
GNet::DnsMessageRRData
A trivial mix-in base class that simplifies method names when accessing data from a DnsMessageRR deri...
Definition: gdnsmessage.h:207
GNet::DnsMessageRRData::byte
unsigned int byte(unsigned int offset) const
Calls rdataByte().
Definition: gdnsmessage.h:418
GNet::DnsMessageRRData::dname
std::string dname(unsigned int rdata_offset) const
Calls rdataDname().
Definition: gdnsmessage.h:388
GNet::DnsMessageRRData::offset
unsigned int offset() const
Calls rdataOffset().
GNet::DnsMessageRRData::span
std::string span(unsigned int begin, unsigned int end) const
Calls rdataSpan().
Definition: gdnsmessage.h:406
GNet::DnsMessageRRData::size
unsigned int size() const
Calls rdataSize().
Definition: gdnsmessage.h:412
GNet::DnsMessageRRData::word
unsigned int word(unsigned int offset) const
Calls rdataWord().
Definition: gdnsmessage.h:424
GNet::DnsMessageRR
Represents DNS response record.
Definition: gdnsmessage.h:241
GNet::DnsMessageRR::type
unsigned int type() const
Returns the RR TYPE value().
Definition: gdnsmessage.cpp:421
GNet::DnsMessageRR::class_
unsigned int class_() const
Returns the RR CLASS value().
Definition: gdnsmessage.cpp:428
GNet::DnsMessageRR::DnsMessageRR
DnsMessageRR(const DnsMessage &, unsigned int offset)
Constructor from DnsMessage data.
Definition: gdnsmessage.cpp:401
GNet::DnsMessageRR::size
unsigned int size() const
Returns the size of the RR.
Definition: gdnsmessage.cpp:439
GNet::DnsMessageRR::address
Address address(unsigned int port=0U) const
Returns the Address if isa(A) or isa(AAAA).
Definition: gdnsmessage.cpp:505
GNet::DnsMessageRR::rdata
const DnsMessageRRData & rdata() const
Provides access to the message RDATA.
Definition: gdnsmessage.h:382
GNet::DnsMessageRR::isa
bool isa(std::string_view) const noexcept
Returns true if the type() has the given name().
Definition: gdnsmessage.cpp:434
GNet::DnsMessageRR::name
std::string name() const
Returns the RR NAME.
Definition: gdnsmessage.cpp:445
GNet::DnsMessageRecordType
A static class for mapping between a RR type name, such as "AAAA", and its corresponding numeric valu...
Definition: gdnsmessage.h:185
GNet::DnsMessageRecordType::value
static unsigned int value(std::string_view type_name)
Returns the type value for the given type name.
Definition: gdnsmessage.cpp:582
GNet::DnsMessageRecordType::name
static std::string name(unsigned int type_value)
Returns the type name for the given type value.
Definition: gdnsmessage.cpp:590
GNet::DnsMessageRequest
Represents a DNS query message.
Definition: gdnsmessage.h:358
GNet::DnsMessageRequest::n
std::size_t n() const
Returns message size.
Definition: gdnsmessage.cpp:85
GNet::DnsMessageRequest::p
const char * p() const
Returns a pointer to the message data.
Definition: gdnsmessage.cpp:80
GNet::DnsMessageRequest::DnsMessageRequest
DnsMessageRequest(const std::string &type, const std::string &hostname, unsigned int id=0U)
Constructor.
Definition: gdnsmessage.cpp:33
GNet::DnsMessage
A DNS message parser, with static factory functions for message composition.
Definition: gdnsmessage.h:56
GNet::DnsMessage::rrAddress
Address rrAddress(unsigned int n) const
Returns the address in the n'th record.
Definition: gdnsmessage.cpp:306
GNet::DnsMessage::ANCOUNT
unsigned int ANCOUNT() const
Returns the header ANCOUNT field, ie.
Definition: gdnsmessage.cpp:219
GNet::DnsMessage::p
const char * p() const noexcept
Returns the raw data.
Definition: gdnsmessage.cpp:110
GNet::DnsMessage::question
Question question(unsigned int n) const
Returns the n'th record as a Question record.
Definition: gdnsmessage.cpp:279
GNet::DnsMessage::RCODE
unsigned int RCODE() const
Returns the header RCODE.
Definition: gdnsmessage.cpp:209
GNet::DnsMessage::QR
bool QR() const
Returns the header QR (query/response).
Definition: gdnsmessage.cpp:168
GNet::DnsMessage::valid
bool valid() const
Returns true if the message data is big enough for a header and its TC() flag is false.
Definition: gdnsmessage.cpp:105
GNet::DnsMessage::Z
unsigned int Z() const
Returns the header Z value (zero).
Definition: gdnsmessage.cpp:203
GNet::DnsMessage::response
static DnsMessage response(const DnsMessage &request, const Address &address)
Factory function for an answer response based on the given request message.
GNet::DnsMessage::QDCOUNT
unsigned int QDCOUNT() const
Returns the header QDCOUNT field, ie.
Definition: gdnsmessage.cpp:214
GNet::DnsMessage::NSCOUNT
unsigned int NSCOUNT() const
Returns the header NSCOUNT field, ie.
Definition: gdnsmessage.cpp:225
GNet::DnsMessage::ARCOUNT
unsigned int ARCOUNT() const
Returns the header ARCOUNT field, ie.
Definition: gdnsmessage.cpp:232
GNet::DnsMessage::AA
bool AA() const
Returns the header AA flag (authorative).
Definition: gdnsmessage.cpp:178
GNet::DnsMessage::OPCODE
unsigned int OPCODE() const
Returns the header OPCODE.
Definition: gdnsmessage.cpp:173
GNet::DnsMessage::recordCount
unsigned int recordCount() const
Returns QDCOUNT()+ANCOUNT()+NSCOUNT()+ARCOUNT().
Definition: gdnsmessage.h:430
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:238
GNet::DnsMessage::TC
bool TC() const
Returns the header TC flag (truncated).
Definition: gdnsmessage.cpp:183
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:127
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:156
GNet::DnsMessage::byte
unsigned int byte(unsigned int byte_index) const
Returns byte at the given offset.
Definition: gdnsmessage.cpp:143
GNet::DnsMessage::addresses
std::vector< Address > addresses() const
Returns the Answer addresses.
Definition: gdnsmessage.cpp:133
GNet::DnsMessage::RD
bool RD() const
Returns the header RD (recursion desired).
Definition: gdnsmessage.cpp:189
GNet::DnsMessage::empty
static DnsMessage empty()
Factory function for an unusable object.
Definition: gdnsmessage.cpp:121
GNet::DnsMessage::ID
unsigned int ID() const
Returns the header ID.
Definition: gdnsmessage.cpp:163
GNet::DnsMessage::RA
bool RA() const
Returns the header RA (recursion available).
Definition: gdnsmessage.cpp:196
GNet::DnsMessage::rr
RR rr(unsigned int n) const
Returns the n'th record as a RR record.
Definition: gdnsmessage.cpp:290
GNet::DnsMessage::word
unsigned int word(unsigned int byte_index) const
Returns word at the given byte offset.
Definition: gdnsmessage.cpp:151
GNet::DnsMessage::n
std::size_t n() const noexcept
Returns the raw data size.
Definition: gdnsmessage.cpp:115
gaddress.h
gexception.h
gstringview.h
GNet
Network classes.
Definition: gdef.h:1243
G::hostname
std::string hostname()
Returns the hostname.
Definition: ghostname_unix.cpp:27
G::tx
constexpr const char * tx(const char *p) noexcept
A briefer alternative to G::gettext_noop().
Definition: ggettext.h:84