关闭

SNMP--How to develop a SNMP extension agent DLL(如何开发一个SNMP扩展代理DLL)

标签: SNMP
899人阅读 评论(0) 收藏 举报
分类:

英文网址为:http://www.codeproject.com/Articles/9024/How-to-develop-a-SNMP-extension-agent-DLL

本文翻译只是出于学习的目的,中文部分仅代表个人观点,有错误还望指正,英文部分来自www.codeproject.com/。其中复制可能有误,可以看懂英文的还请到官网下载。如有版权争议,请联系QQ:643166601,本人会及处理。翻译新手,有错是必然的,求高人指点。欢迎同为新手的你共同学习。

 

 

How to develop a SNMP extension agent DLL

如何开发一个SNMP扩展代理DLL

By Ramanan.T, 11 Dec 2004

--Ramanan.T 20041211 

 

 

Download source files - 22.7 Kb

Download demo project - 15.6 Kb 

 

Introduction

简介

Simple Network Management Protocol is the protocol to mange any system over the network. 

简单网络管理协议是管理任何系统网络上的协议。(--译者注:mange 应该是 manage)

SNMP is a protocol on top of UDP protocol. 

SNMP协议是在UDP协议之上。

Like UDP, it also need two ends, i.e., server and client. 

UDP,它也需要两个段,即服务端和客户端。

Should you manage any system over the network, you need a server running on it. 

如果你管理在网络上的任何系统,你需要一个服务端运行它。

In SNMP terms, server is called as Agent. 

SNMP协议条款中,服务被叫做代理。

Typically, you can find SNMP agent running on internetworking devices like routers, hubs, switches, bridges and even in some printers. 

通常你可以找到SNMP代理运行在互联网设备像路由器,集线器,交换机,网桥甚至在某些打印机上。

Any PC also can have a SNMP agent running. 

任何PC也可以有一个SNMP代理运行。

In this case, you can manage that PC from any where in the world.

在这种情况下,你可以管理PC在世界的任何地方。

 

 

Microsoft has designed SNMP agent as a service. 

Microsoft已经设计SNMP代理作为一个服务。

This service will do all the dirty work on protocol encoding and decoding. 

这个服务将做所有的苦活工作协议,编码和解码。

If we need a custom agent, then all we have to do is just develop an extension agent DLL on top of Windows SNMP service. 

如果我们需要一个自定义代理,我们需要做的仅仅是开发一个在Windows SNMP服务之上的扩展代理DLL

This makes our life much easier. 

这使的我们的工作变得更容易。

Even in Windows, ignoring this service we can write from scratch. 

即使在Windows中忽略了这个服务我们可以从头开始编写。

Those who want to design like that can find the SNMP RFC specification on here. 

谁想要设计,在这里可以找SNMP RFC规范文档。

SNMP is a huge book; here I'll cover some essentials of SNMP and how to develop an SNMP extension agent DLL for Windows. 

SNMP是一个巨大的书;这里我将涵盖一些SNMP必须有的和如何去开发一个WindowsSNMP扩展代理DLL

In the next part, I'll demonstrate how to install SNMP and our custom extension agent DLL on Windows 2000.

在接下来的部分,我将要演示如何在Windows2000上安装SNMP和我们自定义扩展代理DLL

 

 

SNMP on Windows 2000

Windows 2000SNMP

Microsoft has implemented SNMP in two services. 

Microsoft实现SNMP分两次服务。

The first one is SNMP.EXE and the other one is SNMPTRAP.EXE. 

第一个是SNMP.EXE和另一个是SNMPTRAP.EXE

Microsoft also implemented some extension agent DLL along with the services.

Microsoft也实现一些服务的扩展代理DLL

Using this, you can get service pack version, get IE patches version, perform DHCP configurations, perform Windows update, etc. 

利用这一点,你能获得服务包版本,获得IE补丁版本,执行DHCP配置,执行Windows更行等。

You can perform almost every thing on Windows using the default extension agents. 

你可以在Windows上使用默认扩展代理执行几乎每件事情。

So, why you need a custom agent DLL? 

那么,为什么你需要一个自定义代理DLL?

Say if you want to do custom operation from other end of the world, like back up certain files, retrieve your file from any where, configure your custom build software, etc. 

如果说你想从世界的另一端做自定操作,像备份某些文件,从任何地方获取你的文件,配置你的自定义生成软件等。

Then you must need your own custom extension DLL.

然后你必须要用你自己的自定义扩展DLL

 

 

To develop a custom agent, all you got to do is build a DLL with minimum three exported functions. Those are:

去开发一个自定义代理,你想要去构建一个DLL,以最少的3个导出函数。它们是:

SnmpExtensionInit

SnmpExtensionQuery

SnmpExtensionTrap 

 

 

Along with the SNMP services, Microsoft also provided some APIs to deal SNMP. 

随着SNMP服务,Microsoft还提供一些API去处理SNMP

These APIs cover all your needs to develop an SNMP custom agent. 

这些API涵盖所有你需要去开发的一个自定义的SNMP代理。

So what are we waiting for? 

你还在等什么?

Grab these APIs and pack a DLL.

抓住这些API和打包一个DLL

 

 

SNMP Terms

SNMP协议条款 

Before starting the development, it is better to know some SNMP terms. 

在开始开发之前,它能更好地去了解某些SNMP协议条款。

RFC standard may threaten you with some terms. 

RFC标准的某些协议条款可能威胁你。

But I feel, for beginners, knowledge about the following terms is enough.

但是我感觉,对于初学者,了解以下协议条款就足够了。

 

 

MIB: (Management Information Base)

MIB:(管理信息库)

 

 

When dealing with remote devices, there should be some standard to understand the information stored in the SNMP agent. 

当处理远程设备时,应该有一些标准去理解在SNMP代理中的信息存储

SNMP accomplishes that through MIB. 

SNMP完成需要通过MIB

Think of the MIB as a "tree" very similar to a Windows, DOS or UNIX directory structure, with some pre-defined values ("directory" names) and some custom areas for vendors. 

考虑这个MIB树非常像WindowsDOS 或 UNIX目录结构,用某些预定义的值(目录中的名称)和某些自定义的领域厂商。 

Since this database includes all the manageable objects, MIB is the most basic element of network management. 

自从这个数据库包含所有易处理的对象以来,MIB是网络管理的最基本元素。

Here is an example of a MIB entry in the tree:

这有一个MIB入口的例子在这个树中。

 

sysUpTime OBJECT-TYPE

  SYNTAX  TimeTicks

  ACCESS  read-only

  STATUS  mandatory

  DESCRIPTION

     "The time (in hundredths of a second) since the 

     network management portion of the system was last re-initialized."

  ::= { system 3 }

 

 

OID: (Object Identifier)

OID:(对象标识符)

 

 

OID is the ID to identify the node in the MIB (remember MIB as a tree structure). 

OID是在MIB中识别结点的ID,(记得MIB作为一个树结构)

Don't worry about this too much, you will get to know at the end of this tutorial.

不要担心太多,你将会知道在这个教程的结束(之前)

Now if you are new to SNMP, definitely your mind will ask you the following questions..

现在如果你是SNMP的新手,明确你的头脑,问你以下问题..

Where this MIB resides? 

MIB在哪驻留?

How to access this? 

如何访问他?

Do you need any SQL like query to access this? 

你需要哪一个SQL来查询去访问这些(信息)

 

 

Here is the answer to all of that. 

这里上面的答案。

Even though SNMP standard calls as database, it is not an actual database. 

即使SNMP标准称为数据库,它不是一个真实数据。

Think, it is the way or format or standard to hold the information. 

想它是一种方式或格式或标准去保存信息。

Where it resides is up to your decision. 

你决定它驻留在哪里。

If you want, you can put it into registry, or into real Access database, or store it into an ordinary binary file. 

如果你愿意,内可以把它写进注册表,或真实的访问数据库,或存储它到一个普通的二进制文件。

In this example (MyAgent.DLL), I created MIB by hard coding with a group of C++ structures in global memory (really, it is a structure defined by struct keyword).

在这个例子(MyAgent.DLL),我用硬编码方式创建MIB一组C++结构体在全局内存中(实际上,它是一个结构体被定义为结构体关键字)

 

 

Here in this agent, whenever a request comes, I am just going through these structures and fulfilling the request.

在这个代理中,无论什么时候一个请求进来,我只是通过这些构体和执行请求。

 

 

Trap:

陷阱

Traps are like events. 

陷阱像事件。

This is a way the SNMP agent pushes the information to client. 

这种方式的SNMP代理推送信息到客户端。

Asynchronously, events can be fired to client from server (agent).

异步,事件可以从客户端删除服务端(代理)

 

 

NMS: (Network Management Station)

NMS:(网络管理站)

NMS is nothing but a system where SNMP client (manager) runs. 

NSM没什么,只是在SNMP客户端(管理)运行的一个系统。

That is where you sit and view the things going on the other end.

这是你的网站,查看事情在另一个终端。

 

 

Community:

团体:

Community is the kind of group you assign the rights and put your agents into. 

团体是一组由你分配权利和可以进入你的代理。

It has nothing to do with extension agent development. 

它是与扩展代理开发无关的。

It is all in the installation. 

它是在所有的在安装中。

I shall explain that on the next article.

我将会在下一篇文章中解释。

 

Now, we'll get our hands dirty

现在,我们将得到我们的手变脏。

I think you need Platform SDK (I'm not sure). 

我认为你需要平台SDK(我不确定).

Now, create a Win32 DLL project; define and export the following functions:

现在,创建一个Win32 DLL project;定义和导出下面的函数:

BOOL SNMP_FUNC_TYPE SnmpExtensionInit(    DWORD dwUptimeReference,

                    HANDLE *phSubagentTrapEvent,

                    AsnObjectIdentifier *pFirstSupportedRegion )

 

BOOL SNMP_FUNC_TYPE SnmpExtensionQuery(    BYTE bPduType, 

                    SnmpVarBindList *pVarBindList, 

                    AsnInteger32 *pErrorStatus, 

                    AsnInteger32 *pErrorIndex    )

 

// you need this only if you need traps from agent

BOOL SNMP_FUNC_TYPE SnmpExtensionTrap(    AsnObjectIdentifier *pEnterpriseOid, 

                    AsnInteger32 *pGenericTrapId, 

                    AsnInteger32 *pSpecificTrapId, 

                    AsnTimeticks *pTimeStamp, 

                    SnmpVarBindList *pVarBindList    ) 

Then define MIB table (structure) and instances as follows:

然后定义MIB(结构)和实例如下所示:

// template MIB entry

struct MIB_ENTRY

{

    AsnObjectIdentifier asnOid;

    void *              pStorageValue;

    CHAR *              szStorageName;

    BYTE                chType;

    UINT                unAccess;

    MIB_ENTRY*            pMibNext;

};

 

 

// global MIB table instance with three nodes

 

MIB_ENTRY g_MyMibTable[] = {

    {    

        {OID_SIZEOF(g_unAboutOid),g_unAboutOid},

        &g_szAbout,

        "About",

        ASN_OCTETSTRING,

        SNMP_ACCESS_READ_ONLY,

        &g_MyMibTable[1]

    },

    {

        {OID_SIZEOF(g_unNameOid),g_unNameOid},

        &g_szName,

        "Name",

        ASN_OCTETSTRING,

        SNMP_ACCESS_READ_WRITE,

        &g_MyMibTable[2]

    },

    {

        {OID_SIZEOF(g_unAgeOid),g_unAgeOid},

        &g_asnIntAge,

        "Age",

        ASN_INTEGER,

        SNMP_ACCESS_READ_WRITE,

        NULL

    }

}; 

 

 

Our MIB has three nodes:

我们的MIB有三个结点:

About: this is a read only node. Gives out the author's name. 

简介:只是一个只读的结点,给出作者名。

Name: string variable with read and write access. 

名称:字符串变量可以读写访问。

Age: integer variable with read and write access. 

年龄:整型变量可以读写访问。

The visualized MIB table could be like this:

这个可视化的MIB表可能像这样。

 

The next step

接下来的步骤

Here we should code the functionality by placing some code into the exported functions. 

到这里我们将编写功能,放置一些代码到导出函数

Let us peek in to these functions one by one.

让我们一行一行细看这些函数。

 

 

Any MIB node value passed in between the server and client should be a structure containing two sub structures. 

任何MIB结点值通过服务端和客户端将包含两个子结构体。

First one to represent object identifier (OID) and the second one to represent that object's associated value. 

第一个代表对象标识符(OID)和第二个代表对象相关值。

Object's value can be represented in AsnAny structure. 

对象的值可以用AsnAny结构体代表。

Think this structure as similar to VARIANT structure. 

认为这种结构是类似VARIANT结构。

We should use specific SNMP APIs to manipulate these structures. 

我们应该用指定的SNMP API去操作这些结构体。

For example, if you want to copy OID from one variable (AsnObjectIdentifier) to another, you should use SnmpUtilOidCpy.

例如,如果你想要从一个变量复制OID到另一个变量,你应该用SnmpUtilOidCpy

 

 

In the following functions, I have used such SNMP specific APIs. 

在下面的函数中,我使用SNMP指定的API

For more detail about these APIs, refer MSDN.

更多关于API详细信息,参考MSDN

 

 

SnmpExtensionInit: This function is called by the service soon after loading our extension agent DLL (MyAgent.DLL). 

SnmpExtensionInit:这个函数被服务调用不久之后加载我们的扩展代理DLL(MyAgent.DLL)

Here, we will create the trap generation thread, create an event for trap, and initialize the MIB table. 

这里,我们将要创建陷阱生成线程,创建一个事件陷阱,初始化MIB表。

Also, initialize g_dwStartTime variable even though it is not a must. 

此外,初始化g_dwStartTime变量即使它不是必须的。

Most importantly, we will initialize the MIB prefix (pFirstSupportedRegion). 

最重要的,我们将要初始化MIB前缀(pFirstSupportedRegion);

Our MIB prefix (i.e., our MIB branch) is .1.3.6.1.4.1.15. 

我们的MIB前缀(即我们的MIB分支).1.3.6.1.4.1.15

If any request comes to this branch, SNMP service will call our DLL's SnmpExtensionQuery exported function.

如果有任何请求到这个分支,SNMP服务将调用我们的DLLSnmpExtensionQuery导出函数。

 

BOOL SNMP_FUNC_TYPE SnmpExtensionInit(    DWORD dwUptimeReference,

                    HANDLE *phSubagentTrapEvent, 

                    AsnObjectIdentifier *pFirstSupportedRegion)

{

    // creaet this event for the trap

    g_hSimulateTrap = CreateEvent(NULL, FALSE, FALSE, NULL); 

 

    *pFirstSupportedRegion = MIB_OidPrefix;

    *phSubagentTrapEvent = g_hSimulateTrap; // by assigning it passes to 

                        // the SNMP service

                        // So when ever you set this event 

                        // service will call

                        // SnmpExtensionTrap exported function

    

    // on loading the our SNMP DLL create the thread

    g_hTrapGenThread = CreateThread(NULL,0,TrapGenThread,NULL,0,NULL);

 

    // hard coded initialization

    g_szAbout = (char*)malloc(sizeof(char)*64);

    strcpy(g_szAbout,"Author : Ramanan.T");

    g_szName = (char*)malloc(sizeof(char)*64);

    strcpy(g_szName,"Your Name");

    g_asnIntAge = 0;

 

    g_dwStartTime = GetTickCount();

 

    return SNMPAPI_NOERROR;

}

 

SnmpExtensionQuery: This query function will be called whenever the client (manager) request comes to our branch. 

无论什么时候客户端(管理者)请求进入我们的分支将调用查询函数。

This should support at least three request types. 

这将至少支持三个请求类型。

Those are GET, GET NEXT and SET. 

这些包括GETGET NEXT 和 SET

Our internal custom functions GetRequest, GetNextRequest and SetRequest satisfy these requests. 

我们内部自定义函数GetRequestGetNextRequest 和 SetRequest满足这些要求。

For further details, open the source ZIP and check how these functions extract the information from MIB structures.

对于更进一步的详细,打开源码ZIP和查看这些函数如何从MIB结构获得信息。

BOOL SNMP_FUNC_TYPE SnmpExtensionQuery(    BYTE bPduType, 

                    SnmpVarBindList *pVarBindList, 

                    AsnInteger32 *pErrorStatus, 

                    AsnInteger32 *pErrorIndex)

{

    int nRet = 0;

    AsnObjectName;

    

    *pErrorStatus = SNMP_ERRORSTATUS_NOERROR;

    *pErrorIndex = 0;

 

    for(UINT i=0;i<pVarBindList->len;i++)

    {

        *pErrorStatus = SNMP_ERRORSTATUS_NOERROR;

 

        // what type of request we are getting?

        switch(bPduType)

        {

        case SNMP_PDU_GET://gets the variable value 

                    // passed variable in pVarBindList

            *pErrorStatus = GetRequest(&pVarBindList->list[i]);

            if(*pErrorStatus != SNMP_ERRORSTATUS_NOERROR)

                *pErrorIndex++;

            break;

        case SNMP_PDU_GETNEXT: // gets the next variable 

                    // related to the passed variable in pVarBindList

            *pErrorStatus = GetNextRequest(&pVarBindList->list[i]);

            if(*pErrorStatus != SNMP_ERRORSTATUS_NOERROR)

                *pErrorIndex++;

            break;

        case SNMP_PDU_SET: // sets a variable

            *pErrorStatus = SetRequest(&pVarBindList->list[i]);

            if(*pErrorStatus != SNMP_ERRORSTATUS_NOERROR)

                *pErrorIndex++;

            break;

        default:

            *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;

            *pErrorIndex++;

        };

    }    

 

    return SNMPAPI_NOERROR;

 

SnmpExtensionTrap: This function will not generate any traps. 

SnmpExtensionTrap:这个函数将不会产生任何陷阱。

This function will be called whenever the event is set (can you remember the event that we initialized in SnmpExtensionInit function?). 

无论什么时候这个事件被设置这个函数将被调用(你能回想起当我们在SnmpExtensionInit函数中初始化个事件?)

What this function will do is just fill the parameters passed to it. 

这个函数将仅仅是填充这些参数传递给它。

Using this parameters, SNMPTRAP service will compose the trap containing OID, value, time stamp, etc. and send to all connected clients.

使用这个参数,SNMPTRAP服务将组成陷阱包含OID,值,时间戳等,和发送给所有被连接的客户端。

BOOL SNMP_FUNC_TYPE SnmpExtensionTrap(    AsnObjectIdentifier *pEnterpriseOid, 

                    AsnInteger32 *pGenericTrapId, 

                    AsnInteger32 *pSpecificTrapId, 

                    AsnTimeticks *pTimeStamp, 

                    SnmpVarBindList *pVarBindList)

{

    static int nNoOfTraps = 1; // just ignore this, 

                    // I introduced this to 

                    // send many traps at once

                    // any way below we are generating 

                    // one trap with two values

 

    if(nNoOfTraps) // if it is zero don't send traps

    {

        pEnterpriseOid->idLength = sizeof(g_TrapOid);

        pEnterpriseOid->ids = g_TrapOid;

 

        *pGenericTrapId        = SNMP_GENERICTRAP_ENTERSPECIFIC;

        *pSpecificTrapId    = 1;   // ToasterControl Up trap.

        *pTimeStamp            = GetTickCount() - g_dwStartTime;

 

        // Allocate space for the Variable Bindings.

        pVarBindList->list = (SnmpVarBind*)SnmpUtilMemAlloc(2*sizeof(SnmpVarBind));

 

        SnmpUtilOidCpy(&pVarBindList->list[0].name,&MIB_OidPrefix);

        SnmpUtilOidAppend(&pVarBindList->list[0].name,&g_MyMibTable[1].asnOid);

        pVarBindList->list[0].value.asnType = ASN_OCTETSTRING;

        pVarBindList->list[0].value.asnValue.string.dynamic = TRUE;

 

        pVarBindList->list[0].value.asnValue.string.length = 

                strlen(*(LPSTR*)g_MyMibTable[1].pStorageValue);

 

        // oops! code messed up due to alignment problem

        pVarBindList->list[0].value.asnValue.string.stream = 

                (unsigned char*) SnmpUtilMemAlloc (

             pVarBindList->list[0].value.asnValue.string.length * sizeof(char));

    

        memcpy(pVarBindList->list[0].value.asnValue.string.stream,

            *(LPSTR*)g_MyMibTable[1].pStorageValue,pVarBindList->

                list[0].value.asnValue.string.length);

                

        SnmpUtilOidCpy(&pVarBindList->list[1].name,&MIB_OidPrefix);

        SnmpUtilOidAppend(&pVarBindList->list[1].name,&g_MyMibTable[2].asnOid);

        pVarBindList->list[1].value.asnType = ASN_INTEGER;

        pVarBindList->list[1].value.asnValue.number 

                = *((AsnInteger32*)g_MyMibTable[2].pStorageValue);

 

        pVarBindList->len = 2;

 

        nNoOfTraps--;

        // Indicate that valid trap data exists in the parameters.

        return TRUE;

    }

    nNoOfTraps = 1;

 

    // Indicate that no more traps are available

    return FALSE;

 

 

Come to the point...How can you manage using set and get?

到了这里...你如何管理使用setget? 

Oh yeh...you have to do all those :). 

Oh yeh...你必须做这些:)

What you can do is code your own function to do some thing when a particular variable is set to a particular value. 

你可以做的是编写自己的函数做一些事情,为一个特定的变量设置一个特定的值。

Here is one suggestion. 

这是一个建议。

Say you want to launch a URL in IE. 

你想说打开一个URLIE中。

For that, add a node in MIB. 

对于这一点,在MIB中增加一个结点。

Name the variable as launch and make the type as string type. 

变量名称作为开始和数据类型为字符串类型。

When the client makes the request to set this variable with a URL value, inside the agent, set the variable, and using ShellExecute, launch this URL. 

当这个客户端代理产生请求用一个URL值设置的变量代替这个代理,设置这个变量使用ShellExecute启动这个URL

Set and Get just setting & getting. 

设置和获得仅仅用setting getting

According to the variable change, you have to perform the real managing stuff.

根据变量的改变,你必须执行真正的管理的东西。

 

 

Conclusion

结论 

Here we go....Now it's your turn to do some very serious SNMP. 

在这里,我们继续....现在轮到你做一些非常认真的SNMP了。

To make it work, you need to install it properly. 

让他去工作,你需要正确的安装它。

I'll explain that on next article.

我将会在下一篇文章中解释。

 

 

 

License

许可

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. 

这个文章没有明确的附加许可,可以包含使用条款在文章的内容中或下载文件包含的使用条款。

If in doubt please contact the author via the discussion board below.

如果有疑问请联系作者,通过下面的讨论板。

 

 

A list of licenses authors might use can be found here

在这里可以找到一个作者许可证清单。

 

 

About the Author

作者简介

Ramanan.T

Software Developer (Senior)

软件开发人员(高级)

Australia 

澳大利亚

 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:138025次
    • 积分:3164
    • 等级:
    • 排名:第11276名
    • 原创:103篇
    • 转载:3篇
    • 译文:83篇
    • 评论:10条
    最新评论