Commit | Line | Data |
---|---|---|
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 | 32 | using boost::bind; |
36ad976b CH |
33 | using I2n::Logger::GlobalLogger; |
34 | ||
96779587 | 35 | |
36ad976b CH |
36 | DnsMasterItem DnsMaster::TheOnlyInstance; |
37 | ||
8d26221d | 38 | // just delegates work to other create_master function |
96779587 | 39 | void 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 | ||
62 | void 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 | 86 | DnsMaster::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 | ||
103 | DnsMasterItem& 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 |
111 | DnsMaster::~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 |
129 | ResolverItem& 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 | 138 | ResolverItem& 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 | */ |
184 | bool 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 | |
199 | DnsIpProtocol 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 | ||
220 | int DnsMaster::get_resolved_ip_ttl_threshold() const | |
221 | { | |
222 | return ResolvedIpTtlThreshold; | |
223 | } | |
224 | ||
225 | int DnsMaster::get_max_address_resolution_attempts() const | |
96779587 | 226 | { |
923626c0 | 227 | return MaxAddressResolutionAttempts; |
96779587 CH |
228 | } |
229 | ||
cd71d095 CH |
230 | int DnsMaster::get_max_recursion_count() const |
231 | { | |
232 | return MaxRecursionCount; | |
233 | } | |
234 | ||
e18c1337 CH |
235 | std::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 | } |