» 上一篇:
移植7z命令到嵌入式linux系统
» 下一篇:
printf()函数关于不能打印字符的问题
7月 262012
在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管理功能程序 (851)
更多珍贵收藏资源:http://velep.com/downloads
» 文章出处:
reille博客—http://velep.com
, 如果没有特别声明,文章均为reille博客原创作品
» 郑重声明:
原创作品未经允许不得转载,如需转载请联系reille#qq.com(#换成@)