/* ** Copyright (C) 2001-2025 Zabbix SIA ** ** This program is free software: you can redistribute it and/or modify it under the terms of ** the GNU Affero General Public License as published by the Free Software Foundation, version 3. ** ** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; ** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ** See the GNU Affero General Public License for more details. ** ** You should have received a copy of the GNU Affero General Public License along with this program. ** If not, see <https://www.gnu.org/licenses/>. **/ #include "zbxsysinfo.h" #include "../sysinfo.h" #include "../common/zbxsysinfo_common.h" #include "zbxjson.h" #include "zbxnum.h" static struct ifmibdata ifmd; static int get_ifmib_general(const char *if_name, char **error) { int mib[6], ifcount; size_t len; if (NULL == if_name || '\0' == *if_name) { *error = zbx_strdup(NULL, "Network interface name cannot be empty."); return FAIL; } mib[0] = CTL_NET; mib[1] = PF_LINK; mib[2] = NETLINK_GENERIC; mib[3] = IFMIB_SYSTEM; mib[4] = IFMIB_IFCOUNT; len = sizeof(ifcount); if (-1 == sysctl(mib, 5, &ifcount, &len, NULL, 0)) { *error = zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno)); return FAIL; } mib[3] = IFMIB_IFDATA; mib[5] = IFDATA_GENERAL; len = sizeof(ifmd); for (mib[4] = 1; mib[4] <= ifcount; mib[4]++) { if (-1 == sysctl(mib, 6, &ifmd, &len, NULL, 0)) { if (ENOENT == errno) continue; break; } if (0 == strcmp(ifmd.ifmd_name, if_name)) return SUCCEED; } *error = zbx_strdup(NULL, "Cannot find information for this network interface."); return FAIL; } int net_if_in(AGENT_REQUEST *request, AGENT_RESULT *result) { char *if_name, *mode, *error; if (2 < request->nparam) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters.")); return SYSINFO_RET_FAIL; } if_name = get_rparam(request, 0); mode = get_rparam(request, 1); if (FAIL == get_ifmib_general(if_name,&error)) { SET_MSG_RESULT(result, error); return SYSINFO_RET_FAIL; } if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes")) /* default parameter */ SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_ibytes); else if (0 == strcmp(mode, "packets")) SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_ipackets); else if (0 == strcmp(mode, "errors")) SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_ierrors); else if (0 == strcmp(mode, "dropped")) SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_iqdrops); else { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter.")); return SYSINFO_RET_FAIL; } return SYSINFO_RET_OK; } int net_if_out(AGENT_REQUEST *request, AGENT_RESULT *result) { char *if_name, *mode, *error; if (2 < request->nparam) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters.")); return SYSINFO_RET_FAIL; } if_name = get_rparam(request, 0); mode = get_rparam(request, 1); if (FAIL == get_ifmib_general(if_name, &error)) { SET_MSG_RESULT(result, error); return SYSINFO_RET_FAIL; } if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes")) /* default parameter */ SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_obytes); else if (0 == strcmp(mode, "packets")) SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_opackets); else if (0 == strcmp(mode, "errors")) SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_oerrors); else { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter.")); return SYSINFO_RET_FAIL; } return SYSINFO_RET_OK; } int net_if_total(AGENT_REQUEST *request, AGENT_RESULT *result) { char *if_name, *mode, *error; if (2 < request->nparam) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters.")); return SYSINFO_RET_FAIL; } if_name = get_rparam(request, 0); mode = get_rparam(request, 1); if (FAIL == get_ifmib_general(if_name, &error)) { SET_MSG_RESULT(result, error); return SYSINFO_RET_FAIL; } if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes")) /* default parameter */ SET_UI64_RESULT(result, (zbx_uint64_t)ifmd.ifmd_data.ifi_ibytes + ifmd.ifmd_data.ifi_obytes); else if (0 == strcmp(mode, "packets")) SET_UI64_RESULT(result, (zbx_uint64_t)ifmd.ifmd_data.ifi_ipackets + ifmd.ifmd_data.ifi_opackets); else if (0 == strcmp(mode, "errors")) SET_UI64_RESULT(result, (zbx_uint64_t)ifmd.ifmd_data.ifi_ierrors + ifmd.ifmd_data.ifi_oerrors); else { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter.")); return SYSINFO_RET_FAIL; } return SYSINFO_RET_OK; } int net_tcp_listen(AGENT_REQUEST *request, AGENT_RESULT *result) { char *port_str, command[64]; unsigned short port; int res; if (1 < request->nparam) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters.")); return SYSINFO_RET_FAIL; } port_str = get_rparam(request, 0); if (NULL == port_str || SUCCEED != zbx_is_ushort(port_str, &port)) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter.")); return SYSINFO_RET_FAIL; } zbx_snprintf(command, sizeof(command), "netstat -an | grep '^tcp.*\\.%hu[^.].*LISTEN' | wc -l", port); if (SYSINFO_RET_FAIL == (res = execute_int(command, result, request->timeout))) return res; if (1 < result->ui64) result->ui64 = 1; return res; } int net_udp_listen(AGENT_REQUEST *request, AGENT_RESULT *result) { char *port_str, command[64]; unsigned short port; int res; if (1 < request->nparam) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters.")); return SYSINFO_RET_FAIL; } port_str = get_rparam(request, 0); if (NULL == port_str || SUCCEED != zbx_is_ushort(port_str, &port)) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter.")); return SYSINFO_RET_FAIL; } zbx_snprintf(command, sizeof(command), "netstat -an | grep '^udp.*\\.%hu[^.].*\\*\\.\\*' | wc -l", port); if (SYSINFO_RET_FAIL == (res = execute_int(command, result, request->timeout))) return res; if (1 < result->ui64) result->ui64 = 1; return res; } int net_if_collisions(AGENT_REQUEST *request, AGENT_RESULT *result) { char *if_name, *error; if (1 < request->nparam) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters.")); return SYSINFO_RET_FAIL; } if_name = get_rparam(request, 0); if (FAIL == get_ifmib_general(if_name, &error)) { SET_MSG_RESULT(result, error); return SYSINFO_RET_FAIL; } SET_UI64_RESULT(result, ifmd.ifmd_data.ifi_collisions); return SYSINFO_RET_OK; } int net_if_discovery(AGENT_REQUEST *request, AGENT_RESULT *result) { struct zbx_json j; struct if_nameindex *interfaces; if (NULL == (interfaces = if_nameindex())) { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain system information: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN); for (int i = 0; 0 != interfaces[i].if_index; i++) { zbx_json_addobject(&j, NULL); zbx_json_addstring(&j, "{#IFNAME}", interfaces[i].if_name, ZBX_JSON_TYPE_STRING); zbx_json_close(&j); } zbx_json_close(&j); SET_STR_RESULT(result, strdup(j.buffer)); zbx_json_free(&j); if_freenameindex(interfaces); return SYSINFO_RET_OK; }