Small STL usage improvement
[bpdyndnsd] / src / iphelper.cpp
CommitLineData
0665b239
BS
1/** @file
2 * @brief IPHelper class implementation. This class represents a Helper to get the actual IP.
3 *
4 *
5 *
6 * @copyright Intra2net AG
7 * @license GPLv2
8*/
9
10#include "iphelper.h"
11#include <boost/asio.hpp>
1c0908b5 12#include <boost/regex.hpp>
0665b239
BS
13
14using namespace std;
15
16namespace net = boost::asio;
17
18/**
19 * Default constructor.
20 */
21IPHelper::IPHelper()
22 : Hostname("")
019dc0d9
BS
23 , WebcheckIpUrl("")
24 , WebcheckIpUrlAlt("")
0665b239 25 , UseIPv6(false)
68c6b4af 26 , Log(new Logger)
0665b239
BS
27{
28}
29
30
31/**
32 * Constructor.
33 */
019dc0d9 34IPHelper::IPHelper(const Logger::Ptr _log, const string& _webcheck_url, const string& _webcheck_url_alt, const bool _use_ipv6)
0665b239 35 : Hostname("")
0665b239
BS
36{
37 Log = _log;
019dc0d9
BS
38 WebcheckIpUrl = _webcheck_url;
39 WebcheckIpUrlAlt = _webcheck_url_alt;
40 UseIPv6 = _use_ipv6;
41 Hostname = net::ip::host_name();
42
43 Log->print_hostname(Hostname);
0665b239
BS
44}
45
46
47/**
48 * Default destructor
49 */
50IPHelper::~IPHelper()
51{
52}
53
54
55/**
0665b239
BS
56 * Get the actual IP of this host through a conventional DNS query or through a IP webcheck URL if configured so.
57 * @return A string representation of the actual IP in dotted format or an empty string if something went wrong.
58 */
59string IPHelper::get_actual_ip() const
60{
20a5e1e4 61 if ( WebcheckIpUrl.empty() )
0665b239
BS
62 {
63 return dns_query();
64 }
65 else
66 {
67 return webcheck_ip();
68 }
69 return "";
70}
71
0665b239
BS
72
73/**
74 * Get the actual IP of this host through a DNS query.
75 * @return A string representation of the actual IP in dotted format or an empty string if something went wrong.
76 */
77string IPHelper::dns_query() const
78{
20a5e1e4
TJ
79 string ip_addr_v4;
80 string ip_addr_v6;
0665b239
BS
81
82 try
83 {
84 // BOOST asio isn't the simplest way to perform a DNS lookup, but it works just fine.
85 net::io_service io_service;
86 net::ip::tcp::resolver resolver(io_service);
87 net::ip::tcp::resolver::query query(Hostname, "0");
88 net::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
89 net::ip::tcp::resolver::iterator end;
90 while(endpoint_iterator != end)
91 {
019dc0d9
BS
92 net::ip::tcp::endpoint endpoint = endpoint_iterator->endpoint(); // this ends up in a compiler warning: cc1plus: warning: dereferencing pointer 'pretmp.37188' does break strict-aliasing rules
93 net::ip::address ip = endpoint.address(); // but why?
0665b239
BS
94 if ( ip.is_v4() )
95 ip_addr_v4 = ip.to_string();
96 else if ( ip.is_v6() )
97 ip_addr_v6 = ip.to_string();
019dc0d9
BS
98 Log->print_own_ipv4(ip_addr_v4);
99 if ( UseIPv6 == true )
100 Log->print_own_ipv6(ip_addr_v6);
0665b239
BS
101 endpoint_iterator++;
102 }
103 io_service.reset();
104 }
105 catch(exception& e)
106 {
107 Log->print_error_hostname_to_ip(e.what(),Hostname);
108 return "";
109 }
110
111 if ( (UseIPv6 == true) && (ip_addr_v6 != "") )
112 return ip_addr_v6;
113
114 return ip_addr_v4;
115}
116
117
118/**
119 * Get the actual IP of this host through a IP webcheck URL.
120 * @return A string representation of the actual IP in dotted format or an empty string if something went wrong.
121 */
122string IPHelper::webcheck_ip() const
123{
1c0908b5
BS
124 string ip_addr = "";
125
126 // Init CURL buffers
127 string curl_writedata_buff;
128 char curl_err_buff[CURL_ERROR_SIZE];
129 int curl_err_code=1;
130
131 // Init URL List
132 list<string> url_list;
133 url_list.push_back(WebcheckIpUrl);
134 url_list.push_back(WebcheckIpUrlAlt);
135 string actual_url;
136
137 // Init CURL
138 CURL * curl_easy_handle = init_curl(curl_writedata_buff,curl_err_buff);
139
140 // If perform_curl_operation returns a connection problem indicating return code, try the next ip webcheck url if there is one.
141 while ( (curl_err_code == 1) && (url_list.size() != 0) && (url_list.front() != "") )
142 {
143 // Set URL
144 actual_url = url_list.front();
145 url_list.pop_front();
146 set_curl_url(curl_easy_handle,actual_url);
147
148 // Perform curl operation
149 curl_err_code = perform_curl_operation(curl_easy_handle, curl_err_buff, actual_url);
150 }
151
152 // Cleanup CURL handle
153 curl_easy_cleanup(curl_easy_handle);
154
155 // If curl_err_code is not 0, the ip couldn't be determined through any configured webcheck url.
156 if ( curl_err_code != 0 )
157 {
158 Log->print_webcheck_no_ip();
159 // error handling
160 return ip_addr;
161 }
162
163 Log->print_received_curl_data(curl_writedata_buff);
164
165 ip_addr = parse_ip(curl_writedata_buff);
0665b239
BS
166
167 return ip_addr;
168}
1c0908b5
BS
169
170
171/**
172 * Tries to find a valid IPv4 Address in dottet format in a given string and returns the IP-Address found.
173 * @param data The string data to search in for a valid IPv4-Address.
174 * @return The IP Address found or an empty string.
175 */
176string IPHelper::parse_ip(const string& data) const
177{
178 string ip = "";
179
180 // regex for valid ip address
181 boost::regex expr("([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})");
182
183 boost::smatch matches;
184
185 if ( boost::regex_search(data,matches,expr) )
186 {
187 ip = matches[1];
188 Log->print_regex_found_ip(ip);
189 }
190 else
191 {
192 Log->print_regex_ip_not_found(data);
193 }
194
195 return ip;
196}
197
198
199/**
200 * Performs the curl operation.
201 * @param curl_easy_handle The initialized and configured curl handle.
202 * @param curl_err_buff The pointer to the curl error buffer to get error messages from.
203 * @param actual_url The actual configured URL.
204 * @return 0 if all is fine, 1 if an connection problem to the configured url occurs, -1 on other errors.
205 */
206int IPHelper::perform_curl_operation(CURL * curl_easy_handle, char* curl_err_buff, const string& actual_url) const
207{
208 int curl_err_code;
209 if ( (curl_err_code = curl_easy_perform(curl_easy_handle) ) != 0 )
210 {
211 // CURL error occured
212 if ( (curl_err_code == CURLE_COULDNT_CONNECT) || (curl_err_code == CURLE_OPERATION_TIMEOUTED) || (curl_err_code == CURLE_COULDNT_RESOLVE_HOST) )
213 {
214 // In case of connection problems we should return 1, that the fallback url will be used.
215 Log->print_webcheck_url_connection_problem(curl_err_buff, actual_url);
216 return 1;
217 }
218 else
219 {
220 // other error
221 Log->print_webcheck_error(curl_err_buff, actual_url);
222 return -1;
223 }
224 }
225 // Operation performed without any problems
226 return 0;
227}
228
229
230/**
231 * Sets a url to the easy curl handle
232 * @param curl_easy_handle The easy curl handle to set the url for.
233 * @param url The url to set.
234 */
235void IPHelper::set_curl_url(CURL * curl_easy_handle, const string& url) const
236{
237 curl_easy_setopt(curl_easy_handle,CURLOPT_URL,url.c_str());
238}
239
240
241/**
242 * Initialized curl easy handle with a few options.
243 * @param curl_writedata_buff Reference to a string wich will be filled with the curl result
244 * @param curl_err_buff A pointer to an char array which will be filled with error message.
245 * @return A pointer to the easy curl handle.
246 */
247CURL * IPHelper::init_curl(string& curl_writedata_buff,char* curl_err_buff) const
248{
249 CURL *curl_easy_handle = curl_easy_init();
250
251 curl_easy_setopt(curl_easy_handle,CURLOPT_NOPROGRESS,1);
252 curl_easy_setopt(curl_easy_handle,CURLOPT_CONNECTTIMEOUT,5);
253 curl_easy_setopt(curl_easy_handle,CURLOPT_TIMEOUT,10);
254 curl_easy_setopt(curl_easy_handle,CURLOPT_BUFFERSIZE,1024);
255 curl_easy_setopt(curl_easy_handle,CURLOPT_ERRORBUFFER,curl_err_buff);
256 curl_easy_setopt(curl_easy_handle,CURLOPT_WRITEFUNCTION,http_receive);
257 curl_easy_setopt(curl_easy_handle,CURLOPT_WRITEDATA,&curl_writedata_buff);
258
259 return curl_easy_handle;
260}
261
262
263/**
264 * Callback Function is called every time CURL is receiving data from HTTPS-Server and will copy all received Data to the given stream pointer
265 * @param inBuffer Pointer to input.
266 * @param size How many mem blocks are received
267 * @param nmemb size of each memblock
268 * @param outBuffer Pointer to output stream.
269 * @return The size received.
270 */
271int IPHelper::http_receive( char *inBuffer, size_t size, size_t nmemb, string *outBuffer )
272{
273 outBuffer->append(inBuffer);
274 return (size*nmemb);
275}