added option min-time-between-resolves-option and tests for it
[pingcheck] / src / dns / dnsmaster.cpp
CommitLineData
36ad976b
CH
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
c5b4902d 23#include "dns/dnsmaster.h"
36ad976b
CH
24
25#include <logfunc.hpp>
26#include <boost/bind.hpp>
36ad976b
CH
27#include <boost/asio/placeholders.hpp>
28
c5b4902d
CH
29#include "dns/ippseudoresolver.h"
30#include "dns/dnsresolver.h"
96779587 31
36ad976b 32using boost::bind;
36ad976b
CH
33using I2n::Logger::GlobalLogger;
34
96779587 35
36ad976b
CH
36DnsMasterItem DnsMaster::TheOnlyInstance;
37
8d26221d 38// just delegates work to other create_master function
96779587 39void DnsMaster::create_master(const IoServiceItem &io_serv,
ad83004d
CH
40 const boost::asio::ip::address &default_name_server,
41 const int resolved_ip_ttl_threshold,
f833126b 42 const int min_time_between_resolves,
ad83004d
CH
43 const int max_address_resolution_attempts,
44 const std::string &cache_file)
36ad976b 45{
c1abff61 46 GlobalLogger.info() << "DnsMaster: Creating cache";
f833126b
CH
47 DnsCacheItem cache(
48 new DnsCache(io_serv,
49 cache_file,
50 static_cast<uint32_t>(min_time_between_resolves)
51 )
52 );
53 create_master(io_serv,
54 default_name_server,
55 resolved_ip_ttl_threshold,
56 max_address_resolution_attempts,
57 cache);
8d26221d
CH
58}
59
60void DnsMaster::create_master(const IoServiceItem &io_serv,
61 const boost::asio::ip::address &default_name_server,
62 const int resolved_ip_ttl_threshold,
63 const int max_address_resolution_attempts,
64 const DnsCacheItem &cache)
65{
36ad976b
CH
66 if (TheOnlyInstance)
67 {
c1abff61
CH
68 GlobalLogger.warning() << "DnsMaster: "
69 << "Blocking attempt to create another instance!";
96779587 70 return;
36ad976b
CH
71 }
72
c1abff61 73 GlobalLogger.info() << "DNS Master: creating instance";
923626c0 74 TheOnlyInstance.reset( new DnsMaster(io_serv,
ad83004d 75 default_name_server,
923626c0
CH
76 resolved_ip_ttl_threshold,
77 max_address_resolution_attempts,
78 cache)
79 );
36ad976b
CH
80}
81
36ad976b 82DnsMaster::DnsMaster(const IoServiceItem &io_serv,
ad83004d 83 const boost::asio::ip::address &default_name_server,
923626c0
CH
84 const int resolved_ip_ttl_threshold,
85 const int max_address_resolution_attempts,
96779587 86 const DnsCacheItem &cache)
36ad976b 87 : IoService( io_serv )
ad83004d 88 , DefaultNameServer( default_name_server )
923626c0
CH
89 , ResolvedIpTtlThreshold( resolved_ip_ttl_threshold )
90 , MaxAddressResolutionAttempts( max_address_resolution_attempts )
96779587 91 , Cache(cache)
4e7b6ff9 92 , ResolverMap()
36ad976b 93{
36ad976b
CH
94}
95
96
97DnsMasterItem& DnsMaster::get_instance()
98{
99 if ( !TheOnlyInstance )
c1abff61
CH
100 GlobalLogger.error() << "DnsMaster: "
101 << "Request to return instance before creating it!";
36ad976b
CH
102 return TheOnlyInstance;
103}
104
c5b4902d
CH
105DnsMaster::~DnsMaster()
106{
c1abff61 107 GlobalLogger.info() << "DnsMaster: being destructed";
c5b4902d
CH
108
109 if (DnsMaster::TheOnlyInstance)
26b0f687
CH
110 { // apparently, this static variable still exists while itself is
111 // destructed...
c1abff61 112 //GlobalLogger.warning() << "DnsMaster: being destructed but not "
26b0f687 113 // << "singleton instance TheOnlyInstance!";
c5b4902d
CH
114 DnsMaster::TheOnlyInstance.reset();
115 }
116
117 // Items in ResolverMap and the DnsCache might still be referenced by
118 // Resolvers and are smart pointers, anyway --> nothing to do here
119}
120
36ad976b
CH
121
122
923626c0
CH
123ResolverItem& DnsMaster::get_resolver_for( const std::string &hostname,
124 const PingProtocol &ping_protocol )
125{
126 // find suitable DnsIpProtocol for ping protocol
dbe986b9 127 DnsIpProtocol protocol = ping2dns_protocol(ping_protocol);
923626c0
CH
128 return get_resolver_for(hostname, protocol);
129}
130
131
ad83004d 132ResolverItem& DnsMaster::get_resolver_for(const std::string &hostname,
e18c1337 133 const DnsIpProtocol &protocol)
36ad976b 134{
923626c0
CH
135 // create key to ResolverMap
136 resolver_key_type key(hostname, protocol);
dbe986b9 137 if ( ResolverMap.count(key) == 0 )
36ad976b
CH
138 { // need to create a resolver
139
140 // check if it is an ip address, so can create a simple pseudo resolver
dbe986b9 141 if ( is_ip(hostname) )
36ad976b 142 {
923626c0
CH
143 boost::asio::ip::address ip
144 = boost::asio::ip::address::from_string(hostname);
145 if ( (protocol == DNS_IPv4 && !ip.is_v4()) ||
146 (protocol == DNS_IPv6 && !ip.is_v6()) )
c1abff61
CH
147 GlobalLogger.warning() << "DnsMaster:"
148 << "Asked to create a DNS resolver "
923626c0
CH
149 << "for wrong IP protocol: v4 != v6! "
150 << "We will comply.";
c1abff61
CH
151 GlobalLogger.info() << "DnsMaster: Creating PseudoResolver for IP "
152 << ip;
4e7b6ff9
CH
153 ResolverItem new_resolver( new IpPseudoResolver(IoService,
154 hostname,
155 Cache) );
dbe986b9 156 ResolverMap[key] = new_resolver;
36ad976b
CH
157 }
158 else
159 {
dbe986b9
CH
160 GlobalLogger.info() << "DnsMaster: Creating Resolver for host "
161 << hostname << " and protocol " << to_string(protocol);
4e7b6ff9
CH
162 ResolverItem new_resolver( new DnsResolver(IoService,
163 hostname,
923626c0 164 protocol,
4e7b6ff9 165 Cache,
ad83004d 166 DefaultNameServer) );
dbe986b9 167 ResolverMap[key] = new_resolver;
36ad976b
CH
168 }
169 }
dbe986b9 170 return ResolverMap[key];
36ad976b
CH
171}
172
173/**
174 * return true if given hostname string actually is an IP
175 *
96779587 176 * delegates decision to boost::asio::ip::address::from_string
36ad976b
CH
177 */
178bool DnsMaster::is_ip(const std::string &hostname) const
179{
180 try
181 {
96779587
CH
182 boost::asio::ip::address ip = boost::asio::ip::address::from_string(
183 hostname);
36ad976b
CH
184 return ip.is_v4() || ip.is_v6();
185 }
186 catch ( const std::exception &ex )
187 {
188 return false;
189 }
190}
191
923626c0
CH
192
193DnsIpProtocol DnsMaster::ping2dns_protocol(const PingProtocol& pprot)
194{
195 switch (pprot)
196 {
197 case PingProtocol_ICMP: return DNS_IPv4; break;
198 case PingProtocol_ICMPv6: return DNS_IPv6; break;
199 case PingProtocol_TCP: return DNS_IPv4; break;
200 case PingProtocol_TCP_IPv6: return DNS_IPv6; break;
201 default:
c1abff61 202 GlobalLogger.warning() << "DnsMaster: Unexpected ping protocol: "
923626c0
CH
203 << static_cast<int>(pprot);
204 return DNS_IPALL;
205 break;
206 }
207}
208
209/*boost::asio::ip::address &DnsMaster::get_name_server() const
210{
211 return NameServer;
212}*/
213
214int DnsMaster::get_resolved_ip_ttl_threshold() const
215{
216 return ResolvedIpTtlThreshold;
217}
218
219int DnsMaster::get_max_address_resolution_attempts() const
96779587 220{
923626c0 221 return MaxAddressResolutionAttempts;
96779587
CH
222}
223
e18c1337
CH
224std::string to_string(const DnsIpProtocol &protocol)
225{
226 switch (protocol)
227 {
228 case DNS_IPv4: return "IPv4"; break;
229 case DNS_IPv6: return "IPv6"; break;
230 case DNS_IPALL: return "IPv4/6"; break;
231 default: GlobalLogger.warning() << "Unexpected protocol in to_string!";
232 return "Unexpected Protocol"; break;
233 }
234}