snmpwalk介绍及其用法一文中曾经介绍了关于net-snmp软件包中的snmpwalk程序的使用方法。snmpwalk实际上相当于个非常简单的网管程序,可以从snmp代理(snmp agent)中获取指定OID的信息。

在嵌入式领域,一般情况下,我们都是针对snmp代理开发,而基于SNMP协议的网管程序则交给PC端的软件开发工程师。但在net-snmp软件包的支持下,我们也可以实现像snmpwalk功能简单的snmp管理端功能程序。

本文即介绍了一个简单的SNMP管理功能程序,源代码如下:

/*
 * A simple snmp manager test route.
 *
 * Autor: reille - http://velep.com/
 *
 */

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

// -------test udp socket start-----------------
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/select.h>

int udp_data_w(int sockfd, struct sockaddr_in *dest_addr, const unsigned char* dest_ip,
                   const unsigned char* data, int len)
{
    int ret;
	struct hostent *hp;

	if((hp = gethostbyname(dest_ip)) == NULL)
	{
		printf("get host by name from %s failed.\n", dest_ip);
		return	-1;
	}
	memmove(&dest_addr->sin_addr, hp->h_addr, hp->h_length);
	ret = sendto(sockfd, (char*)data, len, 0,
					(struct sockaddr *)dest_addr, sizeof(struct sockaddr));
	return	ret;
}

int udp_data_r(int sockfd, struct sockaddr_in *dest_addr,
                  char* buff, int len, int millSeconds)
{
	struct sockaddr_in	destAddr;
	socklen_t addr_len = sizeof(struct sockaddr);

	struct timeval tv_timeout;
	tv_timeout.tv_sec = millSeconds / 1000;
	tv_timeout.tv_usec = (millSeconds % 1000) * 1000;

	fd_set fs_read;
	FD_ZERO(&fs_read);
	FD_SET(sockfd, &fs_read);
	int ret = select((int)(sockfd+1), &fs_read, NULL, NULL, &tv_timeout);
	if (ret <= 0)
	{
		return	0;
	}

	ret = recvfrom(sockfd, buff, len, 0, (struct sockaddr *)dest_addr, &addr_len);
	if (ret <= 0)
	{
		return	-1;
	}
	return	ret;
}

void test_udp(void)
{
    const unsigned char* dest_ip = "192.168.1.100";
    const unsigned short dest_port = 5111;

    /* open socket */
    int sockfd;
    struct sockaddr_in dest_addr;

    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(dest_port);
    dest_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    sockfd = socket(dest_addr.sin_family, SOCK_DGRAM, 0);
    if (sockfd < 0) {
        printf("open socked failed.\n");
        return;
    }
/*	if (bind(sockfd, (struct sockaddr*)&dest_addr, sizeof(struct sockaddr)) == -1)
	{
        printf("bind socked failed.\n");
        close(sockfd);
		return;
	}
*/

    /* test udp read and write */
    printf("\n----------- UDP TEST START -----------\n\n");
    int r;
    int i;
    unsigned char w_data[] = "-0123456789-";
    unsigned char r_data[512];
    for (i=0; i<50; i++) {
        memset(r_data, 0, sizeof(r_data));

        r = udp_data_w(sockfd, &dest_addr, dest_ip, w_data, sizeof(w_data));
        if (r > 0) {
            printf("send data(%d bytes) : %s\n", sizeof(w_data), w_data);
        }
		r = udp_data_r(sockfd, &dest_addr, r_data, sizeof(r_data), 500);
		if (r > 0)
		{
			printf("recv data(%d bytes) : %s\n", r, r_data);
		}
    }

    close(sockfd);

    printf("\n------------ UDP TEST END ------------\n\n");
}

// -------test udp socket end-----------------

/* change the word "define" to "undef" to try the (insecure) SNMPv1 version */
//#define DEMO_USE_SNMP_VERSION_3

#define OTHER_METHODS

#ifdef DEMO_USE_SNMP_VERSION_3
const char *our_v3_passphrase = "The Net-SNMP Demo Password";
#endif

int main(int argc, char ** argv)
{
    printf("\n----------- start snmp app demo -----------\n\n");

    netsnmp_session session, *ss;
    netsnmp_pdu *pdu;
    netsnmp_pdu *response;

    oid anOID[MAX_OID_LEN];
    size_t anOID_len;

    netsnmp_variable_list *vars;
    int status;
    int count=1;

    /*
     * Initialize the SNMP library
     */
    init_snmp("snmpdemoapp");

    /*
     * Initialize a "session" that defines who we're going to talk to
     */
    snmp_sess_init( &session );                   /* set up defaults */
    //session.peername = strdup("test.net-snmp.org");
    //session.peername = "localhost";
    session.peername = "192.168.1.125";
    if (argc >= 3 && strcmp(argv[1], "-ip") == 0) {
        session.peername = argv[2];
    }

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

    /* set the SNMPv1 community name used for authentication */
//    session.community = "demopublic";
    session.community = "public";
    session.community_len = strlen(session.community);

#endif /* SNMPv1 */

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

    if (!ss) {
      snmp_sess_perror("ack", &session);
      SOCK_CLEANUP;
      exit(1);
    }

    /*
     * Create the PDU for the data for our request.
     *   1) We're going to GET the system.sysDescr.0 node.
     */
    int command = SNMP_MSG_GETNEXT;
//    pdu = snmp_pdu_create(SNMP_MSG_GET);
    pdu = snmp_pdu_create(command);
    anOID_len = MAX_OID_LEN;
//    if (!snmp_parse_oid(".1.3.6.1.2.1.1.1.0", anOID, &anOID_len)) {
//      snmp_perror(".1.3.6.1.2.1.1.1.0");
//      SOCK_CLEANUP;
//      exit(1);
//    }
#ifdef OTHER_METHODS
    /*
     *  These are alternatives to the 'snmp_parse_oid' call above,
     *    e.g. specifying the OID by name rather than numerically.
     */
     read_objid(".1.3.6.1.2.1.1.1", anOID, &anOID_len);
//    read_objid(".1.3.6.1.2.1.1.1.0", anOID, &anOID_len);
//    get_node("sysDescr.0", anOID, &anOID_len);
//    read_objid("system.sysDescr.0", anOID, &anOID_len);
#endif

    snmp_add_null_var(pdu, anOID, anOID_len);

    int i;
    printf("session.peername = %s.\n", session.peername);
    printf("SNMP OID is : ");
    for (i=0; i<anOID_len; i++) {
        printf(".%d", (int)anOID[i]);
    }
    printf("\n\n");

    /*
     * 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) {
        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 if (status == STAT_TIMEOUT)
        fprintf(stderr, "Timeout: No response from %s.\n",
                session.peername);
      else
        snmp_sess_perror("snmpdemoapp", ss);

    }

    /*
     * Clean up:
     *  1) free the response.
     *  2) close the session.
     */
    if (response)
      snmp_free_pdu(response);
    snmp_close(ss);

    printf("\n------------ End snmp app demo ------------\n\n");

    test_udp();

    SOCK_CLEANUP;
    return (0);
} /* main() */

上述代码中,本人加入了UDP包的收发测试,可去掉它。

makefile如下:

#
# Warning: you may need more libraries than are included here on the
# build line.  The agent frequently needs various libraries in order
# to compile pieces of it, but is OS dependent and we can't list all
# the combinations here.  Instead, look at the libraries that were
# used when linking the snmpd master agent and copy those to this
# file.
#

CC=gcc

OBJS1=snmpdemoapp.o
OBJS2=example-demon.o nstAgentSubagentObject.o
OBJS3=asyncapp.o
TARGETS=example-demon snmpdemoapp asyncapp

CFLAGS=-I. `net-snmp-config --cflags`
BUILDLIBS=`net-snmp-config --libs`
BUILDAGENTLIBS=`net-snmp-config --agent-libs`

# shared library flags (assumes gcc)
DLFLAGS=-fPIC -shared

all: $(TARGETS)

snmpdemoapp: $(OBJS1)
	$(CC) -o snmpdemoapp $(OBJS1) $(BUILDLIBS)

asyncapp: $(OBJS3)
	$(CC) -o asyncapp $(OBJS3) $(BUILDLIBS)

example-demon: $(OBJS2)
	$(CC) -o example-demon $(OBJS2)  $(BUILDAGENTLIBS)

clean:
	rm $(OBJS2) $(OBJS2) $(TARGETS)

nstAgentPluginObject.so: nstAgentPluginObject.c Makefile
	$(CC) $(CFLAGS) $(DLFLAGS) -c -o nstAgentPluginObject.o nstAgentPluginObject.c
	$(CC) $(CFLAGS) $(DLFLAGS) -o nstAgentPluginObject.so nstAgentPluginObject.o

编译命令:

make snmpdemoapp

编译后,得到snmpdemoapp可执行程序,在运行该程序之前,先执行如下命令,把snmp lib库路径导出(本人的snmp lib采用默认路径安装,因此,lib在默认路径下):

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib:/usr/local/lib

否则会提示出错:
./snmpdemoapp: error while loading shared libraries: libnetsnmp.so.10: cannot open shared object file: No such file or directory

这是因为snmp的库没有加到默认lib路径,导致加载snmp的动态库失败。

本代码也可从本博客下载:一个简单的SNMP管理功能程序 (848)

更多珍贵收藏资源:http://velep.com/downloads

» 文章出处: reille博客—http://velep.com , 如果没有特别声明,文章均为reille博客原创作品
» 郑重声明: 原创作品未经允许不得转载,如需转载请联系reille#qq.com(#换成@)
分享到:

 Leave a Reply

(必须)

(我会替您保密的)(必须)

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.

   
© 2012 velep.com | reille blog | 管理| 粤ICP备15065318号-2| 谷歌地图| 百度地图| Suffusion theme|Sayontan Sinha

无觅相关文章插件,快速提升流量