/** @file * @brief The abstract service class. This class represents all services. * * * * @copyright Intra2net AG * @license GPLv2 */ #include "service.hpp" #include using namespace std; /// Number of update errors until a service will be blocked const int MaxErrorCount = 3; /// Number of seconds a service will be blocked if MaxErrorCount is reached const int ErrorBlockServiceSeconds = 15 * 60; /** * Default Constructor */ Service::Service() : Login("NOT SERIALIZED") , Password("NOT SERIALIZED") , ActualIP("0.0.0.0") , ActualIPIsBurnt(false) , Activated(false) , UpdateInterval(15) , MaxUpdatesWithinInterval(3) , MaxEqualUpdatesInSuccession(2) , DNSCacheTTL(0) , ErrorCount(0) , ErrorServiceBlockedUntil(0) , Log(new Logger()) { } /** * Default Destructor needed for deserialization. */ Service::~Service() { } /** * Setter for member Protocol. * @param _protocol Value to set Protocol to. */ void Service::set_protocol(const string& _protocol) { Protocol = _protocol; } /** * Getter for memeber Protocol. * @return Value of member Protocol. */ string Service::get_protocol() const { return Protocol; } /** * Setter for member Hostname. * @param _hostname Value to set Hostname to. */ void Service::set_hostname(const string& _hostname) { Hostname = _hostname; } /** * Getter for member Hostname. * @return Value of member Hostname. */ string Service::get_hostname() const { return Hostname; } /** * Setter for member Login. * @param _login Value to set Login to. */ void Service::set_login(const string& _login) { Login = _login; } /** * Getter for member Login. * @return Value of member Login. */ string Service::get_login() const { return Login; } /** * Setter for member Password. * @param _password Value to set Password to. */ void Service::set_password(const string& _password) { Password = _password; } /** * Getter for member Password. * @return Value of member Password. */ string Service::get_password() const { return Password; } void Service::set_logger(const Logger::Ptr& _log) { Log = _log; } /** * Getter for member Log. * @return Shared pointer to Logger object. */ Logger::Ptr Service::get_logger() const { return Log; } /** * Setter for member LastUpdates. * @param _last_updates Value to set LastUpdates to. */ void Service::set_last_updates(std::map _last_updates) { std::map temp = _last_updates; LastUpdates.swap(temp); } /** * Getter for member LastUpdates. * @return Value of member LastUpdates. */ const std::map Service::get_last_updates() const { return LastUpdates; } /** * Setter for member ActualIP. * @param _actual_ip Value to set ActualIP to. */ void Service::set_actual_ip(const std::string& _actual_ip) { ActualIP = _actual_ip; } /** * Getter for member ActualIP. * @return Value of member ActualIP. */ std::string Service::get_actual_ip() const { return ActualIP; } /** * Overloading of comparison operator. * @param other Reference to other Service object. * @return True if they equal, false if not. */ bool Service::operator== (const Service& other) const { if ( ( this->Protocol == other.Protocol ) && ( this->Hostname == other.Hostname ) ) return true; return false; } /** * Overloading of disparate operator. * @param other Reference to other Service object. * @return True if they differ, false if they are equal. */ bool Service::operator!= (const Service& other) const { return !(*this == other); } /** * Checks if update will exceed max update interval or if the IP address is burnt. * @param current_time Current time. * @param changed_to_online True if we just changed to online, false if we were already online * @param ip_host The new ip to set for the hostname. * @return True if update is allowed, false if update would exceed max update interval. */ bool Service::update_allowed(const time_t current_time, bool changed_to_online, const std::string& ip_host) { Log->print_last_updates(ip_host,current_time,UpdateInterval,MaxUpdatesWithinInterval,MaxEqualUpdatesInSuccession,LastUpdates,get_service_name()); // Check for update interval overstepping. int i = 0; for ( std::map::reverse_iterator r_iter = LastUpdates.rbegin(); (r_iter != LastUpdates.rend()) && ( i < MaxUpdatesWithinInterval ); r_iter++) { if ( (i == (MaxUpdatesWithinInterval-1)) && ( (r_iter->first + ((time_t)UpdateInterval*60)) >= current_time ) ) { Log->print_update_not_allowed(changed_to_online,current_time,r_iter->first,MaxUpdatesWithinInterval,get_service_name()); return false; } i++; } if (ActualIPIsBurnt) { // Changed IP address removes the "burnt state" if (ip_host != ActualIP) ActualIPIsBurnt = false; else { // IP is burnt and didn't change -> Update not allowed return false; } } // Check for burnt IP. // Only check for burnt IP address if there are at least max_equal_updates_in_succession entries in the last_updates map. if ( (MaxEqualUpdatesInSuccession != 0) && ((int)LastUpdates.size() >= MaxEqualUpdatesInSuccession) ) { bool ip_burnt = true; i = 0; // Reverse iterate "last_updates" list so the latest update // will be the first entry (map key is the unix timestamp) for ( std::map::reverse_iterator r_iter = LastUpdates.rbegin(); ( r_iter != LastUpdates.rend() ) && ( i < MaxEqualUpdatesInSuccession ); r_iter++ ) { if ( ip_host != r_iter->second ) { ip_burnt = false; break; } i++; } if ( ip_burnt ) { // IP Address is burnt. Too many updates in succession with the same IP. Log once. Log->print_ip_burnt(ip_host,get_service_name()); ActualIPIsBurnt = true; return false; } } return true; } /** * Service update method, common to each service. * @param ip The new ip to set for the hostname. * @param current_time Current time * @param changed_to_online True if we just changed to online, false if we were already online */ void Service::update(const string& ip, const time_t current_time, bool changed_to_online) { const std::string service_name = get_service_name(); // Check if service is blocked for a short period of time (because of update errors) if (ErrorServiceBlockedUntil && current_time < ErrorServiceBlockedUntil) { Log->print_update_service_is_blocked(service_name, ErrorServiceBlockedUntil - current_time); return; } // test if update is permitted by UpdateInterval Status if ( update_allowed(current_time, changed_to_online, ip) ) { Log->print_update_service(service_name); UpdateErrorCode update_res = perform_update(ip); // If update result is other than Generic or NotAuth, we assume that the hostname is activated. if ( (update_res != GenericError) && (update_res != NotAuth) ) set_activated(); if (update_res == UpdateOk) { // if update was successful, we need to set the Lastupdated and ActualIP base member. set_last_update(current_time,ip); ActualIP = ip; Log->print_update_service_successful(service_name,ip); ErrorCount = 0; ErrorServiceBlockedUntil = 0; } else { if (update_res == NoChange || update_res == Blocked) { // Log update for burnt IP logic and update "ActualIP" of this service set_last_update(current_time,ip); ActualIP = ip; } // problem while trying to update service Log->print_update_service_failure(service_name); ++ErrorCount; if (ErrorCount >= MaxErrorCount) { Log->print_block_service(service_name, ErrorBlockServiceSeconds); ErrorServiceBlockedUntil = time(NULL) + ErrorBlockServiceSeconds; ErrorCount = 0; } } } } /** * Sets the given time into the LastUpdates member and deletes expired entries. * @param _timeout Value to set into LastUpdates. */ void Service::set_last_update(const time_t current_time, const string& ip) { // Insert value into the list. LastUpdates.insert(make_pair(current_time,ip)); // Get the maximum of MaxUpdatesWithinInterval and MaxEqualUpdatesInSuccession int maximum = max(MaxUpdatesWithinInterval,MaxEqualUpdatesInSuccession); // Check for expired entries: // MaxUpdatesWithinInterval given in service config, then use this to check for expired entries. if ( maximum > 0 ) { // Delete the oldest entry if there are more than max(MaxUpdatesWithinInterval,MaxEqualUpdatesInSuccession)+1 entries in the list. if ( LastUpdates.size() > (size_t)(maximum+1) ) LastUpdates.erase(LastUpdates.begin()); return; } // UpdateInterval given in service config, then use this to check for expired entries. else if ( UpdateInterval > 0 ) { // Delete the oldest entry if it's older than current_time - UpdateInterval(minutes) + 1. if ( (current_time - ((time_t)UpdateInterval*60) + 1) > LastUpdates.begin()->first ) LastUpdates.erase(LastUpdates.begin()); return; } // Neither MaxUpdatesWithinInterval nor UpdateInterval are given, so keep fix number of 10 entries. else { if ( LastUpdates.size() > 10 ) LastUpdates.erase(LastUpdates.begin()); return; } } /** * Getter the last updated time. * @return Value of the last update as time_t. */ time_t Service::get_last_update_time( ) { time_t last_update = 0; if ( !LastUpdates.empty() ) { std::map::reverse_iterator r_iter = LastUpdates.rbegin(); if ( r_iter != LastUpdates.rend() ) last_update = r_iter->first; } return last_update; } /** * Setter for member Timeout. * @param _timeout Value to set Timeout to. */ void Service::set_update_interval(const int _update_interval) { UpdateInterval = _update_interval; } /** * Getter for member Timeout. * @return Value of Timeout. */ int Service::get_update_interval() const { return UpdateInterval; } /** * Setter for member Max_updates_per_timeout. * @param _max_updates_per_timeout Value to set Max_updates_per_timeout to. */ void Service::set_max_updates_within_interval(const int _max_updates_within_interval) { MaxUpdatesWithinInterval = _max_updates_within_interval; } /** * Getter for member Max_updates_per_timeout. * @return Value of Max_updates_per_timeout. */ int Service::get_max_updates_within_interval() const { return MaxUpdatesWithinInterval; } /** * Setter for member MaxEqualUpdatesInSuccession. * @param _max_equal_updates_in_succession Value to set MaxEqualUpdatesInSuccession to. */ void Service::set_max_equal_updates_in_succession(const int _max_equal_updates_in_succession) { MaxEqualUpdatesInSuccession = _max_equal_updates_in_succession; } /** * Getter for member MaxEqualUpdatesInSuccession. * @return Value of MaxEqualUpdatesInSuccession. */ int Service::get_max_equal_updates_in_succession() const { return MaxEqualUpdatesInSuccession; } /** * Get a unique service identify string * @return A unique service identify string */ string Service::get_service_name() const { string service_name; service_name.append(Protocol); service_name.append(" "); service_name.append(Hostname); return service_name; } /** * Get member DNSCacheTTL * @return DNSCacheTTL */ int Service::get_dns_cache_ttl() const { return DNSCacheTTL; } /** * Set member DNSCacheTTL * @param _dns_cache_ttl DNSCacheTTL */ void Service::set_dns_cache_ttl(const int _dns_cache_ttl) { DNSCacheTTL = _dns_cache_ttl; } /** * Get member Activated * @return Activated */ bool Service::get_activated() const { return Activated; } /** * Set member Activated * @param _activated Activated */ void Service::set_activated() { Activated = true; }