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