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