【问题标题】:Why is my snmp packet not valid为什么我的 snmp 数据包无效
【发布时间】:2017-08-24 22:24:21
【问题描述】:

我写了一个类似的问题here,但没有得到解决我问题的答案,所以我在stackoverflow上再次写了这个问题,希望有人可以帮助我。

这是一个关于我的问题的可运行示例。数据包out_buf_0 代表一个有效的 SNMP 数据包,可以通过 UDP 发送。包out_buf_1out_buf_0 是同一个包,最后多了一个字符0x64。此外,由于附加字符,我提高了所有长度 + 1。 为什么 out_buf_1 不是有效的 SNMPv1 数据包/为什么不能通过 UDP 发送? 注意:由于客户端的请求 ID 与out_buf_0out_buf_1 不同,SNMP 请求无法在终端显示,在wireshark 中查看请求/响应。包括我的 SNMPv1 数据包out_buf_0 在内的整个帧长度是 1368 位,out_buf_1 应该是 1376 位。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define MESSAGE_MAX_LEN  1500 /* MTU, IEEE Std 802.3TM-2015 */
#define PORT 161 /* RFC 1157 */

int out_buf_0_len = 129; /* 0x7f + 2 */
char out_buf_0[] = {
0x30, /* SNMP Packet start */
0x7f, /* SNMP Packet length */
0x02, 0x01, 0x00, /* Version */
0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, /* Community*/
0xa2, /* GetResponsePDU */
0x72, /* GetResponsePDU Length */
0x02, 0x04, 0x2c, 0x80, 0x7e, 0x2f, /* Request id */
0x02, 0x01, 0x00, /*Error status */
0x02, 0x01, 0x00, /*Error index */
0x30, /* Varbind list start */
0x64, /* Varbind list length*/
0x30, /* Varbind value start */
0x62, /* Varbind value length */
0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00, /* OID */
0x04,  /* Value start, type octet-string*/
0x56, /* Value length */
0x61, 0x73, 0x64, 0x20, 0x61, /* Value */
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73 };

int out_buf_1_len = 130; /* 0x80 + 2 */
char out_buf_1[] = {
0x30, /* SNMP Packet start */
0x80, /* SNMP Packet length */
0x02, 0x01, 0x00, /* Version */
0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, /* Community*/
0xa2, /* GetResponsePDU */
0x73, /* GetResponsePDU Length */
0x02, 0x04, 0x2c, 0x80, 0x7e, 0x2f, /* Request id */
0x02, 0x01, 0x00, /*Error status */
0x02, 0x01, 0x00, /*Error index */
0x30, /* Varbind list start */
0x65, /* Varbind list length*/
0x30, /* Varbind value start */
0x63, /* Varbind value length */
0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00, /* OID */
0x04,  /* Value start, type octet-string*/
0x57, /* Value length */
0x61, 0x73, 0x64, 0x20, 0x61, /* Value */
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64, 0x20, 0x61, 0x73, 0x64, 0x20, 0x61,
0x73, 0x64 };

int my_socket;
struct sockaddr_in remote_addr;
int socket_create()
{
    printf("Create socket\n");
    struct sockaddr_in socket_addr;
    if ((my_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        printf("Cannot create socket. Exit.\n");
        return -1;
    }
    memset((char *)&socket_addr, 0, sizeof(socket_addr));
    socket_addr.sin_family = AF_INET;
    socket_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    socket_addr.sin_port = htons(PORT);
    if (bind(my_socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
    {
        printf("Bind failed. Exit.\n");
        return - 1;
    }
    printf("Listen on: %s:%d\n", inet_ntoa(socket_addr.sin_addr), PORT);
    return 0;
}

socklen_t addr_len = sizeof(remote_addr);
void socket_listen(char *in_buf)
{
    int  recv_len; /* Bytes received */
    int  nbyt; /* Bytes count */
    char *out_buf[MESSAGE_MAX_LEN];
    int  out_len = 0;

    for (;;) { /* Receive snmp message from snmp manager */
        recv_len = recvfrom(my_socket, in_buf, MESSAGE_MAX_LEN, 0, (struct sockaddr *)&remote_addr, &addr_len);
        if (recv_len > 0)
            if (sendto(my_socket, out_buf_1, out_buf_1_len, 0, (struct sockaddr *)&remote_addr, addr_len) < 0)
                printf("Cannot send data to destination.\n");
    }
}

/* Disable SNMP on local machine. # systemctl stop snmpd 
 * Execute main(): gcc <filename>.c && ./a.out
 * Run SNMP Request: $ snmpget -v 1 -c public 0.0.0.0:161 1.3.6.1.2.1.1.1.0
 */
char in_buf[MESSAGE_MAX_LEN];
int main(int argc, char **argv)
{
    if (socket_create() == -1)
        exit(2);
    socket_listen(in_buf);
}

【问题讨论】:

    标签: c networking snmp


    【解决方案1】:

    根据 ASN.1 基本编码规则 (BER),ASN.1 编码由单个八位字节标记值、一个或多个长度八位字节以及零个或多个内容八位字节组成。编码的长度部分采用以下两种形式之一:单八位字节形式或多八位字节形式。高位指示长度字段采用哪种形式:unset 是单八位字节长度,其中单八位字节(范围为 00..7F)表示内容长度,set 是多八位字节长度(80.. FF),其中第一个八位字节的剩余位指定有多少后续八位字节构成内容的实际长度。

    int out_buf_1_len = 130; /* 0x80 + 2 */
    char out_buf_1[] = {
    0x30, /* SNMP Packet start */
    0x80, /* SNMP Packet length */
    ...
    

    你这里有一个长度为0x80的八位字节,表示它是一个多字节长度字段,其中长度字段本身的长度为0,因此预期内容的长度为0。你想要什么此时是0x81(此处的 0x80 位表示多字节长度,此处的 0x01 部分表示内容长度后跟一个八位字节),然后是 0x80 八位字节(表示您的内容长度),然后是您的其余部分内容。

    我在那里停止了分析。

    【讨论】:

    • 我不明白你的意思,你能进一步分析一下吗?你是不是想说0x80的SNMP包长度不对?
    • 我将0x80更改为0x81,发送成功,但无法解析为SNMP数据包。你能写下正确的 SNMP 数据包吗?
    • 我的意思是 0x80 的 ASN.1 长度字段是错误的。解码器看到数据包的前两个八位字节是 0x30 0x80 并从该 0x80 确定后面不应有更多八位字节。然而还有更多的八位字节,所以它是无效的编码,更不是有效的 SNMP 消息。这里的 0x80 并不意味着 128 个八位字节的内容,这意味着您的长度字段是 0x80 &amp; ~0x80 == 0 八位字节长在这个八位字节之后。相反,0x81 表示您的长度字段是八位字节后的 0x81 &amp; ~0x80 == 1,而 0x80 八位字节后面的 that 表示内容长度为 128。
    • 我明白了,我写了0x30, /* SNMP Packet start */ 0x81, 0x80, /* SNMP Packet length */ ... 并扩展了out_buf_1_len
    • 0x30, /* SNMP Packet start */ 0x81, 0x80, /* SNMP Packet length */ ...out_buf_1_len = 131 还是不行?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-04
    • 1970-01-01
    • 2011-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-16
    相关资源
    最近更新 更多