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 
22 #include "db.h"
23 #include "log.h"
24 #include "sysinfo.h"
25 #include "zbxicmpping.h"
26 #include "discovery.h"
27 #include "zbxserver.h"
28 #include "zbxself.h"
29 
30 #include "daemon.h"
31 #include "discoverer.h"
32 #include "../poller/checks_agent.h"
33 #include "../poller/checks_snmp.h"
34 #include "zbxcrypto.h"
35 #include "../events.h"
36 
37 extern int		CONFIG_DISCOVERER_FORKS;
38 extern unsigned char	process_type, program_type;
39 extern int		server_num, process_num;
40 
41 #ifdef HAVE_NETSNMP
42 static volatile sig_atomic_t	snmp_cache_reload_requested;
43 #endif
44 
45 #define ZBX_DISCOVERER_IPRANGE_LIMIT	(1 << 16)
46 
47 /******************************************************************************
48  *                                                                            *
49  * Function: proxy_update_service                                             *
50  *                                                                            *
51  * Purpose: process new service status                                        *
52  *                                                                            *
53  * Parameters: service - service info                                         *
54  *                                                                            *
55  ******************************************************************************/
proxy_update_service(zbx_uint64_t druleid,zbx_uint64_t dcheckid,const char * ip,const char * dns,int port,int status,const char * value,int now)56 static void	proxy_update_service(zbx_uint64_t druleid, zbx_uint64_t dcheckid, const char *ip,
57 		const char *dns, int port, int status, const char *value, int now)
58 {
59 	char	*ip_esc, *dns_esc, *value_esc;
60 
61 	ip_esc = DBdyn_escape_field("proxy_dhistory", "ip", ip);
62 	dns_esc = DBdyn_escape_field("proxy_dhistory", "dns", dns);
63 	value_esc = DBdyn_escape_field("proxy_dhistory", "value", value);
64 
65 	DBexecute("insert into proxy_dhistory (clock,druleid,dcheckid,ip,dns,port,value,status)"
66 			" values (%d," ZBX_FS_UI64 "," ZBX_FS_UI64 ",'%s','%s',%d,'%s',%d)",
67 			now, druleid, dcheckid, ip_esc, dns_esc, port, value_esc, status);
68 
69 	zbx_free(value_esc);
70 	zbx_free(dns_esc);
71 	zbx_free(ip_esc);
72 }
73 
74 /******************************************************************************
75  *                                                                            *
76  * Function: proxy_update_host                                                *
77  *                                                                            *
78  * Purpose: process new service status                                        *
79  *                                                                            *
80  * Parameters: service - service info                                         *
81  *                                                                            *
82  ******************************************************************************/
proxy_update_host(zbx_uint64_t druleid,const char * ip,const char * dns,int status,int now)83 static void	proxy_update_host(zbx_uint64_t druleid, const char *ip, const char *dns, int status, int now)
84 {
85 	char	*ip_esc, *dns_esc;
86 
87 	ip_esc = DBdyn_escape_field("proxy_dhistory", "ip", ip);
88 	dns_esc = DBdyn_escape_field("proxy_dhistory", "dns", dns);
89 
90 	DBexecute("insert into proxy_dhistory (clock,druleid,ip,dns,status)"
91 			" values (%d," ZBX_FS_UI64 ",'%s','%s',%d)",
92 			now, druleid, ip_esc, dns_esc, status);
93 
94 	zbx_free(dns_esc);
95 	zbx_free(ip_esc);
96 }
97 
98 /******************************************************************************
99  *                                                                            *
100  * Function: discover_service                                                 *
101  *                                                                            *
102  * Purpose: check if service is available                                     *
103  *                                                                            *
104  * Parameters: service type, ip address, port number                          *
105  *                                                                            *
106  * Return value: SUCCEED - service is UP, FAIL - service not discovered       *
107  *                                                                            *
108  ******************************************************************************/
discover_service(const DB_DCHECK * dcheck,char * ip,int port,char ** value,size_t * value_alloc)109 static int	discover_service(const DB_DCHECK *dcheck, char *ip, int port, char **value, size_t *value_alloc)
110 {
111 	int		ret = SUCCEED;
112 	const char	*service = NULL;
113 	AGENT_RESULT 	result;
114 
115 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
116 
117 	init_result(&result);
118 
119 	**value = '\0';
120 
121 	switch (dcheck->type)
122 	{
123 		case SVC_SSH:
124 			service = "ssh";
125 			break;
126 		case SVC_LDAP:
127 			service = "ldap";
128 			break;
129 		case SVC_SMTP:
130 			service = "smtp";
131 			break;
132 		case SVC_FTP:
133 			service = "ftp";
134 			break;
135 		case SVC_HTTP:
136 			service = "http";
137 			break;
138 		case SVC_POP:
139 			service = "pop";
140 			break;
141 		case SVC_NNTP:
142 			service = "nntp";
143 			break;
144 		case SVC_IMAP:
145 			service = "imap";
146 			break;
147 		case SVC_TCP:
148 			service = "tcp";
149 			break;
150 		case SVC_HTTPS:
151 			service = "https";
152 			break;
153 		case SVC_TELNET:
154 			service = "telnet";
155 			break;
156 		case SVC_AGENT:
157 		case SVC_SNMPv1:
158 		case SVC_SNMPv2c:
159 		case SVC_SNMPv3:
160 		case SVC_ICMPPING:
161 			break;
162 		default:
163 			ret = FAIL;
164 			break;
165 	}
166 
167 	if (SUCCEED == ret)
168 	{
169 		char		**pvalue;
170 		size_t		value_offset = 0;
171 		ZBX_FPING_HOST	host;
172 		DC_ITEM		item;
173 		char		key[MAX_STRING_LEN], error[ITEM_ERROR_LEN_MAX];
174 
175 		zbx_alarm_on(CONFIG_TIMEOUT);
176 
177 		switch (dcheck->type)
178 		{
179 			/* simple checks */
180 			case SVC_SSH:
181 			case SVC_LDAP:
182 			case SVC_SMTP:
183 			case SVC_FTP:
184 			case SVC_HTTP:
185 			case SVC_POP:
186 			case SVC_NNTP:
187 			case SVC_IMAP:
188 			case SVC_TCP:
189 			case SVC_HTTPS:
190 			case SVC_TELNET:
191 				zbx_snprintf(key, sizeof(key), "net.tcp.service[%s,%s,%d]", service, ip, port);
192 
193 				if (SUCCEED != process(key, 0, &result) || NULL == GET_UI64_RESULT(&result) ||
194 						0 == result.ui64)
195 				{
196 					ret = FAIL;
197 				}
198 				break;
199 			/* agent and SNMP checks */
200 			case SVC_AGENT:
201 			case SVC_SNMPv1:
202 			case SVC_SNMPv2c:
203 			case SVC_SNMPv3:
204 				memset(&item, 0, sizeof(DC_ITEM));
205 
206 				strscpy(item.key_orig, dcheck->key_);
207 				item.key = item.key_orig;
208 
209 				item.interface.useip = 1;
210 				item.interface.addr = ip;
211 				item.interface.port = port;
212 
213 				item.value_type	= ITEM_VALUE_TYPE_STR;
214 
215 				switch (dcheck->type)
216 				{
217 					case SVC_SNMPv1:
218 						item.snmp_version = ZBX_IF_SNMP_VERSION_1;
219 						item.type = ITEM_TYPE_SNMP;
220 						break;
221 					case SVC_SNMPv2c:
222 						item.snmp_version = ZBX_IF_SNMP_VERSION_2;
223 						item.type = ITEM_TYPE_SNMP;
224 						break;
225 					case SVC_SNMPv3:
226 						item.snmp_version = ZBX_IF_SNMP_VERSION_3;
227 						item.type = ITEM_TYPE_SNMP;
228 						break;
229 					default:
230 						item.type = ITEM_TYPE_ZABBIX;
231 						break;
232 				}
233 
234 				if (SVC_AGENT == dcheck->type)
235 				{
236 					item.host.tls_connect = ZBX_TCP_SEC_UNENCRYPTED;
237 
238 					if (SUCCEED == get_value_agent(&item, &result) &&
239 							NULL != (pvalue = GET_TEXT_RESULT(&result)))
240 					{
241 						zbx_strcpy_alloc(value, value_alloc, &value_offset, *pvalue);
242 					}
243 					else
244 						ret = FAIL;
245 				}
246 				else
247 #ifdef HAVE_NETSNMP
248 				{
249 					item.snmp_community = strdup(dcheck->snmp_community);
250 					item.snmp_oid = strdup(dcheck->key_);
251 
252 					substitute_simple_macros_unmasked(NULL, NULL, NULL, NULL, NULL, NULL, NULL,
253 							NULL, NULL, NULL, &item.snmp_community, MACRO_TYPE_COMMON,
254 							NULL, 0);
255 					substitute_key_macros(&item.snmp_oid, NULL, NULL, NULL, NULL,
256 							MACRO_TYPE_SNMP_OID, NULL, 0);
257 
258 					if (ZBX_IF_SNMP_VERSION_3 == item.snmp_version)
259 					{
260 						item.snmpv3_securityname =
261 								zbx_strdup(NULL, dcheck->snmpv3_securityname);
262 						item.snmpv3_securitylevel = dcheck->snmpv3_securitylevel;
263 						item.snmpv3_authpassphrase =
264 								zbx_strdup(NULL, dcheck->snmpv3_authpassphrase);
265 						item.snmpv3_privpassphrase =
266 								zbx_strdup(NULL, dcheck->snmpv3_privpassphrase);
267 						item.snmpv3_authprotocol = dcheck->snmpv3_authprotocol;
268 						item.snmpv3_privprotocol = dcheck->snmpv3_privprotocol;
269 						item.snmpv3_contextname = zbx_strdup(NULL, dcheck->snmpv3_contextname);
270 
271 						substitute_simple_macros_unmasked(NULL, NULL, NULL, NULL, NULL, NULL,
272 								NULL, NULL, NULL, NULL, &item.snmpv3_securityname,
273 								MACRO_TYPE_COMMON, NULL, 0);
274 						substitute_simple_macros_unmasked(NULL, NULL, NULL, NULL, NULL, NULL,
275 								NULL, NULL, NULL, NULL, &item.snmpv3_authpassphrase,
276 								MACRO_TYPE_COMMON, NULL, 0);
277 						substitute_simple_macros_unmasked(NULL, NULL, NULL, NULL, NULL, NULL,
278 								NULL, NULL, NULL, NULL, &item.snmpv3_privpassphrase,
279 								MACRO_TYPE_COMMON, NULL, 0);
280 						substitute_simple_macros_unmasked(NULL, NULL, NULL, NULL, NULL, NULL,
281 								NULL, NULL, NULL, NULL, &item.snmpv3_contextname,
282 								MACRO_TYPE_COMMON, NULL, 0);
283 					}
284 
285 					if (SUCCEED == get_value_snmp(&item, &result, ZBX_NO_POLLER) &&
286 							NULL != (pvalue = GET_TEXT_RESULT(&result)))
287 					{
288 						zbx_strcpy_alloc(value, value_alloc, &value_offset, *pvalue);
289 					}
290 					else
291 						ret = FAIL;
292 
293 					zbx_free(item.snmp_community);
294 					zbx_free(item.snmp_oid);
295 
296 					if (ZBX_IF_SNMP_VERSION_3 == item.snmp_version)
297 					{
298 						zbx_free(item.snmpv3_securityname);
299 						zbx_free(item.snmpv3_authpassphrase);
300 						zbx_free(item.snmpv3_privpassphrase);
301 						zbx_free(item.snmpv3_contextname);
302 					}
303 				}
304 #else
305 					ret = FAIL;
306 #endif	/* HAVE_NETSNMP */
307 
308 				if (FAIL == ret && ISSET_MSG(&result))
309 				{
310 					zabbix_log(LOG_LEVEL_DEBUG, "discovery: item [%s] error: %s",
311 							item.key, result.msg);
312 				}
313 				break;
314 			case SVC_ICMPPING:
315 				memset(&host, 0, sizeof(host));
316 				host.addr = strdup(ip);
317 
318 				if (SUCCEED != zbx_ping(&host, 1, 3, 0, 0, 0, error, sizeof(error)) || 0 == host.rcv)
319 					ret = FAIL;
320 
321 				zbx_free(host.addr);
322 				break;
323 			default:
324 				break;
325 		}
326 
327 		zbx_alarm_off();
328 	}
329 	free_result(&result);
330 
331 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
332 
333 	return ret;
334 }
335 
336 /******************************************************************************
337  *                                                                            *
338  * Function: process_check                                                    *
339  *                                                                            *
340  * Purpose: check if service is available and update database                 *
341  *                                                                            *
342  * Parameters: service - service info                                         *
343  *                                                                            *
344  ******************************************************************************/
process_check(const DB_DCHECK * dcheck,int * host_status,char * ip,int now,zbx_vector_ptr_t * services)345 static void	process_check(const DB_DCHECK *dcheck, int *host_status, char *ip, int now, zbx_vector_ptr_t *services)
346 {
347 	const char	*start;
348 	char		*value = NULL;
349 	size_t		value_alloc = 128;
350 
351 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
352 
353 	value = (char *)zbx_malloc(value, value_alloc);
354 
355 	for (start = dcheck->ports; '\0' != *start;)
356 	{
357 		char	*comma, *last_port;
358 		int	port, first, last;
359 
360 		if (NULL != (comma = strchr(start, ',')))
361 			*comma = '\0';
362 
363 		if (NULL != (last_port = strchr(start, '-')))
364 		{
365 			*last_port = '\0';
366 			first = atoi(start);
367 			last = atoi(last_port + 1);
368 			*last_port = '-';
369 		}
370 		else
371 			first = last = atoi(start);
372 
373 		for (port = first; port <= last; port++)
374 		{
375 			zbx_service_t	*service;
376 
377 			zabbix_log(LOG_LEVEL_DEBUG, "%s() port:%d", __func__, port);
378 
379 			service = (zbx_service_t *)zbx_malloc(NULL, sizeof(zbx_service_t));
380 			service->status = (SUCCEED == discover_service(dcheck, ip, port, &value, &value_alloc) ?
381 					DOBJECT_STATUS_UP : DOBJECT_STATUS_DOWN);
382 			service->dcheckid = dcheck->dcheckid;
383 			service->itemtime = (time_t)now;
384 			service->port = port;
385 			zbx_strlcpy_utf8(service->value, value, MAX_DISCOVERED_VALUE_SIZE);
386 			zbx_vector_ptr_append(services, service);
387 
388 			/* update host status */
389 			if (-1 == *host_status || DOBJECT_STATUS_UP == service->status)
390 				*host_status = service->status;
391 		}
392 
393 		if (NULL != comma)
394 		{
395 			*comma = ',';
396 			start = comma + 1;
397 		}
398 		else
399 			break;
400 	}
401 	zbx_free(value);
402 
403 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
404 }
405 
406 /******************************************************************************
407  *                                                                            *
408  * Function: process_checks                                                   *
409  *                                                                            *
410  ******************************************************************************/
process_checks(const DB_DRULE * drule,int * host_status,char * ip,int unique,int now,zbx_vector_ptr_t * services,zbx_vector_uint64_t * dcheckids)411 static void	process_checks(const DB_DRULE *drule, int *host_status, char *ip, int unique, int now,
412 		zbx_vector_ptr_t *services, zbx_vector_uint64_t *dcheckids)
413 {
414 	DB_RESULT	result;
415 	DB_ROW		row;
416 	DB_DCHECK	dcheck;
417 	char		sql[MAX_STRING_LEN];
418 	size_t		offset = 0;
419 
420 	offset += zbx_snprintf(sql + offset, sizeof(sql) - offset,
421 			"select dcheckid,type,key_,snmp_community,snmpv3_securityname,snmpv3_securitylevel,"
422 				"snmpv3_authpassphrase,snmpv3_privpassphrase,snmpv3_authprotocol,snmpv3_privprotocol,"
423 				"ports,snmpv3_contextname"
424 			" from dchecks"
425 			" where druleid=" ZBX_FS_UI64,
426 			drule->druleid);
427 
428 	if (0 != drule->unique_dcheckid)
429 	{
430 		offset += zbx_snprintf(sql + offset, sizeof(sql) - offset, " and dcheckid%s" ZBX_FS_UI64,
431 				unique ? "=" : "<>", drule->unique_dcheckid);
432 	}
433 
434 	zbx_snprintf(sql + offset, sizeof(sql) - offset, " order by dcheckid");
435 
436 	result = DBselect("%s", sql);
437 
438 	while (NULL != (row = DBfetch(result)))
439 	{
440 		memset(&dcheck, 0, sizeof(dcheck));
441 
442 		ZBX_STR2UINT64(dcheck.dcheckid, row[0]);
443 		dcheck.type = atoi(row[1]);
444 		dcheck.key_ = row[2];
445 		dcheck.snmp_community = row[3];
446 		dcheck.snmpv3_securityname = row[4];
447 		dcheck.snmpv3_securitylevel = (unsigned char)atoi(row[5]);
448 		dcheck.snmpv3_authpassphrase = row[6];
449 		dcheck.snmpv3_privpassphrase = row[7];
450 		dcheck.snmpv3_authprotocol = (unsigned char)atoi(row[8]);
451 		dcheck.snmpv3_privprotocol = (unsigned char)atoi(row[9]);
452 		dcheck.ports = row[10];
453 		dcheck.snmpv3_contextname = row[11];
454 
455 		zbx_vector_uint64_append(dcheckids, dcheck.dcheckid);
456 
457 		process_check(&dcheck, host_status, ip, now, services);
458 	}
459 	DBfree_result(result);
460 }
461 
462 /******************************************************************************
463  *                                                                            *
464  * Function: process_services                                                 *
465  *                                                                            *
466  ******************************************************************************/
process_services(const DB_DRULE * drule,DB_DHOST * dhost,const char * ip,const char * dns,int now,const zbx_vector_ptr_t * services,zbx_vector_uint64_t * dcheckids)467 static int	process_services(const DB_DRULE *drule, DB_DHOST *dhost, const char *ip, const char *dns, int now,
468 		const zbx_vector_ptr_t *services, zbx_vector_uint64_t *dcheckids)
469 {
470 	int	i, ret;
471 
472 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
473 
474 	zbx_vector_uint64_sort(dcheckids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
475 
476 	if (SUCCEED != (ret = DBlock_ids("dchecks", "dcheckid", dcheckids)))
477 		goto fail;
478 
479 	for (i = 0; i < services->values_num; i++)
480 	{
481 		zbx_service_t	*service = (zbx_service_t *)services->values[i];
482 
483 		if (FAIL == zbx_vector_uint64_bsearch(dcheckids, service->dcheckid, ZBX_DEFAULT_UINT64_COMPARE_FUNC))
484 			continue;
485 
486 		if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER))
487 		{
488 			discovery_update_service(drule, service->dcheckid, dhost, ip, dns, service->port,
489 					service->status, service->value, now);
490 		}
491 		else if (0 != (program_type & ZBX_PROGRAM_TYPE_PROXY))
492 		{
493 			proxy_update_service(drule->druleid, service->dcheckid, ip, dns, service->port,
494 					service->status, service->value, now);
495 		}
496 	}
497 fail:
498 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
499 
500 	return ret;
501 }
502 
503 /******************************************************************************
504  *                                                                            *
505  * Function: process_rule                                                     *
506  *                                                                            *
507  * Purpose: process single discovery rule                                     *
508  *                                                                            *
509  ******************************************************************************/
process_rule(DB_DRULE * drule)510 static void	process_rule(DB_DRULE *drule)
511 {
512 	DB_DHOST		dhost;
513 	int			host_status, now;
514 	char			ip[INTERFACE_IP_LEN_MAX], *start, *comma, dns[INTERFACE_DNS_LEN_MAX];
515 	int			ipaddress[8];
516 	zbx_iprange_t		iprange;
517 	zbx_vector_ptr_t	services;
518 	zbx_vector_uint64_t	dcheckids;
519 
520 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() rule:'%s' range:'%s'", __func__, drule->name, drule->iprange);
521 
522 	zbx_vector_ptr_create(&services);
523 	zbx_vector_uint64_create(&dcheckids);
524 
525 	for (start = drule->iprange; '\0' != *start;)
526 	{
527 		if (NULL != (comma = strchr(start, ',')))
528 			*comma = '\0';
529 
530 		zabbix_log(LOG_LEVEL_DEBUG, "%s() range:'%s'", __func__, start);
531 
532 		if (SUCCEED != iprange_parse(&iprange, start))
533 		{
534 			zabbix_log(LOG_LEVEL_WARNING, "discovery rule \"%s\": wrong format of IP range \"%s\"",
535 					drule->name, start);
536 			goto next;
537 		}
538 
539 		if (ZBX_DISCOVERER_IPRANGE_LIMIT < iprange_volume(&iprange))
540 		{
541 			zabbix_log(LOG_LEVEL_WARNING, "discovery rule \"%s\": IP range \"%s\" exceeds %d address limit",
542 					drule->name, start, ZBX_DISCOVERER_IPRANGE_LIMIT);
543 			goto next;
544 		}
545 #ifndef HAVE_IPV6
546 		if (ZBX_IPRANGE_V6 == iprange.type)
547 		{
548 			zabbix_log(LOG_LEVEL_WARNING, "discovery rule \"%s\": encountered IP range \"%s\","
549 					" but IPv6 support not compiled in", drule->name, start);
550 			goto next;
551 		}
552 #endif
553 		iprange_first(&iprange, ipaddress);
554 
555 		do
556 		{
557 #ifdef HAVE_IPV6
558 			if (ZBX_IPRANGE_V6 == iprange.type)
559 			{
560 				zbx_snprintf(ip, sizeof(ip), "%x:%x:%x:%x:%x:%x:%x:%x", (unsigned int)ipaddress[0],
561 						(unsigned int)ipaddress[1], (unsigned int)ipaddress[2],
562 						(unsigned int)ipaddress[3], (unsigned int)ipaddress[4],
563 						(unsigned int)ipaddress[5], (unsigned int)ipaddress[6],
564 						(unsigned int)ipaddress[7]);
565 			}
566 			else
567 			{
568 #endif
569 				zbx_snprintf(ip, sizeof(ip), "%u.%u.%u.%u", (unsigned int)ipaddress[0],
570 						(unsigned int)ipaddress[1], (unsigned int)ipaddress[2],
571 						(unsigned int)ipaddress[3]);
572 #ifdef HAVE_IPV6
573 			}
574 #endif
575 			memset(&dhost, 0, sizeof(dhost));
576 			host_status = -1;
577 
578 			now = time(NULL);
579 
580 			zabbix_log(LOG_LEVEL_DEBUG, "%s() ip:'%s'", __func__, ip);
581 
582 			zbx_alarm_on(CONFIG_TIMEOUT);
583 			zbx_gethost_by_ip(ip, dns, sizeof(dns));
584 			zbx_alarm_off();
585 
586 			if (0 != drule->unique_dcheckid)
587 				process_checks(drule, &host_status, ip, 1, now, &services, &dcheckids);
588 			process_checks(drule, &host_status, ip, 0, now, &services, &dcheckids);
589 
590 			DBbegin();
591 
592 			if (SUCCEED != DBlock_druleid(drule->druleid))
593 			{
594 				DBrollback();
595 
596 				zabbix_log(LOG_LEVEL_DEBUG, "discovery rule '%s' was deleted during processing,"
597 						" stopping", drule->name);
598 				zbx_vector_ptr_clear_ext(&services, zbx_ptr_free);
599 				goto out;
600 			}
601 
602 			if (SUCCEED != process_services(drule, &dhost, ip, dns, now, &services, &dcheckids))
603 			{
604 				DBrollback();
605 
606 				zabbix_log(LOG_LEVEL_DEBUG, "all checks where deleted for discovery rule '%s'"
607 						" during processing, stopping", drule->name);
608 				zbx_vector_ptr_clear_ext(&services, zbx_ptr_free);
609 				goto out;
610 			}
611 
612 			zbx_vector_uint64_clear(&dcheckids);
613 			zbx_vector_ptr_clear_ext(&services, zbx_ptr_free);
614 
615 			if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER))
616 			{
617 				discovery_update_host(&dhost, host_status, now);
618 				zbx_process_events(NULL, NULL);
619 				zbx_clean_events();
620 			}
621 			else if (0 != (program_type & ZBX_PROGRAM_TYPE_PROXY))
622 				proxy_update_host(drule->druleid, ip, dns, host_status, now);
623 
624 			DBcommit();
625 		}
626 		while (SUCCEED == iprange_next(&iprange, ipaddress));
627 next:
628 		if (NULL != comma)
629 		{
630 			*comma = ',';
631 			start = comma + 1;
632 		}
633 		else
634 			break;
635 	}
636 out:
637 	zbx_vector_ptr_destroy(&services);
638 	zbx_vector_uint64_destroy(&dcheckids);
639 
640 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
641 }
642 
643 /******************************************************************************
644  *                                                                            *
645  * Function: discovery_clean_services                                         *
646  *                                                                            *
647  * Purpose: clean dservices and dhosts not presenting in drule                *
648  *                                                                            *
649  ******************************************************************************/
discovery_clean_services(zbx_uint64_t druleid)650 static void	discovery_clean_services(zbx_uint64_t druleid)
651 {
652 	DB_RESULT		result;
653 	DB_ROW			row;
654 	char			*iprange = NULL;
655 	zbx_vector_uint64_t	keep_dhostids, del_dhostids, del_dserviceids;
656 	zbx_uint64_t		dhostid, dserviceid;
657 	char			*sql = NULL;
658 	size_t			sql_alloc = 0, sql_offset;
659 
660 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
661 
662 	result = DBselect("select iprange from drules where druleid=" ZBX_FS_UI64, druleid);
663 
664 	if (NULL != (row = DBfetch(result)))
665 		iprange = zbx_strdup(iprange, row[0]);
666 
667 	DBfree_result(result);
668 
669 	if (NULL == iprange)
670 		goto out;
671 
672 	zbx_vector_uint64_create(&keep_dhostids);
673 	zbx_vector_uint64_create(&del_dhostids);
674 	zbx_vector_uint64_create(&del_dserviceids);
675 
676 	result = DBselect(
677 			"select dh.dhostid,ds.dserviceid,ds.ip"
678 			" from dhosts dh"
679 				" left join dservices ds"
680 					" on dh.dhostid=ds.dhostid"
681 			" where dh.druleid=" ZBX_FS_UI64,
682 			druleid);
683 
684 	while (NULL != (row = DBfetch(result)))
685 	{
686 		ZBX_STR2UINT64(dhostid, row[0]);
687 
688 		if (SUCCEED == DBis_null(row[1]))
689 		{
690 			zbx_vector_uint64_append(&del_dhostids, dhostid);
691 		}
692 		else if (SUCCEED != ip_in_list(iprange, row[2]))
693 		{
694 			ZBX_STR2UINT64(dserviceid, row[1]);
695 
696 			zbx_vector_uint64_append(&del_dhostids, dhostid);
697 			zbx_vector_uint64_append(&del_dserviceids, dserviceid);
698 		}
699 		else
700 			zbx_vector_uint64_append(&keep_dhostids, dhostid);
701 	}
702 	DBfree_result(result);
703 
704 	zbx_free(iprange);
705 
706 	if (0 != del_dserviceids.values_num)
707 	{
708 		int	i;
709 
710 		/* remove dservices */
711 
712 		zbx_vector_uint64_sort(&del_dserviceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
713 
714 		sql_offset = 0;
715 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from dservices where");
716 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "dserviceid",
717 				del_dserviceids.values, del_dserviceids.values_num);
718 
719 		DBexecute("%s", sql);
720 
721 		/* remove dhosts */
722 
723 		zbx_vector_uint64_sort(&keep_dhostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
724 		zbx_vector_uint64_uniq(&keep_dhostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
725 
726 		zbx_vector_uint64_sort(&del_dhostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
727 		zbx_vector_uint64_uniq(&del_dhostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
728 
729 		for (i = 0; i < del_dhostids.values_num; i++)
730 		{
731 			dhostid = del_dhostids.values[i];
732 
733 			if (FAIL != zbx_vector_uint64_bsearch(&keep_dhostids, dhostid, ZBX_DEFAULT_UINT64_COMPARE_FUNC))
734 				zbx_vector_uint64_remove_noorder(&del_dhostids, i--);
735 		}
736 	}
737 
738 	if (0 != del_dhostids.values_num)
739 	{
740 		zbx_vector_uint64_sort(&del_dhostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
741 
742 		sql_offset = 0;
743 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from dhosts where");
744 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "dhostid",
745 				del_dhostids.values, del_dhostids.values_num);
746 
747 		DBexecute("%s", sql);
748 	}
749 
750 	zbx_free(sql);
751 
752 	zbx_vector_uint64_destroy(&del_dserviceids);
753 	zbx_vector_uint64_destroy(&del_dhostids);
754 	zbx_vector_uint64_destroy(&keep_dhostids);
755 out:
756 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
757 }
758 
process_discovery(void)759 static int	process_discovery(void)
760 {
761 	DB_RESULT	result;
762 	DB_ROW		row;
763 	int		rule_count = 0;
764 	char		*delay_str = NULL;
765 
766 	result = DBselect(
767 			"select distinct r.druleid,r.iprange,r.name,c.dcheckid,r.proxy_hostid,r.delay"
768 			" from drules r"
769 				" left join dchecks c"
770 					" on c.druleid=r.druleid"
771 						" and c.uniq=1"
772 			" where r.status=%d"
773 				" and r.nextcheck<=%d"
774 				" and " ZBX_SQL_MOD(r.druleid,%d) "=%d",
775 			DRULE_STATUS_MONITORED,
776 			(int)time(NULL),
777 			CONFIG_DISCOVERER_FORKS,
778 			process_num - 1);
779 
780 	while (ZBX_IS_RUNNING() && NULL != (row = DBfetch(result)))
781 	{
782 		int		now, delay;
783 		zbx_uint64_t	druleid;
784 
785 		rule_count++;
786 
787 		ZBX_STR2UINT64(druleid, row[0]);
788 
789 		delay_str = zbx_strdup(delay_str, row[5]);
790 		substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &delay_str,
791 				MACRO_TYPE_COMMON, NULL, 0);
792 
793 		if (SUCCEED != is_time_suffix(delay_str, &delay, ZBX_LENGTH_UNLIMITED))
794 		{
795 			zabbix_log(LOG_LEVEL_WARNING, "discovery rule \"%s\": invalid update interval \"%s\"",
796 					row[2], delay_str);
797 
798 			now = (int)time(NULL);
799 
800 			DBexecute("update drules set nextcheck=%d where druleid=" ZBX_FS_UI64,
801 					0 > now ? ZBX_JAN_2038 : now, druleid);
802 
803 			continue;
804 		}
805 
806 		if (SUCCEED == DBis_null(row[4]))
807 		{
808 			DB_DRULE	drule;
809 
810 			memset(&drule, 0, sizeof(drule));
811 
812 			drule.druleid = druleid;
813 			drule.iprange = row[1];
814 			drule.name = row[2];
815 			ZBX_DBROW2UINT64(drule.unique_dcheckid, row[3]);
816 
817 			process_rule(&drule);
818 		}
819 
820 		if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER))
821 			discovery_clean_services(druleid);
822 
823 		now = (int)time(NULL);
824 		if (0 > now + delay)
825 		{
826 			zabbix_log(LOG_LEVEL_WARNING, "discovery rule \"%s\": nextcheck update causes overflow",
827 					row[2]);
828 			DBexecute("update drules set nextcheck=%d where druleid=" ZBX_FS_UI64, ZBX_JAN_2038, druleid);
829 		}
830 		else
831 			DBexecute("update drules set nextcheck=%d where druleid=" ZBX_FS_UI64, now + delay, druleid);
832 	}
833 	DBfree_result(result);
834 
835 	zbx_free(delay_str);
836 
837 	return rule_count;	/* performance metric */
838 }
839 
get_minnextcheck(void)840 static int	get_minnextcheck(void)
841 {
842 	DB_RESULT	result;
843 	DB_ROW		row;
844 	int		res = FAIL;
845 
846 	result = DBselect(
847 			"select count(*),min(nextcheck)"
848 			" from drules"
849 			" where status=%d"
850 				" and " ZBX_SQL_MOD(druleid,%d) "=%d",
851 			DRULE_STATUS_MONITORED, CONFIG_DISCOVERER_FORKS, process_num - 1);
852 
853 	row = DBfetch(result);
854 
855 	if (NULL == row || DBis_null(row[0]) == SUCCEED || DBis_null(row[1]) == SUCCEED)
856 		zabbix_log(LOG_LEVEL_DEBUG, "get_minnextcheck(): no items to update");
857 	else if (0 != atoi(row[0]))
858 		res = atoi(row[1]);
859 
860 	DBfree_result(result);
861 
862 	return res;
863 }
864 
zbx_discoverer_sigusr_handler(int flags)865 static void	zbx_discoverer_sigusr_handler(int flags)
866 {
867 #ifdef HAVE_NETSNMP
868 	if (ZBX_RTC_SNMP_CACHE_RELOAD == ZBX_RTC_GET_MSG(flags))
869 		snmp_cache_reload_requested = 1;
870 #else
871 	ZBX_UNUSED(flags);
872 #endif
873 }
874 
875 /******************************************************************************
876  *                                                                            *
877  * Function: discoverer_thread                                                *
878  *                                                                            *
879  * Purpose: periodically try to find new hosts and services                   *
880  *                                                                            *
881  ******************************************************************************/
ZBX_THREAD_ENTRY(discoverer_thread,args)882 ZBX_THREAD_ENTRY(discoverer_thread, args)
883 {
884 	int	nextcheck, sleeptime = -1, rule_count = 0, old_rule_count = 0;
885 	double	sec, total_sec = 0.0, old_total_sec = 0.0;
886 	time_t	last_stat_time;
887 
888 	process_type = ((zbx_thread_args_t *)args)->process_type;
889 	server_num = ((zbx_thread_args_t *)args)->server_num;
890 	process_num = ((zbx_thread_args_t *)args)->process_num;
891 
892 	zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type),
893 			server_num, get_process_type_string(process_type), process_num);
894 
895 	update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
896 
897 #define STAT_INTERVAL	5	/* if a process is busy and does not sleep then update status not faster than */
898 				/* once in STAT_INTERVAL seconds */
899 
900 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
901 	zbx_tls_init_child();
902 #endif
903 	zbx_setproctitle("%s #%d [connecting to the database]", get_process_type_string(process_type), process_num);
904 	last_stat_time = time(NULL);
905 
906 	DBconnect(ZBX_DB_CONNECT_NORMAL);
907 
908 	zbx_set_sigusr_handler(zbx_discoverer_sigusr_handler);
909 
910 	while (ZBX_IS_RUNNING())
911 	{
912 		sec = zbx_time();
913 		zbx_update_env(sec);
914 
915 #ifdef HAVE_NETSNMP
916 		if (1 == snmp_cache_reload_requested)
917 		{
918 			zbx_clear_cache_snmp(process_type, process_num);
919 			snmp_cache_reload_requested = 0;
920 		}
921 #endif
922 
923 		if (0 != sleeptime)
924 		{
925 			zbx_setproctitle("%s #%d [processed %d rules in " ZBX_FS_DBL " sec, performing discovery]",
926 					get_process_type_string(process_type), process_num, old_rule_count,
927 					old_total_sec);
928 		}
929 
930 		rule_count += process_discovery();
931 		total_sec += zbx_time() - sec;
932 
933 		nextcheck = get_minnextcheck();
934 		sleeptime = calculate_sleeptime(nextcheck, DISCOVERER_DELAY);
935 
936 		if (0 != sleeptime || STAT_INTERVAL <= time(NULL) - last_stat_time)
937 		{
938 			if (0 == sleeptime)
939 			{
940 				zbx_setproctitle("%s #%d [processed %d rules in " ZBX_FS_DBL " sec, performing "
941 						"discovery]", get_process_type_string(process_type), process_num,
942 						rule_count, total_sec);
943 			}
944 			else
945 			{
946 				zbx_setproctitle("%s #%d [processed %d rules in " ZBX_FS_DBL " sec, idle %d sec]",
947 						get_process_type_string(process_type), process_num, rule_count,
948 						total_sec, sleeptime);
949 				old_rule_count = rule_count;
950 				old_total_sec = total_sec;
951 			}
952 			rule_count = 0;
953 			total_sec = 0.0;
954 			last_stat_time = time(NULL);
955 		}
956 
957 		zbx_sleep_loop(sleeptime);
958 	}
959 
960 	zbx_setproctitle("%s #%d [terminated]", get_process_type_string(process_type), process_num);
961 
962 	while (1)
963 		zbx_sleep(SEC_PER_MIN);
964 #undef STAT_INTERVAL
965 }
966