windows下安装和配置net-snmp和mib2c

时间:2021-07-04 22:22:51
 

测试snmp服务

    从\\192.168.1.222\Div_RD\_P lic\Net-Snmp   下载net-snmp-5.5.0-1.x86.exe 安装。拷贝snmptrapd.conf,snmpd.conf 到安装目录\usr\etc\snmp下。

注意修改snmpd.conf 中com2sec mynet 192.168.1.0/24 p lic

com2sec6 mynet fe80::/64 p lic 中的ip 段和本机一致。

在cmd命令行中执行snmpd p:161, p6:161

打开另一个cmd,执行snmpget -v 2c -c p lic -m all p:localhost:161 sysDescr.0

如果配置通过,将返回agent的信息。

 

Agent 命令 :snmpd p:161, p6:161

 

snmpget -v 2c -c p lic -m all p:localhost:161 sysDescr.0

snmpget -v 2c -c p lic -m all p:127.0.0.1:161 sysDescr.0

snmpget -v 2c -c p lic -m all p:192.168.1.123:161 sysDescr.0

snmpget -v 2c -c p lic -m all p6:[fe80::21f:c6ff:fe24:e2d5]:161 sysDescr.0

 

 

snmptrapd -d -f -Lo p:162, p6:162

 

snmptrap -v 2c -c p lic p:localhost:162 "" ?-SNMP-MIB:?Start

snmptrap -v 2c -c p lic p:127.0.0.1:162 "" ?-SNMP-MIB:?Start

snmptrap -v 2c -c p lic p:192.168.1.123:162 "" ?-SNMP-MIB:?Start

snmptrap -v 2c -c p lic p6:[fe80::21f:c6ff:fe24:e2d5]:162 "" ?-SNMP-MIB:?Start

 

一.安装及配置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目录。

 

 

 在命令行运行如下命令,将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 –v 2c –c p lic localhost sysDescr.0

 

       cmd> snmpset –v 2c -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

 

       TEXT L-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生成模板源代码

 

       运行以下命令:

     set MIBFILES=C:\usr\share\snmp\mibs\PROBA-MIB.txt   将新的mib文件加入环境变量,否则执行下一步时会报错

       cmd>mib2c -c mib2c.scalar.conf  probaCompName

 

       会按照模板配置文件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_reqst_info   *reqinfo,

 

                          netsnmp_reqst_info         *reqsts)

 

{

 

    /* 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 reqst at a time, so

 

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

 

  

 

    switch(reqinfo->mode) {

 

 

 

        case MODE_GET:

 

            snmp_set_var_typed_val(reqsts->reqstvb, 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_reqst_info   *reqinfo,

 

                          netsnmp_reqst_info         *reqsts)

 

{

 

    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 reqst at a time, so

 

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

 

  

 

    switch(reqinfo->mode) {

 

 

 

        case MODE_GET:

 

            snmp_set_var_typed_val(reqsts->reqstvb, 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 REQST

 

         *

 

         * 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(reqsts->reqstvb, ASN_OCTET_STR);

 

            if ( ret != SNMP_ERR_NOERROR ) {

 

                netsnmp_set_reqst_error(reqinfo, reqsts, ret );

 

            }

 

            break;

 

 

 

        case MODE_SET_RESERVE2:

 

            /* XXX malloc "undo" storage b?r */

 

            if (0/* XXX if malloc, or whatever, failed: */) {

 

                netsnmp_set_reqst_error(reqinfo, reqsts, 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 val change here */

 

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

 

                netsnmp_set_reqst_error(reqinfo, reqsts, SNMP_ERR_COMMITFAILED/* some error */);

 

            }

 

            break;

 

 

 

        case MODE_SET_COMMIT:

 

            /* XXX: delete temporary storage */

 

                     memcpy(location, reqsts->reqstvb->b, reqsts->reqstvb->val_len);

 

                     location[reqsts->reqstvb->val_len] = '\0';

 

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

 

                /* try _really_really_ hard to never get to this point */

 

                netsnmp_set_reqst_error(reqinfo, reqsts, SNMP_ERR_COMMITFAILED);

 

            }

 

            break;

 

 

 

        case MODE_SET_UNDO:

 

            /* XXX: UNDO and return to previous val for the object */

 

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

 

                /* try _really_really_ hard to never get to this point */

 

                netsnmp_set_reqst_error(reqinfo, reqsts, 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_incl es.h,添加:

 

#incl e "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节点为例:

 

   str t snmp_session session, *ss;

 

   str t snmp_pdu *pdu;

 

   str t snmp_pdu *response;

 

 

 

   oid anOID[MAX_OID_LEN];

 

   size_t anOID_len = MAX_OID_LEN;

 

 

 

   str t 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_S CESS) {

 

       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*)"p lic";

 

   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 reqst.

 

    *   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 Reqst out.

 

    */

 

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

 

 

 

   /*

 

    * Process the response.

 

    */

 

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

 

     /*

 

      * S CESS: Print the result variables

 

      */

 

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

 

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

 

     /* manip te 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("val #%d is a string: %s\n", count++, sp);

 

         free(sp);

 

       }

 

       else

 

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

 

     }

 

   } else {

 

     /*

 

      * FAILURE: print what went wrong!

 

      */

 

  

 

     if (status == STAT_S CESS)

 

       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;

 

 

 

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

 

#incl e <net-snmp/net-snmp-config.h>

 

#incl e <net-snmp/utilities.h>

 

#incl e <net-snmp/net-snmp-incl es.h>

 

链接netsnmp.lib:

 

#pragma comment(lib, "netsnmp")

 

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

 

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

 

Stdafx.h中添加:

 

#incl e <windows.h>

 

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

 

在编译的过程中发现,不仅要把net-snmp原文件夹下incl e目录添加到【附加包含目录】,还需要把win32目录也添加进去,因为win32\net-snmp\library下有一个snmpv3-security-incl es.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方法,就可以载入这些对应关系了。