/****************************************************************************** * * * Function: register_host * * * * Purpose: register host if one does not exist * * * * Parameters: host ip address * * * * Return value: dhostid or 0 if we didn't add host * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ static void register_host(DB_DHOST *host,DB_DCHECK *check, zbx_uint64_t druleid, char *ip) { DB_RESULT result; DB_ROW row; char hostname[MAX_STRING_LEN], hostname_esc[MAX_STRING_LEN]; assert(host); assert(check); assert(ip); zabbix_log(LOG_LEVEL_DEBUG, "In register_host(ip:%s)", ip); host->dhostid=0; result = DBselect("select dhostid,druleid,ip,status,lastup,lastdown from dhosts where ip='%s'", ip); row=DBfetch(result); if(!row || DBis_null(row[0])==SUCCEED) { /* Add host only if service is up */ if(check->status == DOBJECT_STATUS_UP) { alarm(CONFIG_TIMEOUT); zbx_gethost_by_ip(ip, hostname, sizeof(hostname)); alarm(0); if (hostname[0] != '\0') DBescape_string(hostname, hostname_esc, sizeof(hostname_esc)); else hostname_esc[0] = '\0'; zabbix_log(LOG_LEVEL_DEBUG, "New host discovered at %s (%s)", ip, hostname); host->dhostid = DBget_maxid("dhosts","dhostid"); DBexecute("insert into dhosts (dhostid, druleid, dns, ip) values (" ZBX_FS_UI64 "," ZBX_FS_UI64 ", '%s','%s')", host->dhostid, druleid, hostname_esc, ip); host->druleid = druleid; strscpy(host->ip,ip); host->status = 0; host->lastup = 0; host->lastdown = 0; } } else { zabbix_log(LOG_LEVEL_DEBUG, "Host is already in database"); ZBX_STR2UINT64(host->dhostid,row[0]); ZBX_STR2UINT64(host->druleid,row[1]); strscpy(host->ip, row[2]); host->status = atoi(row[3]); host->lastup = atoi(row[4]); host->lastdown = atoi(row[5]); } DBfree_result(result); zabbix_log(LOG_LEVEL_DEBUG, "End register_host()"); }
/****************************************************************************** * * * Function: add host if not added already * * * * Purpose: add discovered host * * * * Parameters: dhostid - discovered host id * * * * Return value: hostid - new/existing hostid * * * * Author: Alexei Vladishev * * * ******************************************************************************/ static zbx_uint64_t add_discovered_host(DB_EVENT *event) { const char *__function_name = "add_discovered_host"; DB_RESULT result; DB_RESULT result2; DB_ROW row; DB_ROW row2; zbx_uint64_t hostid = 0, proxy_hostid, host_proxy_hostid; char host[MAX_STRING_LEN], *host_esc, *ip_esc, *host_unique, *host_unique_esc; int port; zbx_uint64_t groupid; zabbix_log(LOG_LEVEL_DEBUG, "In %s(eventid:" ZBX_FS_UI64 ")", __function_name, event->eventid); result = DBselect( "select discovery_groupid" " from config" " where 1=1" DB_NODE, DBnode_local("configid")); if (NULL != (row = DBfetch(result))) { ZBX_STR2UINT64(groupid, row[0]); } else { zabbix_log(LOG_LEVEL_WARNING, "cannot add discovered host: group for discovered hosts is not defined"); return 0; } DBfree_result(result); switch (event->object) { case EVENT_OBJECT_DHOST: result = DBselect( "select dr.proxy_hostid,ds.ip" " from drules dr,dchecks dc,dservices ds" " where dc.druleid=dr.druleid" " and ds.dcheckid=dc.dcheckid" " and ds.dhostid=" ZBX_FS_UI64 " order by ds.dserviceid", event->objectid); break; case EVENT_OBJECT_DSERVICE: result = DBselect( "select dr.proxy_hostid,ds.ip" " from drules dr,dchecks dc,dservices ds,dservices ds1" " where dc.druleid=dr.druleid" " and ds.dcheckid=dc.dcheckid" " and ds1.dhostid=ds.dhostid" " and ds1.dserviceid=" ZBX_FS_UI64 " order by ds.dserviceid", event->objectid); break; case EVENT_OBJECT_ZABBIX_ACTIVE: result = DBselect("select proxy_hostid,host from autoreg_host" " where autoreg_hostid=" ZBX_FS_UI64, event->objectid); break; default: return 0; } if (NULL != (row = DBfetch(result))) { ZBX_STR2UINT64(proxy_hostid, row[0]); if (EVENT_OBJECT_ZABBIX_ACTIVE == event->object) { char sql[512]; host_esc = DBdyn_escape_string_len(row[1], HOST_HOST_LEN); zbx_snprintf(sql, sizeof(sql), "select hostid,proxy_hostid" " from hosts" " where host='%s'" DB_NODE " order by hostid", host_esc, DBnode_local("hostid")); result2 = DBselectN(sql, 1); if (NULL == (row2 = DBfetch(result2))) { hostid = DBget_maxid("hosts"); DBexecute("insert into hosts (hostid,proxy_hostid,host,useip,dns)" " values (" ZBX_FS_UI64 "," ZBX_FS_UI64 ",'%s',0,'%s')", hostid, proxy_hostid, host_esc, host_esc); } else { ZBX_STR2UINT64(hostid, row2[0]); ZBX_STR2UINT64(host_proxy_hostid, row2[1]); if (host_proxy_hostid != proxy_hostid) { DBexecute("update hosts" " set proxy_hostid=" ZBX_FS_UI64 " where hostid=" ZBX_FS_UI64, proxy_hostid, hostid); } } DBfree_result(result2); zbx_free(host_esc); } else /* EVENT_OBJECT_DHOST, EVENT_OBJECT_DSERVICE */ { alarm(CONFIG_TIMEOUT); zbx_gethost_by_ip(row[1], host, sizeof(host)); alarm(0); host_esc = DBdyn_escape_string_len(host, HOST_HOST_LEN); ip_esc = DBdyn_escape_string_len(row[1], HOST_IP_LEN); port = get_discovered_agent_port(event); result2 = DBselect( "select hostid,dns,port,proxy_hostid" " from hosts" " where ip='%s'" DB_NODE, ip_esc, DBnode_local("hostid")); if (NULL == (row2 = DBfetch(result2))) { hostid = DBget_maxid("hosts"); /* for host uniqueness purposes */ if ('\0' != *host) { /* by host name */ make_hostname(host); /* replace not-allowed characters */ host_unique = DBget_unique_hostname_by_sample(host); } else { /* by ip */ make_hostname(row[1]); /* replace not-allowed characters */ host_unique = DBget_unique_hostname_by_sample(row[1]); } host_unique_esc = DBdyn_escape_string(host_unique); DBexecute("insert into hosts (hostid,proxy_hostid,host,useip,ip,dns,port)" " values (" ZBX_FS_UI64 "," ZBX_FS_UI64 ",'%s',1,'%s','%s',%d)", hostid, proxy_hostid, host_unique_esc, ip_esc, host_esc, port); zbx_free(host_unique); zbx_free(host_unique_esc); } else { ZBX_STR2UINT64(hostid, row2[0]); ZBX_STR2UINT64(host_proxy_hostid, row2[3]); if (0 != strcmp(host, row2[1]) || host_proxy_hostid != proxy_hostid) { DBexecute("update hosts" " set dns='%s',proxy_hostid=" ZBX_FS_UI64 " where hostid=" ZBX_FS_UI64, host_esc, proxy_hostid, hostid); } } DBfree_result(result2); zbx_free(host_esc); zbx_free(ip_esc); } } DBfree_result(result); if (0 != hostid) add_discovered_host_group(hostid, groupid); zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); return hostid; }
/****************************************************************************** * * * Function: process_rule * * * * Purpose: process single discovery rule * * * * Author: Eugene Grigorjev * * * ******************************************************************************/ static void process_rule(DB_DRULE *drule) { const char *__function_name = "process_rule"; DB_DHOST dhost; int host_status, now; unsigned short j[9]; unsigned int i, first, last, ip_dig; char ip[INTERFACE_IP_LEN_MAX], *start, *comma, *dash, *slash, dns[INTERFACE_DNS_LEN_MAX]; int invalid_range; #ifdef HAVE_IPV6 int ipv6; #endif zabbix_log(LOG_LEVEL_DEBUG, "In %s() rule:'%s' range:'%s'", __function_name, drule->name, drule->iprange); for (start = drule->iprange; '\0' != *start;) { invalid_range = 0; if (NULL != (comma = strchr(start, ','))) *comma = '\0'; zabbix_log(LOG_LEVEL_DEBUG, "%s() range:'%s'", __function_name, start); if (NULL != (dash = strchr(start, '-'))) *dash = '\0'; else if (NULL != (slash = strchr(start, '/'))) *slash = '\0'; if (SUCCEED == ip6_str2dig(start, j)) { #ifdef HAVE_IPV6 ipv6 = 1; if (NULL != dash) { if (1 != sscanf(dash + 1, "%hx", &j[8])) { invalid_range = 1; goto next; } first = j[7]; last = j[8]; } else if (NULL != slash) { unsigned short mask; if (1 != sscanf(slash + 1, "%hu", &j[8]) || 112 > j[8] || j[8] > 128) { invalid_range = 1; goto next; } mask = 0xffff << (128 - j[8]); first = j[7] & mask; last = 0xffff & (j[7] | ~mask); } else { first = j[7]; last = j[7]; } #else invalid_range = 2; goto next; #endif } else if (SUCCEED == ip4_str2dig(start, &ip_dig)) { #ifdef HAVE_IPV6 ipv6 = 0; #endif if (NULL != dash) { if (1 != sscanf(dash + 1, "%hu", &j[4]) || 255 < j[4]) { invalid_range = 1; goto next; } first = ip_dig; last = (ip_dig & 0xffffff00) + j[4]; } else if (NULL != slash) { unsigned int mask; if (1 != sscanf(slash + 1, "%hu", &j[4]) || 16 > j[4] || j[4] > 30) { invalid_range = 1; goto next; } mask = 0xffffffff << (32 - j[4]); first = (ip_dig & mask) + 1; last = (ip_dig | ~mask) - 1; } else { first = ip_dig; last = ip_dig; } } else { invalid_range = 1; goto next; } if (first > last) { invalid_range = 1; goto next; } for (i = first; i <= last; i++) { memset(&dhost, 0, sizeof(dhost)); host_status = -1; now = time(NULL); #ifdef HAVE_IPV6 switch (ipv6) { case 0: #endif zbx_snprintf(ip, sizeof(ip), "%u.%u.%u.%u", (i & 0xff000000) >> 24, (i & 0x00ff0000) >> 16, (i & 0x0000ff00) >> 8, i & 0x000000ff); #ifdef HAVE_IPV6 break; case 1: j[7] = i; ip6_dig2str(j, ip, sizeof(ip)); break; } #endif zabbix_log(LOG_LEVEL_DEBUG, "%s() ip:'%s'", __function_name, ip); alarm(CONFIG_TIMEOUT); zbx_gethost_by_ip(ip, dns, sizeof(dns)); alarm(0); if (drule->unique_dcheckid) process_checks(drule, &dhost, &host_status, ip, dns, 1); process_checks(drule, &dhost, &host_status, ip, dns, 0); DBbegin(); if (0 != (daemon_type & ZBX_DAEMON_TYPE_SERVER)) discovery_update_host(&dhost, ip, host_status, now); else if (0 != (daemon_type & ZBX_DAEMON_TYPE_PROXY)) proxy_update_host(drule, ip, dns, host_status, now); DBcommit(); } next: if (NULL != dash) *dash = '-'; else if (NULL != slash) *slash = '/'; switch (invalid_range) { case 1: zabbix_log(LOG_LEVEL_WARNING, "discovery rule \"%s\": wrong format of IP range \"%s\"", drule->name, start); break; case 2: zabbix_log(LOG_LEVEL_WARNING, "discovery rule \"%s\": encountered IP range \"%s\"," " but IPv6 support not compiled in", drule->name, start); break; } if (NULL != comma) { *comma = ','; start = comma + 1; } else break; } zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); }
/****************************************************************************** * * * Function: get_hostid_by_host * * * * Purpose: check for host name and return hostid * * * * Parameters: host - [IN] require size 'HOST_HOST_LEN_MAX' * * * * Return value: SUCCEED - host is found * * FAIL - an error occurred or host not found * * * * Author: Alexander Vladishev * * * * Comments: * * * ******************************************************************************/ static int get_hostid_by_host(const char *host, const char *ip, unsigned short port, zbx_uint64_t *hostid, char *error) { const char *__function_name = "get_hostid_by_host"; char *host_esc, dns[INTERFACE_DNS_LEN_MAX]; DB_RESULT result; DB_ROW row; int res = FAIL; zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'%s'", __function_name, host); if (FAIL == zbx_check_hostname(host)) { zbx_snprintf(error, MAX_STRING_LEN, "invalid host name [%s]", host); goto out; } host_esc = DBdyn_escape_string(host); result = DBselect( "select hostid,status" " from hosts" " where host='%s'" " and status in (%d,%d)" " and proxy_hostid is null" DB_NODE, host_esc, HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED, DBnode_local("hostid")); if (NULL != (row = DBfetch(result))) { if (HOST_STATUS_MONITORED == atoi(row[1])) { ZBX_STR2UINT64(*hostid, row[0]); res = SUCCEED; } else zbx_snprintf(error, MAX_STRING_LEN, "host [%s] not monitored", host); } else { zbx_snprintf(error, MAX_STRING_LEN, "host [%s] not found", host); /* remove ::ffff: prefix from IPv4-mapped IPv6 addresses */ if (0 == strncmp("::ffff:", ip, 7) && SUCCEED == is_ip4(ip + 7)) ip += 7; alarm(CONFIG_TIMEOUT); zbx_gethost_by_ip(ip, dns, sizeof(dns)); alarm(0); DBbegin(); if (0 != (daemon_type & ZBX_DAEMON_TYPE_SERVER)) { DBregister_host(0, host, ip, dns, port, (int)time(NULL)); } else if (0 != (daemon_type & ZBX_DAEMON_TYPE_PROXY)) { DBproxy_register_host(host, ip, dns, port); } DBcommit(); } DBfree_result(result); zbx_free(host_esc); out: zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(res)); return res; }
/****************************************************************************** * * * Function: get_hostid_by_host * * * * Purpose: check for host name and return hostid * * * * Parameters: host - [IN] require size 'HOST_HOST_LEN_MAX' * * * * Return value: SUCCEED - host is found * * FAIL - an error occurred or host not found * * * * Author: Alexander Vladishev * * * * Comments: NB! adds host to the database if it does not exist * * * ******************************************************************************/ static int get_hostid_by_host(const zbx_socket_t *sock, const char *host, const char *ip, unsigned short port, const char *host_metadata, zbx_uint64_t *hostid, char *error) { const char *__function_name = "get_hostid_by_host"; char *host_esc, dns[INTERFACE_DNS_LEN_MAX], *ch_error; DB_RESULT result; DB_ROW row; int ret = FAIL; zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'%s'", __function_name, host); if (FAIL == zbx_check_hostname(host, &ch_error)) { zbx_snprintf(error, MAX_STRING_LEN, "invalid host name [%s]: %s", host, ch_error); zbx_free(ch_error); goto out; } host_esc = DBdyn_escape_string(host); result = #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) DBselect( "select hostid,status,tls_accept,tls_issuer,tls_subject,tls_psk_identity" " from hosts" " where host='%s'" " and status in (%d,%d)" " and flags<>%d" " and proxy_hostid is null", host_esc, HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED, ZBX_FLAG_DISCOVERY_PROTOTYPE); #else DBselect( "select hostid,status,tls_accept" " from hosts" " where host='%s'" " and status in (%d,%d)" " and flags<>%d" " and proxy_hostid is null", host_esc, HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED, ZBX_FLAG_DISCOVERY_PROTOTYPE); #endif if (NULL != (row = DBfetch(result))) { if (HOST_STATUS_MONITORED == atoi(row[1])) { unsigned int tls_accept; tls_accept = (unsigned int)atoi(row[2]); if (0 == (tls_accept & sock->connection_type)) { zbx_snprintf(error, MAX_STRING_LEN, "connection of type \"%s\" is not allowed for host" " \"%s\"", zbx_tls_connection_type_name(sock->connection_type), host); goto done; } #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) if (ZBX_TCP_SEC_TLS_CERT == sock->connection_type) { zbx_tls_conn_attr_t attr; if (SUCCEED != zbx_tls_get_attr_cert(sock, &attr)) { THIS_SHOULD_NEVER_HAPPEN; zbx_snprintf(error, MAX_STRING_LEN, "cannot get connection attributes for host" " \"%s\"", host); goto done; } /* simplified match, not compliant with RFC 4517, 4518 */ if ('\0' != *row[3] && 0 != strcmp(row[3], attr.issuer)) { zbx_snprintf(error, MAX_STRING_LEN, "certificate issuer does not match for" " host \"%s\"", host); goto done; } /* simplified match, not compliant with RFC 4517, 4518 */ if ('\0' != *row[4] && 0 != strcmp(row[4], attr.subject)) { zbx_snprintf(error, MAX_STRING_LEN, "certificate subject does not match for" " host \"%s\"", host); goto done; } } else if (ZBX_TCP_SEC_TLS_PSK == sock->connection_type) { zbx_tls_conn_attr_t attr; if (SUCCEED != zbx_tls_get_attr_psk(sock, &attr)) { THIS_SHOULD_NEVER_HAPPEN; zbx_snprintf(error, MAX_STRING_LEN, "cannot get connection attributes for host" " \"%s\"", host); goto done; } if (strlen(row[5]) != attr.psk_identity_len || 0 != memcmp(row[5], attr.psk_identity, attr.psk_identity_len)) { zbx_snprintf(error, MAX_STRING_LEN, "false PSK identity for host \"%s\"", host); goto done; } } #endif ZBX_STR2UINT64(*hostid, row[0]); ret = SUCCEED; } else zbx_snprintf(error, MAX_STRING_LEN, "host [%s] not monitored", host); } else { zbx_snprintf(error, MAX_STRING_LEN, "host [%s] not found", host); /* remove ::ffff: prefix from IPv4-mapped IPv6 addresses */ if (0 == strncmp("::ffff:", ip, 7) && SUCCEED == is_ip4(ip + 7)) ip += 7; zbx_alarm_on(CONFIG_TIMEOUT); zbx_gethost_by_ip(ip, dns, sizeof(dns)); zbx_alarm_off(); DBbegin(); if (0 != (program_type & ZBX_PROGRAM_TYPE_SERVER)) DBregister_host(0, host, ip, dns, port, host_metadata, (int)time(NULL)); else if (0 != (program_type & ZBX_PROGRAM_TYPE_PROXY)) DBproxy_register_host(host, ip, dns, port, host_metadata); DBcommit(); } done: DBfree_result(result); zbx_free(host_esc); out: zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret)); return ret; }