Added util class to compute md5 sum (wrapper class which uses high level C interface openssl/evp.h).
Adapted all perform_update member functions.
#include "service_easydns.h"
#include "service_tzo.h"
#include "service_zoneedit.h"
+#include "service_gnudip.h"
#include <time.h>
#include <iostream>
po::options_description opt_desc_service("Service description options");
opt_desc_service.add_options()
("protocol",po::value<string>(),"The service protocol.")
+ ("server",po::value<string>(),"Servername needed for gnudip protocol.")
("host",po::value<string>(),"The hostname to update.")
("login",po::value<string>(),"Login name.")
("password",po::value<string>(),"Corresponding password.")
protocol = ba::to_lower_copy(protocol);
+ string server;
+ if ( VariablesMap.count("server") )
+ server = VariablesMap["server"].as<string>();
+
int update_interval = 0;
if ( VariablesMap.count("update_interval") )
update_interval = VariablesMap["update_interval"].as<int>();
if ( VariablesMap.count("dns_cache_ttl") )
dns_cache_ttl = VariablesMap["dns_cache_ttl"].as<int>();
- Service::Ptr service = create_service(protocol,host,login,password,update_interval,max_updates_within_interval,dns_cache_ttl);
+ Service::Ptr service = create_service(protocol,server,host,login,password,update_interval,max_updates_within_interval,dns_cache_ttl);
if ( service )
{
ServiceHolder->add_service(service);
* @param password Password.
* @return A pointer to the created Service object.
*/
-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)
+Service::Ptr Config::create_service(const string &protocol, const string& server, 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<string> fqhn_parts;
Service::Ptr service_zoneedit(new ServiceZoneedit(protocol,hostname,login,password,Log,update_interval,max_updates_within_interval,dns_cache_ttl,Proxy,ProxyPort));
return service_zoneedit;
}
+ else if(protocol == "gnudip")
+ {
+ cout << "Server: " << server << endl;
+ if ( !server.empty() )
+ {
+ Service::Ptr service_gnudip(new ServiceGnudip(protocol,server,hostname,login,password,Log,update_interval,max_updates_within_interval,dns_cache_ttl,Proxy,ProxyPort));
+ return service_gnudip;
+ }
+ else
+ {
+ Log->print_gnudip_requires_servername();
+ Service::Ptr service;
+ return service;
+ }
+ }
else
{
Log->print_unknown_protocol(protocol);
protocol = ba::to_lower_copy(protocol);
+ string server;
+ if ( vm.count("server") )
+ server = vm["server"].as<string>();
+
int update_interval = 0;
if ( vm.count("update_interval") )
- update_interval = VariablesMap["update_interval"].as<int>();
+ update_interval = vm["update_interval"].as<int>();
int max_updates_within_interval = 0;
if ( vm.count("max_updates_within_interval") )
- max_updates_within_interval = VariablesMap["max_updates_within_interval"].as<int>();
+ max_updates_within_interval = vm["max_updates_within_interval"].as<int>();
int dns_cache_ttl = 0;
if ( vm.count("dns_cache_ttl") )
- dns_cache_ttl = VariablesMap["dns_cache_ttl"].as<int>();
+ dns_cache_ttl = vm["dns_cache_ttl"].as<int>();
- Service::Ptr service = create_service(protocol,host,login,password,update_interval,max_updates_within_interval,dns_cache_ttl);
+ Service::Ptr service = create_service(protocol,server,host,login,password,update_interval,max_updates_within_interval,dns_cache_ttl);
if ( service )
{
ServiceHolder->add_service(service);
std::string ExternalWarningLog;
int ExternalWarningLevel;
- Service::Ptr create_service(const std::string &protocol,const std::string &hostname, const std::string &login, const std::string &password, const int update_interval, const int max_updates_within_interval, const int dns_cache_ttl);
+ Service::Ptr create_service(const std::string& protocol, const std::string& server, const std::string& hostname, const std::string& login, const std::string& password, const int update_interval, const int max_updates_within_interval, const int dns_cache_ttl);
int load_main_config_file(const std::string& full_filename);
int load_service_config_file(const std::string& full_filename);
external.append(msg);
external.append("\"");
int ret_val = system(external.c_str());
+ // TODO: parse return code and error handling
}
}
* @param regex The regex pattern
* @param matching_string The string
*/
-void Logger::print_regex_match(const std::string& regex, const std::string& matching_string) const
+void Logger::print_regex_match(const string& regex, const string& matching_string) const
{
int level = 1;
if ( (level <= Loglevel) || ((level <= ExternalWarningLevel) && (!ExternalWarningLog.empty())) )
log_notice(msg.str(),level);
}
}
+
+
+/**
+ * Regex is not matching
+ * @param regex Regex
+ * @param not_matching_string String
+ */
+void Logger::print_no_regex_match(const string& regex, const string& not_matching_string) const
+{
+ int level = 1;
+ if ( (level <= Loglevel) || ((level <= ExternalWarningLevel) && (!ExternalWarningLog.empty())) )
+ {
+ ostringstream msg;
+ msg << "Regex: " << regex << " is not matching in: " << not_matching_string << endl;
+ log_warning(msg.str(),level);
+ }
+}
+
+
+/**
+ * Could not parse gnudip initial reply.
+ * @param curl_data The data received from gnudip server which should contain salt, time and sign.
+ */
+void Logger::print_could_not_parse_received_data(const string& curl_data) const
+{
+ int level = 0;
+ if ( (level <= Loglevel) || ((level <= ExternalWarningLevel) && (!ExternalWarningLog.empty())) )
+ {
+ ostringstream msg;
+ msg << "Could not parse salt, time and sign from initial gnudip server reply: " << curl_data << endl;
+ log_warning(msg.str(),level);
+ }
+}
+
+
+/**
+ * Gnudip salt, time and sign could not be got from map
+ */
+void Logger::print_could_not_get_initial_gnudip_data() const
+{
+ int level = 0;
+ if ( (level <= Loglevel) || ((level <= ExternalWarningLevel) && (!ExternalWarningLog.empty())) )
+ {
+ ostringstream msg;
+ msg << "Could not get salt, time and sign from map." << endl;
+ log_warning(msg.str(),level);
+ }
+}
+
+
+void Logger::print_gnudip_requires_servername() const
+{
+ int level = 0;
+ if ( (level <= Loglevel) || ((level <= ExternalWarningLevel) && (!ExternalWarningLog.empty())) )
+ {
+ ostringstream msg;
+ msg << "Gnudip requires explicit definition of servername via config!" << endl;
+ log_warning(msg.str(),level);
+ }
+}
void print_ip_is_local(const std::string& ip) const;
void print_regex_match(const std::string& regex, const std::string& matching_string) const;
+
+ void print_no_regex_match(const std::string& regex, const std::string& not_matching_string) const;
+
+ void print_could_not_parse_received_data(const std::string& curl_data) const;
+
+ void print_could_not_get_initial_gnudip_data() const;
+
+ void print_gnudip_requires_servername() const;
};
#endif
#include "iphelper.cpp"
#include "httphelper.cpp"
#include "serializeservicecontainer.cpp"
+#include "util.cpp"
#include "service_dyndns.cpp"
#include "service_dyns.cpp"
#include "service_easydns.cpp"
#include "service_tzo.cpp"
#include "service_zoneedit.cpp"
+#include "service_gnudip.cpp"
using namespace std;
*/
int ServiceDhs::perform_update(const std::string& ip)
{
- int ret_val = -1;
-
string url = BaseUrl;
url.append(ip);
if ( http_status_code == 200 )
{
// TODO: Account related errors should be handled here!
- ret_val = 0;
+ return 0;
}
else if ( http_status_code == 401 )
+ {
get_logger()->print_http_not_authorized(url,get_login(),get_password());
+ }
else
+ {
get_logger()->print_update_failure(url,http_status_code);
+ }
- return ret_val;
+ return -1;
}
*/
int ServiceDyndns::perform_update(const std::string& ip)
{
- int ret_val = -1;
-
// the result string if update was successful
string good = "good ";
good.append(ip);
string curl_data = HTTPHelp->get_curl_data();
if ( curl_data == good )
- ret_val = 0;
+ {
+ return 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);
+ }
+ }
+ else
+ {
+ get_logger()->print_update_failure(url,http_status_code);
}
- return ret_val;
+ return -1;
}
*/
int ServiceDyns::perform_update(const std::string& ip)
{
- int ret_val = -1;
-
string url = BaseUrl;
url.append(ip);
string status_code = parse_status_code(curl_data);
if ( status_code == "200" )
- ret_val = 0;
+ {
+ return 0;
+ }
else if ( status_code == "401" )
+ {
get_logger()->print_http_not_authorized(url,get_login(),get_password());
+ }
else
+ {
get_logger()->print_update_failure(url,curl_data);
+ }
+ }
+ else
+ {
+ get_logger()->print_update_failure(url,http_status_code);
}
- return ret_val;
+ return -1;
}
*/
int ServiceEasydns::perform_update(const std::string& ip)
{
- int ret_val = -1;
-
string url = BaseUrl;
url.append(ip);
string curl_data = HTTPHelp->get_curl_data();
if ( curl_data == "NOERROR" )
- ret_val = 0;
+ {
+ return 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);
+ }
+ }
+ else
+ {
+ get_logger()->print_update_failure(url,http_status_code);
}
- return ret_val;
+ return -1;
}
--- /dev/null
+/** @file
+ * @brief GNUDIP Service class implementation. This class represents the GNUDIP service.
+ *
+ *
+ *
+ * @copyright Intra2net AG
+ * @license GPLv2
+*/
+
+#include "service_gnudip.h"
+#include "util.h"
+
+#include <time.h>
+#include <boost/foreach.hpp>
+#include <boost/regex.hpp>
+
+using namespace std;
+
+
+/**
+ * Default Constructor, needed for object serialization.
+ */
+ServiceGnudip::ServiceGnudip()
+{
+}
+
+
+/**
+ * Constructor.
+ * @param _hostname The hostname to update
+ * @param _login The login name.
+ * @param _password The corresponding password.
+ */
+ServiceGnudip::ServiceGnudip(const string& _protocol, const string& _gnudip_server, 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)
+ : GnudipServer(_gnudip_server)
+{
+ 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(),_gnudip_server);
+}
+
+
+/**
+ * Default destructor
+ */
+ServiceGnudip::~ServiceGnudip()
+{
+}
+
+
+/**
+ * Assemble the dyndns update url from the given fqhn
+ * @param hostname The fqhn hostname to update IP for.
+ * @return The assembled update url without IP.
+ */
+string ServiceGnudip::assemble_base_url(const string& fqhn, const string& gnudip_server) const
+{
+ string base_url;
+
+ base_url = "http://";
+ base_url.append(gnudip_server);
+ base_url.append("/gnudip/cgi-bin/gdipupdt.cgi");
+
+ return base_url;
+}
+
+
+/**
+ * Parses the data received from the initial request, which should contain salt, time and sign.
+ * @param curl_data The complete received curl data.
+ * @return A map with salt, time and sign or an empty map.
+ */
+map<string,string> ServiceGnudip::parse_initial_request(const string& curl_data) const
+{
+ map<string,string> response;
+
+ // regex for salt
+ boost::regex expr_salt("<meta name=\"salt\" content=\"(.*)\">");
+ // regex for time
+ boost::regex expr_time("<meta name=\"time\" content=\"(.*)\">");
+ // regex for sign
+ boost::regex expr_sign("<meta name=\"sign\" content=\"(.*)\">");
+
+ boost::smatch matches;
+
+ // Get the salt out of received http data
+ if ( boost::regex_search(curl_data,matches,expr_salt) )
+ {
+ response.insert(pair<string,string>("salt",matches[1]));
+ get_logger()->print_regex_match(expr_salt.str(),matches[1]);
+ }
+ else
+ {
+ get_logger()->print_no_regex_match(expr_salt.str(),curl_data);
+ response.clear();
+ return response;
+ }
+
+ // Get the time out of received http data
+ if ( boost::regex_search(curl_data,matches,expr_time) )
+ {
+ response.insert(pair<string,string>("time",matches[1]));
+ get_logger()->print_regex_match(expr_salt.str(),matches[1]);
+ }
+ else
+ {
+ get_logger()->print_no_regex_match(expr_salt.str(),curl_data);
+ response.clear();
+ return response;
+ }
+
+ // Get the sign out of received http data
+ if ( boost::regex_search(curl_data,matches,expr_sign) )
+ {
+ response.insert(pair<string,string>("sign",matches[1]));
+ get_logger()->print_regex_match(expr_salt.str(),matches[1]);
+ }
+ else
+ {
+ get_logger()->print_no_regex_match(expr_salt.str(),curl_data);
+ response.clear();
+ return response;
+ }
+
+ return response;
+}
+
+
+/**
+ * Get the assembled update url.
+ * @param salt Salt from the initial request
+ * @param time Time from the initial request
+ * @param sign Sign from the initial request
+ * @param secret Computed md5 secret in HEX
+ * @param ip IP to update
+ * @return The assembled update url.
+ */
+string ServiceGnudip::assemble_update_url(const string& salt, const string& time, const string& sign, const string& secret, const string& ip) const
+{
+ string url = BaseUrl;
+
+ url.append("?salt=");
+ url.append(salt);
+ url.append("&time=");
+ url.append(time);
+ url.append("&sign=");
+ url.append(sign);
+ url.append("&user=");
+ url.append(get_login());
+ url.append("&domn=");
+ url.append(get_hostname());
+ url.append("&pass=");
+ url.append(secret);
+ url.append("&reqc=0&addr=");
+ url.append(ip);
+
+ return url;
+}
+
+
+/**
+ * Performs the Service update.
+ * @param ip IP Address to set.
+ * @return 0 if all is fine, -1 otherwise.
+ */
+int ServiceGnudip::perform_update(const std::string& ip)
+{
+ // initial request
+ long http_status_code = HTTPHelp->http_get(BaseUrl);
+
+ get_logger()->print_http_status_code(BaseUrl,http_status_code);
+
+ if ( http_status_code == 200 )
+ {
+ // Get the received http data which should contain the salt, time and sign
+ string curl_data = HTTPHelp->get_curl_data();
+
+ // Parse salt, time and sign out of the received data
+ map<string,string> salt_time_sign = parse_initial_request(curl_data);
+
+ if ( salt_time_sign.empty() )
+ {
+ get_logger()->print_could_not_parse_received_data(curl_data);
+ return -1;
+ }
+
+ // at this point we have salt, time and sign parsed successfully
+ string salt, time, sign;
+
+ map<string,string>::iterator iter = salt_time_sign.find("salt");
+ if ( iter != salt_time_sign.end() )
+ salt = iter->second;
+
+ iter = salt_time_sign.find("time");
+ if ( iter != salt_time_sign.end() )
+ time = iter->second;
+
+ iter = salt_time_sign.find("sign");
+ if ( iter != salt_time_sign.end() )
+ sign = iter->second;
+
+ if ( salt.empty() || time.empty() || sign.empty() )
+ get_logger()->print_could_not_get_initial_gnudip_data();
+
+ // compute md5 sum from users password and get the HEX representation
+ string pw_md5_hex = Util::compute_md5_digest(get_password());
+
+ // append "." and salt and compute md5 sum and get the HEX representation
+ pw_md5_hex.append(".");
+ pw_md5_hex.append(salt);
+ string secret = Util::compute_md5_digest(pw_md5_hex);
+
+ // Now its time to issue the second http_get operation
+ string url = assemble_update_url(salt, time, sign, secret, ip);
+
+ // perform the update operation
+ http_status_code = HTTPHelp->http_get(url);
+
+ get_logger()->print_http_status_code(url,http_status_code);
+
+ if ( http_status_code == 200 )
+ {
+ // parse the update request return code
+ string update_return_code = HTTPHelp->get_curl_data();
+ if ( update_return_code == "0" )
+ {
+ return 0;
+ }
+ else if ( update_return_code == "1" )
+ {
+ get_logger()->print_http_not_authorized(url,get_login(),get_password());
+ }
+ else
+ {
+ get_logger()->print_update_failure(url,update_return_code);
+ }
+ }
+ else
+ {
+ // second http get operation (update) was not successful
+ get_logger()->print_update_failure(url,http_status_code);
+ }
+ }
+ else
+ {
+ // first http get operation was not successful
+ get_logger()->print_update_failure(BaseUrl,http_status_code);
+ }
+
+ return -1;
+}
+
+
+/**
+ * Serialize function needed by boost/serialization to define which members should be stored as the object state.
+ * @param ar Archive
+ * @param version Version
+ */
+template<class Archive>
+void ServiceGnudip::serialize(Archive & ar, const unsigned int version)
+{
+ ar & boost::serialization::base_object<Service>(*this);
+}
--- /dev/null
+/** @file
+ * @brief GNUDIP Service class header. This class represents the GNUDIP service.
+ *
+ *
+ *
+ * @copyright Intra2net AG
+ * @license GPLv2
+*/
+
+#ifndef ServiceGnudip_H
+#define ServiceGnudip_H
+
+#include <string>
+
+#include "service.h"
+#include "logger.h"
+
+#include <boost/serialization/array.hpp>
+#include <boost/shared_ptr.hpp>
+#include <list>
+#include <map>
+
+class ServiceGnudip : public Service
+{
+
+private:
+
+ friend class boost::serialization::access;
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int version);
+
+ std::string GnudipServer;
+ std::string BaseUrl;
+
+ HTTPHelper::Ptr HTTPHelp;
+
+ std::string assemble_base_url(const std::string& fqhn, const std::string& gnudip_server) const;
+ std::map<std::string,std::string> parse_initial_request(const std::string& curl_data) const;
+ std::string assemble_update_url(const std::string& salt, const std::string& time, const std::string& sign, const std::string& secret, const std::string& ip) const;
+
+public:
+
+ typedef boost::shared_ptr<ServiceGnudip> Ptr;
+
+ ServiceGnudip();
+
+ ServiceGnudip(const std::string& _protocol, const std::string& _gnudip_server ,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);
+
+ ~ServiceGnudip();
+
+ int perform_update(const std::string& ip);
+
+};
+
+#endif
*/
int ServiceTzo::perform_update(const std::string& ip)
{
- int ret_val = -1;
-
string url = BaseUrl;
url.append(ip);
string status_code = parse_status_code(curl_data);
if ( status_code == "200" )
- ret_val = 0;
+ {
+ return 0;
+ }
else if ( status_code == "401" )
+ {
get_logger()->print_http_not_authorized(url,get_login(),get_password());
+ }
else
+ {
get_logger()->print_update_failure(url,curl_data);
+ }
+ }
+ else
+ {
+ get_logger()->print_update_failure(url,http_status_code);
}
- return ret_val;
+ return -1;
}
*/
int ServiceZoneedit::perform_update(const std::string& ip)
{
- int ret_val = -1;
-
string url = BaseUrl;
url.append(ip);
string status_code = parse_status_code(curl_data);
if ( status_code == "200" )
- ret_val = 0;
+ {
+ return 0;
+ }
else
+ {
get_logger()->print_update_failure(url,curl_data);
+ }
}
else if ( http_status_code == 401 )
+ {
get_logger()->print_http_not_authorized(url,get_login(),get_password());
+ }
else
+ {
get_logger()->print_update_failure(url,http_status_code);
+ }
- return ret_val;
+ return -1;
}
#include "service_easydns.h"
#include "service_tzo.h"
#include "service_zoneedit.h"
+#include "service_gnudip.h"
#include <boost/foreach.hpp>
BOOST_CLASS_EXPORT_GUID(ServiceEasydns, "ServiceEasydns")
BOOST_CLASS_EXPORT_GUID(ServiceTzo, "ServiceTzo")
BOOST_CLASS_EXPORT_GUID(ServiceZoneedit, "ServiceZoneedit")
+BOOST_CLASS_EXPORT_GUID(ServiceGnudip, "ServiceGnudip")
namespace fs = boost::filesystem;
--- /dev/null
+/** @file
+ * @brief Util class implementation.
+ *
+ *
+ *
+ * @copyright Intra2net AG
+ * @license GPLv2
+*/
+
+#include "util.h"
+
+#include <stdio.h>
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+
+Util::Util()
+{
+}
+
+Util::~Util()
+{
+}
+
+/**
+ * Computes a MD5 Digest from the given string and returns the HEX representation
+ * @param data The string to compute the md5 for
+ * @return The computed md5 in hex
+ */
+std::string Util::compute_md5_digest(std::string data)
+{
+ // compute an MD5 digest.
+
+ string result;
+ EVP_MD_CTX mdctx;
+ const EVP_MD *md;
+ unsigned char md_value[EVP_MAX_MD_SIZE];
+ unsigned int md_len;
+
+ OpenSSL_add_all_digests();
+
+ md = EVP_get_digestbyname("md5");
+
+ EVP_MD_CTX_init(&mdctx);
+ EVP_DigestInit_ex(&mdctx, md, NULL);
+ EVP_DigestUpdate(&mdctx, data.c_str(), strlen(data.c_str()));
+ EVP_DigestFinal_ex(&mdctx, md_value, &md_len);
+ EVP_MD_CTX_cleanup(&mdctx);
+
+ char buffer[2];
+
+ for(int i = 0; i < md_len; i++)
+ {
+ sprintf(buffer,"%02x", md_value[i]);
+ result.append(buffer);
+ }
+
+ return result;
+}
--- /dev/null
+/** @file
+ * @brief Util class header.
+ *
+ *
+ *
+ * @copyright Intra2net AG
+ * @license GPLv2
+*/
+
+#ifndef UTIL_H
+#define UTIL_H
+
+
+class Util
+{
+private:
+
+
+public:
+
+ Util();
+
+ ~Util();
+
+ static std::string compute_md5_digest(std::string);
+
+};
+
+#endif