使用C语言实现一个SNMP Manager。有简单界面,能接收用户输入的OID,向SNMP Agent发出查询并接收并解析响应。内容涵盖socket编程(UDP)、BER编解码、SNMP报文构造和解析,详细给出代码
时间: 2024-01-22 11:17:25 浏览: 369
基于C#编写的通过OID获取SNMP
3星 · 编辑精心推荐
实现一个SNMP Manager需要用到以下几个步骤:
1. 建立UDP socket并绑定端口
2. 构造SNMP报文,发送给SNMP Agent
3. 接收SNMP Agent返回的响应报文,并解析其中的数据
下面是一个简单的SNMP Manager程序的C语言实现,包括了以上3个步骤:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define SNMP_PORT 161
#define MAX_MSG_SIZE 1024
// SNMP消息头结构体
typedef struct snmp_header {
unsigned char version;
unsigned char community_len;
char community[20];
unsigned char pdu_type;
unsigned int request_id;
unsigned int error_status;
unsigned int error_index;
} snmp_header_t;
// SNMP GetRequest PDU结构体
typedef struct snmp_pdu {
unsigned char pdu_type;
unsigned int request_id;
unsigned int error_status;
unsigned int error_index;
unsigned char varbind[20];
} snmp_pdu_t;
// 构造SNMP消息头
void build_snmp_header(snmp_header_t *header, char *community) {
header->version = 0x00; // SNMPv1
header->community_len = strlen(community);
strcpy(header->community, community);
header->pdu_type = 0xA0; // GetRequest PDU
header->request_id = 1; // 请求ID,可任意设置
header->error_status = 0;
header->error_index = 0;
}
// 构造SNMP GetRequest PDU
void build_snmp_pdu(snmp_pdu_t *pdu, char *oid) {
pdu->pdu_type = 0xA0; // GetRequest PDU
pdu->request_id = 1; // 请求ID,可任意设置
pdu->error_status = 0;
pdu->error_index = 0;
pdu->varbind[0] = 0x06; // OID类型标志
pdu->varbind[1] = strlen(oid); // OID长度
memcpy(&pdu->varbind[2], oid, strlen(oid)); // OID值
}
// BER编码函数
int ber_encode(unsigned char *buf, unsigned int value) {
if (value < 128) {
buf[0] = value;
return 1;
} else if (value < 256) {
buf[0] = 0x81;
buf[1] = value;
return 2;
} else if (value < 65536) {
buf[0] = 0x82;
buf[1] = value >> 8;
buf[2] = value & 0xFF;
return 3;
} else if (value < 16777216) {
buf[0] = 0x83;
buf[1] = value >> 16;
buf[2] = (value >> 8) & 0xFF;
buf[3] = value & 0xFF;
return 4;
} else {
return -1;
}
}
// 发送SNMP消息并接收响应
int send_snmp_request(char *ip_addr, char *community, char *oid) {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1) {
perror("socket");
return -1;
}
struct sockaddr_in agent_addr;
memset(&agent_addr, 0, sizeof(agent_addr));
agent_addr.sin_family = AF_INET;
agent_addr.sin_port = htons(SNMP_PORT);
agent_addr.sin_addr.s_addr = inet_addr(ip_addr);
// 构造SNMP消息头和GetRequest PDU
snmp_header_t header;
build_snmp_header(&header, community);
snmp_pdu_t pdu;
build_snmp_pdu(&pdu, oid);
unsigned char msg[MAX_MSG_SIZE];
memset(msg, 0, MAX_MSG_SIZE);
// BER编码SNMP消息头和GetRequest PDU
int len = 0;
msg[len++] = header.version;
msg[len++] = header.community_len;
memcpy(&msg[len], header.community, header.community_len);
len += header.community_len;
msg[len++] = header.pdu_type;
len += ber_encode(&msg[len], header.request_id);
len += ber_encode(&msg[len], header.error_status);
len += ber_encode(&msg[len], header.error_index);
msg[len++] = pdu.pdu_type;
len += ber_encode(&msg[len], pdu.request_id);
len += ber_encode(&msg[len], pdu.error_status);
len += ber_encode(&msg[len], pdu.error_index);
memcpy(&msg[len], pdu.varbind, pdu.varbind[1] + 2);
len += pdu.varbind[1] + 2;
// 发送SNMP消息
if (sendto(sockfd, msg, len, 0, (struct sockaddr *)&agent_addr, sizeof(agent_addr)) == -1) {
perror("sendto");
close(sockfd);
return -1;
}
// 接收SNMP Agent的响应
unsigned char recv_buf[MAX_MSG_SIZE];
int recv_len = recvfrom(sockfd, recv_buf, MAX_MSG_SIZE, 0, NULL, NULL);
if (recv_len == -1) {
perror("recvfrom");
close(sockfd);
return -1;
}
// 解析SNMP Agent的响应
int pdu_len = recv_buf[6];
int data_len = recv_buf[8 + pdu_len + 1];
unsigned char *data = &recv_buf[8 + pdu_len + 2];
unsigned char value[MAX_MSG_SIZE];
memcpy(value, data, data_len);
// 输出结果
printf("OID %s 的值为:", oid);
for (int i = 0; i < data_len; i++) {
printf("%02X ", value[i]);
}
printf("\n");
close(sockfd);
return 0;
}
int main() {
char ip_addr[20];
char community[20];
char oid[20];
printf("请输入SNMP Agent的IP地址:");
scanf("%s", ip_addr);
printf("请输入community字符串:");
scanf("%s", community);
printf("请输入OID:");
scanf("%s", oid);
send_snmp_request(ip_addr, community, oid);
return 0;
}
```
该程序中使用了SOCKET编程的UDP协议来发送SNMP协议的相关请求,使用了BER编解码方式对SNMP报文进行编码和解码。同时也实现了一个简单的文本化的命令行界面,用户可以输入SNMP Agent的IP地址、community字符串以及OID,程序将向SNMP Agent发送GetRequest PDU,并解析响应报文,最终输出OID对应的值。
需要注意的是,该程序是一个简单的示例程序,未做太多的错误处理和容错处理,仅供参考。实际应用中,需要对各种异常情况进行处理,确保程序的稳定性和正确性。
阅读全文