Net-SNMP的agent开发

anent开发过程中主要参考这篇文章net-snmp的MIBs扩展,但是在开发的过程中遇到一些问题,在这里记录下来。

1、Net-SNMP安装

Net-SNMP的安装参考见这里

2、MIB文件

  • 这里使用参考文章作者的MIB文件,对其中的一个错误进行了修改,否则在后面使用mib2c的生成代码会与作者的不一致。
--开始
TEST-MIB DEFINITIONS ::= BEGIN

--引入部分
IMPORTS
    enterprises
        FROM RFC1155-SMI            
    Integer32,OBJECT-TYPE
        FROM SNMPv2-SMI            
    DisplayString
        FROM SNMPv2-TC
    TEXTUAL-CONVENTION
        FROM SNMPv2-TC; --引用结束,用分号


--定义节点
--enterprises的OID是1.3.6.1.4
test OBJECT IDENTIFIER ::= {enterprises 77587}

readObject  OBJECT IDENTIFIER ::= {test 1}  
writeObject OBJECT IDENTIFIER ::= {test 2}  

    readObject  OBJECT-TYPE --对象名称     --原文中为readobject
    SYNTAX      Integer32   --类型
    MAX-ACCESS read-only        --访问方式
    STATUS      current     --状态
    DESCRIPTION "test read" --描述
    ::= {test 1}                --父节点

    writeObject OBJECT-TYPE --对象名称
    SYNTAX      DisplayString   --类型
    MAX-ACCESS read-write       --访问方式
    STATUS      current     --状态
    DESCRIPTION "test write"    --描述
    ::= {test 2}                --父节点

--结束定义
END
  • 将MIB文件保存为myTest.mib,然后将myTest.mib文件放到你的MIB文件系统路径下,我的放在/usr/local/share/snmp/mibs目录下。可以使用下面两个命令来查看你的MIB系统目录:
in@v-m:~/learn$ net-snmp-config --default-mibdirs
/home/in/.snmp/mibs:/usr/local/share/snmp/mibs
in@v-m:~/learn$ snmpget  -Dparse-mibs  2>&1 | grep directory
parse-mibs: Scanning directory /home/in/.snmp/mibs
parse-mibs: cannot open MIB directory /home/in/.snmp/mibs
parse-mibs: Scanning directory /usr/local/share/snmp/mibs
  • 使用 snmptranslate 查看自定义的 TEST-MIB 是否被加载了。这里也做了写修改原文中访问test在测试时找不到节点,改为TEST-MIB:test
in@v-m:~/learn$ snmptranslate -Tp -IR TEST-MIB:test
+--test(77587)
   |
   +-- -R-- Integer32 readObject(1)
   +-- -RW- String    writeObject(2)
            Textual Convention: DisplayString
            Size: 0..255

3、产生.c和.h文件

使用mib2c命令来产生.c和.h文件

in@v-m:~/learn$ mib2c -c mib2c.int_watch.conf readObject

You didn't give mib2c a valid OID to start with.  IE, I could not find
any information about the mib node "readObject".  This could be caused
because you supplied an incorrectly node, or by the MIB that you're
trying to generate code from isn't loaded.  To make sure your mib is
loaded, run mib2c using this as an example:

   env MIBS="+MY-PERSONAL-MIB" mib2c -c mib2c.int_watch.conf readObject

You might wish to start by reading the MIB loading tutorial at:

   http://www.net-snmp.org/tutorial-5/commands/mib-options.html

And making sure you can get snmptranslate to display information about
your MIB node.  Once snmptranslate works, then come back and try mib2c
again.

并没有产生.c和.h文件,提示我们要指定MIB节点

in@v-m:~/learn$ env MIBS="+TEST-MIB" mib2c -c mib2c.int_watch.conf readObject
writing to -
*** Warning: only generating code for nodes of MIB type INTEGER
writing to readObject.h
writing to readObject.c
running indent on readObject.h
running indent on readObject.c
in@v-m:~/learn$ env MIBS="+TEST-MIB" mib2c -c mib2c.scalar.conf writeObject
writing to writeObject.h
writing to writeObject.c
running indent on writeObject.c
running indent on writeObject.h

成功产生readObject.c readObject.h writeObject.c writeObject.h

4、修改readObject.c和writeObject.c文件

4.1、修改readObject.c

修改后的readObject.c

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "readObject.h"

//这一句是mib2c生成的,默认值设为0
long    readObject = 0;  /* XXX: set default value */

void
init_readObject(void)
{
  netsnmp_handler_registration *reg;

    const oid readObject_oid[] = { 1,3,6,1,4,1,77587,1 };
  static netsnmp_watcher_info readObject_winfo;

  DEBUGMSGTL(("readObject", "Initializing the readObject module\n"));

/******************************************************/
    //这里是我修改的,以便于验证其有效
    readObject = 12345;

/******************************************************/
    DEBUGMSGTL(("readObject",
                "Initializing readObject scalar integer.  Default value = %ld\n",
                readObject));
    reg = netsnmp_create_handler_registration(
             "readObject", NULL,
              readObject_oid, OID_LENGTH(readObject_oid),
              HANDLER_CAN_RONLY);
    netsnmp_init_watcher_info(&readObject_winfo, &readObject, sizeof(long),
                  ASN_INTEGER, WATCHER_FIXED_SIZE);
if (netsnmp_register_watched_scalar( reg, &readObject_winfo ) < 0 ) {
        snmp_log( LOG_ERR, "Failed to register watched readObject" );
    }

  DEBUGMSGTL(("readObject",
              "Done initalizing readObject module\n"));
}
4.2、修改writeObject.c

修改后的writeObject.c

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "writeObject.h"

//这里是添加的,buf用于保存控制端设置的值,也用于返回。
#define BUFSIZE 1024
static char buf[BUFSIZE] = "test Write";    //给一个默认值



/** Initializes the writeObject module */
void
init_writeObject(void)
{
    const oid writeObject_oid[] = { 1,3,6,1,4,1,77587,2 };

  DEBUGMSGTL(("writeObject", "Initializing\n"));

    netsnmp_register_scalar(
        netsnmp_create_handler_registration("writeObject", handle_writeObject,
                               writeObject_oid, OID_LENGTH(writeObject_oid),
                               HANDLER_CAN_RWRITE
        ));
}

int
handle_writeObject(netsnmp_mib_handler *handler,
                          netsnmp_handler_registration *reginfo,
                          netsnmp_agent_request_info   *reqinfo,
                          netsnmp_request_info         *requests)
{
    int ret;

    switch(reqinfo->mode) {
    //是获取操作
        case MODE_GET:
            snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
             /*这里填buf,用于返回数据给控制端*/      buf  /* XXX: a pointer to the scalar's data */,
             /*这里是buf数据字节数,注意writeObject类型*/ strlen(buf)  /* XXX: the length of the data in bytes */);
            break;

        /*
         * SET REQUEST
         *
         * multiple states in the transaction.  See:
         * http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg
         */
    //下面是设置操作的,也就是snmpset

        case MODE_SET_RESERVE1: //这个不管它
                /* or you could use netsnmp_check_vb_type_and_size instead */
            ret = netsnmp_check_vb_type(requests->requestvb, ASN_OCTET_STR);
            if ( ret != SNMP_ERR_NOERROR ) {
                netsnmp_set_request_error(reqinfo, requests, ret );
            }
            break;

        case MODE_SET_RESERVE2: //这个也不管它
            /* XXX malloc "undo" storage buffer */
            //我们不需要动态申请内存,直接略过
            if ( 0 /* XXX if malloc, or whatever, failed: */) {
                netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_RESOURCEUNAVAILABLE);
            }
            break;

        case MODE_SET_FREE:
            /* XXX: free resources allocated in RESERVE1 and/or
               RESERVE2.  Something failed somewhere, and the states
               below won't be called. */
            break;

    /****************************************************************/
    //  这里是我们的重点,控制端传过来的数据就在这里获取

        case MODE_SET_ACTION:
            /* XXX: perform the value change here */
            /* 获取控制端使用snmpset传来的数据 */
            memcpy(buf,requests->requestvb->buf,requests->requestvb->val_len);

            if (0/* XXX: error? */) {   //这个先不管了
                netsnmp_set_request_error(reqinfo, requests, 0 /* some error */);
            }
            break;
//下面的都不管了
        case MODE_SET_COMMIT:
            /* XXX: delete temporary storage */
            if (0 /* XXX: error? */) {
                /* try _really_really_ hard to never get to this point */
                netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_COMMITFAILED);
            }
            break;

        case MODE_SET_UNDO:
            /* XXX: UNDO and return to previous value for the object */
            if (0 /* XXX: error? */) {
                /* try _really_really_ hard to never get to this point */
                netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED);
            }
            break;

        default:
            /* we should never get here, so this is a really bad error */
            snmp_log(LOG_ERR, "unknown mode (%d) in handle_writeObject\n", reqinfo->mode );
            return SNMP_ERR_GENERR;
    }

    return SNMP_ERR_NOERROR;
}

5、编译.c和.h文件

编译的时候需要使用到另一个工具 net-snmp-config 。这个工具用来做两件事,一个是生成中间代码,然后使用gcc来编译它。
为什么要生成中间代码呢?你看上面的生存的 readObject.c 中没有main函数就知道了吧。中间代码包含有main函数,在中间代码中实现了对agent的初始化,mib的初始化等。
具体使用如下
net-snmp-config --compile-subagent readObject readObject.c

  • –compile-subagent的意思是编译为subagent程序。
  • readObject是编译后输出程序名
  • readObject.c是要编译的文件
  • 还可以加上 –norm 参数来阻止编译后删除生成的中间代码文件。我们可以试一下。
in@v-m:~/learn$ net-snmp-config --compile-subagent readObject readObject.c
generating the temporary code file: netsnmptmp.39742.c
void init_readObject(void);
checking for init_readObject in readObject.c
init_readObject(void)
checking for shutdown_readObject in readObject.c
running: gcc  -fno-strict-aliasing -g -O2 -Ulinux -Dlinux=linux  -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64  -I/usr/lib/x86_64-linux-gnu/perl/5.22/CORE   -I. -I/usr/local/include -o readObject netsnmptmp.39742.c  readObject.c -lsensors -L/usr/local/lib -lnetsnmpmibs -lnetsnmpagent -lnetsnmp -lnetsnmpmibs -lsensors -ldl  -lnetsnmpagent  -Wl,-E -lnetsnmp  -lcrypto 
In file included from /usr/local/include/net-snmp/output_api.h:64:0,
                 from /usr/local/include/net-snmp/library/snmp_client.h:32,
                 from /usr/local/include/net-snmp/varbind_api.h:102,
                 from /usr/local/include/net-snmp/library/snmp_api.h:28,
                 from /usr/local/include/net-snmp/types.h:421,
                 from /usr/local/include/net-snmp/definitions.h:22,
                 from /usr/local/include/net-snmp/net-snmp-includes.h:67,
                 from readObject.c:7:
readObject.c: In function ‘init_readObject’:
readObject.c:53:17: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long int’ [-Wformat=]
                 "Initializing readObject scalar integer.  Default value = %d\n"
                 ^
readObject.c:53:17: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long int’ [-Wformat=]
                 "Initializing readObject scalar integer.  Default value = %d\n"
                 ^
removing the temporary code file: netsnmptmp.39742.c
subagent program readObject created
in@v-m:~/learn$ net-snmp-config --compile-subagent writeObject writeObject.c
generating the temporary code file: netsnmptmp.39906.c
void init_writeObject(void);
checking for init_writeObject in writeObject.c
init_writeObject(void)
checking for shutdown_writeObject in writeObject.c
running: gcc  -fno-strict-aliasing -g -O2 -Ulinux -Dlinux=linux  -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64  -I/usr/lib/x86_64-linux-gnu/perl/5.22/CORE   -I. -I/usr/local/include -o writeObject netsnmptmp.39906.c  writeObject.c -lsensors -L/usr/local/lib -lnetsnmpmibs -lnetsnmpagent -lnetsnmp -lnetsnmpmibs -lsensors -ldl  -lnetsnmpagent  -Wl,-E -lnetsnmp  -lcrypto 
removing the temporary code file: netsnmptmp.39906.c
subagent program writeObject created

产生readObjectwriteObject可执行文件。

6、agent测试之前

在启动主代理之前我们还要修改配置文件snmpd.conf,在文件中增加master agentx这行代码,开启子代理

rocommunity public
rwcommunity private
trapcommunity public
master agentx

启动主代理,可以看到打开主代理对子代理的支持,如果snmpd.conf中没有增加这句话的话,是没有第一条的打印的。其中-Le -f是打开调试,也可不带这两个参数。

in@v-m:~/learn$ sudo snmpd -Le -f
Turning on AgentX master support.
NET-SNMP version 5.7.3

7、readObject测试

打开一个新的终端串口,启动子代理(启动时要以管理员权限运行否则会提示Warning: Failed to connect to the agentx master agent ([NIL]):,有提示也是需要运行是加-Le -f打开调试才会输出的,如果没有打开调试,则会正常运行什么输出也没有,但当你使用snmpget -v 2c -c public localhost 1.3.6.1.4.1.77587.1.0访问readObject节点时会出现SNMPv2-SMI::enterprises.77587.1.0 = No Such Object available on this agent at this OID这样的提示。)
所以正确启动子代理的命令如下,其中-Le -f是打开调试选项。

in@v-m:~/learn$ sudo ./readObject -Le -f
NET-SNMP version 5.7.3 AgentX subagent connected

在打开一个新的窗口,使用snmpget命令测试。

in@v-m:~$ snmpget -v 2c -c public localhost 1.3.6.1.4.1.77587.1.0
SNMPv2-SMI::enterprises.77587.1.0 = INTEGER: 12345

也可这样写去访问readObject节点:

in@v-m:~$ snmpget -v 2c -c public localhost TEST-MIB:readObject.0
TEST-MIB::readObject.0 = INTEGER: 12345

原文中节点写的是1.3.6.1.4.1.77587.1这样写,但不能正确访问,提示如下:

in@v-m:~$ snmpget -v 2c -c public localhost 1.3.6.1.4.1.77587.1
SNMPv2-SMI::enterprises.77587.1 = No Such Instance currently exists at this OID

readObject节点测试完了,下面开始测试writeObject节点。

8、writeObject测试

启动writeObject子代理服务:

in@v-m:~/learn$ sudo ./writeObject -Le -f
NET-SNMP version 5.7.3 AgentX subagent connected
8.1、writeObject读测试

使用snmpget命令测试writeObject节点的读。

in@v-m:~$ snmpget -v 2c -c public localhost 1.3.6.1.4.1.77587.2.0
SNMPv2-SMI::enterprises.77587.2.0 = STRING: "test Wriet"

或者

in@v-m:~$ snmpget -v 2c -c public localhost TEST-MIB:writeObject.0
TEST-MIB::writeObject.0 = STRING: test Wriet

原文中的写法还是不能正确获取结果,提示如下:

in@v-m:~$ snmpget -v 2c -c public localhost writeObject.0
writeObject.0: Unknown Object Identifier (Sub-id not found: (top) -> writeObject)
8.2、writeObject写测试

使用snmpset命令测试writeObject节点的写。

in@v-m:~$ snmpset -v 2c -c private localhost TEST-MIB:writeObject.0 s "Hello Net-SNMP"
TEST-MIB::writeObject.0 = STRING: Hello Net-SNMP

注意:-c后面的共同体是private,否则会出现下面的错误。

in@v-m:~$ snmpset -v 2c -c public localhost TEST-MIB:writeObject.0 s "Hello Net-SNMP"
Error in packet.
Reason: noAccess
Failed object: TEST-MIB::writeObject.0

设置成功后再次用snmpget查看节点内容,节点字符串已经是我们设置的值了。

in@v-m:~$ snmpget -v 2c -c public localhost TEST-MIB:writeObject.0
TEST-MIB::writeObject.0 = STRING: Hello Net-SNMP
  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SNMP Agent源码是指基于SNMP协议的网络管理协议代理程序源代码。SNMP是一种用于管理网络设备的协议,通过SNMP Agent可以对网络设备进行监控、管理和配置,是目前网络管理中比较常用的一种协议。SNMP Agent源码主要用于开发SNMP协议代理程序,实现网络设备的监控和管理。SNMP Agent源码是复杂的、庞大的,因为SNMP协议涉及的领域很广,需要实现大量的功能模块。 SNMP Agent源码中包含了大量的代码和库文件,用于实现SNMP协议的各种功能。其中包括对SNMP协议的解析和构建、对SNMP消息的处理和转发、对网络设备的数据采集和监控等。此外,SNMP Agent源码还包含了多种通信模式的实现,如UDP、TCP、SNMP over IPv6等。因此,SNMP Agent源码需要开发者具备一定的网络编程和数据结构知识,同时对SNMP协议有一定的了解。 在开发SNMP Agent源码时,需要注意以下几点:首先,需要根据实际需求进行模块划分,将整个程序分为多个模块,方便后期维护和扩展。其次,需要充分考虑程序的可靠性和安全性,防止攻击者利用SNMP协议进行网络攻击。最后,还需要进行充分的测试工作,确保程序的稳定性和可靠性。 综上所述,SNMP Agent源码是实现SNMP协议代理程序的关键,对于网络管理和监控至关重要。开发SNMP Agent源码需要充分理解SNMP协议的原理和功能,掌握网络编程和数据结构知识,同时注重程序的可靠性、安全性和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值