Log burnt IP only once
[bpdyndnsd] / src / service.cpp
CommitLineData
b1be615b 1/** @file
2bc1878a 2 * @brief The abstract service class. This class represents all services.
b1be615b
BS
3 *
4 *
5 *
6 * @copyright Intra2net AG
7 * @license GPLv2
8*/
9
4de6a9b8 10#include "service.hpp"
3c0cd271 11#include <boost/foreach.hpp>
ca5d6889
BS
12
13using namespace std;
14
0f0908e1
TJ
15/// Number of update errors until a service will be blocked
16const int MaxErrorCount = 3;
17/// Number of seconds a service will be blocked if MaxErrorCount is reached
18const int ErrorBlockServiceSeconds = 15 * 60;
2bc1878a 19
85a0abf9
BS
20/**
21 * Default Constructor
22 */
4545a371 23Service::Service()
9a0aff44 24 : Login("NOT SERIALIZED")
27baf279 25 , Password("NOT SERIALIZED")
025abebb 26 , ActualIP("0.0.0.0")
7be9aed9 27 , ActualIPIsBurnt(false)
b67d84ea
BS
28 , UpdateInterval(15)
29 , MaxUpdatesWithinInterval(3)
4553e833 30 , MaxEqualUpdatesInSuccession(2)
d5a516ba 31 , DNSCacheTTL(0)
0f0908e1
TJ
32 , ErrorCount(0)
33 , ErrorServiceBlockedUntil(0)
2e956a36 34 , Log(new Logger())
4545a371
BS
35{
36}
37
2bc1878a 38
85a0abf9 39/**
27baf279 40 * Default Destructor needed for deserialization.
85a0abf9 41 */
4545a371
BS
42Service::~Service()
43{
44}
45
46
2bc1878a 47/**
3a89ac31
BS
48 * Setter for member Protocol.
49 * @param _protocol Value to set Protocol to.
50 */
51void Service::set_protocol(const string& _protocol)
52{
53 Protocol = _protocol;
54}
55
56
57/**
58 * Getter for memeber Protocol.
59 * @return Value of member Protocol.
60 */
b38684ce 61string Service::get_protocol() const
3a89ac31
BS
62{
63 return Protocol;
64}
65
66
67/**
68 * Setter for member Hostname.
69 * @param _hostname Value to set Hostname to.
70 */
71void Service::set_hostname(const string& _hostname)
72{
73 Hostname = _hostname;
74}
75
76
77/**
78 * Getter for member Hostname.
79 * @return Value of member Hostname.
80 */
b38684ce 81string Service::get_hostname() const
3a89ac31
BS
82{
83 return Hostname;
84}
85
86
87/**
88 * Setter for member Login.
89 * @param _login Value to set Login to.
90 */
91void Service::set_login(const string& _login)
92{
93 Login = _login;
94}
95
96
97/**
98 * Getter for member Login.
99 * @return Value of member Login.
100 */
b38684ce 101string Service::get_login() const
3a89ac31
BS
102{
103 return Login;
104}
105
106
107/**
108 * Setter for member Password.
109 * @param _password Value to set Password to.
110 */
111void Service::set_password(const string& _password)
112{
113 Password = _password;
114}
115
116
117/**
118 * Getter for member Password.
119 * @return Value of member Password.
120 */
b38684ce 121string Service::get_password() const
3a89ac31
BS
122{
123 return Password;
124}
125
126
d55fbd67 127
88a594e8 128void Service::set_logger(const Logger::Ptr& _log)
3a89ac31
BS
129{
130 Log = _log;
131}
132
133
134/**
135 * Getter for member Log.
136 * @return Shared pointer to Logger object.
137 */
b38684ce 138Logger::Ptr Service::get_logger() const
3a89ac31
BS
139{
140 return Log;
2bc1878a
BS
141}
142
143
4553e833
BS
144/**
145 * Setter for member LastUpdates.
146 * @param _last_updates Value to set LastUpdates to.
147 */
148void Service::set_last_updates(std::map<time_t,std::string> _last_updates)
2bc1878a 149{
209fa505
TJ
150 std::map<time_t,std::string> temp = _last_updates;
151 LastUpdates.swap(temp);
2bc1878a
BS
152}
153
154
155/**
4553e833
BS
156 * Getter for member LastUpdates.
157 * @return Value of member LastUpdates.
2bc1878a 158 */
4553e833 159const std::map<time_t,std::string> Service::get_last_updates() const
2bc1878a 160{
c1b8cb79 161 return LastUpdates;
2bc1878a
BS
162}
163
164
165/**
025abebb
BS
166 * Setter for member ActualIP.
167 * @param _actual_ip Value to set ActualIP to.
27baf279
BS
168 */
169void Service::set_actual_ip(const std::string& _actual_ip)
170{
025abebb 171 ActualIP = _actual_ip;
27baf279
BS
172}
173
174
175/**
025abebb
BS
176 * Getter for member ActualIP.
177 * @return Value of member ActualIP.
27baf279 178 */
b38684ce 179std::string Service::get_actual_ip() const
27baf279 180{
025abebb 181 return ActualIP;
27baf279
BS
182}
183
184
27baf279 185/**
3a89ac31
BS
186 * Overloading of comparison operator.
187 * @param other Reference to other Service object.
188 * @return True if they equal, false if not.
2bc1878a 189 */
3a89ac31 190bool Service::operator== (const Service& other) const
2bc1878a 191{
3a89ac31
BS
192 if ( ( this->Protocol == other.Protocol ) && ( this->Hostname == other.Hostname ) )
193 return true;
194 return false;
2bc1878a
BS
195}
196
197
198/**
3a89ac31
BS
199 * Overloading of disparate operator.
200 * @param other Reference to other Service object.
201 * @return True if they differ, false if they are equal.
2bc1878a 202 */
3a89ac31 203bool Service::operator!= (const Service& other) const
2bc1878a 204{
3a89ac31 205 return !(*this == other);
2bc1878a 206}
3c0cd271
BS
207
208
209/**
08e6f339 210 * Checks if update will exceed max update interval or if the IP address is burnt.
3c0cd271 211 * @param current_time Current time.
0ebcd4ef 212 * @param changed_to_online True if we just changed to online, false if we were already online
7be9aed9 213 * @param ip_host The new ip to set for the hostname.
3c0cd271
BS
214 * @return True if update is allowed, false if update would exceed max update interval.
215 */
08e6f339 216bool Service::update_allowed(const time_t current_time, bool changed_to_online, const std::string& ip_host)
3c0cd271 217{
08e6f339
BS
218 Log->print_last_updates(ip_host,current_time,UpdateInterval,MaxUpdatesWithinInterval,MaxEqualUpdatesInSuccession,LastUpdates,get_service_name());
219
220 // Check for update interval overstepping.
4553e833
BS
221 int i = 0;
222 for ( std::map<time_t,std::string>::reverse_iterator r_iter = LastUpdates.rbegin(); (r_iter != LastUpdates.rend()) && ( i < MaxUpdatesWithinInterval ); r_iter++)
3c0cd271 223 {
4553e833 224 if ( (i == (MaxUpdatesWithinInterval-1)) && ( (r_iter->first + ((time_t)UpdateInterval*60)) >= current_time ) )
3c0cd271 225 {
4553e833 226 Log->print_update_not_allowed(changed_to_online,current_time,r_iter->first,MaxUpdatesWithinInterval,get_service_name());
3c0cd271
BS
227 return false;
228 }
229 i++;
230 }
08e6f339 231
7be9aed9
TJ
232 if (ActualIPIsBurnt)
233 {
234 // Changed IP address removes the "burnt state"
235 if (ip_host != ActualIP)
236 ActualIPIsBurnt = false;
237 else
238 {
239 // IP is burnt and didn't change -> Update not allowed
240 return false;
241 }
242 }
243
08e6f339
BS
244 // Check for burnt IP.
245 // Only check for burnt IP address if there are at least max_equal_updates_in_succession entries in the last_updates map.
246 if ( (MaxEqualUpdatesInSuccession != 0) && ((int)LastUpdates.size() >= MaxEqualUpdatesInSuccession) )
247 {
248 bool ip_burnt = true;
249 i = 0;
250 // Reverse iterate "last_updates" list so the latest update
251 // will be the first entry (map key is the unix timestamp)
252 for ( std::map<time_t,std::string>::reverse_iterator r_iter = LastUpdates.rbegin();
253 ( r_iter != LastUpdates.rend() ) && ( i < MaxEqualUpdatesInSuccession ); r_iter++ )
254 {
255 if ( ip_host != r_iter->second )
256 {
257 ip_burnt = false;
258 break;
259 }
260 i++;
261 }
262
263 if ( ip_burnt )
264 {
7be9aed9 265 // IP Address is burnt. Too many updates in succession with the same IP. Log once.
08e6f339 266 Log->print_ip_burnt(ip_host,get_service_name());
7be9aed9 267 ActualIPIsBurnt = true;
08e6f339
BS
268 return false;
269 }
270 }
271
3c0cd271
BS
272 return true;
273}
274
275
276/**
c3dea5dc
BS
277 * Service update method, common to each service.
278 * @param ip The new ip to set for the hostname.
0ebcd4ef
TJ
279 * @param current_time Current time
280 * @param changed_to_online True if we just changed to online, false if we were already online
c3dea5dc 281 */
0ebcd4ef 282void Service::update(const string& ip, const time_t current_time, bool changed_to_online)
c3dea5dc 283{
0f0908e1
TJ
284 const std::string service_name = get_service_name();
285
286 // Check if service is blocked for a short period of time (because of update errors)
287 if (ErrorServiceBlockedUntil && current_time < ErrorServiceBlockedUntil)
288 {
289 Log->print_update_service_is_blocked(service_name, ErrorServiceBlockedUntil - current_time);
290 return;
291 }
292
c3dea5dc 293 // test if update is permitted by UpdateInterval Status
08e6f339 294 if ( update_allowed(current_time, changed_to_online, ip) )
c3dea5dc 295 {
0ebcd4ef
TJ
296 Log->print_update_service(service_name);
297
cd5a41a4
TJ
298 UpdateErrorCode update_res = perform_update(ip);
299
300 if (update_res == UpdateOk)
c3dea5dc
BS
301 {
302 // if update was successful, we need to set the Lastupdated and ActualIP base member.
4553e833 303 set_last_update(current_time,ip);
c3dea5dc 304 ActualIP = ip;
0f0908e1
TJ
305 Log->print_update_service_successful(service_name);
306
307 ErrorCount = 0;
308 ErrorServiceBlockedUntil = 0;
c3dea5dc
BS
309 }
310 else
311 {
cd5a41a4
TJ
312 if (update_res == NoChange || update_res == Blocked)
313 {
314 // Log update for burnt IP logic and update "ActualIP" of this service
315 set_last_update(current_time,ip);
316 ActualIP = ip;
317 }
318
c3dea5dc 319 // problem while trying to update service
0f0908e1
TJ
320 Log->print_update_service_failure(service_name);
321
322 ++ErrorCount;
323 if (ErrorCount >= MaxErrorCount)
324 {
325 Log->print_block_service(service_name, ErrorBlockServiceSeconds);
326
327 ErrorServiceBlockedUntil = time(NULL) + ErrorBlockServiceSeconds;
328 ErrorCount = 0;
329 }
c3dea5dc
BS
330 }
331 }
332}
333
334
335/**
fc613942
BS
336* Sets the given time into the LastUpdates member and deletes expired entries.
337* @param _timeout Value to set into LastUpdates.
338*/
4553e833 339void Service::set_last_update(const time_t current_time, const string& ip)
fc613942
BS
340{
341 // Insert value into the list.
4553e833
BS
342 LastUpdates.insert(make_pair(current_time,ip));
343
344 // Get the maximum of MaxUpdatesWithinInterval and MaxEqualUpdatesInSuccession
345 int maximum = max(MaxUpdatesWithinInterval,MaxEqualUpdatesInSuccession);
fc613942
BS
346
347 // Check for expired entries:
348
349 // MaxUpdatesWithinInterval given in service config, then use this to check for expired entries.
4553e833 350 if ( maximum > 0 )
fc613942 351 {
4553e833
BS
352 // Delete the oldest entry if there are more than max(MaxUpdatesWithinInterval,MaxEqualUpdatesInSuccession)+1 entries in the list.
353 if ( LastUpdates.size() > (size_t)(maximum+1) )
34016300 354 LastUpdates.erase(LastUpdates.begin());
fc613942
BS
355 return;
356 }
357 // UpdateInterval given in service config, then use this to check for expired entries.
358 else if ( UpdateInterval > 0 )
359 {
360 // Delete the oldest entry if it's older than current_time - UpdateInterval(minutes) + 1.
34016300
TJ
361 if ( (current_time - ((time_t)UpdateInterval*60) + 1) > LastUpdates.begin()->first )
362 LastUpdates.erase(LastUpdates.begin());
fc613942
BS
363 return;
364 }
365 // Neither MaxUpdatesWithinInterval nor UpdateInterval are given, so keep fix number of 10 entries.
366 else
367 {
368 if ( LastUpdates.size() > 10 )
34016300 369 LastUpdates.erase(LastUpdates.begin());
fc613942
BS
370 return;
371 }
372}
373
374
375/**
4553e833
BS
376 * Getter the last updated time.
377 * @return Value of the last update as time_t.
378 */
379time_t Service::get_last_update_time( )
380{
0c0344aa
BS
381 time_t last_update = 0;
382 if ( !LastUpdates.empty() )
383 {
384 std::map<time_t,std::string>::reverse_iterator r_iter = LastUpdates.rbegin();
385 if ( r_iter != LastUpdates.rend() )
386 last_update = r_iter->first;
387 }
388 return last_update;
4553e833
BS
389}
390
391
392/**
3c0cd271
BS
393 * Setter for member Timeout.
394 * @param _timeout Value to set Timeout to.
395 */
396void Service::set_update_interval(const int _update_interval)
397{
398 UpdateInterval = _update_interval;
399}
400
401
402/**
403 * Getter for member Timeout.
404 * @return Value of Timeout.
405 */
406int Service::get_update_interval() const
407{
408 return UpdateInterval;
409}
410
411
412/**
413 * Setter for member Max_updates_per_timeout.
414 * @param _max_updates_per_timeout Value to set Max_updates_per_timeout to.
415 */
416void Service::set_max_updates_within_interval(const int _max_updates_within_interval)
417{
418 MaxUpdatesWithinInterval = _max_updates_within_interval;
419}
420
421
422/**
423 * Getter for member Max_updates_per_timeout.
424 * @return Value of Max_updates_per_timeout.
425 */
426int Service::get_max_updates_within_interval() const
427{
428 return MaxUpdatesWithinInterval;
429}
c3dea5dc
BS
430
431
432/**
4553e833
BS
433 * Setter for member MaxEqualUpdatesInSuccession.
434 * @param _max_equal_updates_in_succession Value to set MaxEqualUpdatesInSuccession to.
435 */
436void Service::set_max_equal_updates_in_succession(const int _max_equal_updates_in_succession)
437{
438 MaxEqualUpdatesInSuccession = _max_equal_updates_in_succession;
439}
440
441
442/**
443 * Getter for member MaxEqualUpdatesInSuccession.
444 * @return Value of MaxEqualUpdatesInSuccession.
445 */
446int Service::get_max_equal_updates_in_succession() const
447{
448 return MaxEqualUpdatesInSuccession;
449}
450
451
452/**
c3dea5dc
BS
453 * Get a unique service identify string
454 * @return A unique service identify string
455 */
456string Service::get_service_name() const
457{
458 string service_name;
459
460 service_name.append(Protocol);
461 service_name.append(" ");
462 service_name.append(Hostname);
463
464 return service_name;
465}
466
467
468/**
469 * Get member DNSCacheTTL
470 * @return DNSCacheTTL
471 */
472int Service::get_dns_cache_ttl() const
473{
474 return DNSCacheTTL;
475}
476
477
478/**
479 * Set member DNSCacheTTL
480 * @param _dns_cache_ttl DNSCacheTTL
481 */
482void Service::set_dns_cache_ttl(const int _dns_cache_ttl)
483{
484 DNSCacheTTL = _dns_cache_ttl;
485}