From 1a00eac606252994b8f3d0a69523f73583b4a6e0 Mon Sep 17 00:00:00 2001 From: Bjoern Sikora Date: Fri, 4 Sep 2009 17:59:44 +0200 Subject: [PATCH] First shot on easydns. Implemented checking of configured hostname for service, must contain at least a domain part and a tld. --- src/config.cpp | 16 ++++ src/dhs.cpp | 10 +-- src/easydns.cpp | 243 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/easydns.h | 57 ++++++++++++ src/httphelper.cpp | 2 +- src/logger.cpp | 16 ++++ src/logger.h | 2 + src/main.cpp | 1 + src/updater.cpp | 2 + 9 files changed, 340 insertions(+), 9 deletions(-) create mode 100644 src/easydns.cpp create mode 100644 src/easydns.h diff --git a/src/config.cpp b/src/config.cpp index 7b7d184..335e7ff 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -13,6 +13,7 @@ #include "ods.h" #include "dyndns.h" #include "dyns.h" +#include "easydns.h" #include #include @@ -248,6 +249,16 @@ int Config::parse_cmd_line(int argc, char *argv[]) */ Service::Ptr Config::create_service(const string &protocol,const string &hostname, const string &login, const string &password, const int update_interval, const int max_updates_within_interval, const int dns_cache_ttl) { + // Test for valid hostname. Must contain 3 parts minimum. + list fqhn_parts; + ba::split(fqhn_parts,hostname,boost::is_any_of(".")); + if ( fqhn_parts.size() < 3 ) + { + Log->print_invalid_hostname(protocol); + Service::Ptr service; + return service; + } + if(protocol == "dhs") { Service::Ptr service_dhs(new DHS(protocol,hostname,login,password,Log,update_interval,max_updates_within_interval,dns_cache_ttl,Proxy,ProxyPort)); @@ -268,6 +279,11 @@ Service::Ptr Config::create_service(const string &protocol,const string &hostnam Service::Ptr service_dyns(new DYNS(protocol,hostname,login,password,Log,update_interval,max_updates_within_interval,dns_cache_ttl,Proxy,ProxyPort)); return service_dyns; } + else if(protocol == "easydns") + { + Service::Ptr service_easydns(new EASYDNS(protocol,hostname,login,password,Log,update_interval,max_updates_within_interval,dns_cache_ttl,Proxy,ProxyPort)); + return service_easydns; + } else { Log->print_unknown_protocol(protocol); diff --git a/src/dhs.cpp b/src/dhs.cpp index c3d7f53..bbb9940 100644 --- a/src/dhs.cpp +++ b/src/dhs.cpp @@ -59,14 +59,8 @@ DHS::DHS(const string& _protocol, const string& _hostname, const string& _login, // extract domain part from hostname list host_domain_part = separate_domain_and_host_part(get_hostname()); - if ( host_domain_part.size() <= 1 ) - { - BaseUrl = assemble_base_url(host_domain_part.front(),""); - } - else - { - BaseUrl = assemble_base_url(host_domain_part.front(),host_domain_part.back()); - } + + BaseUrl = assemble_base_url(host_domain_part.front(),host_domain_part.back()); } diff --git a/src/easydns.cpp b/src/easydns.cpp new file mode 100644 index 0000000..8840776 --- /dev/null +++ b/src/easydns.cpp @@ -0,0 +1,243 @@ +/** @file + * @brief EASYDNS Service class implementation. This class represents the EASYDNS service. + * + * + * + * @copyright Intra2net AG + * @license GPLv2 +*/ + +#include "easydns.h" + +#include +#include + +using namespace std; + + +/** + * Default Constructor, needed for object serialization. + */ +EASYDNS::EASYDNS() +{ +} + + +/** + * Constructor. + * @param _hostname The hostname to update + * @param _login The login name. + * @param _password The corresponding password. + */ +EASYDNS::EASYDNS(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(10); // use default protocol value + else + set_update_interval(_update_interval); + + if ( _max_updates_within_interval == -1 ) + set_max_updates_within_interval(1); + else + set_max_updates_within_interval(_max_updates_within_interval); + + if ( _dns_cache_ttl == -1 ) + set_dns_cache_ttl(1200); + 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(); + + // extract domain part from hostname + list host_domain_part = separate_domain_and_host_part(get_hostname()); + + string two_level_tld = get_two_level_tld(host_domain_part.back()); + if ( !two_level_tld.empty() ) + BaseUrl = assemble_base_url(get_hostname(),two_level_tld); + else + BaseUrl = assemble_base_url(get_hostname(),""); +} + + +/** + * Default destructor + */ +EASYDNS::~EASYDNS() +{ +} + + +/** + * Tries to extract the two_level domain part if there is one + * @param domain_part The complete domain part. + * @return Two_level_domain part if there is one or "" if not so. + */ +string EASYDNS::get_two_level_tld(const string& domain_part) const +{ + // TODO: There is a list with all two level TLD's, use it + + // split the domain_part + list domain_tokens = split(domain_part,"."); + + domain_tokens.pop_front(); + + if ( domain_tokens.size() > 1 ) + { + string two_level_tld = domain_tokens.front(); + domain_tokens.pop_front(); + + BOOST_FOREACH(string domain_part, domain_tokens) + { + two_level_tld.append("."); + two_level_tld.append(domain_part); + } + + return two_level_tld; + } + else + { + return ""; + } +} + + +/** + * Assemble the easydns update url from the given hostname and domain part + * @param hostname The hostname to update IP for. + * @param domain_part The domain_part in which the hostname is located. + * @return The assembled update url without IP. + */ +string EASYDNS::assemble_base_url(const string& hostname, const string& two_level_tld) const +{ + string base_url; + if ( !two_level_tld.empty() ) + { + base_url = "https://members.easydns.com"; + base_url.append("/dyn/dyndns.php?hostname="); + base_url.append(hostname); + base_url.append("&tld="); + base_url.append(two_level_tld); + base_url.append("&myip="); + } + else + { + base_url = "https://members.easydns.com"; + base_url.append("/dyn/dyndns.php?hostname="); + base_url.append(hostname); + base_url.append("&myip="); + } + return base_url; +} + + +/** + * Separates the hostname from the domain part. + * @param fqdn Hostname with domain part. + * @return A list with 2 elements (first element is the hostname, second element the domain part), or a list with 1 element if the domain part couldn't be determined. + */ +list EASYDNS::separate_domain_and_host_part(const string& fqdn) const +{ + list splitted = split(fqdn,"."); + + if ( splitted.size() > 1 ) + { + string host = splitted.front(); + splitted.pop_front(); + + string domain = splitted.front(); + splitted.pop_front(); + + BOOST_FOREACH(string domain_part, splitted) + { + domain.append("."); + domain.append(domain_part); + } + + splitted.clear(); + splitted.push_back(host); + splitted.push_back(domain); + } + + return splitted; +} + + +/** + * Splitts a string into single tokens useing given delimiters + * @param str String to split + * @param delimiters Deliminters to use + * @return A list with the single tokens + */ +list EASYDNS::split(const string& str,const string& delimiters) const +{ + list tokens; + // Skip delimiters at beginning. + string::size_type lastPos = str.find_first_not_of(delimiters, 0); + // Find first "non-delimiter". + string::size_type pos = str.find_first_of(delimiters, lastPos); + + while (string::npos != pos || string::npos != lastPos) + { + // Found a token, add it to the list. + tokens.push_back(str.substr(lastPos, pos - lastPos)); + // Skip delimiters. Note the "not_of" + lastPos = str.find_first_not_of(delimiters, pos); + // Find next "non-delimiter" + pos = str.find_first_of(delimiters, lastPos); + } + return tokens; +} + + +/** + * Performs the Service update. + * @param ip IP Address to set. + * @return 0 if all is fine, -1 otherwise. + */ +int EASYDNS::perform_update(const std::string& ip) +{ + int ret_val = -1; + + 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 == "NOERROR" ) + ret_val = 0; + else if ( curl_data == "NOACCESS" ) + 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 EASYDNS::serialize(Archive & ar, const unsigned int version) +{ + ar & boost::serialization::base_object(*this); +} diff --git a/src/easydns.h b/src/easydns.h new file mode 100644 index 0000000..ddd0812 --- /dev/null +++ b/src/easydns.h @@ -0,0 +1,57 @@ +/** @file + * @brief EASYDNS Service class header. This class represents the EASYDNS service. + * + * + * + * @copyright Intra2net AG + * @license GPLv2 +*/ + +#ifndef EASYDNS_H +#define EASYDNS_H + +#include + +#include "service.h" +#include "logger.h" + +#include +#include +#include + +class EASYDNS : public Service +{ + +private: + + friend class boost::serialization::access; + template + void serialize(Archive & ar, const unsigned int version); + + std::string BaseUrl; + + HTTPHelper::Ptr HTTPHelp; + + std::list split(const std::string& str,const std::string& delimiters) const; + + std::list separate_domain_and_host_part(const std::string& str) const; + + std::string assemble_base_url(const std::string& hostname, const std::string& two_level_tld) const; + + std::string get_two_level_tld(const std::string& domain_part) const; + +public: + + typedef boost::shared_ptr Ptr; + + EASYDNS(); + + EASYDNS(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); + + ~EASYDNS(); + + int perform_update(const std::string& ip); + +}; + +#endif diff --git a/src/httphelper.cpp b/src/httphelper.cpp index 5b24702..f3feefd 100644 --- a/src/httphelper.cpp +++ b/src/httphelper.cpp @@ -108,7 +108,7 @@ string HTTPHelper::get_curl_data() const */ CURL* HTTPHelper::init_curl(string& curl_writedata_buff,char* curl_err_buff) const { - string user_agent = "bpdyndnsd Intra2net AG 2009"; + string user_agent = "Bullet Proof DYNDNS Daemon - Intra2net AG 2009"; CURL *curl_easy_handle = curl_easy_init(); diff --git a/src/logger.cpp b/src/logger.cpp index 32f69be..45fc9cc 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -1304,3 +1304,19 @@ void Logger::print_update_failure(const string& url, const string& curl_data) co log_warning(msg.str(),level); } } + + +/** + * Hostname is invalid, contains no or only one domain part. + * @param hostname The full qualified host name. + */ +void Logger::print_invalid_hostname(const std::string& hostname) const +{ + int level = 0; + if ( (level <= Loglevel) || ((level <= ExternalWarningLevel) && (!ExternalWarningLog.empty())) ) + { + ostringstream msg; + msg << "The configured hostname: " << hostname << " is invalid. Please add the corresponding domain part." << endl; + log_warning(msg.str(),level); + } +} diff --git a/src/logger.h b/src/logger.h index f13da6d..3abf4eb 100644 --- a/src/logger.h +++ b/src/logger.h @@ -191,6 +191,8 @@ public: 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; + + void print_invalid_hostname(const std::string& hostname) const; }; #endif diff --git a/src/main.cpp b/src/main.cpp index 4653c69..4deb83e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,6 +41,7 @@ #include "dyns.cpp" #include "ods.cpp" #include "dhs.cpp" +#include "easydns.cpp" using namespace std; diff --git a/src/updater.cpp b/src/updater.cpp index 7650f67..d471c6e 100644 --- a/src/updater.cpp +++ b/src/updater.cpp @@ -14,6 +14,7 @@ #include "ods.h" #include "dyndns.h" #include "dyns.h" +#include "easydns.h" #include @@ -23,6 +24,7 @@ BOOST_CLASS_EXPORT_GUID(ODS, "ODS") BOOST_CLASS_EXPORT_GUID(DHS, "DHS") BOOST_CLASS_EXPORT_GUID(DYNS, "DYNS") BOOST_CLASS_EXPORT_GUID(DYNDNS, "DYNDNS") +BOOST_CLASS_EXPORT_GUID(EASYDNS, "EASYDNS") namespace fs = boost::filesystem; -- 1.7.1