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