2 * @brief IPHelper class implementation. This class represents a Helper to get the actual IP.
6 * @copyright Intra2net AG
10 #include "ip_addr_helper.h"
11 #include <boost/asio.hpp>
12 #include <boost/regex.hpp>
16 namespace net = boost::asio;
19 * Default constructor.
21 IPAddrHelper::IPAddrHelper()
33 IPAddrHelper::IPAddrHelper(const Logger::Ptr _log, const string& _webcheck_url, const string& _webcheck_url_alt, const int _webcheck_interval ,const bool _use_ipv6, const string& _proxy, const int _proxy_port)
35 , WebcheckIpUrl(_webcheck_url)
36 , WebcheckIpUrlAlt(_webcheck_url_alt)
37 , WebcheckInterval(_webcheck_interval)
40 , ProxyPort(_proxy_port)
43 Hostname = net::ip::host_name();
44 Log->print_hostname(Hostname);
51 IPAddrHelper::~IPAddrHelper()
57 * Tests if a given IP is a local address
58 * @param ip The IP to test
59 * @return true if given IP is local, false if not.
61 bool IPAddrHelper::is_local(const string ip) const
64 boost::regex expr_loopback("127\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}");
67 boost::regex expr_192("192\\.168\\.[0-9]{1,3}\\.[0-9]{1,3}");
70 boost::regex expr_10("10\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}");
73 boost::regex expr_169_254("169\\.254\\.[0-9]{1,3}\\.[0-9]{1,3}");
75 // 172.16.x.x -> 172.31.x.x
76 boost::regex expr_172_1("172\\.1[6-9]{1}\\.[0-9]{1,3}\\.[0-9]{1,3}");
77 boost::regex expr_172_2("172\\.2[0-9]{1}\\.[0-9]{1,3}\\.[0-9]{1,3}");
78 boost::regex expr_172_3("172\\.3[0-1]{1}\\.[0-9]{1,3}\\.[0-9]{1,3}");
80 // It's time to test against the regex patterns
81 if ( boost::regex_search(ip,expr_loopback) )
83 Log->print_regex_match(expr_loopback.str(),ip);
86 else if ( boost::regex_search(ip,expr_192) )
88 Log->print_regex_match(expr_192.str(),ip);
91 else if ( boost::regex_search(ip,expr_10) )
93 Log->print_regex_match(expr_10.str(),ip);
96 else if ( boost::regex_search(ip,expr_169_254) )
98 Log->print_regex_match(expr_169_254.str(),ip);
101 else if ( boost::regex_search(ip,expr_172_1) )
103 Log->print_regex_match(expr_172_1.str(),ip);
106 else if ( boost::regex_search(ip,expr_172_2) )
108 Log->print_regex_match(expr_172_2.str(),ip);
111 else if ( boost::regex_search(ip,expr_172_3) )
113 Log->print_regex_match(expr_172_3.str(),ip);
122 * Get the actual IP of this host through a conventional DNS query or through a IP webcheck URL if configured so.
123 * @return A string representation of the actual IP in dotted format or an empty string if something went wrong.
125 string IPAddrHelper::get_actual_ip()
128 if ( WebcheckIpUrl.empty() )
137 // If IP is within a private range then return ""
140 Log->print_ip_is_local(ip);
149 * Get the actual IP of the given host through a DNS query.
150 * @param _hostname The hostname for the dns lookup, if empty string, then perform a dns lookup to the local hostname.
151 * @return A string representation of the actual IP in dotted format or an empty string if something went wrong.
153 string IPAddrHelper::dns_query(const string& _hostname) const
158 string hostname = Hostname;
159 if ( !_hostname.empty() )
160 hostname = _hostname;
164 // BOOST asio isn't the simplest way to perform a DNS lookup, but it works just fine.
165 net::io_service io_service;
166 net::ip::tcp::resolver resolver(io_service);
167 net::ip::tcp::resolver::query query(hostname, "0");
168 net::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
169 net::ip::tcp::resolver::iterator end;
170 while(endpoint_iterator != end)
173 ip = endpoint_iterator->endpoint().address();
175 ip_addr_v4 = ip.to_string();
176 else if ( ip.is_v6() )
177 ip_addr_v6 = ip.to_string();
178 Log->print_own_ipv4(ip_addr_v4, hostname);
179 if ( UseIPv6 == true )
180 Log->print_own_ipv6(ip_addr_v6, hostname);
187 Log->print_error_hostname_to_ip(e.what(),hostname);
191 if ( (UseIPv6 == true) && (ip_addr_v6 != "") )
199 * Get the actual IP of this host through a IP webcheck URL.
200 * @return A string representation of the actual IP in dotted format or an empty string if something went wrong.
202 string IPAddrHelper::webcheck_ip()
204 // Init IPAddress with a empty string.
207 // Get the current time.
208 int current_time = time(NULL);
210 // Test if webcheck is allowed due to webcheck_interval.
211 if ( (LastWebcheck + (WebcheckInterval*60)) >= current_time )
213 // Webcheck not allowed, log it and return empty string.
214 Log->print_webcheck_exceed_interval( LastWebcheck, (WebcheckInterval*60), current_time );
219 string curl_writedata_buff;
220 char curl_err_buff[CURL_ERROR_SIZE];
224 list<string> url_list;
225 url_list.push_back(WebcheckIpUrl);
226 url_list.push_back(WebcheckIpUrlAlt);
230 CURL * curl_easy_handle = init_curl(curl_writedata_buff,curl_err_buff);
232 // If perform_curl_operation returns a connection problem indicating return code, try the next ip webcheck url if there is one.
233 while ( (curl_err_code == 1) && (url_list.size() != 0) && (url_list.front() != "") )
236 actual_url = url_list.front();
237 url_list.pop_front();
238 set_curl_url(curl_easy_handle,actual_url);
240 // Perform curl operation, err_code of 1 indicated connection problem, so try next url.
241 curl_err_code = perform_curl_operation(curl_easy_handle, curl_err_buff, actual_url);
244 // Cleanup CURL handle
245 curl_easy_cleanup(curl_easy_handle);
247 // If curl_err_code is not 0, the ip couldn't be determined through any configured webcheck url.
248 if ( curl_err_code != 0 )
250 // Log it and return the empty string.
251 Log->print_webcheck_no_ip();
255 // Log the received curl data.
256 Log->print_received_curl_data(curl_writedata_buff);
258 // Try to parse a IPAddress out of the received data.
259 ip_addr = parse_ip(curl_writedata_buff);
261 // Set the LastWebcheck time to current time.
262 LastWebcheck = current_time;
264 // Return the parsed IPAddress.
270 * Tries to find a valid IPv4 Address in dottet format in a given string and returns the IP-Address found.
271 * @param data The string data to search in for a valid IPv4-Address.
272 * @return The IP Address found or an empty string.
274 string IPAddrHelper::parse_ip(const string& data) const
278 // Regex for valid ip address
279 boost::regex expr("([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})");
281 boost::smatch matches;
283 if ( boost::regex_search(data,matches,expr) )
286 Log->print_regex_found_ip(ip);
290 Log->print_regex_ip_not_found(data);
298 * Performs the curl operation.
299 * @param curl_easy_handle The initialized and configured curl handle.
300 * @param curl_err_buff The pointer to the curl error buffer to get error messages from.
301 * @param actual_url The actual configured URL.
302 * @return 0 if all is fine, 1 if an connection problem to the configured url occurs, -1 on other errors.
304 int IPAddrHelper::perform_curl_operation(CURL * curl_easy_handle, char* curl_err_buff, const string& actual_url) const
307 if ( (curl_err_code = curl_easy_perform(curl_easy_handle) ) != 0 )
309 // CURL error occured
310 if ( (curl_err_code == CURLE_COULDNT_CONNECT) || (curl_err_code == CURLE_OPERATION_TIMEOUTED) || (curl_err_code == CURLE_COULDNT_RESOLVE_HOST) )
312 // In case of connection problems we should return 1, that the fallback url will be used.
313 Log->print_webcheck_url_connection_problem(curl_err_buff, actual_url);
319 Log->print_webcheck_error(curl_err_buff, actual_url);
323 // Operation performed without any problems
329 * Sets a url to the easy curl handle
330 * @param curl_easy_handle The easy curl handle to set the url for.
331 * @param url The url to set.
333 void IPAddrHelper::set_curl_url(CURL * curl_easy_handle, const string& url) const
335 curl_easy_setopt(curl_easy_handle,CURLOPT_URL,url.c_str());
340 * Initialized curl easy handle with a few options.
341 * @param curl_writedata_buff Reference to a string wich will be filled with the curl result
342 * @param curl_err_buff A pointer to an char array which will be filled with error message.
343 * @return A pointer to the easy curl handle.
345 CURL * IPAddrHelper::init_curl(string& curl_writedata_buff,char* curl_err_buff) const
347 CURL *curl_easy_handle = curl_easy_init();
349 curl_easy_setopt(curl_easy_handle,CURLOPT_NOPROGRESS,1);
350 curl_easy_setopt(curl_easy_handle,CURLOPT_CONNECTTIMEOUT,5);
351 curl_easy_setopt(curl_easy_handle,CURLOPT_TIMEOUT,10);
352 curl_easy_setopt(curl_easy_handle,CURLOPT_BUFFERSIZE,1024);
353 curl_easy_setopt(curl_easy_handle,CURLOPT_ERRORBUFFER,curl_err_buff);
354 curl_easy_setopt(curl_easy_handle,CURLOPT_WRITEFUNCTION,http_receive);
355 curl_easy_setopt(curl_easy_handle,CURLOPT_WRITEDATA,&curl_writedata_buff);
357 if ( !Proxy.empty() )
359 curl_easy_setopt(curl_easy_handle,CURLOPT_PROXY,Proxy.c_str());
360 curl_easy_setopt(curl_easy_handle,CURLOPT_PROXYPORT,ProxyPort);
363 return curl_easy_handle;
368 * Callback Function is called every time CURL is receiving data from HTTPS-Server and will copy all received Data to the given stream pointer
369 * @param inBuffer Pointer to input.
370 * @param size How many mem blocks are received
371 * @param nmemb size of each memblock
372 * @param outBuffer Pointer to output stream.
373 * @return The size received.
375 int IPAddrHelper::http_receive( char *inBuffer, size_t size, size_t nmemb, string *outBuffer )
377 outBuffer->append(inBuffer);