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, &item.snmp_community, MACRO_TYPE_COMMON, NULL, 0);
254 					substitute_key_macros(&item.snmp_oid, NULL, NULL, NULL, NULL,
255 							MACRO_TYPE_SNMP_OID, NULL, 0);
256 
257 					if (ZBX_IF_SNMP_VERSION_3 == item.snmp_version)
258 					{
259 						item.snmpv3_securityname =
260 								zbx_strdup(NULL, dcheck->snmpv3_securityname);
261 						item.snmpv3_securitylevel = dcheck->snmpv3_securitylevel;
262 						item.snmpv3_authpassphrase =
263 								zbx_strdup(NULL, dcheck->snmpv3_authpassphrase);
264 						item.snmpv3_privpassphrase =
265 								zbx_strdup(NULL, dcheck->snmpv3_privpassphrase);
266 						item.snmpv3_authprotocol = dcheck->snmpv3_authprotocol;
267 						item.snmpv3_privprotocol = dcheck->snmpv3_privprotocol;
268 						item.snmpv3_contextname = zbx_strdup(NULL, dcheck->snmpv3_contextname);
269 
270 						substitute_simple_macros_unmasked(NULL, NULL, NULL, NULL, NULL, NULL,
271 								NULL, NULL, NULL, &item.snmpv3_securityname,
272 								MACRO_TYPE_COMMON, NULL, 0);
273 						substitute_simple_macros_unmasked(NULL, NULL, NULL, NULL, NULL, NULL,
274 								NULL, NULL, NULL, &item.snmpv3_authpassphrase,
275 								MACRO_TYPE_COMMON, NULL, 0);
276 						substitute_simple_macros_unmasked(NULL, NULL, NULL, NULL, NULL, NULL,
277 								NULL, NULL, NULL, &item.snmpv3_privpassphrase,
278 								MACRO_TYPE_COMMON, NULL, 0);
279 						substitute_simple_macros_unmasked(NULL, NULL, NULL, NULL, NULL, NULL,
280 								NULL, NULL, NULL, &item.snmpv3_contextname,
281 								MACRO_TYPE_COMMON, NULL, 0);
282 					}
283 
284 					if (SUCCEED == get_value_snmp(&item, &result, ZBX_NO_POLLER) &&
285 							NULL != (pvalue = GET_TEXT_RESULT(&result)))
286 					{
287 						zbx_strcpy_alloc(value, value_alloc, &value_offset, *pvalue);
288 					}
289 					else
290 						ret = FAIL;
291 
292 					zbx_free(item.snmp_community);
293 					zbx_free(item.snmp_oid);
294 
295 					if (ZBX_IF_SNMP_VERSION_3 == item.snmp_version)
296 					{
297 						zbx_free(item.snmpv3_securityname);
298 						zbx_free(item.snmpv3_authpassphrase);
299 						zbx_free(item.snmpv3_privpassphrase);
300 						zbx_free(item.snmpv3_contextname);
301 					}
302 				}
303 #else
304 					ret = FAIL;
305 #endif	/* HAVE_NETSNMP */
306 
307 				if (FAIL == ret && ISSET_MSG(&result))
308 				{
309 					zabbix_log(LOG_LEVEL_DEBUG, "discovery: item [%s] error: %s",
310 							item.key, result.msg);
311 				}
312 				break;
313 			case SVC_ICMPPING:
314 				memset(&host, 0, sizeof(host));
315 				host.addr = strdup(ip);
316 
317 				if (SUCCEED != zbx_ping(&host, 1, 3, 0, 0, 0, error, sizeof(error)) || 0 == host.rcv)
318 					ret = FAIL;
319 
320 				zbx_free(host.addr);
321 				break;
322 			default:
323 				break;
324 		}
325 
326 		zbx_alarm_off();
327 	}
328 	free_result(&result);
329 
330 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
331 
332 	return ret;
333 }
334 
335 /******************************************************************************
336  *                                                                            *
337  * Function: process_check                                                    *
338  *                                                                            *
339  * Purpose: check if service is available and update database                 *
340  *                                                                            *
341  * Parameters: service - service info                                         *
342  *                                                                            *
343  ******************************************************************************/
process_check(const DB_DCHECK * dcheck,int * host_status,char * ip,int now,zbx_vector_ptr_t * services)344 static void	process_check(const DB_DCHECK *dcheck, int *host_status, char *ip, int now, zbx_vector_ptr_t *services)
345 {
346 	const char	*start;
347 	char		*value = NULL;
348 	size_t		value_alloc = 128;
349 
350 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
351 
352 	value = (char *)zbx_malloc(value, value_alloc);
353 
354 	for (start = dcheck->ports; '\0' != *start;)
355 	{
356 		char	*comma, *last_port;
357 		int	port, first, last;
358 
359 		if (NULL != (comma = strchr(start, ',')))
360 			*comma = '\0';
361 
362 		if (NULL != (last_port = strchr(start, '-')))
363 		{
364 			*last_port = '\0';
365 			first = atoi(start);
366 			last = atoi(last_port + 1);
367 			*last_port = '-';
368 		}
369 		else
370 			first = last = atoi(start);
371 
372 		for (port = first; port <= last; port++)
373 		{
374 			zbx_service_t	*service;
375 
376 			zabbix_log(LOG_LEVEL_DEBUG, "%s() port:%d", __func__, port);
377 
378 			service = (zbx_service_t *)zbx_malloc(NULL, sizeof(zbx_service_t));
379 			service->status = (SUCCEED == discover_service(dcheck, ip, port, &value, &value_alloc) ?
380 					DOBJECT_STATUS_UP : DOBJECT_STATUS_DOWN);
381 			service->dcheckid = dcheck->dcheckid;
382 			service->itemtime = (time_t)now;
383 			service->port = port;
384 			zbx_strlcpy_utf8(service->value, value, MAX_DISCOVERED_VALUE_SIZE);
385 			zbx_vector_ptr_append(services, service);
386 
387 			/* update host status */
388 			if (-1 == *host_status || DOBJECT_STATUS_UP == service->status)
389 				*host_status = service->status;
390 		}
391 
392 		if (NULL != comma)
393 		{
394 			*comma = ',';
395 			start = comma + 1;
396 		}
397 		else
398 			break;
399 	}
400 	zbx_free(value);
401 
402 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
403 }
404 
405 /******************************************************************************
406  *                                                                            *
407  * Function: process_checks                                                   *
408  *                                                                            *
409  ******************************************************************************/
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)410 static void	process_checks(const DB_DRULE *drule, int *host_status, char *ip, int unique, int now,
411 		zbx_vector_ptr_t *services, zbx_vector_uint64_t *dcheckids)
412 {
413 	DB_RESULT	result;
414 	DB_ROW		row;
415 	DB_DCHECK	dcheck;
416 	char		sql[MAX_STRING_LEN];
417 	size_t		offset = 0;
418 
419 	offset += zbx_snprintf(sql + offset, sizeof(sql) - offset,
420 			"select dcheckid,type,key_,snmp_community,snmpv3_securityname,snmpv3_securitylevel,"
421 				"snmpv3_authpassphrase,snmpv3_privpassphrase,snmpv3_authprotocol,snmpv3_privprotocol,"
422 				"ports,snmpv3_contextname"
423 			" from dchecks"
424 			" where druleid=" ZBX_FS_UI64,
425 			drule->druleid);
426 
427 	if (0 != drule->unique_dcheckid)
428 	{
429 		offset += zbx_snprintf(sql + offset, sizeof(sql) - offset, " and dcheckid%s" ZBX_FS_UI64,
430 				unique ? "=" : "<>", drule->unique_dcheckid);
431 	}
432 
433 	zbx_snprintf(sql + offset, sizeof(sql) - offset, " order by dcheckid");
434 
435 	result = DBselect("%s", sql);
436 
437 	while (NULL != (row = DBfetch(result)))
438 	{
439 		memset(&dcheck, 0, sizeof(dcheck));
440 
441 		ZBX_STR2UINT64(dcheck.dcheckid, row[0]);
442 		dcheck.type = atoi(row[1]);
443 		dcheck.key_ = row[2];
444 		dcheck.snmp_community = row[3];
445 		dcheck.snmpv3_securityname = row[4];
446 		dcheck.snmpv3_securitylevel = (unsigned char)atoi(row[5]);
447 		dcheck.snmpv3_authpassphrase = row[6];
448 		dcheck.snmpv3_privpassphrase = row[7];
449 		dcheck.snmpv3_authprotocol = (unsigned char)atoi(row[8]);
450 		dcheck.snmpv3_privprotocol = (unsigned char)atoi(row[9]);
451 		dcheck.ports = row[10];
452 		dcheck.snmpv3_contextname = row[11];
453 
454 		zbx_vector_uint64_append(dcheckids, dcheck.dcheckid);
455 
456 		process_check(&dcheck, host_status, ip, now, services);
457 	}
458 	DBfree_result(result);
459 }
460 
461 /******************************************************************************
462  *                                                                            *
463  * Function: process_services                                                 *
464  *                                                                            *
465  ******************************************************************************/
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)466 static int	process_services(const DB_DRULE *drule, DB_DHOST *dhost, const char *ip, const char *dns, int now,
467 		const zbx_vector_ptr_t *services, zbx_vector_uint64_t *dcheckids)
468 {
469 	int	i, ret;
470 
471 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
472 
473 	zbx_vector_uint64_sort(dcheckids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
474 
475 	if (SUCCEED != (ret = DBlock_ids("dchecks", "dcheckid", dcheckids)))
476 		goto fail;
477 
478 	for (i = 0; i < services->values_num; i++)
479 	{
480 		zbx_service_t	*service = (zbx_service_t *)services->values[i];
481 
482 		if (FAIL == zbx_vector_uint64_bsearch(dcheckids, service->dcheckid, ZBX_DEFAULT_UINT64_COMPARE_FUNC))
483 			continue;
484 
485 		if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER))
486 		{
487 			discovery_update_service(drule, service->dcheckid, dhost, ip, dns, service->port,
488 					service->status, service->value, now);
489 		}
490 		else if (0 != (program_type & ZBX_PROGRAM_TYPE_PROXY))
491 		{
492 			proxy_update_service(drule->druleid, service->dcheckid, ip, dns, service->port,
493 					service->status, service->value, now);
494 		}
495 	}
496 fail:
497 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
498 
499 	return ret;
500 }
501 
502 /******************************************************************************
503  *                                                                            *
504  * Function: process_rule                                                     *
505  *                                                                            *
506  * Purpose: process single discovery rule                                     *
507  *                                                                            *
508  ******************************************************************************/
process_rule(DB_DRULE * drule)509 static void	process_rule(DB_DRULE *drule)
510 {
511 	DB_DHOST		dhost;
512 	int			host_status, now;
513 	char			ip[INTERFACE_IP_LEN_MAX], *start, *comma, dns[INTERFACE_DNS_LEN_MAX];
514 	int			ipaddress[8];
515 	zbx_iprange_t		iprange;
516 	zbx_vector_ptr_t	services;
517 	zbx_vector_uint64_t	dcheckids;
518 
519 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() rule:'%s' range:'%s'", __func__, drule->name, drule->iprange);
520 
521 	zbx_vector_ptr_create(&services);
522 	zbx_vector_uint64_create(&dcheckids);
523 
524 	for (start = drule->iprange; '\0' != *start;)
525 	{
526 		if (NULL != (comma = strchr(start, ',')))
527 			*comma = '\0';
528 
529 		zabbix_log(LOG_LEVEL_DEBUG, "%s() range:'%s'", __func__, start);
530 
531 		if (SUCCEED != iprange_parse(&iprange, start))
532 		{
533 			zabbix_log(LOG_LEVEL_WARNING, "discovery rule \"%s\": wrong format of IP range \"%s\"",
534 					drule->name, start);
535 			goto next;
536 		}
537 
538 		if (ZBX_DISCOVERER_IPRANGE_LIMIT < iprange_volume(&iprange))
539 		{
540 			zabbix_log(LOG_LEVEL_WARNING, "discovery rule \"%s\": IP range \"%s\" exceeds %d address limit",
541 					drule->name, start, ZBX_DISCOVERER_IPRANGE_LIMIT);
542 			goto next;
543 		}
544 #ifndef HAVE_IPV6
545 		if (ZBX_IPRANGE_V6 == iprange.type)
546 		{
547 			zabbix_log(LOG_LEVEL_WARNING, "discovery rule \"%s\": encountered IP range \"%s\","
548 					" but IPv6 support not compiled in", drule->name, start);
549 			goto next;
550 		}
551 #endif
552 		iprange_first(&iprange, ipaddress);
553 
554 		do
555 		{
556 #ifdef HAVE_IPV6
557 			if (ZBX_IPRANGE_V6 == iprange.type)
558 			{
559 				zbx_snprintf(ip, sizeof(ip), "%x:%x:%x:%x:%x:%x:%x:%x", (unsigned int)ipaddress[0],
560 						(unsigned int)ipaddress[1], (unsigned int)ipaddress[2],
561 						(unsigned int)ipaddress[3], (unsigned int)ipaddress[4],
562 						(unsigned int)ipaddress[5], (unsigned int)ipaddress[6],
563 						(unsigned int)ipaddress[7]);
564 			}
565 			else
566 			{
567 #endif
568 				zbx_snprintf(ip, sizeof(ip), "%u.%u.%u.%u", (unsigned int)ipaddress[0],
569 						(unsigned int)ipaddress[1], (unsigned int)ipaddress[2],
570 						(unsigned int)ipaddress[3]);
571 #ifdef HAVE_IPV6
572 			}
573 #endif
574 			memset(&dhost, 0, sizeof(dhost));
575 			host_status = -1;
576 
577 			now = time(NULL);
578 
579 			zabbix_log(LOG_LEVEL_DEBUG, "%s() ip:'%s'", __func__, ip);
580 
581 			zbx_alarm_on(CONFIG_TIMEOUT);
582 			zbx_gethost_by_ip(ip, dns, sizeof(dns));
583 			zbx_alarm_off();
584 
585 			if (0 != drule->unique_dcheckid)
586 				process_checks(drule, &host_status, ip, 1, now, &services, &dcheckids);
587 			process_checks(drule, &host_status, ip, 0, now, &services, &dcheckids);
588 
589 			DBbegin();
590 
591 			if (SUCCEED != DBlock_druleid(drule->druleid))
592 			{
593 				DBrollback();
594 
595 				zabbix_log(LOG_LEVEL_DEBUG, "discovery rule '%s' was deleted during processing,"
596 						" stopping", drule->name);
597 				zbx_vector_ptr_clear_ext(&services, zbx_ptr_free);
598 				goto out;
599 			}
600 
601 			if (SUCCEED != process_services(drule, &dhost, ip, dns, now, &services, &dcheckids))
602 			{
603 				DBrollback();
604 
605 				zabbix_log(LOG_LEVEL_DEBUG, "all checks where deleted for discovery rule '%s'"
606 						" during processing, stopping", drule->name);
607 				zbx_vector_ptr_clear_ext(&services, zbx_ptr_free);
608 				goto out;
609 			}
610 
611 			zbx_vector_uint64_clear(&dcheckids);
612 			zbx_vector_ptr_clear_ext(&services, zbx_ptr_free);
613 
614 			if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER))
615 			{
616 				discovery_update_host(&dhost, host_status, now);
617 				zbx_process_events(NULL, NULL);
618 				zbx_clean_events();
619 			}
620 			else if (0 != (program_type & ZBX_PROGRAM_TYPE_PROXY))
621 				proxy_update_host(drule->druleid, ip, dns, host_status, now);
622 
623 			DBcommit();
624 		}
625 		while (SUCCEED == iprange_next(&iprange, ipaddress));
626 next:
627 		if (NULL != comma)
628 		{
629 			*comma = ',';
630 			start = comma + 1;
631 		}
632 		else
633 			break;
634 	}
635 out:
636 	zbx_vector_ptr_destroy(&services);
637 	zbx_vector_uint64_destroy(&dcheckids);
638 
639 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
640 }
641 
642 /******************************************************************************
643  *                                                                            *
644  * Function: discovery_clean_services                                         *
645  *                                                                            *
646  * Purpose: clean dservices and dhosts not presenting in drule                *
647  *                                                                            *
648  ******************************************************************************/
discovery_clean_services(zbx_uint64_t druleid)649 static void	discovery_clean_services(zbx_uint64_t druleid)
650 {
651 	DB_RESULT		result;
652 	DB_ROW			row;
653 	char			*iprange = NULL;
654 	zbx_vector_uint64_t	keep_dhostids, del_dhostids, del_dserviceids;
655 	zbx_uint64_t		dhostid, dserviceid;
656 	char			*sql = NULL;
657 	size_t			sql_alloc = 0, sql_offset;
658 
659 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
660 
661 	result = DBselect("select iprange from drules where druleid=" ZBX_FS_UI64, druleid);
662 
663 	if (NULL != (row = DBfetch(result)))
664 		iprange = zbx_strdup(iprange, row[0]);
665 
666 	DBfree_result(result);
667 
668 	if (NULL == iprange)
669 		goto out;
670 
671 	zbx_vector_uint64_create(&keep_dhostids);
672 	zbx_vector_uint64_create(&del_dhostids);
673 	zbx_vector_uint64_create(&del_dserviceids);
674 
675 	result = DBselect(
676 			"select dh.dhostid,ds.dserviceid,ds.ip"
677 			" from dhosts dh"
678 				" left join dservices ds"
679 					" on dh.dhostid=ds.dhostid"
680 			" where dh.druleid=" ZBX_FS_UI64,
681 			druleid);
682 
683 	while (NULL != (row = DBfetch(result)))
684 	{
685 		ZBX_STR2UINT64(dhostid, row[0]);
686 
687 		if (SUCCEED == DBis_null(row[1]))
688 		{
689 			zbx_vector_uint64_append(&del_dhostids, dhostid);
690 		}
691 		else if (SUCCEED != ip_in_list(iprange, row[2]))
692 		{
693 			ZBX_STR2UINT64(dserviceid, row[1]);
694 
695 			zbx_vector_uint64_append(&del_dhostids, dhostid);
696 			zbx_vector_uint64_append(&del_dserviceids, dserviceid);
697 		}
698 		else
699 			zbx_vector_uint64_append(&keep_dhostids, dhostid);
700 	}
701 	DBfree_result(result);
702 
703 	zbx_free(iprange);
704 
705 	if (0 != del_dserviceids.values_num)
706 	{
707 		int	i;
708 
709 		/* remove dservices */
710 
711 		zbx_vector_uint64_sort(&del_dserviceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
712 
713 		sql_offset = 0;
714 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from dservices where");
715 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "dserviceid",
716 				del_dserviceids.values, del_dserviceids.values_num);
717 
718 		DBexecute("%s", sql);
719 
720 		/* remove dhosts */
721 
722 		zbx_vector_uint64_sort(&keep_dhostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
723 		zbx_vector_uint64_uniq(&keep_dhostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
724 
725 		zbx_vector_uint64_sort(&del_dhostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
726 		zbx_vector_uint64_uniq(&del_dhostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
727 
728 		for (i = 0; i < del_dhostids.values_num; i++)
729 		{
730 			dhostid = del_dhostids.values[i];
731 
732 			if (FAIL != zbx_vector_uint64_bsearch(&keep_dhostids, dhostid, ZBX_DEFAULT_UINT64_COMPARE_FUNC))
733 				zbx_vector_uint64_remove_noorder(&del_dhostids, i--);
734 		}
735 	}
736 
737 	if (0 != del_dhostids.values_num)
738 	{
739 		zbx_vector_uint64_sort(&del_dhostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
740 
741 		sql_offset = 0;
742 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from dhosts where");
743 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "dhostid",
744 				del_dhostids.values, del_dhostids.values_num);
745 
746 		DBexecute("%s", sql);
747 	}
748 
749 	zbx_free(sql);
750 
751 	zbx_vector_uint64_destroy(&del_dserviceids);
752 	zbx_vector_uint64_destroy(&del_dhostids);
753 	zbx_vector_uint64_destroy(&keep_dhostids);
754 out:
755 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
756 }
757 
process_discovery(void)758 static int	process_discovery(void)
759 {
760 	DB_RESULT	result;
761 	DB_ROW		row;
762 	int		rule_count = 0;
763 	char		*delay_str = NULL;
764 
765 	result = DBselect(
766 			"select distinct r.druleid,r.iprange,r.name,c.dcheckid,r.proxy_hostid,r.delay"
767 			" from drules r"
768 				" left join dchecks c"
769 					" on c.druleid=r.druleid"
770 						" and c.uniq=1"
771 			" where r.status=%d"
772 				" and r.nextcheck<=%d"
773 				" and " ZBX_SQL_MOD(r.druleid,%d) "=%d",
774 			DRULE_STATUS_MONITORED,
775 			(int)time(NULL),
776 			CONFIG_DISCOVERER_FORKS,
777 			process_num - 1);
778 
779 	while (ZBX_IS_RUNNING() && NULL != (row = DBfetch(result)))
780 	{
781 		int		now, delay;
782 		zbx_uint64_t	druleid;
783 
784 		rule_count++;
785 
786 		ZBX_STR2UINT64(druleid, row[0]);
787 
788 		delay_str = zbx_strdup(delay_str, row[5]);
789 		substitute_simple_macros(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &delay_str,
790 				MACRO_TYPE_COMMON, NULL, 0);
791 
792 		if (SUCCEED != is_time_suffix(delay_str, &delay, ZBX_LENGTH_UNLIMITED))
793 		{
794 			zbx_config_t	cfg;
795 
796 			zabbix_log(LOG_LEVEL_WARNING, "discovery rule \"%s\": invalid update interval \"%s\"",
797 					row[2], delay_str);
798 
799 			zbx_config_get(&cfg, ZBX_CONFIG_FLAGS_REFRESH_UNSUPPORTED);
800 
801 			now = (int)time(NULL);
802 
803 			DBexecute("update drules set nextcheck=%d where druleid=" ZBX_FS_UI64,
804 					(0 == cfg.refresh_unsupported || 0 > now + cfg.refresh_unsupported ?
805 					ZBX_JAN_2038 : now + cfg.refresh_unsupported), druleid);
806 
807 			zbx_config_clean(&cfg);
808 			continue;
809 		}
810 
811 		if (SUCCEED == DBis_null(row[4]))
812 		{
813 			DB_DRULE	drule;
814 
815 			memset(&drule, 0, sizeof(drule));
816 
817 			drule.druleid = druleid;
818 			drule.iprange = row[1];
819 			drule.name = row[2];
820 			ZBX_DBROW2UINT64(drule.unique_dcheckid, row[3]);
821 
822 			process_rule(&drule);
823 		}
824 
825 		if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER))
826 			discovery_clean_services(druleid);
827 
828 		now = (int)time(NULL);
829 		if (0 > now + delay)
830 		{
831 			zabbix_log(LOG_LEVEL_WARNING, "discovery rule \"%s\": nextcheck update causes overflow",
832 					row[2]);
833 			DBexecute("update drules set nextcheck=%d where druleid=" ZBX_FS_UI64, ZBX_JAN_2038, druleid);
834 		}
835 		else
836 			DBexecute("update drules set nextcheck=%d where druleid=" ZBX_FS_UI64, now + delay, druleid);
837 	}
838 	DBfree_result(result);
839 
840 	zbx_free(delay_str);
841 
842 	return rule_count;	/* performance metric */
843 }
844 
get_minnextcheck(void)845 static int	get_minnextcheck(void)
846 {
847 	DB_RESULT	result;
848 	DB_ROW		row;
849 	int		res = FAIL;
850 
851 	result = DBselect(
852 			"select count(*),min(nextcheck)"
853 			" from drules"
854 			" where status=%d"
855 				" and " ZBX_SQL_MOD(druleid,%d) "=%d",
856 			DRULE_STATUS_MONITORED, CONFIG_DISCOVERER_FORKS, process_num - 1);
857 
858 	row = DBfetch(result);
859 
860 	if (NULL == row || DBis_null(row[0]) == SUCCEED || DBis_null(row[1]) == SUCCEED)
861 		zabbix_log(LOG_LEVEL_DEBUG, "get_minnextcheck(): no items to update");
862 	else if (0 != atoi(row[0]))
863 		res = atoi(row[1]);
864 
865 	DBfree_result(result);
866 
867 	return res;
868 }
869 
zbx_discoverer_sigusr_handler(int flags)870 static void	zbx_discoverer_sigusr_handler(int flags)
871 {
872 #ifdef HAVE_NETSNMP
873 	if (ZBX_RTC_SNMP_CACHE_RELOAD == ZBX_RTC_GET_MSG(flags))
874 		snmp_cache_reload_requested = 1;
875 #else
876 	ZBX_UNUSED(flags);
877 #endif
878 }
879 
880 /******************************************************************************
881  *                                                                            *
882  * Function: discoverer_thread                                                *
883  *                                                                            *
884  * Purpose: periodically try to find new hosts and services                   *
885  *                                                                            *
886  ******************************************************************************/
ZBX_THREAD_ENTRY(discoverer_thread,args)887 ZBX_THREAD_ENTRY(discoverer_thread, args)
888 {
889 	int	nextcheck, sleeptime = -1, rule_count = 0, old_rule_count = 0;
890 	double	sec, total_sec = 0.0, old_total_sec = 0.0;
891 	time_t	last_stat_time;
892 
893 	process_type = ((zbx_thread_args_t *)args)->process_type;
894 	server_num = ((zbx_thread_args_t *)args)->server_num;
895 	process_num = ((zbx_thread_args_t *)args)->process_num;
896 
897 	zabbix_log(LOG_LEVEL_INFORMATION, "%s #%d started [%s #%d]", get_program_type_string(program_type),
898 			server_num, get_process_type_string(process_type), process_num);
899 
900 	update_selfmon_counter(ZBX_PROCESS_STATE_BUSY);
901 
902 #define STAT_INTERVAL	5	/* if a process is busy and does not sleep then update status not faster than */
903 				/* once in STAT_INTERVAL seconds */
904 
905 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
906 	zbx_tls_init_child();
907 #endif
908 	zbx_setproctitle("%s #%d [connecting to the database]", get_process_type_string(process_type), process_num);
909 	last_stat_time = time(NULL);
910 
911 	DBconnect(ZBX_DB_CONNECT_NORMAL);
912 
913 	zbx_set_sigusr_handler(zbx_discoverer_sigusr_handler);
914 
915 	while (ZBX_IS_RUNNING())
916 	{
917 		sec = zbx_time();
918 		zbx_update_env(sec);
919 
920 #ifdef HAVE_NETSNMP
921 		if (1 == snmp_cache_reload_requested)
922 		{
923 			zbx_clear_cache_snmp(process_type, process_num);
924 			snmp_cache_reload_requested = 0;
925 		}
926 #endif
927 
928 		if (0 != sleeptime)
929 		{
930 			zbx_setproctitle("%s #%d [processed %d rules in " ZBX_FS_DBL " sec, performing discovery]",
931 					get_process_type_string(process_type), process_num, old_rule_count,
932 					old_total_sec);
933 		}
934 
935 		rule_count += process_discovery();
936 		total_sec += zbx_time() - sec;
937 
938 		nextcheck = get_minnextcheck();
939 		sleeptime = calculate_sleeptime(nextcheck, DISCOVERER_DELAY);
940 
941 		if (0 != sleeptime || STAT_INTERVAL <= time(NULL) - last_stat_time)
942 		{
943 			if (0 == sleeptime)
944 			{
945 				zbx_setproctitle("%s #%d [processed %d rules in " ZBX_FS_DBL " sec, performing "
946 						"discovery]", get_process_type_string(process_type), process_num,
947 						rule_count, total_sec);
948 			}
949 			else
950 			{
951 				zbx_setproctitle("%s #%d [processed %d rules in " ZBX_FS_DBL " sec, idle %d sec]",
952 						get_process_type_string(process_type), process_num, rule_count,
953 						total_sec, sleeptime);
954 				old_rule_count = rule_count;
955 				old_total_sec = total_sec;
956 			}
957 			rule_count = 0;
958 			total_sec = 0.0;
959 			last_stat_time = time(NULL);
960 		}
961 
962 		zbx_sleep_loop(sleeptime);
963 	}
964 
965 	zbx_setproctitle("%s #%d [terminated]", get_process_type_string(process_type), process_num);
966 
967 	while (1)
968 		zbx_sleep(SEC_PER_MIN);
969 #undef STAT_INTERVAL
970 }
971