Добрый день. Речь пойдет об использовании протокола SNMP, но немного не в том ключе, как все привыкли. Википедия сообщает, что данный «протокол обычно используется в системах сетевого управления для контроля подключенных к сети устройств на предмет условий, которые требуют внимания администратора». Такими устройства зачастую являются маршрутизаторы, хабы, коммутаторы, мосты, принтеры и, естественно, сами компьютеры. Для реализации функции контроля на каждом таком устройстве присутствует агент SNMP, в непосредственные обязанности которого входит сбор информации и передача ее менеджеру по запросу.
Изначально, данная функция реализована в виде службы SNMP, которая берет на себя всю черновую работу, касающуюся деталей протокола. Вся доступная агенту информация находится в базах управляющей информации (MIB), где каждому параметру устройства поставлен в соответствие уникальный идентификатор, называемый OID'ом. Таким образом, чтобы прочитать необходимое значение параметра сетевого устройства, менеджеру необходимо сделать запрос, в котором указать OID данного параметра. Агент, получив запрос, находит в MIB данный параметр и возвращает менеджеру значение. Все очень просто.
Если же нам необходимо расширить базовую функциональность агента, то необходимо написать агента расширения с требуемыми возможностями. Физически, агент расширения представляет из себя dll, которая экспортирует как минимум 3 функции:
- SnmpExtensionInit
- SnmpExtensionQuery
- SnmpExtensionTrap
Работу агента расширения поясню на рисунке:
Допустим, что наш агент расширения установлен на обычном компьютере. При загрузке ОС происходит вызов SnmpExtensionInit, в результате чего агент осуществляет подготовку к работе. Во-первых, он указывает «зону своей ответственности», т.е. диапазон OID'ов, при запросе к которым следует вызывать именно этого агента. Кроме этого, могут выполняться другие подготовительные мероприятия, например, загрузка в память значений параметров, подлежащих мониторингу со стороны менеджера и т.п.
После отправки менеджером запроса, служба SNMP устанавливает, что данный запрос попадает «под ответственность» нашего агента и «дергает» соответствующую dll'ку. И наш агент, в соответствии с запросом, производит либо чтение параметра, либо запись нового значения.
Для регистрации агента в системе, необходимо создать строковый параметр в разделе HKLM->System->CurrentControlSet->services->SNMP->Parameters->ExtensionAgents со следующим по порядку номером.
Значением данного параметра будет путь в реестре к строковому параметру Pathname, который должен находиться в разделе Software. Например, «SoftwareTestSnmpExtAgentCurrentVersion». Т.е. нам нужно создать в Software 3 раздела: Test,SnmpExtAgent и CurrentVersion. Затем, создаем строковый параметр Pathname, значением которого будет путь до нашей dll'ки.
Естественно, у нас на компьютере должна быть установлена служба SNMP. Если ее нет, то идем в Установка и удаление программ"->«Установка компонентов Windows». Там ставим галочку в «Средства управления и наблюдения» и устанавливаем. В Win XP понадобиться установочный диск, в Win 7 обходится без него.
Далее, идем в Мой компьютер->Управление->Службы. Находим заветную строчку «Служба SNMP» и в свойствах, на вкладке «Безопасность» создаем сообщество public с правами READ WRITE. Перезапускаем службу, агент готов к работе.
Теперь немного кода.
Функция SnmpExtensionInit:
BOOL SNMP_FUNC_TYPE SnmpExtensionInit( DWORD dwUptimeReference,
HANDLE *phSubagentTrapEvent,
AsnObjectIdentifier *pFirstSupportedRegion)
{
*pFirstSupportedRegion = MIB_OidPrefix; // это и есть наша "зона ответственности"
*phSubagentTrapEvent = g_hSimulateTrap;//эта строчка относится к использованию ловушек
// инициализируем два строковых и один целочисленный параметр
g_szAbout = (char*)malloc(sizeof(char)*64);
strcpy(g_szAbout,"Author : Ramanan.T");
g_szName = (char*)malloc(sizeof(char)*64);
strcpy(g_szName,"Your Name");
g_asnIntAge = 0;
g_dwStartTime = GetTickCount();
return SNMPAPI_NOERROR;
}
Функция SnmpExtensionQuery:
BOOL SNMP_FUNC_TYPE SnmpExtensionQuery( BYTE bPduType,
SnmpVarBindList *pVarBindList,
AsnInteger32 *pErrorStatus,
AsnInteger32 *pErrorIndex)
{
int nRet = 0;
AsnObjectName;
*pErrorStatus = SNMP_ERRORSTATUS_NOERROR;
*pErrorIndex = 0;
for(UINT i=0;i<pVarBindList->len;i++)
{
*pErrorStatus = SNMP_ERRORSTATUS_NOERROR;
// Перебираем типы запросов
switch(bPduType)
{
case SNMP_PDU_GET: //запрос GET
*pErrorStatus = GetRequest(&pVarBindList->list[i]);
if(*pErrorStatus != SNMP_ERRORSTATUS_NOERROR)
*pErrorIndex++;
break;
case SNMP_PDU_GETNEXT: //запрос GETNEXT
*pErrorStatus = GetNextRequest(&pVarBindList->list[i]);
if(*pErrorStatus != SNMP_ERRORSTATUS_NOERROR)
*pErrorIndex++;
break;
case SNMP_PDU_SET: //запрос SET
*pErrorStatus = SetRequest(&pVarBindList->list[i]);
if(*pErrorStatus != SNMP_ERRORSTATUS_NOERROR)
*pErrorIndex++;
break;
default:
*pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
*pErrorIndex++;
};
}
return SNMPAPI_NOERROR;
}
Видим, что посредством структуры pVarBindList к нам приходит OID требуемого параметра и в функциях GetRequest и GetNextRequest в эту же структуру мы запишем значения этих параметров.
Итак, что же получается в итоге. Мы можем написать dll, которая будет вызываться системой в случае получения запросов по сети. А вот что мы уже будем делать внутри этой самой SnmpExtensionQuery — дело наше. То есть, мы, получив запрос от менеджера имеем возможность выполнять произвольные действия. Учитывая, что служба SNMP есть практически на всех компьютерах, получаем достаточно широкие возможности управления техническими средствами, работающими под управлением компьютеров, т.е. любыми.
Спасибо за внимание.
Ссылки:
1. www.codeproject.com/Articles/9024/How-to-develop-a-SNMP-extension-agent-DLL
Автор: Alf162