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