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