DwmDns-0.1.0
DwmDnsResolver.hh
Go to the documentation of this file.
1 //===========================================================================
2 // @(#) $Name:$
3 // @(#) $Id: DwmDnsResolver.hh 10142 2018-01-28 19:11:40Z dwm $
4 //===========================================================================
5 // Copyright (c) Daniel W. McRobb 2018
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
10 // are met:
11 //
12 // 1. Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 // 2. Redistributions in binary form must reproduce the above copyright
15 // notice, this list of conditions and the following disclaimer in the
16 // documentation and/or other materials provided with the distribution.
17 // 3. The names of the authors and copyright holders may not be used to
18 // endorse or promote products derived from this software without
19 // specific prior written permission.
20 //
21 // IN NO EVENT SHALL DANIEL W. MCROBB BE LIABLE TO ANY PARTY FOR
22 // DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
23 // INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE,
24 // EVEN IF DANIEL W. MCROBB HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
25 // DAMAGE.
26 //
27 // THE SOFTWARE PROVIDED HEREIN IS ON AN "AS IS" BASIS, AND
28 // DANIEL W. MCROBB HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
29 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS. DANIEL W. MCROBB MAKES NO
30 // REPRESENTATIONS AND EXTENDS NO WARRANTIES OF ANY KIND, EITHER
31 // IMPLIED OR EXPRESS, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 // WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE,
33 // OR THAT THE USE OF THIS SOFTWARE WILL NOT INFRINGE ANY PATENT,
34 // TRADEMARK OR OTHER RIGHTS.
35 //===========================================================================
36 
37 //---------------------------------------------------------------------------
40 //---------------------------------------------------------------------------
41 
42 #ifndef _DWMDNSRESOLVER_HH_
43 #define _DWMDNSRESOLVER_HH_
44 
45 #include <atomic>
46 #include <type_traits>
47 #include <vector>
48 
49 #include "DwmDnsEtcHosts.hh"
50 #include "DwmDnsNameServer.hh"
51 
52 namespace Dwm {
53 
54  namespace Dns {
55 
56  //------------------------------------------------------------------------
58  //------------------------------------------------------------------------
59 
60  //------------------------------------------------------------------------
63  //------------------------------------------------------------------------
64  class Resolver
65  {
66  public:
67  //----------------------------------------------------------------------
70  //----------------------------------------------------------------------
71  Resolver(const std::string & filename = "/etc/resolv.conf",
72  const std::string & order = "files,dns");
73 
74  //----------------------------------------------------------------------
78  //----------------------------------------------------------------------
79  bool GetHostByName(const std::string & name,
80  std::vector<in6_addr> & in6Addrs,
81  std::vector<in_addr> & inAddrs);
82 
83  //----------------------------------------------------------------------
87  //----------------------------------------------------------------------
88  bool GetHostByAddr(const in6_addr & addr,
89  std::vector<std::string> & names);
90 
91  //----------------------------------------------------------------------
95  //----------------------------------------------------------------------
96  bool GetHostByAddr(const in_addr & addr,
97  std::vector<std::string> & names);
98 
99  //----------------------------------------------------------------------
109  //----------------------------------------------------------------------
110  bool Get(const std::string & name, uint16_t rrtype,
111  std::vector<ResourceRecord> & results,
112  bool doEDNS = false, bool doDNSSEC = false,
113  bool tcpFallback = true);
114 
115  //----------------------------------------------------------------------
125  //----------------------------------------------------------------------
126  template <typename RRT>
127  bool Get(const std::string & name,
128  std::vector<ResourceRecord> & results,
129  bool doEDNS = false, bool doDNSSEC = false,
130  bool tcpFallback = true)
131  {
132  results.clear();
133  if (std::is_same<RRT,RRDataPTR>::value
134  || std::is_same<RRT,RRDataA>::value
135  || std::is_same<RRT,RRDataAAAA>::value) {
136  if (_order.find("files") == 0) {
137  EtcHosts etcHosts;
138  etcHosts.Get(name, RRT::k_rrtype, results);
139  }
140  }
141 
142  if (results.empty() && (_order.find("dns") != std::string::npos)) {
143  std::vector<std::string> namesToTry;
144  GetNamesToTry(name, RRT::k_rrtype, namesToTry);
145  for (auto & n : namesToTry) {
146  Message message;
147  message.Header().Id(_msgid++);
148  message.Header().RecursionDesired(true);
149  if (doEDNS) {
150  message.EnableEDNS(4096, doDNSSEC);
151  }
152  Dns::MessageQuestion question(n, RRT::k_rrtype,
154  message.Questions().push_back(question);
155  for (auto & ns : _nameservers) {
156  if (GetViaUDP<RRT>(ns, message, results)) {
157  break;
158  }
159  else if (tcpFallback) {
160  if (GetViaTCP<RRT>(ns, message, results)) {
161  break;
162  }
163  }
164  }
165  if (! results.empty()) {
166  break;
167  }
168  }
169  }
170 
171  if (std::is_same<RRT,RRDataPTR>::value
172  || std::is_same<RRT,RRDataA>::value
173  || std::is_same<RRT,RRDataAAAA>::value) {
174  std::string::size_type fidx = _order.find("files");
175  if (results.empty() && (fidx != std::string::npos) && (fidx > 0)) {
176  EtcHosts etcHosts;
177  etcHosts.Get(name, RRT::k_rrtype, results);
178  }
179  }
180 
181  return (! results.empty());
182  }
183 
184  //----------------------------------------------------------------------
193  //----------------------------------------------------------------------
194  template <typename RRT>
195  bool Get(const std::string & name, std::vector<RRT> & results,
196  bool doEDNS = false, bool doDNSSEC = false,
197  bool tcpFallback = true)
198  {
199  results.clear();
200  std::vector<ResourceRecord> rrs;
201  bool rc = Get<RRT>(name, rrs, doEDNS, doDNSSEC, tcpFallback);
202  for (auto rr : rrs) {
203  RRT *data = rr.Data<RRT>();
204  if (data != nullptr) {
205  results.push_back(*data);
206  }
207  }
208  return (! results.empty());
209  }
210 
211  //----------------------------------------------------------------------
213  //----------------------------------------------------------------------
214  const std::vector<NameServer> & NameServers() const
215  {
216  return _nameservers;
217  }
218 
219  //----------------------------------------------------------------------
221  //----------------------------------------------------------------------
222  std::vector<NameServer> & NameServers()
223  {
224  return _nameservers;
225  }
226 
227  private:
228  std::vector<NameServer> _nameservers;
229  std::vector<std::string> _searchList;
230  std::string _domain;
231  std::string _order;
232  std::atomic<uint16_t> _msgid;
233 
234  //----------------------------------------------------------------------
236  //----------------------------------------------------------------------
237  template <typename RRT>
238  bool GetViaUDP(NameServer & ns, Message & querymsg,
239  std::vector<ResourceRecord> & results)
240  {
241  if (ns.SendMessage(querymsg)) {
242  Message rmsg;
243  if (ns.ReceiveMessage(rmsg)) {
244  for (auto & answer : rmsg.Answers()) {
245  RRT *rrdata = answer.Data<RRT>();
246  if (rrdata != nullptr) {
247  results.push_back(answer);
248  }
249  }
250  }
251  }
252  return (! results.empty());
253  }
254 
255  //----------------------------------------------------------------------
257  //----------------------------------------------------------------------
258  template <typename RRT>
259  bool GetViaTCP(NameServer & ns, Message & querymsg,
260  std::vector<ResourceRecord> & results)
261  {
262  if (ns.WriteMessage(querymsg)) {
263  Message rmsg;
264  if (ns.ReadMessage(rmsg)) {
265  for (auto & answer : rmsg.Answers()) {
266  RRT *rrdata = answer.Data<RRT>();
267  if (rrdata != nullptr) {
268  results.push_back(answer);
269  }
270  }
271  }
272  }
273  return (! results.empty());
274  }
275 
276  //----------------------------------------------------------------------
278  //----------------------------------------------------------------------
279  void GetNamesToTry(const std::string & name, uint16_t rrtype,
280  std::vector<std::string> & names) const;
281  };
282 
283  } // namespace Dns
284 
285 } // namespace Dwm
286 
287 #endif // _DWMDNSRESOLVER_HH_
bool SendMessage(const Message &message)
Sends the given message to the name server via UDP.
bool ReadMessage(Message &message)
Reads a message from the name server via TCP.
const std::vector< NameServer > & NameServers() const
Returns a const reference to the contained nameservers.
Definition: DwmDnsResolver.hh:214
bool RecursionDesired() const
Returns true if recursion is desired.
Encapsulates a resolver &#39;hosts&#39; file, such as /etc/hosts.
Definition: DwmDnsEtcHosts.hh:68
const std::vector< ResourceRecord > & Answers() const
Returns a const reference to the records from the answers section of the message. ...
Definition: DwmDnsMessage.hh:122
Dwm::Dns::EtcHosts class definition.
Dwm::Dns::NameServer class definition.
const std::vector< MessageQuestion > & Questions() const
Returns a const reference to the questions in the message.
Definition: DwmDnsMessage.hh:105
Encapsulates a DNS message.
Definition: DwmDnsMessage.hh:68
bool Get(const std::string &name, std::vector< ResourceRecord > &results, bool doEDNS=false, bool doDNSSEC=false, bool tcpFallback=true)
Fetches resource records whose data type is RRT for the given domain name name.
Definition: DwmDnsResolver.hh:127
void EnableEDNS(uint16_t pduSize, bool doDnssec)
Enable EDNS by setting the maximum packet size to pduSize and enable or disable DNSSEC.
Encapsulates a DNS message question.
Definition: DwmDnsMessageQuestion.hh:59
Resolver(const std::string &filename="/etc/resolv.conf", const std::string &order="files,dns")
Construct with the given resolver configuration file and the preferred order of resolver sources (ala...
bool WriteMessage(const Message &message)
Sends the given message to the name server via TCP.
Definition: DwmDnsEtcHosts.hh:60
Simple DNS resolver class.
Definition: DwmDnsResolver.hh:64
bool Get(const std::string &name, uint16_t rrtype, std::vector< ResourceRecord > &results)
Gets DNS resource records of type rrtype for the given host name.
bool ReceiveMessage(Message &message)
Receives a message from the name server via UDP.
static constexpr uint16_t k_classIN
Query classes.
Definition: DwmDnsMessageQuestion.hh:102
bool Get(const std::string &name, std::vector< RRT > &results, bool doEDNS=false, bool doDNSSEC=false, bool tcpFallback=true)
Gets resource record data of type RRT for the given domain name name.
Definition: DwmDnsResolver.hh:195
bool GetHostByName(const std::string &name, std::vector< in6_addr > &in6Addrs, std::vector< in_addr > &inAddrs)
Fetches the IPv6 and IPv4 addresses for the given host name.
bool Get(const std::string &name, uint16_t rrtype, std::vector< ResourceRecord > &results, bool doEDNS=false, bool doDNSSEC=false, bool tcpFallback=true)
Fetches resource records of type rrtype for the given domain name name.
bool GetHostByAddr(const in6_addr &addr, std::vector< std::string > &names)
Fetches the host names for the given IPv6 address addr.
const MessageHeader & Header() const
Returns a const reference to the message header.
Definition: DwmDnsMessage.hh:89
uint16_t Id() const
Returns the message ID.
Encapsulates a DNS name server, from the perspective of a DNS client.
Definition: DwmDnsNameServer.hh:65
std::vector< NameServer > & NameServers()
Returns a mutable reference to the contained nameservers.
Definition: DwmDnsResolver.hh:222