1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21 #include "daemon.h"
22 #include "comms.h"
23 #include "zbxself.h"
24
25 #include "proxypoller.h"
26 #include "zbxserver.h"
27 #include "dbcache.h"
28 #include "db.h"
29 #include "zbxjson.h"
30 #include "log.h"
31 #include "proxy.h"
32 #include "../../libs/zbxcrypto/tls.h"
33 #include "../trapper/proxydata.h"
34
35 extern unsigned char process_type, program_type;
36 extern int server_num, process_num;
37
connect_to_proxy(const DC_PROXY * proxy,zbx_socket_t * sock,int timeout)38 static int connect_to_proxy(const DC_PROXY *proxy, zbx_socket_t *sock, int timeout)
39 {
40 const char *__function_name = "connect_to_proxy";
41
42 int ret = FAIL;
43 const char *tls_arg1, *tls_arg2;
44
45 zabbix_log(LOG_LEVEL_DEBUG, "In %s() address:%s port:%hu timeout:%d conn:%u", __function_name, proxy->addr,
46 proxy->port, timeout, (unsigned int)proxy->tls_connect);
47
48 switch (proxy->tls_connect)
49 {
50 case ZBX_TCP_SEC_UNENCRYPTED:
51 tls_arg1 = NULL;
52 tls_arg2 = NULL;
53 break;
54 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
55 case ZBX_TCP_SEC_TLS_CERT:
56 tls_arg1 = proxy->tls_issuer;
57 tls_arg2 = proxy->tls_subject;
58 break;
59 case ZBX_TCP_SEC_TLS_PSK:
60 tls_arg1 = proxy->tls_psk_identity;
61 tls_arg2 = proxy->tls_psk;
62 break;
63 #else
64 case ZBX_TCP_SEC_TLS_CERT:
65 case ZBX_TCP_SEC_TLS_PSK:
66 zabbix_log(LOG_LEVEL_ERR, "TLS connection is configured to be used with passive proxy \"%s\""
67 " but support for TLS was not compiled into %s.", proxy->host,
68 get_program_type_string(program_type));
69 ret = CONFIG_ERROR;
70 goto out;
71 #endif
72 default:
73 THIS_SHOULD_NEVER_HAPPEN;
74 goto out;
75 }
76
77 if (FAIL == (ret = zbx_tcp_connect(sock, CONFIG_SOURCE_IP, proxy->addr, proxy->port, timeout,
78 proxy->tls_connect, tls_arg1, tls_arg2)))
79 {
80 zabbix_log(LOG_LEVEL_ERR, "cannot connect to proxy \"%s\": %s", proxy->host, zbx_socket_strerror());
81 ret = NETWORK_ERROR;
82 }
83 out:
84 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
85
86 return ret;
87 }
88
send_data_to_proxy(const DC_PROXY * proxy,zbx_socket_t * sock,const char * data,size_t size)89 static int send_data_to_proxy(const DC_PROXY *proxy, zbx_socket_t *sock, const char *data, size_t size)
90 {
91 const char *__function_name = "send_data_to_proxy";
92
93 int ret, flags = ZBX_TCP_PROTOCOL;
94
95 zabbix_log(LOG_LEVEL_DEBUG, "In %s() data:'%s'", __function_name, data);
96
97 if (0 != proxy->auto_compress)
98 flags |= ZBX_TCP_COMPRESS;
99
100 if (FAIL == (ret = zbx_tcp_send_ext(sock, data, size, flags, 0)))
101 {
102 zabbix_log(LOG_LEVEL_ERR, "cannot send data to proxy \"%s\": %s", proxy->host, zbx_socket_strerror());
103
104 ret = NETWORK_ERROR;
105 }
106
107 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
108
109 return ret;
110 }
111
recv_data_from_proxy(const DC_PROXY * proxy,zbx_socket_t * sock)112 static int recv_data_from_proxy(const DC_PROXY *proxy, zbx_socket_t *sock)
113 {
114 const char *__function_name = "recv_data_from_proxy";
115 int ret;
116
117 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
118
119 if (FAIL == (ret = zbx_tcp_recv(sock)))
120 {
121 zabbix_log(LOG_LEVEL_ERR, "cannot obtain data from proxy \"%s\": %s", proxy->host,
122 zbx_socket_strerror());
123 }
124 else
125 zabbix_log(LOG_LEVEL_DEBUG, "obtained data from proxy \"%s\": [%s]", proxy->host, sock->buffer);
126
127 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
128
129 return ret;
130 }
131
disconnect_proxy(zbx_socket_t * sock)132 static void disconnect_proxy(zbx_socket_t *sock)
133 {
134 const char *__function_name = "disconnect_proxy";
135
136 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
137
138 zbx_tcp_close(sock);
139
140 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
141 }
142
143 /******************************************************************************
144 * *
145 * Function: get_data_from_proxy *
146 * *
147 * Purpose: get historical data from proxy *
148 * *
149 * Parameters: proxy - [IN/OUT] proxy data *
150 * request - [IN] requested data type *
151 * data - [OUT] data received from proxy *
152 * ts - [OUT] timestamp when the proxy connection was *
153 * established *
154 * tasks - [IN] proxy task response flag *
155 * *
156 * Return value: SUCCESS - processed successfully *
157 * other code - an error occurred *
158 * *
159 * Comments: The proxy->compress property is updated depending on the *
160 * protocol flags sent by proxy. *
161 * *
162 ******************************************************************************/
get_data_from_proxy(DC_PROXY * proxy,const char * request,char ** data,zbx_timespec_t * ts)163 static int get_data_from_proxy(DC_PROXY *proxy, const char *request, char **data, zbx_timespec_t *ts)
164 {
165 const char *__function_name = "get_data_from_proxy";
166
167 zbx_socket_t s;
168 struct zbx_json j;
169 int ret;
170
171 zabbix_log(LOG_LEVEL_DEBUG, "In %s() request:'%s'", __function_name, request);
172
173 zbx_json_init(&j, ZBX_JSON_STAT_BUF_LEN);
174
175 zbx_json_addstring(&j, "request", request, ZBX_JSON_TYPE_STRING);
176
177 if (SUCCEED == (ret = connect_to_proxy(proxy, &s, CONFIG_TRAPPER_TIMEOUT)))
178 {
179 /* get connection timestamp if required */
180 if (NULL != ts)
181 zbx_timespec(ts);
182
183 if (SUCCEED == (ret = send_data_to_proxy(proxy, &s, j.buffer, j.buffer_size)))
184 {
185 if (SUCCEED == (ret = recv_data_from_proxy(proxy, &s)))
186 {
187 if (0 != (s.protocol & ZBX_TCP_COMPRESS))
188 proxy->auto_compress = 1;
189
190 if (!ZBX_IS_RUNNING())
191 {
192 int flags = ZBX_TCP_PROTOCOL;
193
194 if (0 != (s.protocol & ZBX_TCP_COMPRESS))
195 flags |= ZBX_TCP_COMPRESS;
196
197 zbx_send_response_ext(&s, FAIL, "Zabbix server shutdown in progress", NULL,
198 flags, CONFIG_TIMEOUT);
199
200 zabbix_log(LOG_LEVEL_WARNING, "cannot process proxy data from passive proxy at"
201 " \"%s\": Zabbix server shutdown in progress", s.peer);
202 ret = FAIL;
203 }
204 else
205 {
206 ret = zbx_send_proxy_data_response(proxy, &s, NULL);
207
208 if (SUCCEED == ret)
209 *data = zbx_strdup(*data, s.buffer);
210 }
211 }
212 }
213
214 disconnect_proxy(&s);
215 }
216
217 zbx_json_free(&j);
218
219 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
220
221 return ret;
222 }
223
224 /******************************************************************************
225 * *
226 * Function: proxy_send_configuration *
227 * *
228 * Purpose: sends configuration data to proxy *
229 * *
230 * Parameters: proxy - [IN/OUT] proxy data *
231 * *
232 * Return value: SUCCEED - processed successfully *
233 * other code - an error occurred *
234 * *
235 * Comments: This function updates proxy version, compress and lastaccess *
236 * properties. *
237 * *
238 ******************************************************************************/
proxy_send_configuration(DC_PROXY * proxy)239 static int proxy_send_configuration(DC_PROXY *proxy)
240 {
241 char *error = NULL;
242 int ret;
243 zbx_socket_t s;
244 struct zbx_json j;
245
246 zbx_json_init(&j, 512 * ZBX_KIBIBYTE);
247
248 zbx_json_addstring(&j, ZBX_PROTO_TAG_REQUEST, ZBX_PROTO_VALUE_PROXY_CONFIG, ZBX_JSON_TYPE_STRING);
249 zbx_json_addobject(&j, ZBX_PROTO_TAG_DATA);
250
251 if (SUCCEED != (ret = get_proxyconfig_data(proxy->hostid, &j, &error)))
252 {
253 zabbix_log(LOG_LEVEL_ERR, "cannot collect configuration data for proxy \"%s\": %s",
254 proxy->host, error);
255 goto out;
256 }
257
258 if (SUCCEED != (ret = connect_to_proxy(proxy, &s, CONFIG_TRAPPER_TIMEOUT)))
259 goto out;
260
261 zabbix_log(LOG_LEVEL_WARNING, "sending configuration data to proxy \"%s\" at \"%s\", datalen " ZBX_FS_SIZE_T,
262 proxy->host, s.peer, (zbx_fs_size_t)j.buffer_size);
263
264 if (SUCCEED == (ret = send_data_to_proxy(proxy, &s, j.buffer, j.buffer_size)))
265 {
266 if (SUCCEED != (ret = zbx_recv_response(&s, 0, &error)))
267 {
268 zabbix_log(LOG_LEVEL_WARNING, "cannot send configuration data to proxy"
269 " \"%s\" at \"%s\": %s", proxy->host, s.peer, error);
270 }
271 else
272 {
273 struct zbx_json_parse jp;
274
275 if (SUCCEED != zbx_json_open(s.buffer, &jp))
276 {
277 zabbix_log(LOG_LEVEL_WARNING, "invalid configuration data response received from proxy"
278 " \"%s\" at \"%s\": %s", proxy->host, s.peer, zbx_json_strerror());
279 }
280 else
281 {
282 proxy->version = zbx_get_protocol_version(&jp);
283 proxy->auto_compress = (0 != (s.protocol & ZBX_TCP_COMPRESS) ? 1 : 0);
284 proxy->lastaccess = time(NULL);
285 }
286 }
287 }
288
289 disconnect_proxy(&s);
290 out:
291 zbx_free(error);
292 zbx_json_free(&j);
293
294 return ret;
295 }
296
297 /******************************************************************************
298 * *
299 * Function: proxy_check_error_response *
300 * *
301 * Purpose: checks proxy response for error message *
302 * *
303 * Parameters: jp - [IN] the json data received form proxy *
304 * error - [OUT] the error message *
305 * *
306 * Return value: SUCCEED - proxy response doesn't have error message *
307 * FAIL - otherwise *
308 * *
309 ******************************************************************************/
proxy_check_error_response(const struct zbx_json_parse * jp,char ** error)310 static int proxy_check_error_response(const struct zbx_json_parse *jp, char **error)
311 {
312 char response[MAX_STRING_LEN], *info = NULL;
313 size_t info_alloc = 0;
314
315 /* response tag will be set only in the case of errors */
316 if (SUCCEED != zbx_json_value_by_name(jp, ZBX_PROTO_TAG_RESPONSE, response, sizeof(response), NULL))
317 return SUCCEED;
318
319 if (0 != strcmp(response, ZBX_PROTO_VALUE_FAILED))
320 return SUCCEED;
321
322 if (SUCCEED == zbx_json_value_by_name_dyn(jp, ZBX_PROTO_TAG_INFO, &info, &info_alloc, NULL))
323 {
324 zbx_free(*error);
325 *error = info;
326 }
327 else
328 *error = zbx_strdup(*error, "Unknown error");
329
330 return FAIL;
331 }
332
333 /******************************************************************************
334 * *
335 * Function: proxy_get_host_availability *
336 * *
337 * Purpose: gets host availability data from proxy *
338 * ('host availability' request) *
339 * *
340 * Parameters: proxy - [IN/OUT] proxy data *
341 * *
342 * Return value: SUCCEED - data were received and processed successfully *
343 * other code - an error occurred *
344 * *
345 * Comments: The proxy->version property is updated with the version number *
346 * sent by proxy. *
347 * *
348 ******************************************************************************/
proxy_get_host_availability(DC_PROXY * proxy)349 static int proxy_get_host_availability(DC_PROXY *proxy)
350 {
351 char *answer = NULL, *error = NULL;
352 struct zbx_json_parse jp;
353 int ret = FAIL;
354
355 if (SUCCEED != (ret = get_data_from_proxy(proxy, ZBX_PROTO_VALUE_HOST_AVAILABILITY, &answer, NULL)))
356 {
357 goto out;
358 }
359
360 if ('\0' == *answer)
361 {
362 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned no host availability data:"
363 " check allowed connection types and access rights", proxy->host, proxy->addr);
364 goto out;
365 }
366
367 if (SUCCEED != zbx_json_open(answer, &jp))
368 {
369 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned invalid host availability data:"
370 " %s", proxy->host, proxy->addr, zbx_json_strerror());
371 goto out;
372 }
373
374 proxy->version = zbx_get_protocol_version(&jp);
375
376 if (SUCCEED != zbx_check_protocol_version(proxy))
377 {
378 goto out;
379 }
380
381 if (SUCCEED != proxy_check_error_response(&jp, &error))
382 {
383 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned invalid host availability data:"
384 " %s", proxy->host, proxy->addr, error);
385 goto out;
386 }
387
388 if (SUCCEED != process_host_availability(&jp, &error))
389 {
390 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned invalid host availability data:"
391 " %s", proxy->host, proxy->addr, error);
392 goto out;
393 }
394
395 ret = SUCCEED;
396 out:
397 zbx_free(error);
398 zbx_free(answer);
399
400 return ret;
401 }
402
403 /******************************************************************************
404 * *
405 * Function: proxy_get_history_data *
406 * *
407 * Purpose: gets historical data from proxy *
408 * ('history data' request) *
409 * *
410 * Parameters: proxy - [IN/OUT] proxy data *
411 * *
412 * Return value: SUCCEED - data were received and processed successfully *
413 * other code - an error occurred *
414 * *
415 * Comments: The proxy->version property is updated with the version number *
416 * sent by proxy. *
417 * *
418 ******************************************************************************/
proxy_get_history_data(DC_PROXY * proxy)419 static int proxy_get_history_data(DC_PROXY *proxy)
420 {
421 char *answer = NULL, *error = NULL;
422 struct zbx_json_parse jp, jp_data;
423 int ret = FAIL;
424 zbx_timespec_t ts;
425
426 while (SUCCEED == (ret = get_data_from_proxy(proxy, ZBX_PROTO_VALUE_HISTORY_DATA, &answer, &ts)))
427 {
428 if ('\0' == *answer)
429 {
430 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned no history"
431 " data: check allowed connection types and access rights",
432 proxy->host, proxy->addr);
433 break;
434 }
435
436 if (SUCCEED != zbx_json_open(answer, &jp))
437 {
438 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned invalid"
439 " history data: %s", proxy->host, proxy->addr, zbx_json_strerror());
440 break;
441 }
442
443 proxy->version = zbx_get_protocol_version(&jp);
444
445 if (SUCCEED != zbx_check_protocol_version(proxy))
446 {
447 break;
448 }
449
450 if (SUCCEED != proxy_check_error_response(&jp, &error))
451 {
452 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned invalid history data:"
453 " %s", proxy->host, proxy->addr, error);
454 break;
455 }
456
457 if (SUCCEED != process_proxy_history_data(proxy, &jp, &ts, &error))
458 {
459 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned invalid"
460 " history data: %s", proxy->host, proxy->addr, error);
461 break;
462 }
463
464 if (SUCCEED == zbx_json_brackets_by_name(&jp, ZBX_PROTO_TAG_DATA, &jp_data))
465 {
466 if (ZBX_MAX_HRECORDS > zbx_json_count(&jp_data))
467 {
468 ret = SUCCEED;
469 break;
470 }
471 }
472 }
473
474 zbx_free(error);
475 zbx_free(answer);
476
477 return ret;
478 }
479
480 /******************************************************************************
481 * *
482 * Function: proxy_get_discovery_data *
483 * *
484 * Purpose: gets discovery data from proxy *
485 * ('discovery data' request) *
486 * *
487 * Parameters: proxy - [IN/OUT] proxy data *
488 * *
489 * Return value: SUCCEED - data were received and processed successfully *
490 * other code - an error occurred *
491 * *
492 * Comments: The proxy->version property is updated with the version number *
493 * sent by proxy. *
494 * *
495 ******************************************************************************/
proxy_get_discovery_data(DC_PROXY * proxy)496 static int proxy_get_discovery_data(DC_PROXY *proxy)
497 {
498 char *answer = NULL, *error = NULL;
499 struct zbx_json_parse jp, jp_data;
500 int ret = FAIL;
501 zbx_timespec_t ts;
502
503 while (SUCCEED == (ret = get_data_from_proxy(proxy, ZBX_PROTO_VALUE_DISCOVERY_DATA, &answer, &ts)))
504 {
505 if ('\0' == *answer)
506 {
507 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned no discovery"
508 " data: check allowed connection types and access rights",
509 proxy->host, proxy->addr);
510 break;
511 }
512
513 if (SUCCEED != zbx_json_open(answer, &jp))
514 {
515 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned invalid"
516 " discovery data: %s", proxy->host, proxy->addr,
517 zbx_json_strerror());
518 break;
519 }
520
521 proxy->version = zbx_get_protocol_version(&jp);
522
523 if (SUCCEED != zbx_check_protocol_version(proxy))
524 {
525 break;
526 }
527
528 if (SUCCEED != proxy_check_error_response(&jp, &error))
529 {
530 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned invalid discovery data:"
531 " %s", proxy->host, proxy->addr, error);
532 break;
533 }
534
535 if (SUCCEED != process_discovery_data(&jp, &ts, &error))
536 {
537 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned invalid"
538 " discovery data: %s", proxy->host, proxy->addr, error);
539 break;
540 }
541
542 if (SUCCEED == zbx_json_brackets_by_name(&jp, ZBX_PROTO_TAG_DATA, &jp_data))
543 {
544 if (ZBX_MAX_HRECORDS > zbx_json_count(&jp_data))
545 {
546 ret = SUCCEED;
547 break;
548 }
549 }
550 }
551
552 zbx_free(error);
553 zbx_free(answer);
554
555 return ret;
556 }
557
558 /******************************************************************************
559 * *
560 * Function: proxy_get_auto_registration *
561 * *
562 * Purpose: gets auto registration data from proxy *
563 * ('auto registration' request) *
564 * *
565 * Parameters: proxy - [IN/OUT] proxy data *
566 * *
567 * Return value: SUCCEED - data were received and processed successfully *
568 * other code - an error occurred *
569 * *
570 * Comments: The proxy->version property is updated with the version number *
571 * sent by proxy. *
572 * *
573 ******************************************************************************/
proxy_get_auto_registration(DC_PROXY * proxy)574 static int proxy_get_auto_registration(DC_PROXY *proxy)
575 {
576 char *answer = NULL, *error = NULL;
577 struct zbx_json_parse jp, jp_data;
578 int ret = FAIL;
579 zbx_timespec_t ts;
580
581 while (SUCCEED == (ret = get_data_from_proxy(proxy, ZBX_PROTO_VALUE_AUTO_REGISTRATION_DATA, &answer, &ts)))
582 {
583 if ('\0' == *answer)
584 {
585 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned no auto"
586 " registration data: check allowed connection types and"
587 " access rights", proxy->host, proxy->addr);
588 break;
589 }
590
591 if (SUCCEED != zbx_json_open(answer, &jp))
592 {
593 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned invalid"
594 " auto registration data: %s", proxy->host, proxy->addr,
595 zbx_json_strerror());
596 break;
597 }
598
599 proxy->version = zbx_get_protocol_version(&jp);
600
601 if (SUCCEED != zbx_check_protocol_version(proxy))
602 {
603 break;
604 }
605
606 if (SUCCEED != proxy_check_error_response(&jp, &error))
607 {
608 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned invalid auto registration data:"
609 " %s", proxy->host, proxy->addr, error);
610 break;
611 }
612
613 if (SUCCEED != process_auto_registration(&jp, proxy->hostid, &ts, &error))
614 {
615 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned invalid"
616 " auto registration data: %s", proxy->host, proxy->addr, error);
617 break;
618 }
619
620 if (SUCCEED == zbx_json_brackets_by_name(&jp, ZBX_PROTO_TAG_DATA, &jp_data))
621 {
622 if (ZBX_MAX_HRECORDS > zbx_json_count(&jp_data))
623 {
624 ret = SUCCEED;
625 break;
626 }
627 }
628 }
629
630 zbx_free(error);
631 zbx_free(answer);
632
633 return ret;
634 }
635
636 /******************************************************************************
637 * *
638 * Function: proxy_process_proxy_data *
639 * *
640 * Purpose: processes proxy data request *
641 * *
642 * Parameters: proxy - [IN/OUT] proxy data *
643 * answer - [IN] data received from proxy *
644 * ts - [IN] timestamp when the proxy connection was *
645 * established *
646 * more - [OUT] available data flag *
647 * *
648 * Return value: SUCCEED - data were received and processed successfully *
649 * FAIL - otherwise *
650 * *
651 * Comments: The proxy->version property is updated with the version number *
652 * sent by proxy. *
653 * *
654 ******************************************************************************/
proxy_process_proxy_data(DC_PROXY * proxy,const char * answer,zbx_timespec_t * ts,int * more)655 static int proxy_process_proxy_data(DC_PROXY *proxy, const char *answer, zbx_timespec_t *ts, int *more)
656 {
657 const char *__function_name = "proxy_process_proxy_data";
658
659 struct zbx_json_parse jp;
660 char *error = NULL;
661 int ret = FAIL;
662
663 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
664
665 *more = ZBX_PROXY_DATA_DONE;
666
667 if ('\0' == *answer)
668 {
669 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned no proxy data:"
670 " check allowed connection types and access rights", proxy->host, proxy->addr);
671 goto out;
672 }
673
674 if (SUCCEED != zbx_json_open(answer, &jp))
675 {
676 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned invalid proxy data: %s",
677 proxy->host, proxy->addr, zbx_json_strerror());
678 goto out;
679 }
680
681 proxy->version = zbx_get_protocol_version(&jp);
682
683 if (SUCCEED != zbx_check_protocol_version(proxy))
684 {
685 goto out;
686 }
687
688 if (SUCCEED != (ret = process_proxy_data(proxy, &jp, ts, &error)))
689 {
690 zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned invalid proxy data: %s",
691 proxy->host, proxy->addr, error);
692 }
693 else
694 {
695 char value[MAX_STRING_LEN];
696
697 if (SUCCEED == zbx_json_value_by_name(&jp, ZBX_PROTO_TAG_MORE, value, sizeof(value), NULL))
698 *more = atoi(value);
699 }
700 out:
701 zbx_free(error);
702
703 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
704
705 return ret;
706 }
707
708 /******************************************************************************
709 * *
710 * Function: proxy_get_data *
711 * *
712 * Purpose: gets data from proxy ('proxy data' request) *
713 * *
714 * Parameters: proxy - [IN] proxy data *
715 * more - [OUT] available data flag *
716 * *
717 * Return value: SUCCEED - data were received and processed successfully *
718 * other code - an error occurred *
719 * *
720 * Comments: This function updates proxy version, compress and lastaccess *
721 * properties. *
722 * *
723 ******************************************************************************/
proxy_get_data(DC_PROXY * proxy,int * more)724 static int proxy_get_data(DC_PROXY *proxy, int *more)
725 {
726 const char *__function_name = "proxy_get_data";
727
728 char *answer = NULL;
729 int ret;
730 zbx_timespec_t ts;
731
732 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
733
734 if (0 == proxy->version)
735 {
736 if (SUCCEED != (ret = get_data_from_proxy(proxy, ZBX_PROTO_VALUE_PROXY_DATA, &answer, &ts)))
737 goto out;
738
739 if ('\0' == *answer)
740 {
741 proxy->version = ZBX_COMPONENT_VERSION(3, 2);
742 zbx_free(answer);
743 }
744 }
745
746 if (ZBX_COMPONENT_VERSION(3, 2) == proxy->version)
747 {
748 if (SUCCEED != (ret = proxy_get_host_availability(proxy)))
749 goto out;
750
751 proxy->lastaccess = time(NULL);
752
753 if (SUCCEED != (ret = proxy_get_history_data(proxy)))
754 goto out;
755
756 proxy->lastaccess = time(NULL);
757
758 if (SUCCEED != (ret = proxy_get_discovery_data(proxy)))
759 goto out;
760
761 proxy->lastaccess = time(NULL);
762
763 if (SUCCEED != (ret = proxy_get_auto_registration(proxy)))
764 goto out;
765
766 proxy->lastaccess = time(NULL);
767
768 /* the above functions will retrieve all available data for 3.2 and older proxies */
769 *more = ZBX_PROXY_DATA_DONE;
770 goto out;
771 }
772
773 if (NULL == answer && SUCCEED != (ret = get_data_from_proxy(proxy, ZBX_PROTO_VALUE_PROXY_DATA, &answer, &ts)))
774 goto out;
775
776 proxy->lastaccess = time(NULL);
777
778 ret = proxy_process_proxy_data(proxy, answer, &ts, more);
779
780 zbx_free(answer);
781 out:
782 if (SUCCEED == ret)
783 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s more:%d", __function_name, zbx_result_string(ret), *more);
784 else
785 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
786
787 return ret;
788 }
789
790 /******************************************************************************
791 * *
792 * Function: proxy_get_tasks *
793 * *
794 * Purpose: gets data from proxy ('proxy data' request) *
795 * *
796 * Parameters: proxy - [IN/OUT] the proxy data *
797 * *
798 * Return value: SUCCEED - data were received and processed successfully *
799 * other code - an error occurred *
800 * *
801 * Comments: This function updates proxy version, compress and lastaccess *
802 * properties. *
803 * *
804 ******************************************************************************/
proxy_get_tasks(DC_PROXY * proxy)805 static int proxy_get_tasks(DC_PROXY *proxy)
806 {
807 const char *__function_name = "proxy_get_tasks";
808
809 char *answer = NULL;
810 int ret = FAIL, more;
811 zbx_timespec_t ts;
812
813 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
814
815 if (ZBX_COMPONENT_VERSION(3, 2) >= proxy->version)
816 goto out;
817
818 if (SUCCEED != (ret = get_data_from_proxy(proxy, ZBX_PROTO_VALUE_PROXY_TASKS, &answer, &ts)))
819 goto out;
820
821 proxy->lastaccess = time(NULL);
822
823 ret = proxy_process_proxy_data(proxy, answer, &ts, &more);
824
825 zbx_free(answer);
826 out:
827 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
828
829 return ret;
830 }
831
832 /******************************************************************************
833 * *
834 * Function: process_proxy *
835 * *
836 * Purpose: retrieve values of metrics from monitored hosts *
837 * *
838 * Parameters: *
839 * *
840 * Return value: *
841 * *
842 * Author: Alexei Vladishev *
843 * *
844 * Comments: *
845 * *
846 ******************************************************************************/
process_proxy(void)847 static int process_proxy(void)
848 {
849 const char *__function_name = "process_proxy";
850
851 DC_PROXY proxy, proxy_old;
852 int num, i;
853 time_t now;
854
855 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
856
857 if (0 == (num = DCconfig_get_proxypoller_hosts(&proxy, 1)))
858 goto exit;
859
860 now = time(NULL);
861
862 for (i = 0; i < num; i++)
863 {
864 int ret = FAIL;
865 unsigned char update_nextcheck = 0;
866
867 memcpy(&proxy_old, &proxy, sizeof(DC_PROXY));
868
869 if (proxy.proxy_config_nextcheck <= now)
870 update_nextcheck |= ZBX_PROXY_CONFIG_NEXTCHECK;
871 if (proxy.proxy_data_nextcheck <= now)
872 update_nextcheck |= ZBX_PROXY_DATA_NEXTCHECK;
873 if (proxy.proxy_tasks_nextcheck <= now)
874 update_nextcheck |= ZBX_PROXY_TASKS_NEXTCHECK;
875
876 /* Check if passive proxy has been misconfigured on the server side. If it has happened more */
877 /* recently than last synchronisation of cache then there is no point to retry connecting to */
878 /* proxy again. The next reconnection attempt will happen after cache synchronisation. */
879 if (proxy.last_cfg_error_time < DCconfig_get_last_sync_time())
880 {
881 char *port = NULL;
882
883 proxy.addr = proxy.addr_orig;
884
885 port = zbx_strdup(port, proxy.port_orig);
886 substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
887 &port, MACRO_TYPE_COMMON, NULL, 0);
888 if (FAIL == is_ushort(port, &proxy.port))
889 {
890 zabbix_log(LOG_LEVEL_ERR, "invalid proxy \"%s\" port: \"%s\"", proxy.host, port);
891 ret = CONFIG_ERROR;
892 zbx_free(port);
893 goto error;
894 }
895 zbx_free(port);
896
897 if (proxy.proxy_config_nextcheck <= now)
898 {
899 if (SUCCEED != (ret = proxy_send_configuration(&proxy)))
900 goto error;
901 }
902
903 if (proxy.proxy_data_nextcheck <= now)
904 {
905 int more;
906
907 do
908 {
909 if (SUCCEED != (ret = proxy_get_data(&proxy, &more)))
910 goto error;
911 }
912 while (ZBX_PROXY_DATA_MORE == more);
913 }
914 else if (proxy.proxy_tasks_nextcheck <= now)
915 {
916 if (SUCCEED != (ret = proxy_get_tasks(&proxy)))
917 goto error;
918 }
919 }
920 error:
921 if (proxy_old.version != proxy.version || proxy_old.auto_compress != proxy.auto_compress ||
922 proxy_old.lastaccess != proxy.lastaccess)
923 {
924 zbx_update_proxy_data(&proxy_old, proxy.version, proxy.lastaccess, proxy.auto_compress);
925 }
926
927 DCrequeue_proxy(proxy.hostid, update_nextcheck, ret);
928 }
929 exit:
930 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
931
932 return num;
933 }
934
ZBX_THREAD_ENTRY(proxypoller_thread,args)935 ZBX_THREAD_ENTRY(proxypoller_thread, args)
936 {
937 int nextcheck, sleeptime = -1, processed = 0, old_processed = 0;
938 double sec, total_sec = 0.0, old_total_sec = 0.0;
939 time_t last_stat_time;
940
941 process_type = ((zbx_thread_args_t *)args)->process_type;
942 server_num = ((zbx_thread_args_t *)args)->server_num;
943 process_num = ((zbx_thread_args_t *)args)->process_num;
944
945 zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type),
946 server_num, get_process_type_string(process_type), process_num);
947
948 update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
949
950 #define STAT_INTERVAL 5 /* if a process is busy and does not sleep then update status not faster than */
951 /* once in STAT_INTERVAL seconds */
952
953 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
954 zbx_tls_init_child();
955 #endif
956 zbx_setproctitle("%s #%d [connecting to the database]", get_process_type_string(process_type), process_num);
957 last_stat_time = time(NULL);
958
959 DBconnect(ZBX_DB_CONNECT_NORMAL);
960
961 while (ZBX_IS_RUNNING())
962 {
963 sec = zbx_time();
964 zbx_update_env(sec);
965
966 if (0 != sleeptime)
967 {
968 zbx_setproctitle("%s #%d [exchanged data with %d proxies in " ZBX_FS_DBL " sec,"
969 " exchanging data]", get_process_type_string(process_type), process_num,
970 old_processed, old_total_sec);
971 }
972
973 processed += process_proxy();
974 total_sec += zbx_time() - sec;
975
976 nextcheck = DCconfig_get_proxypoller_nextcheck();
977 sleeptime = calculate_sleeptime(nextcheck, POLLER_DELAY);
978
979 if (0 != sleeptime || STAT_INTERVAL <= time(NULL) - last_stat_time)
980 {
981 if (0 == sleeptime)
982 {
983 zbx_setproctitle("%s #%d [exchanged data with %d proxies in " ZBX_FS_DBL " sec,"
984 " exchanging data]", get_process_type_string(process_type), process_num,
985 processed, total_sec);
986 }
987 else
988 {
989 zbx_setproctitle("%s #%d [exchanged data with %d proxies in " ZBX_FS_DBL " sec,"
990 " idle %d sec]", get_process_type_string(process_type), process_num,
991 processed, total_sec, sleeptime);
992 old_processed = processed;
993 old_total_sec = total_sec;
994 }
995 processed = 0;
996 total_sec = 0.0;
997 last_stat_time = time(NULL);
998 }
999
1000 zbx_sleep_loop(sleeptime);
1001 }
1002
1003 zbx_setproctitle("%s #%d [terminated]", get_process_type_string(process_type), process_num);
1004
1005 while (1)
1006 zbx_sleep(SEC_PER_MIN);
1007 #undef STAT_INTERVAL
1008 }
1009