简单网络管理协议(SNMP)是设计用于IP网路管理网络节点的一种标准协议,它是应用层协议
SNMP协议目前在用的有3个版本,分别是V1,V2C,V3版本
认证方式有SHA,MD5
加密方式有DES,AES
需要支持版本、认证、加密不同的方式功能
自己也是各种找资料,但是很多资料都是复制粘贴,也不全;
所以就把自己的部分实现贴出来,仅供参考:
/*
*@author: 赵秋然
*@date:2021年8月7日
*@description:snmp.h
*/
#ifndef __SNMP_H__
#define __SNMP_H__
#include "public.h"
#include "cJSON.h"
#include<stdio.h>
#include<signal.h>
#include<string.h>
#include<net-snmp/net-snmp-config.h>
#include<net-snmp/net-snmp-includes.h>
#define SNMP_CONF "/backend-c/snmp/snmp_device.conf"
///snmp版本类型
typedef enum{
SNMP_V1 = 1,
SNMP_V2,
SNMP_V3
} snmp_v;
//snmp认证方式
typedef enum{
NOAUTH = 0,
SHA,
MD5
} auth_t;
//snmp加密连接方式
typedef enum{
OPRIV = 0,
DES,
AES
} priv_t;
//snmp 机器类型
typedef enum{
COMMON = 0,
CISCO
} machine_t;
// snmp 通用机器内存 oid信息枚举
typedef enum{
MEMTOTAL = 0,
MEMAVAILABLE,
MEM_SHARE,
MEM_BUFFER,
MEM_CACHE
}machine_common;
typedef enum{
MEM_USE = 0,
MEM_UNUSE
}machine_cscio;
#define RES_LEN 10
#define OID_LEN 30
#define LEN 256
#define SUCCE 0
#define ERROR -1
typedef struct snmp_basic_i{
int snmp_on; // snmp主服务启用
int snmp_cycle_time;//服务更新设备间隔(秒)
int snmp_count;//snmp设备个数统计
}snmp_basic_info;
typedef struct snmp_machine{
int snmp_device_on;//当前设备是否启用获取
char m_ip[20]; // 机器ip
int snmp_version;// snmp 版本号
int snmp_auth;//snmp加密方式
int snmp_ency;//snmp认证方式
char community[LEN]; //snmp 团体字
int time_cycle;// 获取周期时间 5秒 10秒等更新周期
char security_name[LEN];//登录名称
char security_pass[LEN];//密码
char priiv_pass[LEN];//私钥
struct timeval cur_time;///开始获取时间 戳 上一次更新的时间戳
int machine_type;// 机器分类 common 思科 后续需要扩展
char machine_name[LEN];// 机器名称
char machine_id[LEN];// 机器id
char cpu_oid[5][OID_LEN];// cpu oid
char mem_oid[6][OID_LEN];// 内存 oid
char cpu_use_percent[RES_LEN];//cpu 使用率
char mem_use_percent[RES_LEN];//内存使用率
netsnmp_session s_session;
}snmp_machine_info;
int is_valic_ip(char *ip);
int snmp_get_info(netsnmp_session * session,char *dest_ip ,char * oid_val, int * res);
int snmp_dialog_create(snmp_machine_info * snmp_machine,snmp_basic_info snmp_info);
int snmp_basic_conf(snmp_basic_info * snmp_info,cJSON * root);
int snmp_device_conf(snmp_machine_info * machine,cJSON * root);
int snmp_config_init(snmp_machine_info ** snmp_machine,snmp_basic_info * snmp_info);
int get_cycle_second(struct timeval mache,int mache_time_cycle);
//通用 机器cpu 内存获取
void snmp_common(snmp_machine_info *snmp_machine);
//思科 路由 cpu 内存获取
void snmp_cisco(snmp_machine_info *snmp_machine);
void snmp_get_message(snmp_machine_info * snmp_machine);
void snmp_interval_get(snmp_machine_info *snmp_machine,snmp_basic_info snmp_info);
void snmp_free(snmp_machine_info * snmp_machine);
void * snmp_init(void * tmp);
void snmp_start();
#endif
/*
*@author: 赵秋然
*@date:2021年8月7日
*@description:snmp.c
*/
#include "snmp.h"
int quit = 0;
pthread_t snmp_tid;
int is_valic_ip(char *ip){
if(ip == NULL){
return ERROR;
}
char ip_val[30] = {'\0'};
int a,b,c,d;
strncpy(ip_val,ip,sizeof(ip_val)/sizeof(char)-1);
if (4==sscanf(ip_val,"%d.%d.%d.%d",&a,&b,&c,&d)){
if (0<=a && a<=255
&& 0<=b && b<=255
&& 0<=c && c<=255
&& 0<=d && d<=255){
return SUCCE;
}
}
return ERROR;
}
int snmp_get_info(netsnmp_session * session,char *dest_ip ,char * oid_val, int * res){
netsnmp_session * ss = NULL;
netsnmp_pdu * pdu;
netsnmp_pdu * response;
struct variable_list *vars;
int status;
if(session == NULL || dest_ip == NULL || oid_val == NULL || res == NULL){
printf("snmp_get_info parameter is error \n");
return STAT_ERROR;
}
if(is_valic_ip(dest_ip)){
printf("snmp_get_info is_valic_ip ip is error \n");
return STAT_ERROR;
}
session->peername =strdup(dest_ip) ;
ss = snmp_open(session);
if(ss == NULL){
snmp_sess_perror("snmp_open", session);
return STAT_ERROR;
}
oid requestOid[MAX_OID_LEN];
size_t requestOidLength = MAX_OID_LEN;
snmp_parse_oid(oid_val, requestOid, &requestOidLength);
pdu = snmp_pdu_create(SNMP_MSG_GET);
snmp_add_null_var(pdu,requestOid,requestOidLength);
status = snmp_synch_response(ss, pdu,&response);
if(status != STAT_SUCCESS || !response){
snmp_sess_perror("faile snmp_synch_response",ss);
status = STAT_ERROR;
goto SNMP_FREE;
}
if (response->errstat != SNMP_ERR_NOERROR){
printf ("snmp: Error in packet: %s\n",snmp_errstring(response->errstat));
status = STAT_ERROR;
goto SNMP_FREE;
}
for(vars = response->variables;vars; vars = vars->next_variable){
if(vars->type == ASN_INTEGER || vars->type == ASN_GAUGE){
//printf("FINISH value 33 [%d] \n",*vars->val.integer);
*res = *vars->val.integer;
}
else if(vars->type == ASN_NULL){
printf("OID value IS NULL wait a moment [%s] \n", oid_val);
*res = 0;
}
else{
// printf("type value IS error [%d] , \n", vars->type);
*res = 0;
}
}
SNMP_FREE:
snmp_free_pdu(response);
snmp_close(ss);
return status;
}
int snmp_dialog_create(snmp_machine_info * snmp_machine,snmp_basic_info snmp_info){
if(snmp_machine == NULL || snmp_info.snmp_count <= 0 ){
printf("snmp_create_info parameter is error \n");
return STAT_ERROR;
}
//snmp_machine_info * snmp_machine = *snmp_m;
init_snmp("SNMP GET CPU MEMORY");
int i = 0;
for(i = 0;i<snmp_info.snmp_count;++i){
snmp_sess_init(&snmp_machine[i].s_session);
snmp_machine[i].s_session.community=(u_char*)snmp_machine[i].community;
snmp_machine[i].s_session.community_len = strlen((const char*)snmp_machine[i].community);
switch (snmp_machine[i].snmp_version){
case SNMP_V1:
snmp_machine[i].s_session.version = SNMP_VERSION_1;
break;
case SNMP_V2:
snmp_machine[i].s_session.version = SNMP_VERSION_2c;
break;
case SNMP_V3:
snmp_machine[i].s_session.version = SNMP_VERSION_3;
// strncpy(snmp_machine[i].s_session.securityName , snmp_machine[i].security_name,strlen(snmp_machine[i].security_name)) ;
snmp_machine[i].s_session.securityName = snmp_machine[i].security_name;
snmp_machine[i].s_session.securityNameLen = strlen(snmp_machine[i].security_name);
/* 设置认证方法 */
if(snmp_machine[i].snmp_auth == MD5){
snmp_machine[i].s_session.securityAuthProto = usmHMACMD5AuthProtocol;
snmp_machine[i].s_session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
}
else if(snmp_machine[i].snmp_auth == SHA){
snmp_machine[i].s_session.securityAuthProto = usmHMACSHA1AuthProtocol;
snmp_machine[i].s_session.securityAuthProtoLen = USM_AUTH_PROTO_SHA_LEN;
}
/*需要进行认证 */
if((snmp_machine[i].snmp_auth == MD5) || (snmp_machine[i].snmp_auth == SHA))
{
snmp_machine[i].s_session.securityAuthKeyLen = USM_AUTH_KU_LEN;
// 设置认证级别
snmp_machine[i].s_session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
if (generate_Ku(snmp_machine[i].s_session.securityAuthProto,
snmp_machine[i].s_session.securityAuthProtoLen,
(u_char *)snmp_machine[i].security_pass, strlen(snmp_machine[i].security_pass),
snmp_machine[i].s_session.securityAuthKey,
&snmp_machine[i].s_session.securityAuthKeyLen) != SNMPERR_SUCCESS)
{
snmp_perror("AUTH");
snmp_log(LOG_ERR,
"AUTH Error generating Ku from priv cation pass phrase. \n");
return STAT_ERROR;
}
}
if(snmp_machine[i].snmp_ency == OPRIV){
//printf("SNMP ONLY AUTH \n");
return STAT_SUCCESS;
}
/* 设置加密方式 */
if(snmp_machine[i].snmp_ency == DES){
snmp_machine[i].s_session.securityPrivProto = usmDESPrivProtocol;
snmp_machine[i].s_session.securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
}
else if(snmp_machine[i].snmp_ency == AES){
snmp_machine[i].s_session.securityPrivProto = usmAESPrivProtocol;
snmp_machine[i].s_session.securityPrivProtoLen = USM_PRIV_PROTO_AES_LEN;
}
/*需要加密连接 */
if((snmp_machine[i].snmp_ency == DES) || (snmp_machine[i].snmp_ency == AES)){
snmp_machine[i].s_session.securityPrivKeyLen = USM_PRIV_KU_LEN;
/// 加密等级 认证 并 加密
snmp_machine[i].s_session.securityLevel = SNMP_SEC_LEVEL_AUTHPRIV;//;
if (generate_Ku(snmp_machine[i].s_session.securityAuthProto,
snmp_machine[i].s_session.securityAuthProtoLen,
(u_char *)snmp_machine[i].priiv_pass, strlen(snmp_machine[i].priiv_pass),
snmp_machine[i].s_session.securityPrivKey,
&snmp_machine[i].s_session.securityPrivKeyLen) != SNMPERR_SUCCESS){
snmp_perror("ENCRY Error");
snmp_log(LOG_ERR,
"ENCRY Error generating Ku from priv cation pass phrase. \n");
return STAT_ERROR;
}
}
break;
}
}
return STAT_SUCCESS;
}
int snmp_basic_conf(snmp_basic_info * snmp_info,cJSON * root){
if(root == NULL){
printf("snmp_basic_conf cJSON failed \n");
return ERROR;
}
cJSON *object = cJSON_GetObjectItem(root,"snmp_basic_setting");
cJSON* js_value;
js_value = cJSON_GetObjectItem(object, "snmp_on");
if(NULL == js_value){
printf( "snmp_basic_conf snmp_on \n");
return ERROR;
}
else{
snmp_info->snmp_on = js_value->valueint;
}
js_value = cJSON_GetObjectItem(object, "snmp_cycle_time");
if(NULL == js_value){
printf( "snmp_basic_conf snmp_cycle_time \n");
return ERROR;
}
else{
snmp_info->snmp_cycle_time = js_value->valueint;
}
js_value = cJSON_GetObjectItem(object, "snmp_count");
if(NULL == js_value){
printf( "snmp_basic_conf snmp_count \n");
return ERROR;
}
else{
snmp_info->snmp_count = js_value->valueint;
}
return SUCCE;
}
#define GET_CJSON_NUM_VALUE(object, buffer,value) \
{\
cJSON* js_value = cJSON_GetObjectItem(object, buffer); \
if(js_value != NULL) \
{\
value = js_value->valueint;\
}\
else\
{ \
printf("GET_CJSON_NUM_VALUE %s failed \n",buffer);\
return ERROR;\
}\
}
#define GET_CJSON_STR_VALUE(object,buffer,value) \
{\
cJSON* js_value = cJSON_GetObjectItem(object, buffer); \
if(js_value != NULL)\
{\
if(js_value->valuestring != NULL) \
{\
strncpy(value , js_value->valuestring,sizeof(value));\
}\
else\
{ \
printf("GET_CJSON_STR_VALUE %s failed \n",buffer);\
return ERROR;\
}\
}\
}
#define GET_CJSON_ARR_STR_VALUE(object, n, value)\
{\
cJSON * values = cJSON_GetArrayItem(object, n);\
if(values != NULL)\
{\
if(NULL != values->valuestring)\
{\
strncpy(value, values->valuestring, sizeof(value));\
}\
else\
{\
printf("GET_CJSON_ARR_STR_VALUE failed \n");\
return ERROR;\
}\
}\
}
int snmp_device_conf(snmp_machine_info * machine,cJSON * root)
{
if(root == NULL){
printf(" snmp_device_conf cJSON failed \n");
return ERROR;
}
cJSON *array_item = cJSON_GetObjectItem(root,"snmp_device");
int object_count = cJSON_GetArraySize(array_item), i = 0;
for(i = 0;i<object_count;++i){
cJSON *object = cJSON_GetArrayItem(array_item,i);
GET_CJSON_NUM_VALUE(object,"snmp_device_on",machine[i].snmp_device_on);
GET_CJSON_STR_VALUE(object,"machine_name",machine[i].machine_name);
GET_CJSON_STR_VALUE(object,"machine_id",machine[i].machine_id);
GET_CJSON_NUM_VALUE(object,"machine_type",machine[i].machine_type);
GET_CJSON_STR_VALUE(object,"snmp_ip",machine[i].m_ip);
GET_CJSON_NUM_VALUE(object,"snmp_version",machine[i].snmp_version);
GET_CJSON_NUM_VALUE(object,"snmp_auth",machine[i].snmp_auth);
GET_CJSON_NUM_VALUE(object,"snmp_ency",machine[i].snmp_ency);
GET_CJSON_STR_VALUE(object,"community",machine[i].community);
GET_CJSON_NUM_VALUE(object,"time_cycle",machine[i].time_cycle);
GET_CJSON_STR_VALUE(object,"security_name",machine[i].security_name);
GET_CJSON_STR_VALUE(object,"security_pass",machine[i].security_pass);
GET_CJSON_STR_VALUE(object,"priiv_pass",machine[i].priiv_pass);
gettimeofday(&machine[i].cur_time, NULL);
cJSON* cpu_value = cJSON_GetObjectItem(object, "cpu_oid");
int cpu_count = cJSON_GetArraySize(cpu_value), j = 0;
for(j = 0;j<cpu_count;++j){
GET_CJSON_ARR_STR_VALUE(cpu_value,j, machine[i].cpu_oid[j]);
}
cJSON* mem_value = cJSON_GetObjectItem(object, "mem_oid");
int mem_count = cJSON_GetArraySize(mem_value), k = 0;
for(k = 0;k<mem_count;++k){
GET_CJSON_ARR_STR_VALUE(mem_value,k, machine[i].mem_oid[k]);
}
}
return SUCCE;
}
int snmp_config_init(snmp_machine_info ** snmp_machine,snmp_basic_info * snmp_info){
char *p = NULL;
cJSON *root = NULL;
int ret = ERROR;
p = file_get_contents(SNMP_CONF);
// printf("SNMP__P [%s] \n",p);
root = cJSON_Parse(p);
if(root == NULL){
printf(" snmp_config_init cJSON_Parse failed: [%s]\n",cJSON_GetErrorPtr());
return ERROR;
}
ret = snmp_basic_conf(snmp_info,root);
if(snmp_info->snmp_count == 0 || snmp_info->snmp_on == 0 ){
goto END;
}
snmp_machine_info * machine = (snmp_machine_info *)malloc(snmp_info->snmp_count*sizeof(snmp_machine_info));
if(machine == NULL){
printf(" snmp_config_init parameter failed \n");
return ERROR;
}
memset(machine,'\0',snmp_info->snmp_count*sizeof(machine));
ret = snmp_device_conf(machine,root);
cJSON_Delete(root);
safe_free(p);
*snmp_machine = machine;
END:
return ret;
}
int get_cycle_second(struct timeval mache,int mache_time_cycle){
struct timeval cur_time;
gettimeofday(&cur_time, NULL);
int timer0 = cur_time.tv_sec - mache.tv_sec;
return (timer0 > mache_time_cycle)?1:0;
}
//通用 机器cpu 内存获取
void snmp_common(snmp_machine_info *snmp_machine){
if(snmp_machine == NULL){
printf(" snmp_common parameter failed \n");
return ;
}
int mem_total = 0,mem_aval=0,mem_share = 0,mem_buff = 0, mem_cache = 0;
int cpu_free = 0;
int status = snmp_get_info(&snmp_machine->s_session,snmp_machine->m_ip ,snmp_machine->mem_oid[MEMTOTAL], &mem_total);
status = snmp_get_info(&snmp_machine->s_session,snmp_machine->m_ip ,snmp_machine->mem_oid[MEMAVAILABLE], &mem_aval);
status = snmp_get_info(&snmp_machine->s_session,snmp_machine->m_ip ,snmp_machine->mem_oid[MEM_SHARE], &mem_share);
status = snmp_get_info(&snmp_machine->s_session,snmp_machine->m_ip ,snmp_machine->mem_oid[MEM_BUFFER], &mem_buff);
status =snmp_get_info(&snmp_machine->s_session,snmp_machine->m_ip ,snmp_machine->mem_oid[MEM_CACHE], &mem_cache);
if(status != SUCCE){
printf("snmp_common snmp_get_info memory failed \n");
return;
}
float mem_use_percent=0;
if(mem_share +mem_buff + mem_cache > mem_total){
mem_use_percent = (float)(mem_total - mem_aval - mem_buff - mem_cache + mem_share) / (float)mem_total *100;
//printf(" 000 [%d] , [%d] \n",mem_total - mem_aval - mem_buff - mem_cache + mem_share,mem_total);
}
else{
mem_use_percent = (float)(mem_total - mem_aval - mem_buff - mem_cache ) / (float)mem_total *100;
// printf(" 111 [%d] , [%d] \n",mem_total - mem_aval - mem_buff - mem_cache,mem_total);
}
snprintf(snmp_machine->mem_use_percent ,RES_LEN,"%.3f",mem_use_percent);
printf("a通用机器 内存使用率 %s%% \t", snmp_machine->mem_use_percent);
snmp_get_info(&snmp_machine->s_session,snmp_machine->m_ip ,snmp_machine->cpu_oid[0], &cpu_free);
if(status != SUCCE){
printf("snmp_common snmp_get_info memory failed \n");
return;
}
float cpu_use_percent = (float)((cpu_free == 0)?0:(100 -cpu_free));
snprintf(snmp_machine->cpu_use_percent ,RES_LEN,"%.3f",cpu_use_percent);
printf(" cpu 使用率 [%s%%] \n", snmp_machine->cpu_use_percent);
}
//思科 路由 cpu 内存获取
void snmp_cisco(snmp_machine_info *snmp_machine){
if(snmp_machine == NULL){
printf(" snmp_cisco parameter failed \n");
return ;
}
int mess_use = 0, mess_unuse = 0;
int status = snmp_get_info(&snmp_machine->s_session,snmp_machine->m_ip ,snmp_machine->mem_oid[MEM_USE],&mess_use);
status = snmp_get_info(&snmp_machine->s_session,snmp_machine->m_ip ,snmp_machine->mem_oid[MEM_UNUSE],&mess_unuse);
if(status != SUCCE){
printf("snmp_cisco snmp_get_info memory failed \n");
return;
}
float mem_use_percent = (float)mess_use / (float)(mess_use+mess_unuse) * 100;
snprintf(snmp_machine->mem_use_percent ,RES_LEN,"%.3f",mem_use_percent);
int cpu_use = 0;
status = snmp_get_info(&snmp_machine->s_session,snmp_machine->m_ip ,snmp_machine->cpu_oid[0],&cpu_use);
if(status != SUCCE){
printf("snmp_cisco snmp_get_info cpu failed \n");
return;
}
float cpu_use_percent = (float)((cpu_use == 0)?0:(cpu_use));
snprintf(snmp_machine->cpu_use_percent ,RES_LEN,"%.3f",cpu_use_percent);
printf("思科 内存使用率 %s%% cpu 5分钟 %s%% \n",snmp_machine->mem_use_percent ,snmp_machine->cpu_use_percent);
}
void snmp_get_message(snmp_machine_info * snmp_machine){
if(snmp_machine == NULL) {
printf(" snmp_get_message parameter failed \n");
return ;
}
switch (snmp_machine->machine_type) {
case COMMON:
snmp_common(snmp_machine);
break;
case CISCO:
snmp_cisco(snmp_machine);
break;
default:
printf("未知类型");
}
}
void snmp_interval_get(snmp_machine_info *snmp_machine,snmp_basic_info snmp_info){
if(snmp_machine == NULL|| snmp_info.snmp_count <= 0){
printf(" snmp_interval_get parameter failed \n");
return ;
}
int i = 0;
while(!quit){
for(i = 0;i<snmp_info.snmp_count;++i){
if(snmp_machine[i].snmp_device_on){
if(get_cycle_second(snmp_machine[i].cur_time,snmp_machine[i].time_cycle)) {
gettimeofday(&snmp_machine[i].cur_time,NULL);
snmp_get_message(&snmp_machine[i]);
}
}
}
///每隔1秒钟,进行整体循环一次 ,更新周期1秒钟
sleep(snmp_info.snmp_cycle_time);
i = 0;
}
}
void snmp_free(snmp_machine_info * snmp_machine){
if(snmp_machine){
snmp_machine = NULL;
free(snmp_machine);
}
}
void sigroutine(int signo){
switch (signo){
case SIGINT:
printf("SNMP service ctrl+c GET a signal , program exit!\n");
quit = 1;
pthread_join(snmp_tid,NULL);
break;
}
}
void * snmp_init(void * tmp){
// 创建s_session
// 定时获取 cpu 内存信息 ,这里确定一下 是否支持异步获取
snmp_machine_info * snmp_machine = NULL;
int statu = -1;
snmp_basic_info snmp_info;
memset(&snmp_info,'\0',sizeof(snmp_info));
/// snmp配置信息 初始化
statu = snmp_config_init(&snmp_machine, &snmp_info);
if(ERROR == statu){
goto FIN;
}
if(snmp_info.snmp_count == 0 || snmp_info.snmp_on == 0 ){
printf("snmp not configure no run!\n");
goto FIN;
}
// snmp 会话创建
statu =snmp_dialog_create(snmp_machine,snmp_info);
if(ERROR == statu){
goto FIN;
}
// snmp 信息 间隔获取
snmp_interval_get(snmp_machine,snmp_info);
FIN:
///snmp 堆空间释放
snmp_free(snmp_machine);
return 0;
}
void snmp_start(){
void * tmp = NULL;
signal(SIGINT,sigroutine);
pthread_create(&snmp_tid,NULL,snmp_init,tmp);
}