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 
34 extern unsigned char	process_type, program_type;
35 extern int		server_num, process_num;
36 
connect_to_proxy(DC_PROXY * proxy,zbx_socket_t * sock,int timeout)37 static int	connect_to_proxy(DC_PROXY *proxy, zbx_socket_t *sock, int timeout)
38 {
39 	const char	*__function_name = "connect_to_proxy";
40 	int		ret;
41 
42 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() address:%s port:%hu timeout:%d conn:%u", __function_name, proxy->addr,
43 			proxy->port, timeout, (unsigned int)proxy->tls_connect);
44 
45 	if (FAIL == (ret = zbx_tcp_connect(sock, CONFIG_SOURCE_IP, proxy->addr, proxy->port, timeout,
46 			proxy->tls_connect, proxy->tls_arg1, proxy->tls_arg2)))
47 	{
48 		zabbix_log(LOG_LEVEL_ERR, "cannot connect to proxy \"%s\": %s", proxy->host, zbx_socket_strerror());
49 		ret = NETWORK_ERROR;
50 	}
51 
52 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
53 
54 	return ret;
55 }
56 
send_data_to_proxy(DC_PROXY * proxy,zbx_socket_t * sock,const char * data)57 static int	send_data_to_proxy(DC_PROXY *proxy, zbx_socket_t *sock, const char *data)
58 {
59 	const char	*__function_name = "send_data_to_proxy";
60 	int		ret;
61 
62 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() data:'%s'", __function_name, data);
63 
64 	if (FAIL == (ret = zbx_tcp_send(sock, data)))
65 	{
66 		zabbix_log(LOG_LEVEL_ERR, "cannot send data to proxy \"%s\": %s", proxy->host, zbx_socket_strerror());
67 
68 		ret = NETWORK_ERROR;
69 	}
70 
71 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
72 
73 	return ret;
74 }
75 
recv_data_from_proxy(DC_PROXY * proxy,zbx_socket_t * sock)76 static int	recv_data_from_proxy(DC_PROXY *proxy, zbx_socket_t *sock)
77 {
78 	const char	*__function_name = "recv_data_from_proxy";
79 	int		ret;
80 
81 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
82 
83 	if (FAIL == (ret = zbx_tcp_recv(sock)))
84 	{
85 		zabbix_log(LOG_LEVEL_ERR, "cannot obtain data from proxy \"%s\": %s", proxy->host,
86 				zbx_socket_strerror());
87 	}
88 	else
89 		zabbix_log(LOG_LEVEL_DEBUG, "obtained data from proxy \"%s\": [%s]", proxy->host, sock->buffer);
90 
91 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
92 
93 	return ret;
94 }
95 
disconnect_proxy(zbx_socket_t * sock)96 static void	disconnect_proxy(zbx_socket_t *sock)
97 {
98 	const char	*__function_name = "disconnect_proxy";
99 
100 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
101 
102 	zbx_tcp_close(sock);
103 
104 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
105 }
106 
107 /******************************************************************************
108  *                                                                            *
109  * Function: get_data_from_proxy                                              *
110  *                                                                            *
111  * Purpose: get historical data from proxy                                    *
112  *                                                                            *
113  * Parameters: proxy   - [IN] proxy data                                      *
114  *             request - [IN] requested data type                             *
115  *             data    - [OUT] data received from proxy                       *
116  *             ts      - [OUT] timestamp when the proxy connection was        *
117  *                             established                                    *
118  *                                                                            *
119  * Return value: SUCCESS - processed successfully                             *
120  *               FAIL - an error occurred                                     *
121  *                                                                            *
122  * Author: Alexander Vladishev                                                *
123  *                                                                            *
124  ******************************************************************************/
get_data_from_proxy(DC_PROXY * proxy,const char * request,char ** data,zbx_timespec_t * ts)125 static int	get_data_from_proxy(DC_PROXY *proxy, const char *request, char **data, zbx_timespec_t *ts)
126 {
127 	const char	*__function_name = "get_data_from_proxy";
128 	zbx_socket_t	s;
129 	struct zbx_json	j;
130 	int		ret = FAIL;
131 
132 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() request:'%s'", __function_name, request);
133 
134 	zbx_json_init(&j, ZBX_JSON_STAT_BUF_LEN);
135 
136 	zbx_json_addstring(&j, "request", request, ZBX_JSON_TYPE_STRING);
137 
138 	if (SUCCEED == (ret = connect_to_proxy(proxy, &s, CONFIG_TRAPPER_TIMEOUT)))
139 	{
140 		/* get connection timestamp if required */
141 		if (NULL != ts)
142 			zbx_timespec(ts);
143 
144 		if (SUCCEED == (ret = send_data_to_proxy(proxy, &s, j.buffer)))
145 		{
146 			if (SUCCEED == (ret = recv_data_from_proxy(proxy, &s)))
147 			{
148 				if (SUCCEED == (ret = zbx_send_response(&s, SUCCEED, NULL, 0)))
149 					*data = zbx_strdup(*data, s.buffer);
150 			}
151 		}
152 
153 		disconnect_proxy(&s);
154 	}
155 
156 	zbx_json_free(&j);
157 
158 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret));
159 
160 	return ret;
161 }
162 
163 /******************************************************************************
164  *                                                                            *
165  * Function: process_proxy                                                    *
166  *                                                                            *
167  * Purpose: retrieve values of metrics from monitored hosts                   *
168  *                                                                            *
169  * Parameters:                                                                *
170  *                                                                            *
171  * Return value:                                                              *
172  *                                                                            *
173  * Author: Alexei Vladishev                                                   *
174  *                                                                            *
175  * Comments:                                                                  *
176  *                                                                            *
177  ******************************************************************************/
process_proxy(void)178 static int	process_proxy(void)
179 {
180 	const char		*__function_name = "process_proxy";
181 	DC_PROXY		proxy;
182 	int			num, i, ret;
183 	struct zbx_json		j;
184 	struct zbx_json_parse	jp, jp_data;
185 	zbx_socket_t		s;
186 	char			*answer = NULL, *port = NULL;
187 	time_t			now, last_access;
188 	unsigned char		update_nextcheck;
189 	zbx_timespec_t		ts;
190 
191 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
192 
193 	if (0 == (num = DCconfig_get_proxypoller_hosts(&proxy, 1)))
194 		goto exit;
195 
196 	now = time(NULL);
197 
198 	zbx_json_init(&j, 512 * 1024);
199 
200 	for (i = 0; i < num; i++)
201 	{
202 		update_nextcheck = 0;
203 		last_access = 0;
204 
205 		if (proxy.proxy_config_nextcheck <= now)
206 			update_nextcheck |= 0x01;
207 		if (proxy.proxy_data_nextcheck <= now)
208 			update_nextcheck |= 0x02;
209 
210 		proxy.addr = proxy.addr_orig;
211 
212 		port = zbx_strdup(port, proxy.port_orig);
213 		substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
214 				&port, MACRO_TYPE_COMMON, NULL, 0);
215 		if (FAIL == is_ushort(port, &proxy.port))
216 		{
217 			zabbix_log(LOG_LEVEL_ERR, "invalid proxy \"%s\" port: \"%s\"", proxy.host, port);
218 			goto network_error;
219 		}
220 
221 		if (proxy.proxy_config_nextcheck <= now)
222 		{
223 			char	*error = NULL;
224 
225 			zbx_json_clean(&j);
226 
227 			zbx_json_addstring(&j, ZBX_PROTO_TAG_REQUEST,
228 					ZBX_PROTO_VALUE_PROXY_CONFIG, ZBX_JSON_TYPE_STRING);
229 			zbx_json_addobject(&j, ZBX_PROTO_TAG_DATA);
230 
231 			if (SUCCEED != (ret = get_proxyconfig_data(proxy.hostid, &j, &error)))
232 			{
233 				zabbix_log(LOG_LEVEL_ERR, "cannot collect configuration data for proxy \"%s\": %s",
234 						proxy.host, error);
235 				zbx_free(error);
236 
237 				goto network_error;
238 			}
239 
240 			if (SUCCEED == (ret = connect_to_proxy(&proxy, &s, CONFIG_TRAPPER_TIMEOUT)))
241 			{
242 				zabbix_log(LOG_LEVEL_WARNING, "sending configuration data to proxy \"%s\" at \"%s\","
243 						" datalen " ZBX_FS_SIZE_T,
244 						proxy.host, s.peer, (zbx_fs_size_t)j.buffer_size);
245 
246 				if (SUCCEED == (ret = send_data_to_proxy(&proxy, &s, j.buffer)))
247 				{
248 					if (SUCCEED != (ret = zbx_recv_response(&s, 0, &error)))
249 					{
250 						zabbix_log(LOG_LEVEL_WARNING, "cannot send configuration data to proxy"
251 								" \"%s\" at \"%s\": %s", proxy.host, s.peer, error);
252 					}
253 
254 					zbx_free(error);
255 				}
256 
257 				disconnect_proxy(&s);
258 			}
259 
260 			if (SUCCEED != ret)
261 				goto network_error;
262 
263 			last_access = time(NULL);
264 		}
265 
266 		if (proxy.proxy_data_nextcheck <= now)
267 		{
268 			if (SUCCEED == get_data_from_proxy(&proxy,
269 					ZBX_PROTO_VALUE_HOST_AVAILABILITY, &answer, NULL))
270 			{
271 				if ('\0' == *answer)
272 				{
273 					zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned no host"
274 							" availability data: check allowed connection types and"
275 							" access rights", proxy.host, proxy.addr);
276 					zbx_free(answer);
277 					goto network_error;
278 				}
279 
280 				if (SUCCEED == zbx_json_open(answer, &jp))
281 				{
282 					last_access = time(NULL);
283 					process_host_availability(&jp);
284 				}
285 
286 				zbx_free(answer);
287 			}
288 			else
289 				goto network_error;
290 retry_history:
291 			if (SUCCEED == get_data_from_proxy(&proxy,
292 					ZBX_PROTO_VALUE_HISTORY_DATA, &answer, &ts))
293 			{
294 				if ('\0' == *answer)
295 				{
296 					zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned no history"
297 							" data: check allowed connection types and access rights",
298 							proxy.host, proxy.addr);
299 					zbx_free(answer);
300 					goto network_error;
301 				}
302 
303 				if (SUCCEED == zbx_json_open(answer, &jp))
304 				{
305 					last_access = time(NULL);
306 
307 					process_hist_data(NULL, &jp, proxy.hostid, &ts, NULL);
308 
309 					if (SUCCEED == zbx_json_brackets_by_name(&jp, ZBX_PROTO_TAG_DATA, &jp_data))
310 					{
311 						if (ZBX_MAX_HRECORDS <= zbx_json_count(&jp_data))
312 						{
313 							zbx_free(answer);
314 							goto retry_history;
315 						}
316 					}
317 				}
318 
319 				zbx_free(answer);
320 			}
321 			else
322 				goto network_error;
323 retry_dhistory:
324 			if (SUCCEED == get_data_from_proxy(&proxy,
325 					ZBX_PROTO_VALUE_DISCOVERY_DATA, &answer, NULL))
326 			{
327 				if ('\0' == *answer)
328 				{
329 					zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned no discovery"
330 							" data: check allowed connection types and access rights",
331 							proxy.host, proxy.addr);
332 					zbx_free(answer);
333 					goto network_error;
334 				}
335 
336 				if (SUCCEED == zbx_json_open(answer, &jp))
337 				{
338 					last_access = time(NULL);
339 
340 					process_dhis_data(&jp);
341 
342 					if (SUCCEED == zbx_json_brackets_by_name(&jp, ZBX_PROTO_TAG_DATA, &jp_data))
343 					{
344 						if (ZBX_MAX_HRECORDS <= zbx_json_count(&jp_data))
345 						{
346 							zbx_free(answer);
347 							goto retry_dhistory;
348 						}
349 					}
350 				}
351 
352 				zbx_free(answer);
353 			}
354 			else
355 				goto network_error;
356 retry_autoreg_host:
357 			if (SUCCEED == get_data_from_proxy(&proxy,
358 					ZBX_PROTO_VALUE_AUTO_REGISTRATION_DATA, &answer, NULL))
359 			{
360 				if ('\0' == *answer)
361 				{
362 					zabbix_log(LOG_LEVEL_WARNING, "proxy \"%s\" at \"%s\" returned no auto"
363 							" registration data: check allowed connection types and"
364 							" access rights", proxy.host, proxy.addr);
365 					zbx_free(answer);
366 					goto network_error;
367 				}
368 
369 				if (SUCCEED == zbx_json_open(answer, &jp))
370 				{
371 					last_access = time(NULL);
372 
373 					process_areg_data(&jp, proxy.hostid);
374 
375 					if (SUCCEED == zbx_json_brackets_by_name(&jp, ZBX_PROTO_TAG_DATA, &jp_data))
376 					{
377 						if (ZBX_MAX_HRECORDS <= zbx_json_count(&jp_data))
378 						{
379 							zbx_free(answer);
380 							goto retry_autoreg_host;
381 						}
382 					}
383 				}
384 
385 				zbx_free(answer);
386 			}
387 			else
388 				goto network_error;
389 		}
390 network_error:
391 		if (0 != last_access)
392 		{
393 			DBbegin();
394 			update_proxy_lastaccess(proxy.hostid, last_access);
395 			DBcommit();
396 		}
397 
398 		DCrequeue_proxy(proxy.hostid, update_nextcheck);
399 	}
400 
401 	zbx_free(port);
402 
403 	zbx_json_free(&j);
404 exit:
405 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
406 
407 	return num;
408 }
409 
ZBX_THREAD_ENTRY(proxypoller_thread,args)410 ZBX_THREAD_ENTRY(proxypoller_thread, args)
411 {
412 	int	nextcheck, sleeptime = -1, processed = 0, old_processed = 0;
413 	double	sec, total_sec = 0.0, old_total_sec = 0.0;
414 	time_t	last_stat_time;
415 
416 	process_type = ((zbx_thread_args_t *)args)->process_type;
417 	server_num = ((zbx_thread_args_t *)args)->server_num;
418 	process_num = ((zbx_thread_args_t *)args)->process_num;
419 
420 	zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type),
421 			server_num, get_process_type_string(process_type), process_num);
422 
423 #define STAT_INTERVAL	5	/* if a process is busy and does not sleep then update status not faster than */
424 				/* once in STAT_INTERVAL seconds */
425 
426 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
427 	zbx_tls_init_child();
428 #endif
429 	zbx_setproctitle("%s #%d [connecting to the database]", get_process_type_string(process_type), process_num);
430 	last_stat_time = time(NULL);
431 
432 	DBconnect(ZBX_DB_CONNECT_NORMAL);
433 
434 	for (;;)
435 	{
436 		zbx_handle_log();
437 
438 		if (0 != sleeptime)
439 		{
440 			zbx_setproctitle("%s #%d [exchanged data with %d proxies in " ZBX_FS_DBL " sec,"
441 					" exchanging data]", get_process_type_string(process_type), process_num,
442 					old_processed, old_total_sec);
443 		}
444 
445 		sec = zbx_time();
446 		processed += process_proxy();
447 		total_sec += zbx_time() - sec;
448 
449 		nextcheck = DCconfig_get_proxypoller_nextcheck();
450 		sleeptime = calculate_sleeptime(nextcheck, POLLER_DELAY);
451 
452 		if (0 != sleeptime || STAT_INTERVAL <= time(NULL) - last_stat_time)
453 		{
454 			if (0 == sleeptime)
455 			{
456 				zbx_setproctitle("%s #%d [exchanged data with %d proxies in " ZBX_FS_DBL " sec,"
457 						" exchanging data]", get_process_type_string(process_type), process_num,
458 						processed, total_sec);
459 			}
460 			else
461 			{
462 				zbx_setproctitle("%s #%d [exchanged data with %d proxies in " ZBX_FS_DBL " sec,"
463 						" idle %d sec]", get_process_type_string(process_type), process_num,
464 						processed, total_sec, sleeptime);
465 				old_processed = processed;
466 				old_total_sec = total_sec;
467 			}
468 			processed = 0;
469 			total_sec = 0.0;
470 			last_stat_time = time(NULL);
471 		}
472 
473 		zbx_sleep_loop(sleeptime);
474 
475 #if !defined(_WINDOWS) && defined(HAVE_RESOLV_H)
476 		zbx_update_resolver_conf();	/* handle /etc/resolv.conf update */
477 #endif
478 	}
479 #undef STAT_INTERVAL
480 }
481