[SNMP]使用widows MGMTAPI 发送SNMP消息

文章目录

  • Linux 开启SNMP功能
  • Windows控制台程序
    • 参考文章和工具
    • 代码实现
    • 结果截图
  • 不足

我想研究一下,windows 怎么通过SNMP协议探测LINUX设备的状态。
目前使用Windows SNMP MGMTAPI 来做一个简单的控制台程序,发送SNMP Request给一个打开了SNMP功能的Linux设备,然后输出SNMP 返回信息到控制台窗口。

Linux 开启SNMP功能

按照这篇文章设置即可:
Ubuntu上snmp安装、配置、启动及远程测试完整过程
注意在配置SNMP时,要开启远程访问的权限,才能用windows访问。

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表。
[SNMP]使用widows MGMTAPI 发送SNMP消息_第1张图片

代码实现

需要的头文件,和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到的结果是一样的。
[SNMP]使用widows MGMTAPI 发送SNMP消息_第2张图片

不足

  1. windows的snmp api没有提供SNMPv3的功能,应该可以在windwos中导入net-snmp等开源库,来实现SNMPv3的通信。这是后续需要研究的。
  2. 这篇文章中,尝试了GET 和GETNEXT ,还有TRAP等没有尝试。

你可能感兴趣的:(SNMP,linux,网络,tcp/ip,c++,windows)