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