5fa5139eb24fe3dd8a4f7e0d3ce89d858c96f85c
[pingcheck] / src / dns / dnsmaster.cpp
1 /*
2  The software in this package is distributed under the GNU General
3  Public License version 2 (with a special exception described below).
4
5  A copy of GNU General Public License (GPL) is included in this distribution,
6  in the file COPYING.GPL.
7
8  As a special exception, if other files instantiate templates or use macros
9  or inline functions from this file, or you compile this file and link it
10  with other works to produce a work based on this file, this file
11  does not by itself cause the resulting work to be covered
12  by the GNU General Public License.
13
14  However the source code for this file must still be made available
15  in accordance with section (3) of the GNU General Public License.
16
17  This exception does not invalidate any other reasons why a work based
18  on this file might be covered by the GNU General Public License.
19
20  Christian Herdtweck, Intra2net AG 2015
21  */
22
23 #include "dns/dnsmaster.h"
24
25 #include <logfunc.hpp>
26 #include <boost/bind.hpp>
27 #include <boost/asio/placeholders.hpp>
28
29 #include "dns/ippseudoresolver.h"
30 #include "dns/dnsresolver.h"
31
32 using boost::bind;
33 using I2n::Logger::GlobalLogger;
34
35
36 DnsMasterItem DnsMaster::TheOnlyInstance;
37
38 void DnsMaster::create_master(const IoServiceItem &io_serv,
39                             const boost::asio::ip::address &default_name_server,
40                             const int resolved_ip_ttl_threshold,
41                             const int max_address_resolution_attempts,
42                             const std::string &cache_file)
43 {
44     if (TheOnlyInstance)
45     {
46         GlobalLogger.warning()
47             << "Blocking attempt to create another DnsMaster instance!";
48         return;
49     }
50
51     GlobalLogger.info() << "Creating DNS Cache and Master";
52     DnsCacheItem cache( new DnsCache(io_serv, cache_file) );
53     TheOnlyInstance.reset( new DnsMaster(io_serv,
54                                          default_name_server,
55                                          resolved_ip_ttl_threshold,
56                                          max_address_resolution_attempts,
57                                          cache)
58                          );
59 }
60
61
62 DnsMaster::DnsMaster(const IoServiceItem &io_serv,
63                      const boost::asio::ip::address &default_name_server,
64                      const int resolved_ip_ttl_threshold,
65                      const int max_address_resolution_attempts,
66                      const DnsCacheItem &cache)
67     : IoService( io_serv )
68     , DefaultNameServer( default_name_server )
69     , ResolvedIpTtlThreshold( resolved_ip_ttl_threshold )
70     , MaxAddressResolutionAttempts( max_address_resolution_attempts )
71     , Cache(cache)
72     , ResolverMap()
73 {
74 }
75
76
77 DnsMasterItem& DnsMaster::get_instance()
78 {
79     if ( !TheOnlyInstance )
80         GlobalLogger.error()
81             << "Request to return DnsMaster instance before creating it!";
82     return TheOnlyInstance;
83 }
84
85 DnsMaster::~DnsMaster()
86 {
87     GlobalLogger.info() << "DnsMaster is being destructed";
88
89     if (DnsMaster::TheOnlyInstance)
90     {    // just to be sure ...
91         GlobalLogger.warning() << "DnsMaster is being destructed that is not "
92                                << "singleton instance TheOnlyInstance!";
93         DnsMaster::TheOnlyInstance.reset();
94     }
95
96     // Items in ResolverMap and the DnsCache might still be referenced by
97     // Resolvers and are smart pointers, anyway --> nothing to do here
98 }
99
100
101
102 ResolverItem& DnsMaster::get_resolver_for( const std::string &hostname,
103                                            const PingProtocol &ping_protocol )
104 {
105     // find suitable DnsIpProtocol for ping protocol
106     DnsIpProtocol protocol = DnsMaster::ping2dns_protocol(ping_protocol);
107     return get_resolver_for(hostname, protocol);
108 }
109
110
111 ResolverItem& DnsMaster::get_resolver_for(const std::string &hostname,
112                                     const DnsIpProtocol &protocol)
113 {
114     DnsMasterItem master = get_instance();
115
116     // create key to ResolverMap
117     resolver_key_type key(hostname, protocol);
118     if ( master->ResolverMap.count(key) == 0 )
119     {   // need to create a resolver
120
121         // check if it is an ip address, so can create a simple pseudo resolver
122         if ( master->is_ip(hostname) )
123         {
124             boost::asio::ip::address ip
125                               = boost::asio::ip::address::from_string(hostname);
126             if ( (protocol == DNS_IPv4 && !ip.is_v4()) ||
127                  (protocol == DNS_IPv6 && !ip.is_v6()) )
128                 GlobalLogger.warning() << "Asked to create a DNS resolver "
129                                        << "for wrong IP protocol: v4 != v6! "
130                                        << "We will comply.";
131             GlobalLogger.info() << "Creating PseudoResolver for IP " << ip;
132             ResolverItem new_resolver( new IpPseudoResolver(IoService,
133                                                             hostname,
134                                                             Cache) );
135             master->ResolverMap[key] = new_resolver;
136         }
137         else
138         {
139             GlobalLogger.info() << "Creating Resolver for host " << hostname;
140             ResolverItem new_resolver( new DnsResolver(IoService,
141                                                        hostname,
142                                                        protocol,
143                                                        Cache,
144                                                        DefaultNameServer) );
145             master->ResolverMap[key] = new_resolver;
146         }
147     }
148     return master->ResolverMap[key];
149 }
150
151 // create resolver but do not remember it in ResolverMap
152 ResolverItem DnsMaster::get_recursor_for(const std::string &hostname,
153                                          const DnsIpProtocol &protocol,
154                                     const boost::asio::ip::address &name_server)
155 {
156     ResolverItem new_resolver( new DnsResolver(IoService,
157                                                hostname,
158                                                protocol,
159                                                Cache,
160                                                name_server) );
161     return new_resolver;
162 }
163
164 /**
165  * return true if given hostname string actually is an IP
166  *
167  * delegates decision to boost::asio::ip::address::from_string
168  */
169 bool DnsMaster::is_ip(const std::string &hostname) const
170 {
171     try
172     {
173         boost::asio::ip::address ip = boost::asio::ip::address::from_string(
174                                                                       hostname);
175         return ip.is_v4() || ip.is_v6();
176     }
177     catch ( const std::exception &ex )
178     {
179         return false;
180     }
181 }
182
183
184 DnsIpProtocol DnsMaster::ping2dns_protocol(const PingProtocol& pprot)
185 {
186     switch (pprot)
187     {
188         case PingProtocol_ICMP:     return DNS_IPv4; break;
189         case PingProtocol_ICMPv6:   return DNS_IPv6; break;
190         case PingProtocol_TCP:      return DNS_IPv4; break;
191         case PingProtocol_TCP_IPv6: return DNS_IPv6; break;
192         default:
193             GlobalLogger.warning() << "Unexpected ping protocol: "
194                                    << static_cast<int>(pprot);
195             return DNS_IPALL;
196             break;
197     }
198 }
199
200 /*boost::asio::ip::address &DnsMaster::get_name_server() const
201 {
202     return NameServer;
203 }*/
204
205 int DnsMaster::get_resolved_ip_ttl_threshold() const
206 {
207     return ResolvedIpTtlThreshold;
208 }
209
210 int DnsMaster::get_max_address_resolution_attempts() const
211 {
212     return MaxAddressResolutionAttempts;
213 }
214
215 // (created using vim -- the world's best text editor)
216