E-MailRelay
gdnsmessage.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2023 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( G::string_view type_name ) ;
188 ///< Returns the type value for the given type name.
189 ///< Throws on error.
190
191 static unsigned int value( G::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( G::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
278private:
279 friend class GNet::DnsMessageRRData ;
280 std::string rdataDname( unsigned int rdata_offset ) const ;
281 std::string rdataDname( unsigned int * rdata_offset_inout_p ) const ;
282 std::string rdataSpan( unsigned int begin ) const ;
283 std::string rdataSpan( unsigned int begin , unsigned int end ) const ;
284 unsigned int rdataOffset() const ;
285 unsigned int rdataSize() const ;
286 unsigned int rdataByte( unsigned int offset ) const ;
287 unsigned int rdataWord( unsigned int offset ) const ;
288 GNet::Address addressImp( unsigned int port , bool & ok ) const ;
289
290private:
291 const DnsMessage & m_msg ;
292 unsigned int m_offset ;
293 unsigned int m_size ;
294 unsigned int m_type ;
295 unsigned int m_class ;
296 unsigned int m_rdata_offset ;
297 unsigned int m_rdata_size ;
298 std::string m_name ;
299} ;
300
301//| \class GNet::DnsMessageQuestion
302/// Represents DNS question record.
303///
305{
306public:
307 DnsMessageQuestion( const DnsMessage & , unsigned int offset ) ;
308 ///< Constructor.
309
310 unsigned int size() const ;
311 ///< Returns the record size.
312
313 unsigned int qtype() const ;
314 ///< Returns the question QTYPE value.
315
316 unsigned int qclass() const ;
317 ///< Returns the question QCLASS value.
318
319 std::string qname() const ;
320 ///< Returns the question domain name (QNAME).
321
322private:
323 unsigned int m_size ;
324 unsigned int m_qtype ;
325 unsigned int m_qclass ;
326 std::string m_qname ;
327} ;
328
329//| \class GNet::DnsMessageNameParser
330/// An implementation class used by GNet::DnsMessage to parse
331/// compressed domain names.
332///
334{
335public:
336 static unsigned int size( const DnsMessage & msg , unsigned int ) ;
337 ///< Returns the size of the compressed name at the given offset.
338
339 static std::string read( const DnsMessage & msg , unsigned int ) ;
340 ///< Returns the decompressed domain name at the given offset,
341 ///< made up of the labels with dots inbetween.
342
343public:
344 DnsMessageNameParser() = delete ;
345} ;
346
347//| \class GNet::DnsMessageRequest
348/// Represents a DNS query message.
349///
351{
352public:
353 using RR = DnsMessageRR ;
354
355 DnsMessageRequest( const std::string & type , const std::string & hostname , unsigned int id = 0U ) ;
356 ///< Constructor.
357
358 const char * p() const ;
359 ///< Returns a pointer to the message data.
360
361 std::size_t n() const ;
362 ///< Returns message size.
363
364private:
365 void addDomainName( const std::string & domain , char sep ) ;
366 void addLabel( G::string_view ) ;
367 void addWord( unsigned int ) ;
368 void addByte( unsigned int ) ;
369
370private:
371 std::string m_data ;
372} ;
373
374inline
376{
377 return *this ;
378}
379
380inline
381std::string GNet::DnsMessageRRData::dname( unsigned int offset ) const
382{
383 return static_cast<const DnsMessageRR *>(this)->rdataDname( offset ) ;
384}
385
386inline
387std::string GNet::DnsMessageRRData::dname( unsigned int * offset_inout_p ) const
388{
389 return static_cast<const DnsMessageRR *>(this)->rdataDname( offset_inout_p ) ;
390}
391
392inline
393std::string GNet::DnsMessageRRData::span( unsigned int begin ) const
394{
395 return static_cast<const DnsMessageRR *>(this)->rdataSpan( begin ) ;
396}
397
398inline
399std::string GNet::DnsMessageRRData::span( unsigned int begin , unsigned int end ) const
400{
401 return static_cast<const DnsMessageRR *>(this)->rdataSpan( begin , end ) ;
402}
403
404inline
406{
407 return static_cast<const DnsMessageRR *>(this)->rdataSize() ;
408}
409
410inline
411unsigned int GNet::DnsMessageRRData::byte( unsigned int offset ) const
412{
413 return static_cast<const DnsMessageRR *>(this)->rdataByte( offset ) ;
414}
415
416inline
417unsigned int GNet::DnsMessageRRData::word( unsigned int offset ) const
418{
419 return static_cast<const DnsMessageRR *>(this)->rdataWord( offset ) ;
420}
421
422inline
424{
425 return QDCOUNT() + ANCOUNT() + NSCOUNT() + ARCOUNT() ;
426}
427
428#endif
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:62
An implementation class used by GNet::DnsMessage to parse compressed domain names.
Definition: gdnsmessage.h:334
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:305
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:411
std::string dname(unsigned int rdata_offset) const
Calls rdataDname().
Definition: gdnsmessage.h:381
unsigned int offset() const
Calls rdataOffset().
std::string span(unsigned int begin, unsigned int end) const
Calls rdataSpan().
Definition: gdnsmessage.h:399
unsigned int size() const
Calls rdataSize().
Definition: gdnsmessage.h:405
unsigned int word(unsigned int offset) const
Calls rdataWord().
Definition: gdnsmessage.h:417
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:375
std::string name() const
Returns the RR NAME.
bool isa(G::string_view) const noexcept
Returns true if the type() has the given 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(G::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:351
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:423
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.
A class like c++17's std::string_view.
Definition: gstringview.h:51
Network classes.
Definition: gdef.h:1144
std::string hostname()
Returns the hostname.
constexpr const char * tx(const char *p)
A briefer alternative to G::gettext_noop().
Definition: ggettext.h:84