一.安裝及配置SNMP(win32環境)
1.下載
從www.sourceforge.net下載到最新的net-snmp(目前最新版本
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 –v
cmd> snmpset -v
如果正常,會的到取得和設置成功的提示,出錯會給出錯誤提示。
二.MIB文件編寫
MIB文件會存放於C:/usr/share/snmp/mibs/目錄下,是*.txt,純文本文件,可以直接打開查看和更改。RFC1213中定義的MIB節點信息的定義存放與RFC1213-MIB.txt,這些節點是比較重要的,會經常用到。
如果要擴展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提供了一個MIB
1.配置net-snmp的perl模塊
用使用mib
在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>mib
會按照模板配置文件mib
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, "
。。。。。。
}
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(".
//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方法,就可以載入這些對應關係了。