当前位置: 首页 > 工具软件 > Net-snmp > 使用案例 >

【Net-Snmp学习笔记二——添加自定义MIB文件】

龙佐
2023-12-01

上一篇文章(学习笔记一)我们已经实现Net-Snmp源码的编译安装,并且测试了snmpd服务,不过我们是获取的默认的MIB文件参数值,今天我们进行添加一个自定义的MIB文件。

1.编写MIB文件

既然是添加自定义MIB文件,那么首先我们就要先编写一个MIB文件!这里我先给出我自己简单的MIB文件,存放位置放在"/home/lijun/net-snmp-5.9.3/out/share/snmp/mibs"(总之就是放在安装net snmp 位置下的share/snmp/mibs文件夹)。

MY-TEST-MIB DEFINITIONS ::= BEGIN 

IMPORTS 
	enterprises, OBJECT-TYPE, MODULE-IDENTITY
		FROM SNMPv2-SMI
	DisplayString
		FROM SNMPv2-TC;
		
Test MODULE-IDENTITY ::= { enterprises 9527}
	
Time OBJECT IDENTIFIER ::= { Test 1 }
	
GetTime OBJECT-TYPE
	SYNTAX DisplayString 
	MAX-ACCESS read-only
	STATUS current
	DESCRIPTION
		"Example : 2022/12/09"
::= { Time 1 }

END 

1.1 MIB 文件的开始和结束

所有的MIB file的都以DEFINITIONS ::= BEGIN关键字开始,以END结束。我们所有添加的节点均应在此之间

MY-TEST-MIB DEFINITIONS::=BEGIN
...
...
END

1.2 模板引用区域

在MIB开始关键字后,即是模块引用区域,利用IMPORTS标识,所有的模块引用及群组的引用均使用FROM关键字说明其出处,引用使用分号(;)结束

MY-TEST-MIB DEFINITIONS ::= BEGIN 

IMPORTS 
	enterprises, OBJECT-TYPE, MODULE-IDENTITY
		FROM SNMPv2-SMI
	DisplayString
		FROM SNMPv2-TC;
...
...

END 

1.3 公共标示段顶层描述

MODULE-IDENTITY ,该定义添加了一个公共的标示段来对整个信息描述块进行顶层的文字描述,以加强对管理MIB描述块的文档管理和控制,每个MIB定义中都会有该定义。

MY-TEST-MIB DEFINITIONS ::= BEGIN 

IMPORTS 
	enterprises, OBJECT-TYPE, MODULE-IDENTITY
		FROM SNMPv2-SMI
	DisplayString
		FROM SNMPv2-TC;
		
Test MODULE-IDENTITY ::= { enterprises 9527 }
	
...

END 

1.4 对象标识

对象标识用关键字OBJECT IDENTIFIER声明,它的主要功能是用来将一类功能的对象结合起来。展开或折叠此对象标识即可展开或折叠此类功能的所有对象。 在ASN.1中,对象标识符类型描述对象的抽象信息,MIB树中的每一个标号是用对象标识符描述的。(声明一个Time 节点, Time是一个子树支,它定义在Test树支下,“9527” 是子树Time 在父树Test下的一个唯一对象标识符。 )

MY-TEST-MIB DEFINITIONS ::= BEGIN 

IMPORTS 
	enterprises, OBJECT-TYPE, MODULE-IDENTITY
		FROM SNMPv2-SMI
	DisplayString
		FROM SNMPv2-TC;
	
	Test MODULE-IDENTITY ::= { enterprises 9527 }
	
	Time OBJECT IDENTIFIER ::= { Test 1 }
	
	...
END 

1.5 标量节点

在每一个树支下,可以定义被管理资源的管理对象,其中一类是标量节点(直观地看象树叶的节点)。利用OBJECT-TYPE定义。其定义的句法如下:

ObjName OBJECT-TYPE
	SYNTAX DisplayString 
    MAX-ACCESS read-only
    STATUS current
    DESCRIPTION
::= { ${parent} ${number} }
关键字说明备注
ObjName被管理的对象名字
OBJECT-TYPE每一个叶子对象所必须的关键字
syntax被管理对象类型的关键字Counter(计数) Gauge(标准) DisplayString(显示字符串) Interger(整数) TimeTicks(时间戳)NetworkAddress(网络地址) IpAddress(Ipv4地址)
access该节点支持的访问方式read-only(只读) read-write(读写) read-create(读和创建) no-accessible(不可访问)
status该节点的状态current (当前的) deprecated (反对的) obsolete(废弃的)
description对被管理对象的功能、特征等进行描述的关键字

最后将MIB文件补充完整:

MY-TEST-MIB DEFINITIONS ::= BEGIN 
IMPORTS 
	enterprises, OBJECT-TYPE, MODULE-IDENTITY
		FROM SNMPv2-SMI
	DisplayString
		FROM SNMPv2-TC;
		
	Test MODULE-IDENTITY ::= { enterprises 9527}
	
	Time OBJECT IDENTIFIER ::= { Test 1 }
	
	GetTime OBJECT-TYPE
		SYNTAX 		DisplayString 
		MAX-ACCESS 	read-only
		STATUS 		current
		DESCRIPTION
					"Example : 2022/12/09"
	::= { Time 1 }
END 

2. 使用snmpdtranslate工具查看文件格式

使用snmpdtranslate工具查看MIB文件格式是否正确:

# MY-TEST-MIB 是我们编写的MIB文件名
# Test 对象的顶层描述
[root@hecs-332420 net-snmp-5.9.3]# cd ./out/bin/
[root@hecs-332420 bin]# ./snmptranslate -Tp -IR MY-TEST-MIB::Test
Expected LAST-UPDATED (:): At line 8 in /home/lijun/net-snmp-5.9.3/out/share/snmp/mibs/MY-TEST-MIB.txt
+--Test(9527)
   |
   +--Time(1)
      |
      +-- -R-- String    GetTime(1)
               Textual Convention: DisplayString
               Size: 0..255
[root@hecs-332420 bin]#

3. 使用mib2c工具

我们需要将MIB文件转换为 .c 文件,这里就需要使用到mib2c工具,如上第三步configure配置时携带了--disable-scripts这一项,那么在我们 out/bin 路径下不会有mib2c工具,但是在源码路径下的local文件夹中存在mib2c,我们可以使用这个,先查看mib2c工具是否可用。

[root@hecs-332420 net-snmp-5.9.3]# cd ./local
[root@hecs-332420 local]# ./mib2c -h
./mib2c [-h] [-c configfile] [-f prefix] mibNode

  -h            This message.

  -c configfile Specifies the configuration file to use
                that dictates what the output of mib2c will look like.

  -I PATH       Specifies a path to look for configuration files in

  -f prefix     Specifies the output prefix to use.  All code
                will be put into prefix.c and prefix.h

  -d            debugging output (don't do it.  trust me.)

  -S VAR=VAL    Set $VAR variable to $VAL

  -i            Don't run indent on the resulting code

  -s            Don't look for mibNode.sed and run sed on the resulting code

  mibNode       The name of the top level mib node you want to
                generate code for.  By default, the code will be stored in
                mibNode.c and mibNode.h (use the -f flag to change this)

# 如果出现如下错误,就说明没有安装perl模块(在./configure配置时需要加上 --with-perl-modules)
# ERROR: You don't have the SNMP perl module installed.  Please obtain
# this by getting the latest source release of the net-snmp toolkit from
# http://www.net-snmp.org/download/ .  Once you download the source and
# unpack it, the perl module is contained in the perl/SNMP directory.
# See the README file there for instructions.

确定mib2c可用时,再将MIB文件转换为c文件,命令如下:env MIBS=“+/home/lijun/net-snmp-5.9.3/out/share/snmp/mibs/MY-TEST-MIB.txt” ./mib2c Test ;这里MIBS后的路径需要指定自己的路径位置,先选择2,再选择1。

[root@hecs-332420 local]# env MIBS="+/home/lijun/net-snmp-5.9.3/out/share/snmp/mibs/MY-TEST-MIB.txt" ./mib2c Test
Expected LAST-UPDATED (:): At line 8 in /home/lijun/net-snmp-5.9.3/out/share/snmp/mibs/MY-TEST-MIB.txt
writing to -
mib2c has multiple configuration files depending on the type of
code you need to write.  You must pick one depending on your need.

You requested mib2c to be run on the following part of the MIB tree:
  OID:                              Test
  numeric translation:              .1.3.6.1.4.1.9527
  number of scalars within:         1
  number of tables within:          0
  number of notifications within:   0

First, do you want to generate code that is compatible with the
ucd-snmp 4.X line of code, or code for the newer Net-SNMP 5.X code
base (which provides a much greater choice of APIs to pick from).  You
can also generate C-header files containing define statements for
column numbers, enums, etc.  Or do you simply want to translate the
MIB structures into documentation?

  1) ucd-snmp style code
  2) Net-SNMP style code
  3) Generate header files
  4) Generate documentation

Select your choice : 2

**********************************************************************
                 GENERATING CODE FOR SCALAR OBJECTS:
**********************************************************************

  It looks like you have some scalars in the mib you requested, so I
  will now generate code for them if you wish.  You have two choices
  for scalar API styles currently.  Pick between them, or choose not
  to generate any code for the scalars:

  1) If you're writing code for some generic scalars
     (by hand use: "mib2c -c mib2c.scalar.conf Test")

  2) If you want to magically "tie" integer variables to integer
     scalars
     (by hand use: "mib2c -c mib2c.int_watch.conf Test")

  3) Don't generate any code for the scalars

Select your choice: 1
    using the mib2c.scalar.conf configuration file to generate your code.
writing to Test.h
writing to Test.c



**********************************************************************
* NOTE WELL: The code generated by mib2c is only a template.  *YOU*  *
* must fill in the code before it'll work most of the time.  In many *
* cases, spots that MUST be edited within the files are marked with  *
* /* XXX */ or /* TODO */ comments.                                  *
**********************************************************************
running indent on Test.h
running indent on Test.c

最后我们可以看见就在当前路径下生产了Test.c Test.h文件

[root@hecs-332420 local]# ll | grep Test
-rw-r--r-- 1 root root  1715 Dec  9 17:20 Test.c
-rw-r--r-- 1 root root   227 Dec  9 17:20 Test.h
[root@hecs-332420 local]#

这里我把文件贴出来:
Test.h

/*
 * Note: this file originally auto-generated by mib2c
 * using mib2c.scalar.conf
 */
#ifndef TEST_H
#define TEST_H

/* function declarations */
void init_Test(void);
Netsnmp_Node_Handler handle_GetTime;

#endif /* TEST_H */

Test.c

/*
 * Note: this file originally auto-generated by mib2c
 * using mib2c.scalar.conf
 */

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

/** Initializes the Test module */
void
init_Test(void)
{
    const oid GetTime_oid[] = { 1,3,6,1,4,1,9527,1,1 };

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

    netsnmp_register_scalar(
        netsnmp_create_handler_registration("GetTime", handle_GetTime,
                               GetTime_oid, OID_LENGTH(GetTime_oid),
                               HANDLER_CAN_RONLY
        ));
}

int
handle_GetTime(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,
                                     /* XXX: a pointer to the scalar's data */,
                                     /* 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_GetTime\n", reqinfo->mode );
            return SNMP_ERR_GENERR;
    }

    return SNMP_ERR_NOERROR;
}

接下来我们只需要对.c文件做简单的添加即可,这儿我做的很简单,就是在GET方法中,获取本地时间再返回,附上我修改后的.c文件:

/*
 * Note: this file originally auto-generated by mib2c
 * using mib2c.scalar.conf
 */

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "Test.h"
#include <time.h>
/** Initializes the Test module */
void
init_Test(void)
{
    const oid GetTime_oid[] = { 1,3,6,1,4,1,9527,1,1 };

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

    netsnmp_register_scalar(
        netsnmp_create_handler_registration("GetTime", handle_GetTime,
                               GetTime_oid, OID_LENGTH(GetTime_oid),
                               HANDLER_CAN_RONLY
        ));
}

int
handle_GetTime(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:
		{
			time_t t;
			time(&t);
			char timeStr[100];
			snprintf(timeStr, 100, ctime(&t));
			snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
                                     /* XXX: a pointer to the scalar's data */
									 timeStr,
                                     /* XXX: the length of the data in bytes */
									 strlen(timeStr));
		}
            
        break;

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

    return SNMP_ERR_NOERROR;
}

!注意:我们也可以不使用 mib2c 工具进行转换 ,可以自己直接编写 .c 文件(当然格式需要正确)进行编译。

4. 静态链接

将我们自定义的MIB文件生成的源代码Test.c Test.h 加入到NET-SNMP源代码中,将 Test.c 和 Test.h 复制到/home/lijun/net-snmp-5.9.3/agent/mibgroup中,然后修改编译配置,将将 --with-mib-modules=“notification agentx” 修改为 --with-mib-modules=“Test”,再运行配置脚本 ./localBuild.sh,再make && make install,这里我不重复赘述,可以看我上一篇文章学习笔记一

最后我们可以看见已经将我们的 init_Test()初始化函数放入到mib_module_inits.h文件中

[root@hecs-332420 net-snmp-5.9.3]# cat ./agent/mibgroup/mib_module_inits.h
/* This file is automatically generated by configure.  Do not modify by hand. */
  if (should_init("Test")) init_Test();
  if (should_init("snmp_mib")) init_snmp_mib();
  if (should_init("system_mib")) init_system_mib();
  if (should_init("sysORTable")) init_sysORTable();
  if (should_init("vacm_vars")) init_vacm_vars();
  if (should_init("snmpEngine")) init_snmpEngine();
  if (should_init("snmpMPDStats")) init_snmpMPDStats();
  if (should_init("usmStats")) init_usmStats();
  if (should_init("usmUser")) init_usmUser();
  if (should_init("vacm_context")) init_vacm_context();
[root@hecs-332420 net-snmp-5.9.3]#

5. 查看自定义命令是否生效

加载完成后,我们就可以测试自定义的命令是否生效了,首先启动snmpd服务

[root@hecs-332420 net-snmp-5.9.3]# cd ./out/sbin/
[root@hecs-332420 sbin]# ./snmpd -f -Lo -d
/home/lijun/net-snmp-5.9.3/out/share/snmp/snmpd.conf: line 90: Warning: Unknown token: proc.
/home/lijun/net-snmp-5.9.3/out/share/snmp/snmpd.conf: line 92: Warning: Unknown token: proc.
/home/lijun/net-snmp-5.9.3/out/share/snmp/snmpd.conf: line 94: Warning: Unknown token: proc.
/home/lijun/net-snmp-5.9.3/out/share/snmp/snmpd.conf: line 104: Warning: Unknown token: disk.
/home/lijun/net-snmp-5.9.3/out/share/snmp/snmpd.conf: line 105: Warning: Unknown token: disk.
/home/lijun/net-snmp-5.9.3/out/share/snmp/snmpd.conf: line 106: Warning: Unknown token: includeAllDisks.
/home/lijun/net-snmp-5.9.3/out/share/snmp/snmpd.conf: line 116: Warning: Unknown token: load.
/home/lijun/net-snmp-5.9.3/out/share/snmp/snmpd.conf: line 143: Warning: Unknown token: iquerySecName.
/home/lijun/net-snmp-5.9.3/out/share/snmp/snmpd.conf: line 146: Warning: Unknown token: defaultMonitors.
/home/lijun/net-snmp-5.9.3/out/share/snmp/snmpd.conf: line 148: Warning: Unknown token: linkUpDownNotifications.
/home/lijun/net-snmp-5.9.3/out/share/snmp/snmpd.conf: line 160: Warning: Unknown token: extend.
/home/lijun/net-snmp-5.9.3/out/share/snmp/snmpd.conf: line 161: Warning: Unknown token: extend-sh.
/home/lijun/net-snmp-5.9.3/out/share/snmp/snmpd.conf: line 193: Warning: Unknown token: master.

Sending 44 bytes to UDP: [127.0.0.1]:162->[127.0.0.1]:53974
0000: 30 2A 02 01  00 04 06 70  75 62 6C 69  63 A4 1D 06    0*.....public...
0016: 0A 2B 06 01  04 01 BF 08  03 02 0A 40  04 C0 A8 00    .+.........@....
0032: EB 02 01 00  02 01 00 43  01 01 30 00                 .......C..0.

NET-SNMP version 5.9.3

再新窗口运行snmpget,查看我们自定义的OID

[root@hecs-332420 bin]# ./snmpget -v 2c -c public localhost .1.3.6.1.4.1.9527.1.1.0
SNMPv2-SMI::enterprises.9527.1.1.0 = No Such Object available on this agent at this OID
[root@hecs-332420 bin]#

我们发现会提示报错,说找不到这个OID,实际上是因为我们的snmpd.conf中没有配置,先停止snmpd服务,在snmpd.conf配置文件中ACCESS CONTROL项增加我们自定义的OID,再重启我们snmpd服务

###############################################################################
#
#  ACCESS CONTROL
#

                                                 #  system + hrSystem groups only
view   systemonly  included   .1.3.6.1.2.1.1
view   systemonly  included   .1.3.6.1.2.1.25.1
#新增我们自定义OID
view   systemonly  included   .1.3.6.1.4.1.9527.1.1

                                                 #  Full access from the local host
#rocommunity public  localhost
                                                 #  Default access to basic system info
 rocommunity public  default    -V systemonly

重新运行snmpget

[root@hecs-332420 sbin]# cd ../bin/
[root@hecs-332420 bin]# ./snmpget -v 2c -c public localhost .1.3.6.1.4.1.9527.1.1.0
SNMPv2-SMI::enterprises.9527.1.1.0 = STRING: "Fri Dec  9 17:49:53 2022
"
[root@hecs-332420 bin]# ./snmpget -v 2c -c public localhost MY-TEST-MIB::GetTime.0
Expected LAST-UPDATED (:): At line 8 in /home/lijun/net-snmp-5.9.3/out/share/snmp/mibs/MY-TEST-MIB.txt
MY-TEST-MIB::GetTime.0 = STRING: Fri Dec  9 17:50:14 2022

[root@hecs-332420 bin]#

6. 完结

 类似资料: