From 1c0908b541291f08bbc306292386b7b952a9ea17 Mon Sep 17 00:00:00 2001 From: Bjoern Sikora Date: Thu, 13 Aug 2009 17:57:11 +0200 Subject: [PATCH] Implemented determining IP through WEBCHECK URL. --- src/iphelper.cpp | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/iphelper.h | 12 ++++ src/logger.cpp | 99 ++++++++++++++++++++++++++++++++++- src/logger.h | 14 +++++- src/updater.cpp | 2 +- 5 files changed, 273 insertions(+), 5 deletions(-) diff --git a/src/iphelper.cpp b/src/iphelper.cpp index 634cc5f..4d81e07 100644 --- a/src/iphelper.cpp +++ b/src/iphelper.cpp @@ -9,6 +9,7 @@ #include "iphelper.h" #include +#include using namespace std; @@ -120,7 +121,155 @@ string IPHelper::dns_query() const */ string IPHelper::webcheck_ip() const { - string ip_addr = "127.0.0.1"; + string ip_addr = ""; + + // Init CURL buffers + string curl_writedata_buff; + char curl_err_buff[CURL_ERROR_SIZE]; + int curl_err_code=1; + + // Init URL List + list url_list; + url_list.push_back(WebcheckIpUrl); + url_list.push_back(WebcheckIpUrlAlt); + string actual_url; + + // Init CURL + CURL * curl_easy_handle = init_curl(curl_writedata_buff,curl_err_buff); + + // If perform_curl_operation returns a connection problem indicating return code, try the next ip webcheck url if there is one. + while ( (curl_err_code == 1) && (url_list.size() != 0) && (url_list.front() != "") ) + { + // Set URL + actual_url = url_list.front(); + url_list.pop_front(); + set_curl_url(curl_easy_handle,actual_url); + + // Perform curl operation + curl_err_code = perform_curl_operation(curl_easy_handle, curl_err_buff, actual_url); + } + + // Cleanup CURL handle + curl_easy_cleanup(curl_easy_handle); + + // If curl_err_code is not 0, the ip couldn't be determined through any configured webcheck url. + if ( curl_err_code != 0 ) + { + Log->print_webcheck_no_ip(); + // error handling + return ip_addr; + } + + Log->print_received_curl_data(curl_writedata_buff); + + ip_addr = parse_ip(curl_writedata_buff); return ip_addr; } + + +/** + * Tries to find a valid IPv4 Address in dottet format in a given string and returns the IP-Address found. + * @param data The string data to search in for a valid IPv4-Address. + * @return The IP Address found or an empty string. + */ +string IPHelper::parse_ip(const string& data) const +{ + string ip = ""; + + // regex for valid ip address + boost::regex expr("([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})"); + + boost::smatch matches; + + if ( boost::regex_search(data,matches,expr) ) + { + ip = matches[1]; + Log->print_regex_found_ip(ip); + } + else + { + Log->print_regex_ip_not_found(data); + } + + return ip; +} + + +/** + * Performs the curl operation. + * @param curl_easy_handle The initialized and configured curl handle. + * @param curl_err_buff The pointer to the curl error buffer to get error messages from. + * @param actual_url The actual configured URL. + * @return 0 if all is fine, 1 if an connection problem to the configured url occurs, -1 on other errors. + */ +int IPHelper::perform_curl_operation(CURL * curl_easy_handle, char* curl_err_buff, const string& actual_url) const +{ + int curl_err_code; + if ( (curl_err_code = curl_easy_perform(curl_easy_handle) ) != 0 ) + { + // CURL error occured + if ( (curl_err_code == CURLE_COULDNT_CONNECT) || (curl_err_code == CURLE_OPERATION_TIMEOUTED) || (curl_err_code == CURLE_COULDNT_RESOLVE_HOST) ) + { + // In case of connection problems we should return 1, that the fallback url will be used. + Log->print_webcheck_url_connection_problem(curl_err_buff, actual_url); + return 1; + } + else + { + // other error + Log->print_webcheck_error(curl_err_buff, actual_url); + return -1; + } + } + // Operation performed without any problems + return 0; +} + + +/** + * Sets a url to the easy curl handle + * @param curl_easy_handle The easy curl handle to set the url for. + * @param url The url to set. + */ +void IPHelper::set_curl_url(CURL * curl_easy_handle, const string& url) const +{ + curl_easy_setopt(curl_easy_handle,CURLOPT_URL,url.c_str()); +} + + +/** + * Initialized curl easy handle with a few options. + * @param curl_writedata_buff Reference to a string wich will be filled with the curl result + * @param curl_err_buff A pointer to an char array which will be filled with error message. + * @return A pointer to the easy curl handle. + */ +CURL * IPHelper::init_curl(string& curl_writedata_buff,char* curl_err_buff) const +{ + CURL *curl_easy_handle = curl_easy_init(); + + curl_easy_setopt(curl_easy_handle,CURLOPT_NOPROGRESS,1); + curl_easy_setopt(curl_easy_handle,CURLOPT_CONNECTTIMEOUT,5); + curl_easy_setopt(curl_easy_handle,CURLOPT_TIMEOUT,10); + curl_easy_setopt(curl_easy_handle,CURLOPT_BUFFERSIZE,1024); + curl_easy_setopt(curl_easy_handle,CURLOPT_ERRORBUFFER,curl_err_buff); + curl_easy_setopt(curl_easy_handle,CURLOPT_WRITEFUNCTION,http_receive); + curl_easy_setopt(curl_easy_handle,CURLOPT_WRITEDATA,&curl_writedata_buff); + + return curl_easy_handle; +} + + +/** + * Callback Function is called every time CURL is receiving data from HTTPS-Server and will copy all received Data to the given stream pointer + * @param inBuffer Pointer to input. + * @param size How many mem blocks are received + * @param nmemb size of each memblock + * @param outBuffer Pointer to output stream. + * @return The size received. + */ +int IPHelper::http_receive( char *inBuffer, size_t size, size_t nmemb, string *outBuffer ) +{ + outBuffer->append(inBuffer); + return (size*nmemb); +} diff --git a/src/iphelper.h b/src/iphelper.h index 0cf4787..98622fd 100644 --- a/src/iphelper.h +++ b/src/iphelper.h @@ -13,6 +13,7 @@ #include "logger.h" #include +#include /** @author Bjoern Sikora @@ -43,6 +44,17 @@ public: std::string dns_query() const; std::string webcheck_ip() const; + + // libcurl is a C library, so we have to make the callback member function static :-( + static int http_receive( char *, size_t, size_t, std::string* ); + + CURL * init_curl(std::string&, char*) const; + + void set_curl_url(CURL *, const std::string&) const; + + int perform_curl_operation(CURL *, char*, const std::string&) const; + + std::string parse_ip(const std::string&) const; }; #endif diff --git a/src/logger.cpp b/src/logger.cpp index cab7b5e..93f8ed2 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -749,7 +749,7 @@ void Logger::print_own_ipv6(const std::string& ip_addr_v6) const * @param exception The exception caught. * @param hostname The hostname. */ -void Logger::print_error_hostname_to_ip(const std::string& exception, const std::string& hostname) const +void Logger::print_error_hostname_to_ip(const string& exception, const string& hostname) const { if ( 1 <= Loglevel ) { @@ -760,12 +760,107 @@ void Logger::print_error_hostname_to_ip(const std::string& exception, const std: } -void Logger::print_update_service_successful(const std::string& service) +/** + * The update of the given service was successful. + * @param service The service. + */ +void Logger::print_update_service_successful(const string& service) const { if ( 0 <= Loglevel ) { ostringstream msg; msg << "Updated service successful: " << service << endl; + log_notice(msg.str()); + } +} + + +/** + * No ip could be determined through webcheck + */ +void Logger::print_webcheck_no_ip() const +{ + if ( 0 <= Loglevel ) + { + ostringstream msg; + msg << "This hosts' IP could not be determined through any configured webcheck url." << endl; + log_error(msg.str()); + } +} + + +/** + * Connection problem while trying to get ip through webcheck url + * @param curl_err_buff Curl error message + * @param url the url + */ +void Logger::print_webcheck_url_connection_problem(const char * curl_err_buff, const string& url) const +{ + if ( 1 <= Loglevel ) + { + ostringstream msg; + msg << "There was a problem while trying to connect to following URL: " << url << " CURL error: " << curl_err_buff << endl; + log_warning(msg.str()); + } +} + + +/** + * Prints out curl error. + * @param curl_err_buff Curl error message. + * @param url URL + */ +void Logger::print_webcheck_error(const char * curl_err_buff, const string& url) const +{ + if ( 0 <= Loglevel ) + { + ostringstream msg; + msg << "There was an error while trying to connect to following URL: " << url << " CURL error: " << curl_err_buff << endl; log_error(msg.str()); } } + + +/** + * Prints out the received data through curl. + * @param curl_data Data string + */ +void Logger::print_received_curl_data(const string& curl_data) const +{ + if ( 1 <= Loglevel ) + { + ostringstream msg; + msg << "Received CURL data: " << curl_data << endl; + log_notice(msg.str()); + } +} + + +/** + * IP was foudn through regex + * @param ip The IP found. + */ +void Logger::print_regex_found_ip(const string& ip) const +{ + if ( 1 <= Loglevel ) + { + ostringstream msg; + msg << "Found IP-Address via regex: " << ip << endl; + log_notice(msg.str()); + } +} + + +/** + * No IP was found through regex. + * @param data The data string which should contain a valid IP.s + */ +void Logger::print_regex_ip_not_found(const string& data) const +{ + if ( 0 <= Loglevel ) + { + ostringstream msg; + msg << "Could not extract an IP-Address via regex from following data:\n" << data << endl; + log_warning(msg.str()); + } +} diff --git a/src/logger.h b/src/logger.h index a7fd2df..b2a584f 100644 --- a/src/logger.h +++ b/src/logger.h @@ -133,7 +133,19 @@ public: void print_error_hostname_to_ip(const std::string&, const std::string&) const; - void print_update_service_successful(const std::string&); + void print_update_service_successful(const std::string&) const; + + void print_webcheck_no_ip() const; + + void print_webcheck_url_connection_problem(const char *, const std::string&) const; + + void print_webcheck_error(const char *, const std::string&) const; + + void print_received_curl_data(const std::string&) const; + + void print_regex_found_ip(const std::string&) const; + + void print_regex_ip_not_found(const std::string&) const; }; #endif diff --git a/src/updater.cpp b/src/updater.cpp index bc46127..17ed7da 100644 --- a/src/updater.cpp +++ b/src/updater.cpp @@ -163,7 +163,7 @@ void Updater::update_services() BOOST_FOREACH(Service::Ptr &service, services ) { - // TODO: only update if IP differs. + // TODO: only update if IP differs and is_valid and is_not_empty. service->update(ip); } } -- 1.7.1