我想研究一下,windows 怎么通过SNMP协议探测LINUX设备的状态。
目前使用Windows SNMP MGMTAPI 来做一个简单的控制台程序,发送SNMP Request给一个打开了SNMP功能的Linux设备,然后输出SNMP 返回信息到控制台窗口。
按照这篇文章设置即可:
Ubuntu上snmp安装、配置、启动及远程测试完整过程
注意在配置SNMP时,要开启远程访问的权限,才能用windows访问。
控制台程序只是和Linux上的SNMP代理发送消息,不需要专门打开Windows的SNMP功能。
MGMTAPI 函数的参数和返回值可以参考以下MS文档
Mgmtapi.h
有WINSNMP API 和 MGMT API,我认为WINSNMP 需要和窗口交互,
而MGMT不需要添加hwnd等参数,使用更方便。
控制台代码可以参考以下文章:
vc++实现SNMP信息刺探程序
C++ 打印机状态查询之SNMP协议 ←这篇文章的代码部分更简洁,便于理解
目标Linux设备的OID,最好先下载一个Mib browser这样的软件,来查看一下,有哪些OID。
可以到官网下载免费版,使用非常简单,网上很多帮助文章:
ireasoning MIB Browser
Mib Browser中我对目标Linux设备的System进行了walk获取,右侧试图展示出了获取到的OID表。
需要的头文件,和lib引用
#include
#include
#include
#include
#include
#pragma comment(lib,"Snmpapi.lib")
#pragma comment(lib,"Mgmtapi.lib")
using std::cout;
using std::endl;
把目标linux设备的IP、community name、想要查询的初始OID等定义为全局变量,方便测试修改。
//SNMP Agent Information
const char* IPv4_addr = "192.168.1.18";
const char* community = "public";
const char* targetOID = ".1.3.6.1.2.1.1.1.0";
const int common_timeout = 2000;
const int common_retries = 3;
//golbal settings
#define COMMON_ARRAY_SIZE 256
main函数
只需要SnmpMgrOpen()
和 SnmpMgrRequest()
2个API就可以完成 。
其余代码都是参数初始化或者返回值解析之类的。
int main()
{
//****初始化SnmpMgrOpen API 参数
LPSTR lpAgentAddress = new char[COMMON_ARRAY_SIZE];
memset(lpAgentAddress, 0x00, COMMON_ARRAY_SIZE);
strcpy_s(lpAgentAddress, COMMON_ARRAY_SIZE,IPv4_addr);
LPSTR lpAgentCommunity = new char[COMMON_ARRAY_SIZE];
memset(lpAgentCommunity, 0x00, COMMON_ARRAY_SIZE);
strcpy_s(lpAgentCommunity, COMMON_ARRAY_SIZE,community);
INT nTimeOut = common_timeout;
INT nRetries = common_retries;
//****SnmpMgrOpen API 执行,初始化snmpMgr
LPSNMP_MGR_SESSION psession = SnmpMgrOpen(
lpAgentAddress,
lpAgentCommunity,
nTimeOut,
nRetries
);
if (psession == NULL) {
cout << "SnmpMgrOpen err:" << GetLastError() << endl;
return -1;
}
//****初始化SnmpMgrRequest API参数
AsnObjectIdentifier AsbObj;
if (SnmpMgrStrToOid((LPSTR)targetOID, &AsbObj) == 0) {
cout << "SnmpMgrStrToOid err:" << GetLastError() << endl;
}
RFC1157VarBindList* variableBindings = (RFC1157VarBindList*)SnmpUtilMemAlloc(sizeof(RFC1157VarBindList));
variableBindings->len = 1;
variableBindings->list = (SnmpVarBind*)SnmpUtilMemAlloc(sizeof(SnmpVarBind));
variableBindings->list->name.ids = AsbObj.ids;
variableBindings->list->name.idLength = AsbObj.idLength;
variableBindings->list->value.asnType = ASN_NULL;
AsnInteger errorStatus;
AsnInteger errorIndex;
BYTE requestType = SNMP_PDU_GET;
while (1) {
//****SnmpMgrRequest API,发送SNMP消息,解析返回值
SNMPAPI ret = SnmpMgrRequest(
psession,
requestType,
variableBindings,
&errorStatus,
&errorIndex
);
if (ret != NULL)
{
//****正常返回值的解析
if (errorStatus == SNMP_ERRORSTATUS_NOERROR)
{
if (variableBindings->list->value.asnType == ASN_OCTETSTRING) {
cout << "OID:" << SnmpUtilOidToA(&variableBindings->list->name) <<
",Type:ASN_OCTETSTRING,Value:" <<
variableBindings->list->value.asnValue.string.stream << endl;
}
else if (variableBindings->list->value.asnType == ASN_INTEGER) {
cout << "OID:" << SnmpUtilOidToA(&variableBindings->list->name) <<
",Type:ASN_INTEGER,Value:" <<
variableBindings->list->value.asnValue.number << endl;
}
else if (variableBindings->list->value.asnType == ASN_OBJECTIDENTIFIER) {
cout << "OID:" << SnmpUtilOidToA(&variableBindings->list->name) <<
",Type:ASN_OBJECTIDENTIFIER,Value:" <<
SnmpUtilOidToA(&variableBindings->list->value.asnValue.object) << endl;
}
else if (variableBindings->list->value.asnType == ASN_TIMETICKS) {
cout << "OID:" << SnmpUtilOidToA(&variableBindings->list->name) <<
",Type:ASN_TIMETICKS,Value:" <<
variableBindings->list->value.asnValue.ticks << endl;
}
else {
cout << "SnmpMgrRequest unknow value type" << endl;
}
}
//****异常返回值的解析
else if (errorStatus == SNMP_ERRORSTATUS_NOSUCHNAME) {
cout << "End of Mib, current mib:" << SnmpUtilOidToA(&variableBindings->list->name) << endl;
break;
}
else if(SnmpUtilOidNCmp(&variableBindings->list->name, &AsbObj, AsbObj.idLength)) {
cout << "End of Mib 1, current mib:" << SnmpUtilOidToA(&variableBindings->list->name) << endl;
break;
}
else
{
cout << "SnmpMgrRequest err status:" << errorStatus << ",err index:" << errorIndex << endl;
SnmpUtilVarBindListFree(variableBindings);
SnmpMgrClose(psession);
return -1;
}
}
else
{
cout << "SnmpMgrRequest err:" << GetLastError() << endl;
SnmpUtilVarBindListFree(variableBindings);
SnmpMgrClose(psession);
return -1;
}
//**** 切换成GET NEXT 继续循环,不然会一直重复初始目标OID的GET。
//**** 切换成GET NEXT后,会自动访问下一条OID
requestType = SNMP_PDU_GETNEXT;
}
//**** 释放空间
SnmpUtilVarBindListFree(variableBindings);
SnmpMgrClose(psession);
return 0;
}
可以看到,和上面Mib Browser中walk到的结果是一样的。