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
34namespace 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///
56{
57public:
58 G_EXCEPTION( Error , tx("dns message error") )
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
168private:
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
176private:
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///
185{
186public:
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
198public:
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///
207{
208public:
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
233protected:
234 DnsMessageRRData() = default ;
235} ;
236
237//| \class GNet::DnsMessageRR
238/// Represents DNS response record.
239///
241{
242public:
243 using RR = DnsMessageRR ;
244
245public:
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
278public:
279 ~DnsMessageRR() = default ;
280 DnsMessageRR( const DnsMessageRR & ) = default ;
281 DnsMessageRR( DnsMessageRR && ) = default ;
282 DnsMessageRR & operator=( const DnsMessageRR & ) = delete ;
283 DnsMessageRR & operator=( DnsMessageRR && ) = delete ;
284
285private:
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
297private:
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///
312{
313public:
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
329private:
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///
341{
342public:
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
350public:
351 DnsMessageNameParser() = delete ;
352} ;
353
354//| \class GNet::DnsMessageRequest
355/// Represents a DNS query message.
356///
358{
359public:
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
371private:
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
377private:
378 std::string m_data ;
379} ;
380
381inline
383{
384 return *this ;
385}
386
387inline
388std::string GNet::DnsMessageRRData::dname( unsigned int offset ) const
389{
390 return static_cast<const DnsMessageRR *>(this)->rdataDname( offset ) ;
391}
392
393inline
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
399inline
400std::string GNet::DnsMessageRRData::span( unsigned int begin ) const
401{
402 return static_cast<const DnsMessageRR *>(this)->rdataSpan( begin ) ;
403}
404
405inline
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
411inline
413{
414 return static_cast<const DnsMessageRR *>(this)->rdataSize() ;
415}
416
417inline
418unsigned int GNet::DnsMessageRRData::byte( unsigned int offset ) const
419{
420 return static_cast<const DnsMessageRR *>(this)->rdataByte( offset ) ;
421}
422
423inline
424unsigned int GNet::DnsMessageRRData::word( unsigned int offset ) const
425{
426 return static_cast<const DnsMessageRR *>(this)->rdataWord( offset ) ;
427}
428
429inline
431{
432 return QDCOUNT() + ANCOUNT() + NSCOUNT() + ARCOUNT() ;
433}
434
435#endif
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:63
An implementation class used by GNet::DnsMessage to parse compressed domain names.
Definition: gdnsmessage.h:341
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.
Definition: gdnsmessage.h:312
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.
A trivial mix-in base class that simplifies method names when accessing data from a DnsMessageRR deri...
Definition: gdnsmessage.h:207
unsigned int byte(unsigned int offset) const
Calls rdataByte().
Definition: gdnsmessage.h:418
std::string dname(unsigned int rdata_offset) const
Calls rdataDname().
Definition: gdnsmessage.h:388
unsigned int offset() const
Calls rdataOffset().
std::string span(unsigned int begin, unsigned int end) const
Calls rdataSpan().
Definition: gdnsmessage.h:406
unsigned int size() const
Calls rdataSize().
Definition: gdnsmessage.h:412
unsigned int word(unsigned int offset) const
Calls rdataWord().
Definition: gdnsmessage.h:424
Represents DNS response record.
Definition: gdnsmessage.h:241
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).
const DnsMessageRRData & rdata() const
Provides access to the message RDATA.
Definition: gdnsmessage.h:382
bool isa(std::string_view) const noexcept
Returns true if the type() has the given name().
std::string name() const
Returns the RR NAME.
A static class for mapping between a RR type name, such as "AAAA", and its corresponding numeric valu...
Definition: gdnsmessage.h:185
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.
Definition: gdnsmessage.h:358
std::size_t n() const
Returns message size.
Definition: gdnsmessage.cpp:85
const char * p() const
Returns a pointer to the message data.
Definition: gdnsmessage.cpp:80
DnsMessageRequest(const std::string &type, const std::string &hostname, unsigned int id=0U)
Constructor.
Definition: gdnsmessage.cpp:33
A DNS message parser, with static factory functions for message composition.
Definition: gdnsmessage.h:56
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).
static DnsMessage response(const DnsMessage &request, const Address &address)
Factory function for an answer response based on the given request message.
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.
unsigned int recordCount() const
Returns QDCOUNT()+ANCOUNT()+NSCOUNT()+ARCOUNT().
Definition: gdnsmessage.h:430
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.
Network classes.
Definition: gdef.h:1243
std::string hostname()
Returns the hostname.
constexpr const char * tx(const char *p) noexcept
A briefer alternative to G::gettext_noop().
Definition: ggettext.h:84