Например в шаблоне Template OS Windows rus
сами СПЕЦИФИЧНЫЕ КЛЮЧИ ЭЛЕМЕНТОВ и КЛЮЧИ ЭЛЕМЕНТОВ ДАННЫХ
например как происходит работа ключей
net.if.discovery
net.if.list
proc.num
и т.д.
Оф документация Сборка Zabbix агента на Win
Компиляцию модно сделать на
1.C компилятором (например, VS 2017 RC), С++
2.NASM (https://www.nasm.us/),
3.Perl (например, Strawberry Perl с http://strawberryperl.com/),
4.Perl модуль Text::Template (cpan Text::Template).
Загрузка исходника git clone https://git.zabbix.com/scm/zbx/zabbix.git далее распаковка из архива
сам проект \zabbix-5.0.0\build\win32\project
дальше у нас есть папки zabbix-agent-win32 и win32
Далее есть у нас файл win32.c
В нем как раз таки и прописаны стандартные ключи
#include "common.h"
#include "sysinfo.h"
#include "service.h"
ZBX_METRIC parameters_specific[] =
/* KEY FLAG FUNCTION TEST PARAMETERS */
{
{"vfs.fs.size", CF_HAVEPARAMS, VFS_FS_SIZE, "c:,free"},
{"vfs.fs.discovery", 0, VFS_FS_DISCOVERY, NULL},
{"vfs.fs.get", 0, VFS_FS_GET, NULL},
{"net.tcp.listen", CF_HAVEPARAMS, NET_TCP_LISTEN, "80"},
{"net.if.in", CF_HAVEPARAMS, NET_IF_IN, "MS TCP Loopback interface,bytes"},
{"net.if.out", CF_HAVEPARAMS, NET_IF_OUT, "MS TCP Loopback interface,bytes"},
{"net.if.total", CF_HAVEPARAMS, NET_IF_TOTAL, "MS TCP Loopback interface,bytes"},
{"net.if.discovery", 0, NET_IF_DISCOVERY, NULL},
{"net.if.list", 0, NET_IF_LIST, NULL},
{"vm.memory.size", CF_HAVEPARAMS, VM_MEMORY_SIZE, "free"},
{"proc.num", CF_HAVEPARAMS, PROC_NUM, "svchost.exe"},
{"system.cpu.util", CF_HAVEPARAMS, SYSTEM_CPU_UTIL, "all,system,avg1"},
{"system.cpu.load", CF_HAVEPARAMS, SYSTEM_CPU_LOAD, "all,avg1"},
{"system.cpu.num", CF_HAVEPARAMS, SYSTEM_CPU_NUM, "online"},
{"system.cpu.discovery",0, SYSTEM_CPU_DISCOVERY, NULL},
{"system.sw.arch", 0, SYSTEM_SW_ARCH, NULL},
{"system.swap.size", CF_HAVEPARAMS, SYSTEM_SWAP_SIZE, "all,free"},
{"vm.vmemory.size", CF_HAVEPARAMS, VM_VMEMORY_SIZE, "total"},
{"system.uptime", 0, SYSTEM_UPTIME, NULL},
{"system.uname", 0, SYSTEM_UNAME, NULL},
{"service.discovery", 0, SERVICE_DISCOVERY, NULL},
{"service.info", CF_HAVEPARAMS, SERVICE_INFO, ZABBIX_SERVICE_NAME},
{"service_state", CF_HAVEPARAMS, SERVICE_STATE, ZABBIX_SERVICE_NAME},
{"services", CF_HAVEPARAMS, SERVICES, NULL},
{"perf_counter", CF_HAVEPARAMS, PERF_COUNTER, "\\System\\Processes"},
{"perf_counter_en", CF_HAVEPARAMS, PERF_COUNTER_EN, "\\System\\Processes"},
{"perf_instance.discovery", CF_HAVEPARAMS, PERF_INSTANCE_DISCOVERY, "Processor"},
{"perf_instance_en.discovery", CF_HAVEPARAMS, PERF_INSTANCE_DISCOVERY_EN, "Processor"},
{"proc_info", CF_HAVEPARAMS, PROC_INFO, "svchost.exe"},
{"__UserPerfCounter", CF_HAVEPARAMS, USER_PERF_COUNTER, ""},
{"wmi.get", CF_HAVEPARAMS, WMI_GET, "root\\cimv2,select Caption from Win32_OperatingSystem"},
{"wmi.getall", CF_HAVEPARAMS, WMI_GETALL, "root\\cimv2,select * from Win32_OperatingSystem"},
{NULL}
};
В самом верху указаны подключаемые файлы библиотеки include
Например нам интересен Список обнаружения интерфейсов и его статистика это блок ключей
{"net.if.in", CF_HAVEPARAMS, NET_IF_IN, "MS TCP Loopback interface,bytes"},
{"net.if.out", CF_HAVEPARAMS, NET_IF_OUT, "MS TCP Loopback interface,bytes"},
{"net.if.total", CF_HAVEPARAMS, NET_IF_TOTAL, "MS TCP Loopback interface,bytes"},
{"net.if.discovery", 0, NET_IF_DISCOVERY, NULL},
{"net.if.list", 0, NET_IF_LIST, NULL},
Есть соответствующий файл net.c
он так же ссылается на другие
#include "common.h"
#include "sysinfo.h"
#include "log.h"
#include "zbxjson.h"
Содержимое net.c
Показать
/*
** Zabbix
** Авторское право (C) 2001-2021 Zabbix SIA
**
** Эта программа является бесплатным программным обеспечением; вы можете распространять ее и/или изменять
** это в соответствии с условиями Общей публичной лицензии GNU, опубликованной
** Фонд свободного программного обеспечения; либо версия 2 Лицензии, либо
** (по вашему выбору) любая более поздняя версия.
**
** Эта программа распространяется в надежде, что она будет полезна,
** но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ; даже без подразумеваемой гарантии
** ТОВАРНОЙ ПРИГОДНОСТИ или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ. См.
** Общая публичная лицензия GNU для получения более подробной информации.
**
** Вы должны были получить копию Общей публичной лицензии GNU
** вместе с этой программой; если нет, напишите в Свободное программное обеспечение
** Foundation, Inc., 51 Франклин-стрит, Пятый этаж, Бостон, Массачусетс 02110-1301, США.
**/
#include "common.h"
#include "sysinfo.h"
#include "log.h"
#include "zbxjson.h"
/* __соглашение о вызове stdcall используется для GetIfEntry2(). Для того, чтобы объявить */
/* указатель на GetIfEntry2() мы должны развернуть макрос NETIOPAPI_API вручную, так как */
/* часть его должна быть вместе с именем указателя в круглых скобках. */
typedef NETIO_STATUS (NETIOAPI_API_ *pGetIfEntry2_t)(PMIB_IF_ROW2 Row);
/* GetIfEntry2() доступен с Windows Vista и Windows Server 2008. В */
/* более ранние выпуски Windows этот указатель остается равным НУЛЮ, а GetIfEntry() является */
/* используется непосредственно вместо этого. */
static pGetIfEntry2_t pGetIfEntry2 = NULL;
/* GetIfEntry2() и GetIfEntry() работают с различными структурами интерфейса MIB. */
/* /* Используйте переменные zbx_if row_t и функции zbx_if row_*() ниже вместо */
/* API интерфейса MIB для конкретной версии. */
typedef struct
{
MIB_IFROW *ifRow; /* 32-разрядные счетчики */
MIB_IF_ROW2 *ifRow2; /* 64-разрядные счетчики, поддерживаемые начиная с Windows Vista, Server 2008 */
}
zbx_ifrow_t;
/******************************************************************************
* *
* * Функция: zbx_if row_init *
* *
* * Цель: инициализировать переменную zbx_if row_t *
* *
* Параметры: *
* * pIfRow - [ВХОД/ВЫХОД] указатель на переменную zbx_if row_t со всеми *
* члены имеют значение NULL *
* *
* * Комментарии: выделяет память, вызывает zbx_if row_clean() с тем же указателем *
* чтобы освободить его *
* *
******************************************************************************/
static void zbx_ifrow_init(zbx_ifrow_t *pIfRow)
{
HMODULE module;
static char check_done = FALSE;
/* проверьте (один раз) , доступен ли GetIfEntry2() в этой системе */
if (FALSE == check_done)
{
if (NULL != (module = GetModuleHandle(L"iphlpapi.dll")))
{
if (NULL == (pGetIfEntry2 = (pGetIfEntry2_t)GetProcAddress(module, "GetIfEntry2")))
{
zabbix_log(LOG_LEVEL_DEBUG, "GetProcAddress failed with error: %s",
strerror_from_system(GetLastError()));
}
}
else
{
zabbix_log(LOG_LEVEL_DEBUG, "GetModuleHandle failed with error: %s",
strerror_from_system(GetLastError()));
}
check_done = TRUE;
}
/* выделите соответствующую структуру интерфейса MIB */
if (NULL != pGetIfEntry2)
pIfRow->ifRow2 = zbx_malloc(pIfRow->ifRow2, sizeof(MIB_IF_ROW2));
else
pIfRow->ifRow = zbx_malloc(pIfRow->ifRow, sizeof(MIB_IFROW));
}
/******************************************************************************
* *
* Функция: zbx_if очистка строк *
* *
* Цель: очистить переменную zbx_if row_t *
* *
* Параметры: *
* pIfRow - [ВХОД/ВЫХОД] указатель на инициализированную переменную zbx_if row_t *
* *
* Комментарии: устанавливает для членов значение NULL, чтобы переменную можно было использовать повторно *
* *
******************************************************************************/
static void zbx_ifrow_clean(zbx_ifrow_t *pIfRow)
{
zbx_free(pIfRow->ifRow);
zbx_free(pIfRow->ifRow2);
}
/******************************************************************************
* *
* Функция: zbx_if row_call_get_if_entry *
* *
* Цель: вызовите GetIfEntry() или GetIfEntry2() в зависимости от Windows *
* отпустите, чтобы заполнить переданную структуру интерфейса MIB. *
* *
* Параметры: *
* pIfRow - [ВХОД/ВЫХОД] указатель на инициализированную переменную zbx_if row_t *
* *
* Комментарии: индекс интерфейса должен быть задан с *
* * zbx_if row_set_index(), в противном случае эта функция вернет ошибку *
* *
******************************************************************************/
static DWORD zbx_ifrow_call_get_if_entry(zbx_ifrow_t *pIfRow)
{
/* on success both functions return 0 (NO_ERROR and STATUS_SUCCESS) */
if (NULL != pIfRow->ifRow2)
return pGetIfEntry2(pIfRow->ifRow2);
else
return GetIfEntry(pIfRow->ifRow);
}
/******************************************************************************
* *
* Общие функции доступа для интерфейса MIB для конкретного выпуска *
* члены структуры. Тип возвращаемого значения, определяемый контекстом в *
* какие функции вызываются. *
* *
******************************************************************************/
static DWORD zbx_ifrow_get_index(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->InterfaceIndex;
else
return pIfRow->ifRow->dwIndex;
}
static void zbx_ifrow_set_index(zbx_ifrow_t *pIfRow, DWORD index)
{
if (NULL != pIfRow->ifRow2)
{
pIfRow->ifRow2->InterfaceLuid.Value = 0;
pIfRow->ifRow2->InterfaceIndex = index;
}
else
pIfRow->ifRow->dwIndex = index;
}
static DWORD zbx_ifrow_get_type(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->Type;
else
return pIfRow->ifRow->dwType;
}
static DWORD zbx_ifrow_get_admin_status(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->AdminStatus;
else
return pIfRow->ifRow->dwAdminStatus;
}
static ULONG64 zbx_ifrow_get_in_octets(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->InOctets;
else
return pIfRow->ifRow->dwInOctets;
}
static ULONG64 zbx_ifrow_get_in_ucast_pkts(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->InUcastPkts;
else
return pIfRow->ifRow->dwInUcastPkts;
}
static ULONG64 zbx_ifrow_get_in_nucast_pkts(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->InNUcastPkts;
else
return pIfRow->ifRow->dwInNUcastPkts;
}
static ULONG64 zbx_ifrow_get_in_errors(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->InErrors;
else
return pIfRow->ifRow->dwInErrors;
}
static ULONG64 zbx_ifrow_get_in_discards(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->InDiscards;
else
return pIfRow->ifRow->dwInDiscards;
}
static ULONG64 zbx_ifrow_get_in_unknown_protos(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->InUnknownProtos;
else
return pIfRow->ifRow->dwInUnknownProtos;
}
static ULONG64 zbx_ifrow_get_out_octets(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->OutOctets;
else
return pIfRow->ifRow->dwOutOctets;
}
static ULONG64 zbx_ifrow_get_out_ucast_pkts(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->OutUcastPkts;
else
return pIfRow->ifRow->dwOutUcastPkts;
}
static ULONG64 zbx_ifrow_get_out_nucast_pkts(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->OutNUcastPkts;
else
return pIfRow->ifRow->dwOutNUcastPkts;
}
static ULONG64 zbx_ifrow_get_out_errors(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->OutErrors;
else
return pIfRow->ifRow->dwOutErrors;
}
static ULONG64 zbx_ifrow_get_out_discards(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->OutDiscards;
else
return pIfRow->ifRow->dwOutDiscards;
}
/******************************************************************************
* *
* Функция: zbx_if row_get_utf 8_description *
* *
* Назначение: возвращает описание интерфейса, закодированное в формате UTF-8 *
* *
* Параметры: *
* pIfRow - [IN] указатель на инициализированную переменную zbx_if row_t *
* *
* Комментарии: возвращает указатель на динамически выделяемую память, вызывающий должен *
* освободите его *
* *
******************************************************************************/
static char *zbx_ifrow_get_utf8_description(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return zbx_unicode_to_utf8(pIfRow->ifRow2->Description);
else
{
static wchar_t *(*mb_to_unicode)(const char *) = NULL;
wchar_t *wdescr;
char *utf8_descr;
if (NULL == mb_to_unicode)
{
const OSVERSIONINFOEX *vi;
/* начиная с Windows Vista (Windows Server 2008) описание интерфейса */
/* кодируется в кодовой странице OEM, в то время как в более ранних версиях использовалась кодовая страница ANSI */
if (NULL != (vi = zbx_win_getversion()) && 6 <= vi->dwMajorVersion)
mb_to_unicode = zbx_oemcp_to_unicode;
else
mb_to_unicode = zbx_acp_to_unicode;
}
wdescr = mb_to_unicode(pIfRow->ifRow->bDescr);
utf8_descr = zbx_unicode_to_utf8(wdescr);
zbx_free(wdescr);
return utf8_descr;
}
}
/*
* возвращает статистику интерфейса по IP-адресу или имени интерфейса
*/
static int get_if_stats(const char *if_name, zbx_ifrow_t *ifrow)
{
DWORD dwSize, dwRetVal, i, j;
int ret = FAIL;
char ip[16];
/* переменные, используемые для GetIfTable и GetIfEntry */
MIB_IFTABLE *pIfTable = NULL;
/* переменные, используемые для getipaddr-таблицы */
MIB_IPADDRTABLE *pIPAddrTable = NULL;
IN_ADDR in_addr;
/* Выделите память для наших указателей. */
dwSize = sizeof(MIB_IPADDRTABLE);
pIPAddrTable = (MIB_IPADDRTABLE *)zbx_malloc(pIPAddrTable, sizeof(MIB_IPADDRTABLE));
/*Сделайте первоначальный вызов GetIpAddrTable, чтобы получить необходимый размер в переменной dwSize */
if (ERROR_INSUFFICIENT_BUFFER == GetIpAddrTable(pIPAddrTable, &dwSize, 0))
pIPAddrTable = (MIB_IPADDRTABLE *)zbx_realloc(pIPAddrTable, dwSize);
/* Сделайте второй звонок в GetIpAddrTable, чтобы получить фактические данные, которые нам нужны */
if (NO_ERROR != (dwRetVal = GetIpAddrTable(pIPAddrTable, &dwSize, 0)))
{
zabbix_log(LOG_LEVEL_DEBUG, "GetIpAddrTable failed with error: %s", strerror_from_system(dwRetVal));
goto clean;
}
/* Выделите память для наших указателей. */
dwSize = sizeof(MIB_IFTABLE);
pIfTable = (MIB_IFTABLE *)zbx_malloc(pIfTable, dwSize);
/* Перед вызовом GetIfEntry мы вызываем GetIfTable, чтобы убедиться, что есть записи для получения и извлечения индекса интерфейса.
Сделайте первоначальный вызов GetIfTable, чтобы получить необходимый размер в dwSize */
if (ERROR_INSUFFICIENT_BUFFER == GetIfTable(pIfTable, &dwSize, 0))
pIfTable = (MIB_IFTABLE *)zbx_realloc(pIfTable, dwSize);
/* Сделайте второй звонок в GetIfTable, чтобы получить фактические данные, которые нам нужны. */
if (NO_ERROR != (dwRetVal = GetIfTable(pIfTable, &dwSize, 0)))
{
zabbix_log(LOG_LEVEL_DEBUG, "GetIfTable failed with error: %s", strerror_from_system(dwRetVal));
goto clean;
}
for (i = 0; i < pIfTable->dwNumEntries; i++)
{
char *utf8_descr;
zbx_ifrow_set_index(ifrow, pIfTable->table.dwIndex);
if (NO_ERROR != (dwRetVal = zbx_ifrow_call_get_if_entry(ifrow)))
{
zabbix_log(LOG_LEVEL_DEBUG, "zbx_ifrow_call_get_if_entry failed with error: %s",
strerror_from_system(dwRetVal));
continue;
}
utf8_descr = zbx_ifrow_get_utf8_description(ifrow);
if (0 == strcmp(if_name, utf8_descr))
ret = SUCCEED;
zbx_free(utf8_descr);
if (SUCCEED == ret)
break;
for (j = 0; j < pIPAddrTable->dwNumEntries; j++)
{
if (pIPAddrTable->table[j].dwIndex == zbx_ifrow_get_index(ifrow))
{
in_addr.S_un.S_addr = pIPAddrTable->table[j].dwAddr;
zbx_snprintf(ip, sizeof(ip), "%s", inet_ntoa(in_addr));
if (0 == strcmp(if_name, ip))
{
ret = SUCCEED;
break;
}
}
}
if (SUCCEED == ret)
break;
}
clean:
zbx_free(pIfTable);
zbx_free(pIPAddrTable);
return ret;
}
/* net.if.in Статистика по входящему трафику сетевого интерфейса. */
int NET_IF_IN(AGENT_REQUEST *request, AGENT_RESULT *result)
{
char *if_name, *mode;
zbx_ifrow_t ifrow = {NULL, NULL};
int ret = SYSINFO_RET_FAIL;
zbx_ifrow_init(&ifrow);
if (2 < request->nparam)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Слишком много параметров."));
goto clean;
}
if_name = get_rparam(request, 0);
mode = get_rparam(request, 1);
if (NULL == if_name || '\0' == *if_name)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Неверный первый параметр."));
goto clean;
}
if (FAIL == get_if_stats(if_name, &ifrow))
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Не удается получить информацию о сетевом интерфейсе."));
goto clean;
}
if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes")) /* параметр по умолчанию */
SET_UI64_RESULT(result, zbx_ifrow_get_in_octets(&ifrow));
else if (0 == strcmp(mode, "packets"))
SET_UI64_RESULT(result, zbx_ifrow_get_in_ucast_pkts(&ifrow) + zbx_ifrow_get_in_nucast_pkts(&ifrow));
else if (0 == strcmp(mode, "errors"))
SET_UI64_RESULT(result, zbx_ifrow_get_in_errors(&ifrow));
else if (0 == strcmp(mode, "dropped"))
SET_UI64_RESULT(result, zbx_ifrow_get_in_discards(&ifrow) + zbx_ifrow_get_in_unknown_protos(&ifrow));
else
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Недопустимый второй параметр."));
goto clean;
}
ret = SYSINFO_RET_OK;
clean:
zbx_ifrow_clean(&ifrow);
return ret;
}
/* net.if.out Статистика по исходящему трафику сетевого интерфейса. */
int NET_IF_OUT(AGENT_REQUEST *request, AGENT_RESULT *result)
{
char *if_name, *mode;
zbx_ifrow_t ifrow = {NULL, NULL};
int ret = SYSINFO_RET_FAIL;
zbx_ifrow_init(&ifrow);
if (2 < request->nparam)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Слишком много параметров."));
goto clean;
}
if_name = get_rparam(request, 0);
mode = get_rparam(request, 1);
if (NULL == if_name || '\0' == *if_name)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Неверный первый параметр."));
goto clean;
}
if (FAIL == get_if_stats(if_name, &ifrow))
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Не удается получить информацию о сетевом интерфейсе."));
goto clean;
}
if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes")) /* параметр по умолчанию */
SET_UI64_RESULT(result, zbx_ifrow_get_out_octets(&ifrow));
else if (0 == strcmp(mode, "packets"))
SET_UI64_RESULT(result, zbx_ifrow_get_out_ucast_pkts(&ifrow) + zbx_ifrow_get_out_nucast_pkts(&ifrow));
else if (0 == strcmp(mode, "errors"))
SET_UI64_RESULT(result, zbx_ifrow_get_out_errors(&ifrow));
else if (0 == strcmp(mode, "dropped"))
SET_UI64_RESULT(result, zbx_ifrow_get_out_discards(&ifrow));
else
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Недопустимый второй параметр."));
goto clean;
}
ret = SYSINFO_RET_OK;
clean:
zbx_ifrow_clean(&ifrow);
return ret;
}
/* net.if.total Суммарная статистика входящего и исходящего трафика на сетевом интерфейсе. */
int NET_IF_TOTAL(AGENT_REQUEST *request, AGENT_RESULT *result)
{
char *if_name, *mode;
zbx_ifrow_t ifrow = {NULL, NULL};
int ret = SYSINFO_RET_FAIL;
zbx_ifrow_init(&ifrow);
if (2 < request->nparam)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Слишком много параметров."));
goto clean;
}
if_name = get_rparam(request, 0);
mode = get_rparam(request, 1);
if (NULL == if_name || '\0' == *if_name)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Неверный первый параметр."));
goto clean;
}
if (FAIL == get_if_stats(if_name, &ifrow))
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Не удается получить информацию о сетевом интерфейсе."));
goto clean;
}
if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes")) /* параметр по умолчанию */
SET_UI64_RESULT(result, zbx_ifrow_get_in_octets(&ifrow) + zbx_ifrow_get_out_octets(&ifrow));
else if (0 == strcmp(mode, "packets"))
SET_UI64_RESULT(result, zbx_ifrow_get_in_ucast_pkts(&ifrow) + zbx_ifrow_get_in_nucast_pkts(&ifrow) +
zbx_ifrow_get_out_ucast_pkts(&ifrow) + zbx_ifrow_get_out_nucast_pkts(&ifrow));
else if (0 == strcmp(mode, "errors"))
SET_UI64_RESULT(result, zbx_ifrow_get_in_errors(&ifrow) + zbx_ifrow_get_out_errors(&ifrow));
else if (0 == strcmp(mode, "dropped"))
SET_UI64_RESULT(result, zbx_ifrow_get_in_discards(&ifrow) + zbx_ifrow_get_in_unknown_protos(&ifrow) +
zbx_ifrow_get_out_discards(&ifrow));
else
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Недопустимый второй параметр."));
goto clean;
}
ret = SYSINFO_RET_OK;
clean:
zbx_ifrow_clean(&ifrow);
return ret;
}
/* net.if.discovery Список сетевых интерфейсов. Используется низкоуровневым обнаружением */
int NET_IF_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result)
{
DWORD dwSize, dwRetVal, i;
int ret = SYSINFO_RET_FAIL;
/* переменные, используемые для GetIfTable и GetIfEntry */
MIB_IFTABLE *pIfTable = NULL;
zbx_ifrow_t ifrow = {NULL, NULL};
struct zbx_json j;
char *utf8_descr;
/* Выделите память для наших указателей. */
dwSize = sizeof(MIB_IFTABLE);
pIfTable = (MIB_IFTABLE *)zbx_malloc(pIfTable, dwSize);
/*Перед вызовом GetIfEntry мы вызываем GetIfTable, чтобы сделать убедитесь, что есть записи для получения и извлечения индекса интерфейса. Сделайте первоначальный вызов GetIfTable, чтобы получить необходимый размер в dwSize */
if (ERROR_INSUFFICIENT_BUFFER == GetIfTable(pIfTable, &dwSize, 0))
pIfTable = (MIB_IFTABLE *)zbx_realloc(pIfTable, dwSize);
/* Сделайте второй звонок в GetIfTable, чтобы получить фактические данные, которые нам нужны. */
if (NO_ERROR != (dwRetVal = GetIfTable(pIfTable, &dwSize, 0)))
{
zabbix_log(LOG_LEVEL_DEBUG, "GetIfTable не удалось с ошибкой: %s",ошибка_из_системе(dwRetVal));
SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Не удается получить системную информацию: %s",
strerror_from_system(dwRetVal)));
goto clean;
}
zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
zbx_ifrow_init(&ifrow);
for (i = 0; i < pIfTable->dwNumEntries; i++)
{
zbx_ifrow_set_index(&ifrow, pIfTable->table.dwIndex);
if (NO_ERROR != (dwRetVal = zbx_ifrow_call_get_if_entry(&ifrow)))
{
zabbix_log(LOG_LEVEL_DEBUG, "zbx_if row_call_get_if_entry произошел сбой с ошибкой: %s",
ошибка_из_системы(dwRetVal));
continue;
}
zbx_json_addobject(&j, NULL);
utf8_descr = zbx_ifrow_get_utf8_description(&ifrow);
zbx_json_addstring(&j, "{#IFNAME}", utf8_descr, ZBX_JSON_TYPE_STRING);
zbx_free(utf8_descr);
zbx_json_close(&j);
}
zbx_ifrow_clean(&ifrow);
zbx_json_close(&j);
SET_STR_RESULT(result, strdup(j.buffer));
zbx_json_free(&j);
ret = SYSINFO_RET_OK;
clean:
zbx_free(pIfTable);
return ret;
}
/* Тип интерфейса: Другой, Интернет, топологией кольца, PPP, Обратная связь ПО, ATM, WI-FI, Инкапсуляция туннельного типа, последовательная высокоскоростная шина, неизвестный */
/*Это относится быстрее всего к Обнаружение интерфейсов хостов в Zabbix, Тип интерфейса {#IF.TYPE} (“AGENT”, “SNMP”, “JMX”, или “IPMI”), Запрос zabbix[host,discovery,interfaces]*/
/*https://www.zabbix.com/documentation/cu ... interfaces*/
static char *get_if_type_string(DWORD type)
{
switch (type)
{
case IF_TYPE_OTHER: return "Other";
case IF_TYPE_ETHERNET_CSMACD: return "Ethernet";
case IF_TYPE_ISO88025_TOKENRING: return "Token Ring";
case IF_TYPE_PPP: return "PPP";
case IF_TYPE_SOFTWARE_LOOPBACK: return "Software Loopback";
case IF_TYPE_ATM: return "ATM";
case IF_TYPE_IEEE80211: return "IEEE 802.11 Wireless";
case IF_TYPE_TUNNEL: return "Tunnel type encapsulation";
case IF_TYPE_IEEE1394: return "IEEE 1394 Firewire";
default: return "unknown";
}
}
/* Статус: Подключен, Отключен, Неизвестен */
/* Быстрее всего для snmp ifAdminStatus 1.3.6.1.2.1.2.2.1.7 - Текущее административное состояние интерфейса.*/
/*https://www.zabbix.com/documentation/cu ... ecial_mibs*/
static char *get_if_adminstatus_string(DWORD status)
{
switch (status)
{
case 0: return "disabled";
case 1: return "enabled";
default: return "unknown";
}
}
/* net.if.list Список сетевых интерфейсов (включая тип, состояние, IPv4 адрес, описание интерфейса). */
int NET_IF_LIST(AGENT_REQUEST *request, AGENT_RESULT *result)
{
DWORD dwSize, dwRetVal, i, j;
char *buf = NULL;
size_t buf_alloc = 512, buf_offset = 0;
int ret = SYSINFO_RET_FAIL;
/* переменные, используемые для GetIfTable и GetIfEntry */
MIB_IFTABLE *pIfTable = NULL;
/* переменные, используемые для getipaddr-таблицы */
MIB_IPADDRTABLE *pIPAddrTable = NULL;
IN_ADDR in_addr;
/* Выделите память для наших указателей. */
dwSize = sizeof(MIB_IPADDRTABLE);
pIPAddrTable = (MIB_IPADDRTABLE *)zbx_malloc(pIPAddrTable, sizeof(MIB_IPADDRTABLE));
/* Сделайте первоначальный вызов GetIpAddrTable, чтобы получить необходимый размер в переменной dwSize */
if (ERROR_INSUFFICIENT_BUFFER == GetIpAddrTable(pIPAddrTable, &dwSize, 0))
pIPAddrTable = (MIB_IPADDRTABLE *)zbx_realloc(pIPAddrTable, dwSize);
/* Сделайте второй звонок в GetIpAddrTable, чтобы получить фактические данные, которые нам нужны */
if (NO_ERROR != (dwRetVal = GetIpAddrTable(pIPAddrTable, &dwSize, 0)))
{
zabbix_log(LOG_LEVEL_DEBUG, "GetIpAddrTable не удалось с ошибкой: %s", ошибка_из_системы(dwRetVal));
SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Не удается получить информацию об IP-адресе: %s",
ошибка_из_системы(dwRetVal)));
goto clean;
}
/* Выделите память для наших указателей. */
dwSize = sizeof(MIB_IFTABLE);
pIfTable = (MIB_IFTABLE *)zbx_malloc(pIfTable, dwSize);
/* Перед вызовом GetIfEntry мы вызываем GetIfTable, чтобы сделать
убедитесь, что есть записи для получения и извлечения индекса интерфейса.
Сделайте первоначальный вызов GetIfTable, чтобы получить необходимый размер в dwSize */
if (ERROR_INSUFFICIENT_BUFFER == GetIfTable(pIfTable, &dwSize, 0))
pIfTable = (MIB_IFTABLE *)zbx_realloc(pIfTable, dwSize);
/* Сделайте второй звонок в GetIfTable, чтобы получить фактические данные, которые нам нужны. */
if (NO_ERROR != (dwRetVal = GetIfTable(pIfTable, &dwSize, 0)))
{
zabbix_log(LOG_LEVEL_DEBUG, "GetIfTable не удалось с ошибкой: %s", ошибка_из_системы(dwRetVal));
SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Не удается получить информацию о сетевом интерфейсе: %s",
ошибка_из_системы(dwRetVal)));
goto clean;
}
buf = (char *)zbx_malloc(buf, sizeof(char) * buf_alloc);
if (pIfTable->dwNumEntries > 0)
{
zbx_ifrow_t ifrow = {NULL, NULL};
zbx_ifrow_init(&ifrow);
for (i = 0; i < (int)pIfTable->dwNumEntries; i++)
{
char *utf8_descr;
zbx_ifrow_set_index(&ifrow, pIfTable->table.dwIndex);
if (NO_ERROR != (dwRetVal = zbx_ifrow_call_get_if_entry(&ifrow)))
{
zabbix_log(LOG_LEVEL_ERR, "zbx_if row_call_get_if_entry произошел сбой с ошибкой: %s",
ошибка_из_системы(dwRetVal));
continue;
}
zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset,
"%-25s", get_if_type_string(zbx_ifrow_get_type(&ifrow)));
zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset,
" %-8s", get_if_adminstatus_string(zbx_ifrow_get_admin_status(&ifrow)));
for (j = 0; j < pIPAddrTable->dwNumEntries; j++)
if (pIPAddrTable->table[j].dwIndex == zbx_ifrow_get_index(&ifrow))
{
in_addr.S_un.S_addr = pIPAddrTable->table[j].dwAddr;
zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset,
" %-15s", inet_ntoa(in_addr));
break;
}
if (j == pIPAddrTable->dwNumEntries)
zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, " -");
utf8_descr = zbx_ifrow_get_utf8_description(&ifrow);
zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, " %s\n", utf8_descr);
zbx_free(utf8_descr);
}
zbx_ifrow_clean(&ifrow);
}
SET_TEXT_RESULT(result, buf);
ret = SYSINFO_RET_OK;
clean:
zbx_free(pIfTable);
zbx_free(pIPAddrTable);
return ret;
}
/* net.tcp.listen Проверка, находится ли TCP порт в состоянии LISTEN. */
int NET_TCP_LISTEN(AGENT_REQUEST *request, AGENT_RESULT *result)
{
MIB_TCPTABLE *pTcpTable = NULL;
DWORD dwSize, dwRetVal;
int i, ret = SYSINFO_RET_FAIL;
unsigned short port;
char *port_str;
if (1 < request->nparam)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Слишком много параметров."));
return SYSINFO_RET_FAIL;
}
port_str = get_rparam(request, 0);
if (NULL == port_str || SUCCEED != is_ushort(port_str, &port))
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Неверный первый параметр."));
return SYSINFO_RET_FAIL;
}
dwSize = sizeof(MIB_TCPTABLE);
pTcpTable = (MIB_TCPTABLE *)zbx_malloc(pTcpTable, dwSize);
/* Сделайте первоначальный вызов GetTcpTable, чтобы
получить необходимый размер в переменной dwSize */
if (ERROR_INSUFFICIENT_BUFFER == (dwRetVal = GetTcpTable(pTcpTable, &dwSize, TRUE)))
pTcpTable = (MIB_TCPTABLE *)zbx_realloc(pTcpTable, dwSize);
/* Сделайте второй звонок в GetTcpTable, чтобы получить
необходимые нам фактические данные */
if (NO_ERROR == (dwRetVal = GetTcpTable(pTcpTable, &dwSize, TRUE)))
{
for (i = 0; i < (int)pTcpTable->dwNumEntries; i++)
{
if (MIB_TCP_STATE_LISTEN == pTcpTable->table.dwState &&
port == ntohs((u_short)pTcpTable->table.dwLocalPort))
{
SET_UI64_RESULT(result, 1);
break;
}
}
ret = SYSINFO_RET_OK;
}
else
{
zabbix_log(LOG_LEVEL_DEBUG, "GetTcpTable не удалось с ошибкой: %s", ошибка_из_системы(dwRetVal));
SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Не удается получить системную информацию: %s",
ошибка_из_системы(dwRetVal)));
goto clean;
}
if (!ISSET_UI64(result))
SET_UI64_RESULT(result, 0);
clean:
zbx_free(pTcpTable);
return ret;
}
** Zabbix
** Авторское право (C) 2001-2021 Zabbix SIA
**
** Эта программа является бесплатным программным обеспечением; вы можете распространять ее и/или изменять
** это в соответствии с условиями Общей публичной лицензии GNU, опубликованной
** Фонд свободного программного обеспечения; либо версия 2 Лицензии, либо
** (по вашему выбору) любая более поздняя версия.
**
** Эта программа распространяется в надежде, что она будет полезна,
** но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ; даже без подразумеваемой гарантии
** ТОВАРНОЙ ПРИГОДНОСТИ или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ. См.
** Общая публичная лицензия GNU для получения более подробной информации.
**
** Вы должны были получить копию Общей публичной лицензии GNU
** вместе с этой программой; если нет, напишите в Свободное программное обеспечение
** Foundation, Inc., 51 Франклин-стрит, Пятый этаж, Бостон, Массачусетс 02110-1301, США.
**/
#include "common.h"
#include "sysinfo.h"
#include "log.h"
#include "zbxjson.h"
/* __соглашение о вызове stdcall используется для GetIfEntry2(). Для того, чтобы объявить */
/* указатель на GetIfEntry2() мы должны развернуть макрос NETIOPAPI_API вручную, так как */
/* часть его должна быть вместе с именем указателя в круглых скобках. */
typedef NETIO_STATUS (NETIOAPI_API_ *pGetIfEntry2_t)(PMIB_IF_ROW2 Row);
/* GetIfEntry2() доступен с Windows Vista и Windows Server 2008. В */
/* более ранние выпуски Windows этот указатель остается равным НУЛЮ, а GetIfEntry() является */
/* используется непосредственно вместо этого. */
static pGetIfEntry2_t pGetIfEntry2 = NULL;
/* GetIfEntry2() и GetIfEntry() работают с различными структурами интерфейса MIB. */
/* /* Используйте переменные zbx_if row_t и функции zbx_if row_*() ниже вместо */
/* API интерфейса MIB для конкретной версии. */
typedef struct
{
MIB_IFROW *ifRow; /* 32-разрядные счетчики */
MIB_IF_ROW2 *ifRow2; /* 64-разрядные счетчики, поддерживаемые начиная с Windows Vista, Server 2008 */
}
zbx_ifrow_t;
/******************************************************************************
* *
* * Функция: zbx_if row_init *
* *
* * Цель: инициализировать переменную zbx_if row_t *
* *
* Параметры: *
* * pIfRow - [ВХОД/ВЫХОД] указатель на переменную zbx_if row_t со всеми *
* члены имеют значение NULL *
* *
* * Комментарии: выделяет память, вызывает zbx_if row_clean() с тем же указателем *
* чтобы освободить его *
* *
******************************************************************************/
static void zbx_ifrow_init(zbx_ifrow_t *pIfRow)
{
HMODULE module;
static char check_done = FALSE;
/* проверьте (один раз) , доступен ли GetIfEntry2() в этой системе */
if (FALSE == check_done)
{
if (NULL != (module = GetModuleHandle(L"iphlpapi.dll")))
{
if (NULL == (pGetIfEntry2 = (pGetIfEntry2_t)GetProcAddress(module, "GetIfEntry2")))
{
zabbix_log(LOG_LEVEL_DEBUG, "GetProcAddress failed with error: %s",
strerror_from_system(GetLastError()));
}
}
else
{
zabbix_log(LOG_LEVEL_DEBUG, "GetModuleHandle failed with error: %s",
strerror_from_system(GetLastError()));
}
check_done = TRUE;
}
/* выделите соответствующую структуру интерфейса MIB */
if (NULL != pGetIfEntry2)
pIfRow->ifRow2 = zbx_malloc(pIfRow->ifRow2, sizeof(MIB_IF_ROW2));
else
pIfRow->ifRow = zbx_malloc(pIfRow->ifRow, sizeof(MIB_IFROW));
}
/******************************************************************************
* *
* Функция: zbx_if очистка строк *
* *
* Цель: очистить переменную zbx_if row_t *
* *
* Параметры: *
* pIfRow - [ВХОД/ВЫХОД] указатель на инициализированную переменную zbx_if row_t *
* *
* Комментарии: устанавливает для членов значение NULL, чтобы переменную можно было использовать повторно *
* *
******************************************************************************/
static void zbx_ifrow_clean(zbx_ifrow_t *pIfRow)
{
zbx_free(pIfRow->ifRow);
zbx_free(pIfRow->ifRow2);
}
/******************************************************************************
* *
* Функция: zbx_if row_call_get_if_entry *
* *
* Цель: вызовите GetIfEntry() или GetIfEntry2() в зависимости от Windows *
* отпустите, чтобы заполнить переданную структуру интерфейса MIB. *
* *
* Параметры: *
* pIfRow - [ВХОД/ВЫХОД] указатель на инициализированную переменную zbx_if row_t *
* *
* Комментарии: индекс интерфейса должен быть задан с *
* * zbx_if row_set_index(), в противном случае эта функция вернет ошибку *
* *
******************************************************************************/
static DWORD zbx_ifrow_call_get_if_entry(zbx_ifrow_t *pIfRow)
{
/* on success both functions return 0 (NO_ERROR and STATUS_SUCCESS) */
if (NULL != pIfRow->ifRow2)
return pGetIfEntry2(pIfRow->ifRow2);
else
return GetIfEntry(pIfRow->ifRow);
}
/******************************************************************************
* *
* Общие функции доступа для интерфейса MIB для конкретного выпуска *
* члены структуры. Тип возвращаемого значения, определяемый контекстом в *
* какие функции вызываются. *
* *
******************************************************************************/
static DWORD zbx_ifrow_get_index(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->InterfaceIndex;
else
return pIfRow->ifRow->dwIndex;
}
static void zbx_ifrow_set_index(zbx_ifrow_t *pIfRow, DWORD index)
{
if (NULL != pIfRow->ifRow2)
{
pIfRow->ifRow2->InterfaceLuid.Value = 0;
pIfRow->ifRow2->InterfaceIndex = index;
}
else
pIfRow->ifRow->dwIndex = index;
}
static DWORD zbx_ifrow_get_type(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->Type;
else
return pIfRow->ifRow->dwType;
}
static DWORD zbx_ifrow_get_admin_status(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->AdminStatus;
else
return pIfRow->ifRow->dwAdminStatus;
}
static ULONG64 zbx_ifrow_get_in_octets(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->InOctets;
else
return pIfRow->ifRow->dwInOctets;
}
static ULONG64 zbx_ifrow_get_in_ucast_pkts(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->InUcastPkts;
else
return pIfRow->ifRow->dwInUcastPkts;
}
static ULONG64 zbx_ifrow_get_in_nucast_pkts(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->InNUcastPkts;
else
return pIfRow->ifRow->dwInNUcastPkts;
}
static ULONG64 zbx_ifrow_get_in_errors(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->InErrors;
else
return pIfRow->ifRow->dwInErrors;
}
static ULONG64 zbx_ifrow_get_in_discards(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->InDiscards;
else
return pIfRow->ifRow->dwInDiscards;
}
static ULONG64 zbx_ifrow_get_in_unknown_protos(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->InUnknownProtos;
else
return pIfRow->ifRow->dwInUnknownProtos;
}
static ULONG64 zbx_ifrow_get_out_octets(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->OutOctets;
else
return pIfRow->ifRow->dwOutOctets;
}
static ULONG64 zbx_ifrow_get_out_ucast_pkts(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->OutUcastPkts;
else
return pIfRow->ifRow->dwOutUcastPkts;
}
static ULONG64 zbx_ifrow_get_out_nucast_pkts(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->OutNUcastPkts;
else
return pIfRow->ifRow->dwOutNUcastPkts;
}
static ULONG64 zbx_ifrow_get_out_errors(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->OutErrors;
else
return pIfRow->ifRow->dwOutErrors;
}
static ULONG64 zbx_ifrow_get_out_discards(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return pIfRow->ifRow2->OutDiscards;
else
return pIfRow->ifRow->dwOutDiscards;
}
/******************************************************************************
* *
* Функция: zbx_if row_get_utf 8_description *
* *
* Назначение: возвращает описание интерфейса, закодированное в формате UTF-8 *
* *
* Параметры: *
* pIfRow - [IN] указатель на инициализированную переменную zbx_if row_t *
* *
* Комментарии: возвращает указатель на динамически выделяемую память, вызывающий должен *
* освободите его *
* *
******************************************************************************/
static char *zbx_ifrow_get_utf8_description(const zbx_ifrow_t *pIfRow)
{
if (NULL != pIfRow->ifRow2)
return zbx_unicode_to_utf8(pIfRow->ifRow2->Description);
else
{
static wchar_t *(*mb_to_unicode)(const char *) = NULL;
wchar_t *wdescr;
char *utf8_descr;
if (NULL == mb_to_unicode)
{
const OSVERSIONINFOEX *vi;
/* начиная с Windows Vista (Windows Server 2008) описание интерфейса */
/* кодируется в кодовой странице OEM, в то время как в более ранних версиях использовалась кодовая страница ANSI */
if (NULL != (vi = zbx_win_getversion()) && 6 <= vi->dwMajorVersion)
mb_to_unicode = zbx_oemcp_to_unicode;
else
mb_to_unicode = zbx_acp_to_unicode;
}
wdescr = mb_to_unicode(pIfRow->ifRow->bDescr);
utf8_descr = zbx_unicode_to_utf8(wdescr);
zbx_free(wdescr);
return utf8_descr;
}
}
/*
* возвращает статистику интерфейса по IP-адресу или имени интерфейса
*/
static int get_if_stats(const char *if_name, zbx_ifrow_t *ifrow)
{
DWORD dwSize, dwRetVal, i, j;
int ret = FAIL;
char ip[16];
/* переменные, используемые для GetIfTable и GetIfEntry */
MIB_IFTABLE *pIfTable = NULL;
/* переменные, используемые для getipaddr-таблицы */
MIB_IPADDRTABLE *pIPAddrTable = NULL;
IN_ADDR in_addr;
/* Выделите память для наших указателей. */
dwSize = sizeof(MIB_IPADDRTABLE);
pIPAddrTable = (MIB_IPADDRTABLE *)zbx_malloc(pIPAddrTable, sizeof(MIB_IPADDRTABLE));
/*Сделайте первоначальный вызов GetIpAddrTable, чтобы получить необходимый размер в переменной dwSize */
if (ERROR_INSUFFICIENT_BUFFER == GetIpAddrTable(pIPAddrTable, &dwSize, 0))
pIPAddrTable = (MIB_IPADDRTABLE *)zbx_realloc(pIPAddrTable, dwSize);
/* Сделайте второй звонок в GetIpAddrTable, чтобы получить фактические данные, которые нам нужны */
if (NO_ERROR != (dwRetVal = GetIpAddrTable(pIPAddrTable, &dwSize, 0)))
{
zabbix_log(LOG_LEVEL_DEBUG, "GetIpAddrTable failed with error: %s", strerror_from_system(dwRetVal));
goto clean;
}
/* Выделите память для наших указателей. */
dwSize = sizeof(MIB_IFTABLE);
pIfTable = (MIB_IFTABLE *)zbx_malloc(pIfTable, dwSize);
/* Перед вызовом GetIfEntry мы вызываем GetIfTable, чтобы убедиться, что есть записи для получения и извлечения индекса интерфейса.
Сделайте первоначальный вызов GetIfTable, чтобы получить необходимый размер в dwSize */
if (ERROR_INSUFFICIENT_BUFFER == GetIfTable(pIfTable, &dwSize, 0))
pIfTable = (MIB_IFTABLE *)zbx_realloc(pIfTable, dwSize);
/* Сделайте второй звонок в GetIfTable, чтобы получить фактические данные, которые нам нужны. */
if (NO_ERROR != (dwRetVal = GetIfTable(pIfTable, &dwSize, 0)))
{
zabbix_log(LOG_LEVEL_DEBUG, "GetIfTable failed with error: %s", strerror_from_system(dwRetVal));
goto clean;
}
for (i = 0; i < pIfTable->dwNumEntries; i++)
{
char *utf8_descr;
zbx_ifrow_set_index(ifrow, pIfTable->table.dwIndex);
if (NO_ERROR != (dwRetVal = zbx_ifrow_call_get_if_entry(ifrow)))
{
zabbix_log(LOG_LEVEL_DEBUG, "zbx_ifrow_call_get_if_entry failed with error: %s",
strerror_from_system(dwRetVal));
continue;
}
utf8_descr = zbx_ifrow_get_utf8_description(ifrow);
if (0 == strcmp(if_name, utf8_descr))
ret = SUCCEED;
zbx_free(utf8_descr);
if (SUCCEED == ret)
break;
for (j = 0; j < pIPAddrTable->dwNumEntries; j++)
{
if (pIPAddrTable->table[j].dwIndex == zbx_ifrow_get_index(ifrow))
{
in_addr.S_un.S_addr = pIPAddrTable->table[j].dwAddr;
zbx_snprintf(ip, sizeof(ip), "%s", inet_ntoa(in_addr));
if (0 == strcmp(if_name, ip))
{
ret = SUCCEED;
break;
}
}
}
if (SUCCEED == ret)
break;
}
clean:
zbx_free(pIfTable);
zbx_free(pIPAddrTable);
return ret;
}
/* net.if.in Статистика по входящему трафику сетевого интерфейса. */
int NET_IF_IN(AGENT_REQUEST *request, AGENT_RESULT *result)
{
char *if_name, *mode;
zbx_ifrow_t ifrow = {NULL, NULL};
int ret = SYSINFO_RET_FAIL;
zbx_ifrow_init(&ifrow);
if (2 < request->nparam)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Слишком много параметров."));
goto clean;
}
if_name = get_rparam(request, 0);
mode = get_rparam(request, 1);
if (NULL == if_name || '\0' == *if_name)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Неверный первый параметр."));
goto clean;
}
if (FAIL == get_if_stats(if_name, &ifrow))
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Не удается получить информацию о сетевом интерфейсе."));
goto clean;
}
if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes")) /* параметр по умолчанию */
SET_UI64_RESULT(result, zbx_ifrow_get_in_octets(&ifrow));
else if (0 == strcmp(mode, "packets"))
SET_UI64_RESULT(result, zbx_ifrow_get_in_ucast_pkts(&ifrow) + zbx_ifrow_get_in_nucast_pkts(&ifrow));
else if (0 == strcmp(mode, "errors"))
SET_UI64_RESULT(result, zbx_ifrow_get_in_errors(&ifrow));
else if (0 == strcmp(mode, "dropped"))
SET_UI64_RESULT(result, zbx_ifrow_get_in_discards(&ifrow) + zbx_ifrow_get_in_unknown_protos(&ifrow));
else
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Недопустимый второй параметр."));
goto clean;
}
ret = SYSINFO_RET_OK;
clean:
zbx_ifrow_clean(&ifrow);
return ret;
}
/* net.if.out Статистика по исходящему трафику сетевого интерфейса. */
int NET_IF_OUT(AGENT_REQUEST *request, AGENT_RESULT *result)
{
char *if_name, *mode;
zbx_ifrow_t ifrow = {NULL, NULL};
int ret = SYSINFO_RET_FAIL;
zbx_ifrow_init(&ifrow);
if (2 < request->nparam)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Слишком много параметров."));
goto clean;
}
if_name = get_rparam(request, 0);
mode = get_rparam(request, 1);
if (NULL == if_name || '\0' == *if_name)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Неверный первый параметр."));
goto clean;
}
if (FAIL == get_if_stats(if_name, &ifrow))
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Не удается получить информацию о сетевом интерфейсе."));
goto clean;
}
if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes")) /* параметр по умолчанию */
SET_UI64_RESULT(result, zbx_ifrow_get_out_octets(&ifrow));
else if (0 == strcmp(mode, "packets"))
SET_UI64_RESULT(result, zbx_ifrow_get_out_ucast_pkts(&ifrow) + zbx_ifrow_get_out_nucast_pkts(&ifrow));
else if (0 == strcmp(mode, "errors"))
SET_UI64_RESULT(result, zbx_ifrow_get_out_errors(&ifrow));
else if (0 == strcmp(mode, "dropped"))
SET_UI64_RESULT(result, zbx_ifrow_get_out_discards(&ifrow));
else
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Недопустимый второй параметр."));
goto clean;
}
ret = SYSINFO_RET_OK;
clean:
zbx_ifrow_clean(&ifrow);
return ret;
}
/* net.if.total Суммарная статистика входящего и исходящего трафика на сетевом интерфейсе. */
int NET_IF_TOTAL(AGENT_REQUEST *request, AGENT_RESULT *result)
{
char *if_name, *mode;
zbx_ifrow_t ifrow = {NULL, NULL};
int ret = SYSINFO_RET_FAIL;
zbx_ifrow_init(&ifrow);
if (2 < request->nparam)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Слишком много параметров."));
goto clean;
}
if_name = get_rparam(request, 0);
mode = get_rparam(request, 1);
if (NULL == if_name || '\0' == *if_name)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Неверный первый параметр."));
goto clean;
}
if (FAIL == get_if_stats(if_name, &ifrow))
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Не удается получить информацию о сетевом интерфейсе."));
goto clean;
}
if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "bytes")) /* параметр по умолчанию */
SET_UI64_RESULT(result, zbx_ifrow_get_in_octets(&ifrow) + zbx_ifrow_get_out_octets(&ifrow));
else if (0 == strcmp(mode, "packets"))
SET_UI64_RESULT(result, zbx_ifrow_get_in_ucast_pkts(&ifrow) + zbx_ifrow_get_in_nucast_pkts(&ifrow) +
zbx_ifrow_get_out_ucast_pkts(&ifrow) + zbx_ifrow_get_out_nucast_pkts(&ifrow));
else if (0 == strcmp(mode, "errors"))
SET_UI64_RESULT(result, zbx_ifrow_get_in_errors(&ifrow) + zbx_ifrow_get_out_errors(&ifrow));
else if (0 == strcmp(mode, "dropped"))
SET_UI64_RESULT(result, zbx_ifrow_get_in_discards(&ifrow) + zbx_ifrow_get_in_unknown_protos(&ifrow) +
zbx_ifrow_get_out_discards(&ifrow));
else
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Недопустимый второй параметр."));
goto clean;
}
ret = SYSINFO_RET_OK;
clean:
zbx_ifrow_clean(&ifrow);
return ret;
}
/* net.if.discovery Список сетевых интерфейсов. Используется низкоуровневым обнаружением */
int NET_IF_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result)
{
DWORD dwSize, dwRetVal, i;
int ret = SYSINFO_RET_FAIL;
/* переменные, используемые для GetIfTable и GetIfEntry */
MIB_IFTABLE *pIfTable = NULL;
zbx_ifrow_t ifrow = {NULL, NULL};
struct zbx_json j;
char *utf8_descr;
/* Выделите память для наших указателей. */
dwSize = sizeof(MIB_IFTABLE);
pIfTable = (MIB_IFTABLE *)zbx_malloc(pIfTable, dwSize);
/*Перед вызовом GetIfEntry мы вызываем GetIfTable, чтобы сделать убедитесь, что есть записи для получения и извлечения индекса интерфейса. Сделайте первоначальный вызов GetIfTable, чтобы получить необходимый размер в dwSize */
if (ERROR_INSUFFICIENT_BUFFER == GetIfTable(pIfTable, &dwSize, 0))
pIfTable = (MIB_IFTABLE *)zbx_realloc(pIfTable, dwSize);
/* Сделайте второй звонок в GetIfTable, чтобы получить фактические данные, которые нам нужны. */
if (NO_ERROR != (dwRetVal = GetIfTable(pIfTable, &dwSize, 0)))
{
zabbix_log(LOG_LEVEL_DEBUG, "GetIfTable не удалось с ошибкой: %s",ошибка_из_системе(dwRetVal));
SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Не удается получить системную информацию: %s",
strerror_from_system(dwRetVal)));
goto clean;
}
zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN);
zbx_ifrow_init(&ifrow);
for (i = 0; i < pIfTable->dwNumEntries; i++)
{
zbx_ifrow_set_index(&ifrow, pIfTable->table.dwIndex);
if (NO_ERROR != (dwRetVal = zbx_ifrow_call_get_if_entry(&ifrow)))
{
zabbix_log(LOG_LEVEL_DEBUG, "zbx_if row_call_get_if_entry произошел сбой с ошибкой: %s",
ошибка_из_системы(dwRetVal));
continue;
}
zbx_json_addobject(&j, NULL);
utf8_descr = zbx_ifrow_get_utf8_description(&ifrow);
zbx_json_addstring(&j, "{#IFNAME}", utf8_descr, ZBX_JSON_TYPE_STRING);
zbx_free(utf8_descr);
zbx_json_close(&j);
}
zbx_ifrow_clean(&ifrow);
zbx_json_close(&j);
SET_STR_RESULT(result, strdup(j.buffer));
zbx_json_free(&j);
ret = SYSINFO_RET_OK;
clean:
zbx_free(pIfTable);
return ret;
}
/* Тип интерфейса: Другой, Интернет, топологией кольца, PPP, Обратная связь ПО, ATM, WI-FI, Инкапсуляция туннельного типа, последовательная высокоскоростная шина, неизвестный */
/*Это относится быстрее всего к Обнаружение интерфейсов хостов в Zabbix, Тип интерфейса {#IF.TYPE} (“AGENT”, “SNMP”, “JMX”, или “IPMI”), Запрос zabbix[host,discovery,interfaces]*/
/*https://www.zabbix.com/documentation/cu ... interfaces*/
static char *get_if_type_string(DWORD type)
{
switch (type)
{
case IF_TYPE_OTHER: return "Other";
case IF_TYPE_ETHERNET_CSMACD: return "Ethernet";
case IF_TYPE_ISO88025_TOKENRING: return "Token Ring";
case IF_TYPE_PPP: return "PPP";
case IF_TYPE_SOFTWARE_LOOPBACK: return "Software Loopback";
case IF_TYPE_ATM: return "ATM";
case IF_TYPE_IEEE80211: return "IEEE 802.11 Wireless";
case IF_TYPE_TUNNEL: return "Tunnel type encapsulation";
case IF_TYPE_IEEE1394: return "IEEE 1394 Firewire";
default: return "unknown";
}
}
/* Статус: Подключен, Отключен, Неизвестен */
/* Быстрее всего для snmp ifAdminStatus 1.3.6.1.2.1.2.2.1.7 - Текущее административное состояние интерфейса.*/
/*https://www.zabbix.com/documentation/cu ... ecial_mibs*/
static char *get_if_adminstatus_string(DWORD status)
{
switch (status)
{
case 0: return "disabled";
case 1: return "enabled";
default: return "unknown";
}
}
/* net.if.list Список сетевых интерфейсов (включая тип, состояние, IPv4 адрес, описание интерфейса). */
int NET_IF_LIST(AGENT_REQUEST *request, AGENT_RESULT *result)
{
DWORD dwSize, dwRetVal, i, j;
char *buf = NULL;
size_t buf_alloc = 512, buf_offset = 0;
int ret = SYSINFO_RET_FAIL;
/* переменные, используемые для GetIfTable и GetIfEntry */
MIB_IFTABLE *pIfTable = NULL;
/* переменные, используемые для getipaddr-таблицы */
MIB_IPADDRTABLE *pIPAddrTable = NULL;
IN_ADDR in_addr;
/* Выделите память для наших указателей. */
dwSize = sizeof(MIB_IPADDRTABLE);
pIPAddrTable = (MIB_IPADDRTABLE *)zbx_malloc(pIPAddrTable, sizeof(MIB_IPADDRTABLE));
/* Сделайте первоначальный вызов GetIpAddrTable, чтобы получить необходимый размер в переменной dwSize */
if (ERROR_INSUFFICIENT_BUFFER == GetIpAddrTable(pIPAddrTable, &dwSize, 0))
pIPAddrTable = (MIB_IPADDRTABLE *)zbx_realloc(pIPAddrTable, dwSize);
/* Сделайте второй звонок в GetIpAddrTable, чтобы получить фактические данные, которые нам нужны */
if (NO_ERROR != (dwRetVal = GetIpAddrTable(pIPAddrTable, &dwSize, 0)))
{
zabbix_log(LOG_LEVEL_DEBUG, "GetIpAddrTable не удалось с ошибкой: %s", ошибка_из_системы(dwRetVal));
SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Не удается получить информацию об IP-адресе: %s",
ошибка_из_системы(dwRetVal)));
goto clean;
}
/* Выделите память для наших указателей. */
dwSize = sizeof(MIB_IFTABLE);
pIfTable = (MIB_IFTABLE *)zbx_malloc(pIfTable, dwSize);
/* Перед вызовом GetIfEntry мы вызываем GetIfTable, чтобы сделать
убедитесь, что есть записи для получения и извлечения индекса интерфейса.
Сделайте первоначальный вызов GetIfTable, чтобы получить необходимый размер в dwSize */
if (ERROR_INSUFFICIENT_BUFFER == GetIfTable(pIfTable, &dwSize, 0))
pIfTable = (MIB_IFTABLE *)zbx_realloc(pIfTable, dwSize);
/* Сделайте второй звонок в GetIfTable, чтобы получить фактические данные, которые нам нужны. */
if (NO_ERROR != (dwRetVal = GetIfTable(pIfTable, &dwSize, 0)))
{
zabbix_log(LOG_LEVEL_DEBUG, "GetIfTable не удалось с ошибкой: %s", ошибка_из_системы(dwRetVal));
SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Не удается получить информацию о сетевом интерфейсе: %s",
ошибка_из_системы(dwRetVal)));
goto clean;
}
buf = (char *)zbx_malloc(buf, sizeof(char) * buf_alloc);
if (pIfTable->dwNumEntries > 0)
{
zbx_ifrow_t ifrow = {NULL, NULL};
zbx_ifrow_init(&ifrow);
for (i = 0; i < (int)pIfTable->dwNumEntries; i++)
{
char *utf8_descr;
zbx_ifrow_set_index(&ifrow, pIfTable->table.dwIndex);
if (NO_ERROR != (dwRetVal = zbx_ifrow_call_get_if_entry(&ifrow)))
{
zabbix_log(LOG_LEVEL_ERR, "zbx_if row_call_get_if_entry произошел сбой с ошибкой: %s",
ошибка_из_системы(dwRetVal));
continue;
}
zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset,
"%-25s", get_if_type_string(zbx_ifrow_get_type(&ifrow)));
zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset,
" %-8s", get_if_adminstatus_string(zbx_ifrow_get_admin_status(&ifrow)));
for (j = 0; j < pIPAddrTable->dwNumEntries; j++)
if (pIPAddrTable->table[j].dwIndex == zbx_ifrow_get_index(&ifrow))
{
in_addr.S_un.S_addr = pIPAddrTable->table[j].dwAddr;
zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset,
" %-15s", inet_ntoa(in_addr));
break;
}
if (j == pIPAddrTable->dwNumEntries)
zbx_strcpy_alloc(&buf, &buf_alloc, &buf_offset, " -");
utf8_descr = zbx_ifrow_get_utf8_description(&ifrow);
zbx_snprintf_alloc(&buf, &buf_alloc, &buf_offset, " %s\n", utf8_descr);
zbx_free(utf8_descr);
}
zbx_ifrow_clean(&ifrow);
}
SET_TEXT_RESULT(result, buf);
ret = SYSINFO_RET_OK;
clean:
zbx_free(pIfTable);
zbx_free(pIPAddrTable);
return ret;
}
/* net.tcp.listen Проверка, находится ли TCP порт в состоянии LISTEN. */
int NET_TCP_LISTEN(AGENT_REQUEST *request, AGENT_RESULT *result)
{
MIB_TCPTABLE *pTcpTable = NULL;
DWORD dwSize, dwRetVal;
int i, ret = SYSINFO_RET_FAIL;
unsigned short port;
char *port_str;
if (1 < request->nparam)
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Слишком много параметров."));
return SYSINFO_RET_FAIL;
}
port_str = get_rparam(request, 0);
if (NULL == port_str || SUCCEED != is_ushort(port_str, &port))
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Неверный первый параметр."));
return SYSINFO_RET_FAIL;
}
dwSize = sizeof(MIB_TCPTABLE);
pTcpTable = (MIB_TCPTABLE *)zbx_malloc(pTcpTable, dwSize);
/* Сделайте первоначальный вызов GetTcpTable, чтобы
получить необходимый размер в переменной dwSize */
if (ERROR_INSUFFICIENT_BUFFER == (dwRetVal = GetTcpTable(pTcpTable, &dwSize, TRUE)))
pTcpTable = (MIB_TCPTABLE *)zbx_realloc(pTcpTable, dwSize);
/* Сделайте второй звонок в GetTcpTable, чтобы получить
необходимые нам фактические данные */
if (NO_ERROR == (dwRetVal = GetTcpTable(pTcpTable, &dwSize, TRUE)))
{
for (i = 0; i < (int)pTcpTable->dwNumEntries; i++)
{
if (MIB_TCP_STATE_LISTEN == pTcpTable->table.dwState &&
port == ntohs((u_short)pTcpTable->table.dwLocalPort))
{
SET_UI64_RESULT(result, 1);
break;
}
}
ret = SYSINFO_RET_OK;
}
else
{
zabbix_log(LOG_LEVEL_DEBUG, "GetTcpTable не удалось с ошибкой: %s", ошибка_из_системы(dwRetVal));
SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Не удается получить системную информацию: %s",
ошибка_из_системы(dwRetVal)));
goto clean;
}
if (!ISSET_UI64(result))
SET_UI64_RESULT(result, 0);
clean:
zbx_free(pTcpTable);
return ret;
}
Запросы API C++
GetIfEntry2
Функция GetIfEntry2 извлекает информацию для указанного интерфейса на локальном компьютере.
Функция GetIfEntry2 (драйверы для Windows)
Функция GetAdaptersAddresses
Данная функция возвращает подробную информацию о сетевых адаптерах: адреса, имена, тип и т.д. и т.п., структура выходной записи имеет более 30 полей. Особенно приятно что функция в отличии от предыдущей возвращает и friendlyname - "человеческое" имя сетевого адаптера, которое мы можем видеть в списке сетевых подключений в виндовс. Итак, пример, которые возвращает список всех человеческих имен всех адаптеров
Функции GetIfEntry и GetIfTable
GetIfTable служит для получения списка сетевых интерфейсов (не путать с адаптерами!). А GetIfEntry для подробной информации о конкретном интерфейсе;