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