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