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