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