net-snmp配置开发及注意事项

一.安装及配置 SNMP win32 环境)

1. 下载

www.sourceforge.net 下载到最新的 net-snmp (目前最新版本 5.4.1 net-snmp-5.4.1.zip

2. 解压编译

解压后,可以看到有 一个 win32 目 录,里面存放的是和 win32 环境相关的文件,有 3 dsw

       libsdll.dsw             编译 lib 文件和 dll 文件的工程

       win32.dsw            编译 lib 文件和工具文件如 snmpget,snmpset 的工程

       win32sdk.dsw              类似于 win32.dsw ,区别在于:需要安装 Platform SDK 。如果需要 agent 能支持 interfaces 等一些高级功能,必须 用此工程编译。 XPSP2 Platform SDK 的下载地址

http://www.microsoft.com/msdownload/platformsdk/sdkupdate/XPSP2FULLInstall.htm

       只需要安装 Core SDK 就可以了,安装完后需要从开始菜单中 Register 一下。

       注意编译的顺序,最好先编译 libsdll.dsw ,把 netsnmp.lib netsnmpagent.lib netsnmphelpers.lib netsnmpmibs.lib netsnmptrapd.lib 文件先编译好,再编译 win32sdk.dsw 中的项目。

3. 安装

运行 win32 目录下的 install-net-snmp.bat 批 处理文件,会把上一步编译生成的文件及相关的头文件等拷贝到 c:/usr 目录。

4. 配置

       c:/usr/etc/snmp 目录添加配置文件 snmpd.conf ,添加如下内容:

rocommunity  public

rwcommunity  private

       它表示的含义是,启动 agent 服务后,通过 public 共同体是只读的, private 共同体可读也可写。

       在命令行运行如下命令,将 snmp 注册为 windows 的服务:

              cmd>”C:/usr/bin/snmpd.exe” –register -Lf "C:/usr/log/snmpd.log"

       注册成功后可以在【控制面板】 -> 【管理工具】 -> 【服务】中看到刚注册的服务,服务名是: net-snmp agent

5. 运行

       cmd>net start “net-snmp agent”

       如果正常,会得到启动服务成功的提示

6. 验证

       cmd>snmpget –v2c –c public localhost 1.3.6.1.2.1.1.5.0

       cmd> snmpset -v2c -c private localhost sysContact.0 = piyeyong

       如果正常,会的到取得和设置成功的提示,出错会给出 错误提示。

二. MIB 文件编写

       MIB 文件会存放于 C:/usr/share/snmp/mibs/ 目录下,是 *.txt ,纯文本文件,可以直接打开查看和更改。 RFC1213 中定义的 MIB 节点信息的定义存放与 RFC1213-MIB.txt ,这些节点是比较重要的,会经常用到。

       如果要扩展 MIB ,应该定义在 1.3.6 .1.4.1(.iso.org.dod.internet.private.enterprises) 子树下。自定义 MIB 的节点,只需要描述该节点的 SYNTAX ACCESS STATUS DESCRIPTION 等属性及它属于父节点的第几个子节点即可。如下所示,为扩展 MIB 的一个简单例子:

PROBA-MIB DEFINITIONS::=BEGIN

       IMPORTS     

              enterprises,OBJECT-TYPE,Integer32,TimeTicks

                    FROM SNMPv2-SMI

       TEXTUAL-CONVENTION,  DisplayString FROM SNMPv2-TC;

 

-- proba node

       proba OBJECT IDENTIFIER::={enterprises 8888}

 

baseinfo     OBJECT IDENTIFIER ::= { proba 1 }

 

-- company name

       probaCompName OBJECT-TYPE

              SYNTAX DisplayString (SIZE (0..255))

               ACCESS read-only

              STATUS mandatory

              DESCRIPTION "The Name of company"

              ::={baseinfo 1}

 

-- company location

       probaLocation OBJECT-TYPE

              SYNTAX DisplayString (SIZE (0..255))

               ACCESS read-write

              STATUS mandatory

              DESCRIPTION "The Location of company"

              ::={baseinfo 2}

             

-- employee number

       probaEmployeeNumber OBJECT-TYPE

              SYNTAX INTEGER

              ACCESS read-only

              STATUS mandatory

              DESCRIPTION "The number of employee"

              ::={baseinfo 3}

END

三. Agent 端开发

       在上一步中定义好 MIB 的结构后,现在就开始编码实现定义好的节点。 net-snmp 提供了一个 MIB2C 工具,利用它可以根据 MIB 的定义和配置文件自动生成 *.c *.h 模板文件,然后只需要在相应位置添加对节点数据的处理就可以了。

1. 配置 net-snmp perl 模块

       用使用 mib2c 工具,需要 perl 模块的支持,可以从 http://www.ActiveState.com/ActivePerl 下载,目前最新版是 5.8.8

       net-snmp 源文件的 perl 目录下,运行以下命令:

       cmd>perl makefile.pl

如果成功,会生成 makefile 文件

cmd>nmake

cmd>nmake install

       这时,会将 net-snmp 相关的 perl 模块编译好并安装到 c:/perl/site/lib 目录下。

       注:有时候运行 nmake 会失败,把其它机器上安装好的 c:/perl/site/lib 目录下的文件拷贝过来,也可以运行。

2. mib2c 生成模板源代码

       运行以下命令:

       cmd>mib2c -c mib2c.scalar.conf baseinfo

       会按照模板配置文件 mib2c.scalar.conf 生成 baseinfo.h baseinfo.c 文件。注意: baseinfo 是上一步在 MIB 中定义的 proba 下的一个节点。在 baseinfo.c 中有很多 /* XXX 注释 */ 的地方,这些地方是需要我们修改,填上我们对节点数据的处理代码。

3. read-only 节点的代码修改

       probaCompName 节点为例:

int

handle_probaCompName(netsnmp_mib_handler *handler,

                          netsnmp_handler_registration *reginfo,

                          netsnmp_agent_request_info   *reqinfo,

                          netsnmp_request_info         *requests)

{

    /* We are never called for a GETNEXT if it's registered as a

       "instance", as it's "magically" handled for us.  */

 

    /* a instance handler also only hands us one request at a time, so

       we don't need to loop over a list of requests; we'll only get one. */

   

    switch (reqinfo->mode) {

 

        case MODE_GET:

            snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,

                                     (u_char *) "proba" /* XXX: a pointer to the scalar's data */ ,

                                     strlen( "proba" ) /* XXX: the length of the data in bytes */ );

            break ;

 

 

        default :

            /* we should never get here, so this is a really bad error */

            snmp_log(LOG_ERR, "unknown mode (%d) in handle_probaCompName/n" , reqinfo->mode );

            return SNMP_ERR_GENERR;

    }

 

    return SNMP_ERR_NOERROR;

}

       从上面的代码看出,只需在两处 /* XXX 注释 */ 的代码处 填上这个节点的数据即可,管理站在执行 get 命令时这个值会返回给管理站。

4. read-write 节 点的代码修改

       probaLocation 节点为例:

 

static char location[256];

void

init_baseinfo( void )

{

       memset(location, '/0' , sizeof location);

       memcpy(location, "beijing" , sizeof "beijing" );

       。。。。。。

}

int

handle_probaLocation(netsnmp_mib_handler *handler,

                          netsnmp_handler_registration *reginfo,

                          netsnmp_agent_request_info   *reqinfo,

                          netsnmp_request_info         *requests)

{

    int ret;

 

    /* We are never called for a GETNEXT if it's registered as a

       "instance", as it's "magically" handled for us.  */

 

    /* a instance handler also only hands us one request at a time, so

       we don't need to loop over a list of requests; we'll only get one. */

   

    switch (reqinfo->mode) {

 

        case MODE_GET:

            snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,

                                      (u_char *)location /* XXX: a pointer to the scalar's data */ ,

                                     strlen(location) /* 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

         */

        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 */

            if (0 /* XXX: error? */ ) {

                netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_COMMITFAILED /* some error */ );

            }

            break ;

 

        case MODE_SET_COMMIT:

            /* XXX: delete temporary storage */

                     memcpy(location, requests->requestvb->buf, requests->requestvb->val_len);

                     location[requests->requestvb->val_len] = '/0' ;

            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_probaLocation/n" , reqinfo->mode );

            return SNMP_ERR_GENERR;

    }

 

    return SNMP_ERR_NOERROR;

}

对于 read-write 节点的处理要复杂一点,对每一次管理站的 set 请求,代理站的处理会经过如下图所示的步骤:

       从图中可以看出,通过这种机制,在处理出错的时候,可以根据需要实现回滚操作。

5. 重新编译

       按照一下步骤重新编译工程:

       1 )把 baseinfo.h baseinfo.c 文件拷贝到 net-snmp 源文件下 agent/mibgroup 目录下;

2 )打开 win32sdk ,将其添加到 netsnmpmibssdk 工程;

3 )打开 net-snmp 源文件下 win32 目录下的 mib_module_includes.h ,添加:

#include "mibgroup/proba/baseinfo.h"

       4 )打开 net-snmp 源文件下 win32 目录下的 mib_module_inits.h ,添加:

                if (should_init("baseinfo")) init_baseinfo();

       5 )重新编译 netsnmpmibssdk 工程和 snmpdsdk 工程,把生成的 snmpd.exe 拷贝到 c:/usr/bin netsnmpmibs.lib 拷贝到 c:/usr/lib

四.管理站开发

以获取 sysName 节点为 例:

   struct snmp_session session, *ss;

   struct snmp_pdu *pdu;

   struct snmp_pdu *response;

 

   oid anOID[MAX_OID_LEN];

   size_t anOID_len = MAX_OID_LEN;

  

   struct variable_list *vars;

   int status;

 

   /*

    * Initialize the SNMP library

    */

   init_snmp( "snmpapp" );

 

    /*

    * Initialize a "session" that defines who we're going to talk to

    */

   snmp_sess_init( &session );                   /* set up defaults */

   session.peername = "localhost" ;

  

   /* set up the authentication parameters for talking to the server */

  

   #ifdef DEMO_USE_SNMP_VERSION_3

  

   /* Use SNMPv3 to talk to the experimental server */

  

   /* set the SNMP version number */

   session.version=SNMP_VERSION_3;

       

   /* set the SNMPv3 user name */

    session.securityName = strdup("MD5User");

   session.securityNameLen = strlen(session.securityName);

  

   /* set the security level to authenticated, but not encrypted */

   session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;

  

   /* set the authentication method to MD5 */

   session.securityAuthProto = usmHMACMD5AuthProtocol;

   session.securityAuthProtoLen = sizeof(usmHMACMD5AuthProtocol)/sizeof(oid);

   session.securityAuthKeyLen = USM_AUTH_KU_LEN;

   

   /* set the authentication key to a MD5 hashed version of our

      passphrase "The Net-SNMP Demo Password" (which must be at least 8

      characters long) */

   if (generate_Ku(session.securityAuthProto,

                   session.securityAuthProtoLen,

                   (u_char *) our_v3_passphrase, strlen(our_v3_passphrase),

                   session.securityAuthKey,

                   &session.securityAuthKeyLen) != SNMPERR_SUCCESS) {

       snmp_perror(argv[0]);

       snmp_log(LOG_ERR,

                "Error generating Ku from authentication pass phrase. /n");

       exit(1);

   }

  

   #else /* we'll use the insecure (but simplier) SNMPv1 */

  

   /* set the SNMP version number */

   session.version = SNMP_VERSION_1;

  

   /* set the SNMPv1 community name used for authentication */

   session.community = (u_char*) "public" ;

   session.community[6] = '/0' ;

   session.community_len = 6;

  

   #endif /* SNMPv1 */

 

   /* windows32 specific initialization (is a noop on unix) */

   SOCK_STARTUP;

  

   /*

    * Open the session

    */

   ss = snmp_open(&session);                     /* establish the session */

 

   if (!ss) {

       snmp_perror( "ack" );

       snmp_log(LOG_ERR, "something horrible happened!!!/n" );

       exit(2);

   }

 

   /*

    * Create the PDU for the data for our request.

    *    1) We're going to GET the system.sysDescr.0 node.

    */

   pdu = snmp_pdu_create(SNMP_MSG_GET);

 

   read_objid( ".1.3.6.1.2.1.1.5.0" , anOID, &anOID_len);

   //get_node("sysDescr.0", anOID, &anOID_len);

 

   snmp_add_null_var(pdu, anOID, anOID_len);

 

   /*

    * Send the Request out.

    */

   status = snmp_synch_response(ss, pdu, &response);

 

   /*

    * Process the response.

    */

   if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) {

     /*

      * SUCCESS: Print the result variables

      */

     for (vars = response->variables; vars; vars = vars->next_variable)

       print_variable(vars->name, vars->name_length, vars);

     /* manipuate the information ourselves */

     for (vars = response->variables; vars; vars = vars->next_variable) {

       int count=1;

       if (vars->type == ASN_OCTET_STR) {

         char *sp = ( char *)malloc(1 + vars->val_len);

         memcpy(sp, vars->val.string, vars->val_len);

         sp[vars->val_len] = '/0' ;

         printf( "value #%d is a string: %s/n" , count++, sp);

         free(sp);

       }

       else

         printf( "value #%d is NOT a string! Ack!/n" , count++);

     }

   } else {

     /*

      * FAILURE: print what went wrong!

      */

   

     if (status == STAT_SUCCESS)

       fprintf(stderr, "Error in packet/nReason: %s/n" ,

               snmp_errstring(response->errstat));

     else

       snmp_sess_perror( "snmpget" , ss);

   

   }

 

   /*

    * Clean up:

    *  1) free the response.

    *  2) close the session.

    */

   if (response)

     snmp_free_pdu(response);

   snmp_close(ss);

   

   /* windows32 specific cleanup (is a noop on unix) */

   SOCK_CLEANUP;

  

注意:需要引用以 下头文件:

#include <net-snmp/net-snmp-config.h>

#include <net-snmp/utilities.h>

#include <net-snmp/net-snmp-includes.h>

链接netsnmp.lib:

#pragma comment ( lib , "netsnmp" )

    使用的编译环境为VC++2005.net

需要把netsnmp.lib 所在的目录添加到【附加库目录】中,Release 版 的【代码生成】-> 【运行时库】选择【多线程 DLL (/MD) 】,Debug 版选择【多线程调试 DLL (/MDd) 】;

Stdafx.h 中添加:

#include <windows.h>

    MFC 的 使用】选择【使用标准 Windows 库】

在编译的过程中发 现,不仅要把net-snmp 原文件夹下include 目 录添加到【附加包含目录】,还需要把win32 目录也添加进去,因为win32/net-snmp/library 下有一个snmpv3-security-includes.h 文 件。

五.其它注意事项

1.        如果是采用下载可执行文件安装 net-snmp 时, Net-SNMP Agent Service 项选择 Standard agent ,否则无法从管理器上读取到 Agent System 等节点下的信息。

使用 SNMP++ 提供的一个 C# 组件。控制面板添加安装组件中添加 SNMP 组件后, system32 目录下会增加许多 *.mib 文件,如 dhcp.mib ,这些文件是 mib 库,存放的是 OID 与名字和描述的对应关系,相当于 DNS 。有了这些文件,在 SNMP++.net 开发包中,调用 MIB 类的 loadDirectoryMib 方法,就可以载入这些对应关系了。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值