[SNMP] Agent++库使用(一)

本文详细介绍了如何使用Agent++库编译SNMPagent,包括MIB结构、初始化、添加和删除MIB节点,以及处理SNMPGET和SET请求的基本示例。还涵盖了SNMPv2版本的安全设置和调试方法。
摘要由CSDN通过智能技术生成

1. 说明

要使用Agent++库开发snmp agent,首先要编译snmp++库,二者编译的方法在另一篇文章中有说明。
SNMP++及Agent++交叉编译

2. Agent++框架

agent++主要是有MIB类及其派生类组成,其结构如下图所示。
在这里插入图片描述

agent++简单使用可分为如下几步:

  1. 初始化snmp socket网络。
  2. 通过Mib中成员函数add创建任意所需的MIB节点,通过remove来移除。
  3. 创建request列表,将创建的mib对象关联上。(v2 和v3版本有区别)
  4. 通过receive来监听NSM管理端消息。

3.简单的SNMP Agent代码

如下是一个用Agent++开发的agent代理的例子,此例子可用于SNMP v1和v2版本,v2版本只需设置下读写社区,v3需要用到安全认证,将在下一篇文章中介绍。

#include <stdio.h>
#include <signal.h>

#include "agent_pp/agent++.h"
#include "agent_pp/snmp_group.h"
#include "agent_pp/system_group.h"
#include "agent_pp/snmp_target_mib.h"
#include "agent_pp/snmp_notification_mib.h"
#include "agent_pp/notification_originator.h"
#include "agent_pp/mib_complex_entry.h"
#include "agent_pp/v3_mib.h"
#include "agent_pp/vacm.h"

#include "snmp_pp/oid_def.h"
#include "snmp_pp/mp_v3.h"
#include "snmp_pp/log.h"


#ifdef SNMP_PP_NAMESPACE
using namespace Snmp_pp;
#endif


#ifdef AGENTPP_NAMESPACE
using namespace Agentpp;
#endif


bool run = TRUE;

static void sig(int signo)
{
	if ((signo == SIGTERM) || (signo == SIGINT) ||
	    (signo == SIGSEGV)) {

		printf ("\n");
      
		switch (signo) {
		case SIGSEGV: {
			printf ("Segmentation fault, aborting.\n");
			exit(1);
		}
		case SIGTERM: 
		case SIGINT: {
			if (run) {
				printf ("User abort\n");
				run = FALSE;
			}
		}
		}
	}
}

void init_signals()
{
	signal (SIGTERM, sig);
	signal (SIGINT, sig);
	signal (SIGSEGV, sig); 
}


int main()
{
    int status;
    Snmp::socket_startup();  //初始化socket子系统

    unsigned short port = 161; //161为监听端口 162为Trap端口
    Snmpx snmp(status, port);

    if( SNMP_CLASS_SUCCESS == status)
    {
        Mib mib;
       
        //mib节点创建 使用的是MibLeaf构造函数生成
        MibEntry* mib100 = mib.add(new MibLeaf("1.3.6.1.4.1.100", READWRITE, new SnmpInt32(3)));
        MibEntry* mib101 = mib.add(new MibLeaf("1.3.6.1.4.1.101", READWRITE, new OctetStr("haioneuw12")));
        mib.add(new MibLeaf("1.3.6.1.4.1.102", READWRITE, new SnmpInt32(-3434)));
        mib.add(new MibLeaf("1.3.6.1.4.1.103", READWRITE, new SnmpInt32(-55)));
    
        //获取值
		  int _int_32 = 0;
        ((MibLeaf*)mib100)->get_value(_int_32);
        
	     std::string str_;
	     ((MibLeaf*)mib101)->get_value((char*)str_.c_str());

		  printf("----111------100 value is %s------------\n", _int_32);
        printf("----111------101 value is %s------------\n", str_.c_str());

	     //修改值
		  SnmpInt32* inttmp = new SnmpInt32(-92);
	     ((MibLeaf*)mib100)->set_value(*((SnmpSyntax*)inttmp));

	     OctetStr* strtmp = new OctetStr("hello");
	     ((MibLeaf*)mib101)->set_value(*((SnmpSyntax*)strtmp));

		  //创建RequestList
        RequestList* reqList = new RequestList(&mib);

        mib.set_request_list(reqList);

        init_signals();

        reqList->set_snmp(&snmp);
        
        //v2版本 设置读写社区
	     reqList->set_read_community("public");
	     reqList->set_write_community("public");

        mib.init(); //mib 初始化 

        //监听循环 此处循环何时退出可根据实际情况来做修改
        Request* req; 
        while (run)
        {
            req = reqList->receive(2);

            if (req)
            {
                mib.process_request(req);
            }
            else
            {
                mib.cleanup();
            }
        }
        delete reqList;
        Snmp::socket_cleanup();
    }
    else
    {
        printf("snmp port init failed!\n");
    }

    return 0;
}

4. 重载MibLeaf实现读写过程处理

之前简单介绍了如何使用agent++来实现一个代理,其中mib是直接调用add添加oid节点的,那如果想要在nsm get或者set时处理一些事物,要如何做呢?

以下是一个简单示例

#include <agent_pp/agent++.h>
#include <agent_pp/snmp_request.h>
#include <agent_pp/snmp_textual_conventions.h>
#include <snmp_pp/snmp_pp.h>

using namespace Snmp_pp;
using namespace Agentpp;

// 定义一个简单的MIB对象
class MyMibObject : public MibLeaf {

public:
    MyMibObject(const Oidx& id) : MibLeaf(id, READWRITE, new SnmpInt32(0)) {}

    void get_request(Request* req, int index) override {
        // 这里可以添加获取请求的处理逻辑
        MibLeaf::get_request(req, index);
    }

    int set(const Vbx& vb) override {
        // 这里可以添加设置请求的处理逻辑
        return MibLeaf::set(vb);
    }
};

int main() {
    // 初始化SNMP++库
    Snmp::socket_startup();

    // 创建代理实例
    Mib mib;

    // 创建并注册MIB对象
    mib.add(new MyMibObject("1.3.6.1.4.1.99999.1"));

    // 设置代理的配置(端口号、版本等)
    RequestList reqList(&mib);
    UdpAddress address("0.0.0.0/161"); // 监听所有接口,端口161
    Snmpx snmpx(SNMP_VERSION_2c, address, "public");

    // 主循环,监听并处理请求
    while (true) {
        snmpx.receive();
        reqList.process();
    }

    // 清理SNMP++库资源
    Snmp::socket_cleanup();
}

当实现使用Agent++来创建SNMP代理时,获取请求的处理逻辑是一个关键环节。在SNMP代理中,获取请求主要指的是对SNMP GET、GETNEXT、和GETBULK操作的响应。

你需要为每个你想管理的MIB(管理信息库)对象实现特定的方法来处理获取请求。通常,你会从 MibLeaf 或类似的类派生你的MIB对象类。

4.1 定义MIB对象

首先,你需要定义一个MIB对象。这个对象将代表SNMP树中的一个节点(一个OID)。

class MyMibObject : public MibLeaf {
public:
    MyMibObject(const Oidx& id) : MibLeaf(id, READONLY, new SnmpInt32(0)) {}

    void get_request(Request* req, int index) override {
        // 在这里添加处理GET请求的逻辑
        MibLeaf::get_request(req, index);
    }
};

4.2 实现GET请求的处理逻辑

get_request 方法中,你需要实现处理GET请求的逻辑。这通常涉及读取或计算该MIB对象的当前值,并将这个值返回给请求者。

void MyMibObject::get_request(Request* req, int index) {
    // 假设我们只是返回当前的值
    // 在实际应用中,这里可能会有更复杂的逻辑,比如读取硬件状态或进行计算
    MibLeaf::get_request(req, index);
}

在这个简单的例子中,我们只是调用了父类 MibLeafget_request 方法,它会自动处理返回MIB对象的当前值。在实际的应用中,你可能需要在这里添加更复杂的逻辑。

4.3 注册MIB对象

在你的主函数或代理的初始化代码中,你需要创建并注册你的MIB对象。

Mib mib;
mib.add(new MyMibObject("1.3.6.1.4.1.99999.1"));

在这里,你创建了一个 MyMibObject 实例,并将其添加到MIB中。这样,当代理收到对应的OID(在这个例子中是 "1.3.6.1.4.1.99999.1")的GET请求时,你的 get_request 方法就会被调用。

4.4 补充说明
  • 对于GETNEXT和GETBULK请求,处理逻辑类似,但可能需要额外的逻辑来确定返回哪个OID的值。
  • 确保你的代理能够正确地处理并发请求和异常情况。
  • 考虑到安全性,确保你的代理不会泄露敏感信息,并且正确处理不同类型的请求。
4.5 SNMP SET请求的处理阶段
  1. 预处理阶段 (prepare_set_request):

    • 这是处理SET请求的第一阶段。
    • 在这个阶段,通常进行参数有效性检查,例如检查提供的值是否在允许的范围内。
    • 这个阶段不应该修改任何实际的状态或数据。
  2. 提交阶段 (commit_set_request):

    • 在预处理阶段成功后,紧接着是提交阶段。
    • 这个阶段用于实际应用更改。
    • 如果这个阶段成功,更改将被保留;如果失败,将触发回滚机制。
  3. 应用阶段 (set 方法):

    • 这是最终阶段,用于实际设置值。
    • 这个阶段通常在 commit_set_request 成功之后调用。
    • 这个阶段应该保证操作的不可逆性,确保更改被应用且不会回滚。
  4. 回滚阶段 (undo_set_request):

    • 如果在提交阶段发生错误,将调用此阶段来撤销之前的更改。
    • 这是异常处理的一部分,确保系统返回到初始状态。

5.SNMP调试

调试可以使用MIB Browser或者 SNMP测试工具snmp tester 等对节点进行读写值
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
在Qt中使用snmp++可以非常方便地实现snmp操作。以下是实现snmp get操作的示例代码: ``` #include <QCoreApplication> #include <iostream> #include <snmp_pp/snmp_pp.h> using namespace std; using namespace Snmp_pp; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); int status; Snmp::socket_startup(); // 初始化socket // 创建SNMP对象 Snmp snmp(status, 0); if (status != SNMP_CLASS_SUCCESS) { cerr << "SNMP++ initialization failed: " << snmp.error_msg(status) << endl; Snmp::socket_cleanup(); // 清理socket return -1; } // 创建PDU对象 Pdu pdu; Vb vb("sysDescr.0"); pdu += vb; vb.set_oid("sysUpTime.0"); pdu += vb; // 发送SNMP GET请求 UdpAddress address("127.0.0.1/161"); // SNMP agent的IP地址和端口号 SnmpTarget target(address); target.set_version(version1); // 设置SNMP版本 target.set_retry(1); // 设置重试次数 target.set_timeout(1000); // 设置超时时间,单位为毫秒 cout << "Sending SNMP GET request..." << endl; snmp.get(pdu, target); // 处理SNMP响应 if (pdu.get_error_status() != SNMP_ERROR_SUCCESS || pdu.get_error_index() != 0) { cerr << "Error in SNMP response: " << pdu.get_error_status_text() << endl; } else { cout << "SNMP response received:" << endl; pdu.get_vb(vb, 0); cout << vb.get_printable_value() << endl; // 输出sysDescr.0的值 pdu.get_vb(vb, 1); cout << vb.get_printable_value() << endl; // 输出sysUpTime.0的值 } Snmp::socket_cleanup(); // 清理socket return a.exec(); } ``` 上述代码首先初始化了socket,并创建了一个SNMP对象。然后创建了一个PDU对象,设置了要获取的OID。接着创建了一个SnmpTarget对象,设置了SNMP agent的IP地址和端口号,以及SNMP版本、重试次数和超时时间。最后通过SNMP对象的get方法发送SNMP GET请求,并处理响应。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值