From: Bjoern Sikora Date: Thu, 3 Sep 2009 10:46:57 +0000 (+0200) Subject: Implemented dyndns service. X-Git-Tag: v1.1~207 X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=b622876149b3e0a6a7041dbdcbe72abc2df245eb;p=bpdyndnsd Implemented dyndns service. Added user agent info to curl operations. Added access to CurlWritedataBuff. Bug fix: Do not append IP to member BaseUrl. --- diff --git a/src/config.cpp b/src/config.cpp index a4fa6bf..a255f75 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -11,6 +11,7 @@ #include "dhs.h" #include "ods.h" +#include "dyndns.h" #include #include @@ -260,6 +261,11 @@ Service::Ptr Config::create_service(const string &protocol,const string &hostnam Service::Ptr service_ods(new ODS(protocol,hostname,login,password,Log,update_interval,max_updates_within_interval,dns_cache_ttl)); return service_ods; } + else if(protocol == "dyndns") + { + Service::Ptr service_dyndns(new DYNDNS(protocol,hostname,login,password,Log,update_interval,max_updates_within_interval,dns_cache_ttl,Proxy,ProxyPort)); + return service_dyndns; + } else { Log->print_unknown_protocol(protocol); diff --git a/src/config.h b/src/config.h index daa169d..712eb8b 100644 --- a/src/config.h +++ b/src/config.h @@ -15,6 +15,7 @@ #include "logger.h" #include "serviceholder.h" #include "httphelper.h" +#include "service.h" #include #include diff --git a/src/dhs.cpp b/src/dhs.cpp index cbefaae..c3d7f53 100644 --- a/src/dhs.cpp +++ b/src/dhs.cpp @@ -173,13 +173,14 @@ list DHS::split(const string& str,const string& delimiters) const */ int DHS::perform_update(const std::string& ip) { - int ret_val = 0; + int ret_val = -1; - BaseUrl.append(ip); + string url = BaseUrl; + url.append(ip); - long output = HTTPHelp->http_get(BaseUrl); + long output = HTTPHelp->http_get(url); - get_logger()->print_http_status_code(BaseUrl,output); + get_logger()->print_http_status_code(url,output); if ( output == 200 ) { @@ -191,7 +192,7 @@ int DHS::perform_update(const std::string& ip) } else if ( output == 401 ) { - get_logger()->print_http_not_authorized(BaseUrl,get_login(),get_password()); + get_logger()->print_http_not_authorized(url,get_login(),get_password()); // not authorized ret_val = -1; } diff --git a/src/dyndns.cpp b/src/dyndns.cpp new file mode 100644 index 0000000..c8eacda --- /dev/null +++ b/src/dyndns.cpp @@ -0,0 +1,136 @@ +/** @file + * @brief DYNDNS Service class implementation. This class represents the DYNDNS service. + * + * + * + * @copyright Intra2net AG + * @license GPLv2 +*/ + +#include "dyndns.h" + +#include +#include + +using namespace std; + + +/** + * Default Constructor, needed for object serialization. + */ +DYNDNS::DYNDNS() +{ +} + + +/** + * Constructor. + * @param _hostname The hostname to update + * @param _login The login name. + * @param _password The corresponding password. + */ +DYNDNS::DYNDNS(const string& _protocol, const string& _hostname, const string& _login, const string& _password, const Logger::Ptr& _logger, const int _update_interval, const int _max_updates_within_interval, const int _dns_cache_ttl, const string& _proxy, const int _proxy_port) +{ + if ( _update_interval == -1 ) // If _update_interval is default po::option_desc (not specified via config) + set_update_interval(0); // use default protocol value + else + set_update_interval(_update_interval); + + if ( _max_updates_within_interval == -1 ) + set_max_updates_within_interval(0); + else + set_max_updates_within_interval(_max_updates_within_interval); + + if ( _dns_cache_ttl == -1 ) + set_dns_cache_ttl(60); + else + set_dns_cache_ttl(_dns_cache_ttl); + + set_protocol(_protocol); + set_hostname(_hostname); + set_login(_login); + set_password(_password); + set_logger(_logger); + + // create http helper class + HTTPHelper::Ptr _http_help(new HTTPHelper(_logger,_proxy,_proxy_port,_login,_password)); + HTTPHelp = _http_help; + _http_help.reset(); + + BaseUrl = assemble_base_url(get_hostname()); +} + + +/** + * Default destructor + */ +DYNDNS::~DYNDNS() +{ +} + + +/** + * Assemble the dhs update url from the given fqhn + * @param hostname The fqhn hostname to update IP for. + * @return The assembled update url without IP. + */ +string DYNDNS::assemble_base_url(const string& fqhn) const +{ + string base_url; + + base_url = "https://members.dyndns.org"; + base_url.append("/nic/update?hostname="); + base_url.append(fqhn); + base_url.append("&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG&myip="); + + return base_url; +} + + +/** + * Performs the Service update. + * @param ip IP Address to set. + * @return 0 if all is fine, -1 otherwise. + */ +int DYNDNS::perform_update(const std::string& ip) +{ + int ret_val = -1; + + // the result string if update was successful + string good = "good "; + good.append(ip); + + string url = BaseUrl; + url.append(ip); + + long output = HTTPHelp->http_get(url); + + get_logger()->print_http_status_code(url,output); + + // HTTP operation completed successful, now we have to parse the data received by curl cause http status code is not significant for dyndns update errors + if ( output == 200 ) + { + string curl_data = HTTPHelp->get_curl_data(); + + if ( curl_data == good ) + ret_val = 0; + else if ( curl_data == "badauth" ) + get_logger()->print_http_not_authorized(url,get_login(),get_password()); + else + get_logger()->print_update_failure(url, curl_data); + } + + return ret_val; +} + + +/** + * Serialize function needed by boost/serialization to define which members should be stored as the object state. + * @param ar Archive + * @param version Version + */ +template +void DYNDNS::serialize(Archive & ar, const unsigned int version) +{ + ar & boost::serialization::base_object(*this); +} diff --git a/src/dyndns.h b/src/dyndns.h new file mode 100644 index 0000000..2bf38db --- /dev/null +++ b/src/dyndns.h @@ -0,0 +1,51 @@ +/** @file + * @brief DYNDNS Service class header. This class represents the DYNDNS service. + * + * + * + * @copyright Intra2net AG + * @license GPLv2 +*/ + +#ifndef DYNDNS_H +#define DYNDNS_H + +#include + +#include "service.h" +#include "logger.h" + +#include +#include +#include + +class DYNDNS : public Service +{ + +private: + + friend class boost::serialization::access; + template + void serialize(Archive & ar, const unsigned int version); + + std::string BaseUrl; + + HTTPHelper::Ptr HTTPHelp; + + std::string assemble_base_url(const std::string& fqhn) const; + +public: + + typedef boost::shared_ptr Ptr; + + DYNDNS(); + + DYNDNS(const std::string& _protocol, const std::string& _hostname, const std::string& _login, const std::string& _password, const Logger::Ptr& _logger, const int _update_interval, const int _max_updates_within_interval, const int dns_cache_ttl, const std::string& proxy, const int proxy_port); + + ~DYNDNS(); + + int perform_update(const std::string& ip); + +}; + +#endif diff --git a/src/httphelper.cpp b/src/httphelper.cpp index 036051e..5794362 100644 --- a/src/httphelper.cpp +++ b/src/httphelper.cpp @@ -78,6 +78,16 @@ long HTTPHelper::http_get(const string& url) /** + * Getter for member CurlWritedataBuff + * @return CurlWritedataBuff + */ +string HTTPHelper::get_curl_data() const +{ + return CurlWritedataBuff; +} + + +/** * 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. @@ -85,6 +95,8 @@ long HTTPHelper::http_get(const string& url) */ CURL* HTTPHelper::init_curl(string& curl_writedata_buff,char* curl_err_buff) const { + string user_agent = "bpdyndnsd Intra2net AG 2009"; + CURL *curl_easy_handle = curl_easy_init(); curl_easy_setopt(curl_easy_handle,CURLOPT_NOPROGRESS,1); @@ -94,6 +106,7 @@ CURL* HTTPHelper::init_curl(string& curl_writedata_buff,char* curl_err_buff) con 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); + curl_easy_setopt(curl_easy_handle,CURLOPT_USERAGENT,&user_agent); if ( !Proxy.empty() ) { diff --git a/src/httphelper.h b/src/httphelper.h index b63e45c..97df6b8 100644 --- a/src/httphelper.h +++ b/src/httphelper.h @@ -46,6 +46,8 @@ public: long http_get(const std::string& ip); + std::string get_curl_data() const; + // libcurl is a C library, so we have to make the callback member function static :-( static int http_receive(char *inBuffer, size_t size, size_t nmemb, std::string *outBuffer); }; diff --git a/src/logger.cpp b/src/logger.cpp index 9fe824f..27a0d7b 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -1249,7 +1249,7 @@ void Logger::print_curl_data(const string& curl_writedata_buff) const if ( (level <= Loglevel) || ((level <= ExternalWarningLevel) && (!ExternalWarningLog.empty())) ) { ostringstream msg; - msg << "Data received by curl:\n" << curl_writedata_buff << endl; + msg << "Data received by curl: " << curl_writedata_buff << endl; log_notice(msg.str(),level); } } @@ -1267,7 +1267,7 @@ void Logger::print_http_not_authorized(const string& url, const string& username if ( (level <= Loglevel) || ((level <= ExternalWarningLevel) && (!ExternalWarningLog.empty())) ) { ostringstream msg; - msg << "Not authorized to perform update operation on url: " << url << "\n Please check username and password: " << username << ":" << password << endl; + msg << "Not authorized to perform update operation on url: " << url << " Please check username and password: " << username << ":" << password << endl; log_warning(msg.str(),level); } } @@ -1288,3 +1288,20 @@ void Logger::print_http_status_code(const std::string& url, const long http_code log_notice(msg.str(),level); } } + + +/** + * Generic failure while trying to update service + * @param url The requested URL + * @param curl_data The received curl_data from the server + */ +void Logger::print_update_failure(const string& url, const string& curl_data) const +{ + int level = 0; + if ( (level <= Loglevel) || ((level <= ExternalWarningLevel) && (!ExternalWarningLog.empty())) ) + { + ostringstream msg; + msg << "Problem while trying to updating service. Requested URL: " << url << " Error Code from Server: " << curl_data << endl; + log_warning(msg.str(),level); + } +} diff --git a/src/logger.h b/src/logger.h index 710be11..f13da6d 100644 --- a/src/logger.h +++ b/src/logger.h @@ -189,6 +189,8 @@ public: void print_http_not_authorized(const std::string& url, const std::string& username, const std::string& password) const; void print_http_status_code(const std::string& url, const long http_code) const; + + void print_update_failure(const std::string& url, const std::string& curl_data) const; }; #endif diff --git a/src/main.cpp b/src/main.cpp index ed86fd2..55ab56d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,6 +38,7 @@ #include "iphelper.cpp" #include "httphelper.cpp" #include "serializeservicecontainer.cpp" +#include "dyndns.cpp" using namespace std; diff --git a/src/updater.cpp b/src/updater.cpp index d966d14..e1fa1ae 100644 --- a/src/updater.cpp +++ b/src/updater.cpp @@ -19,6 +19,7 @@ // Following boost macros are needed for serialization of derived classes through a base class pointer (Service *). BOOST_CLASS_EXPORT_GUID(ODS, "ODS") BOOST_CLASS_EXPORT_GUID(DHS, "DHS") +BOOST_CLASS_EXPORT_GUID(DYNDNS, "DYNDNS") namespace fs = boost::filesystem;