【问题标题】:Bad Checksum when Calculating UDP Checksum计算 UDP 校验和时校验和错误
【发布时间】:2018-04-16 00:08:12
【问题描述】:

我花了一些时间尝试计算 UDP 校验和,但每次我在 Wireshark 中观察数据包时,它都说校验和不正确。 代码如下:

uint16_t compute_udp_checksum(IP *ip, UDP *u, 
               void *data, int data_len)
{
    uint32_t sum = 0;
    uint16_t *arr = NULL;
    void *buffer = NULL;
    int size = 0;
    PSEUDO_HDR *ps = NULL;

    size = PS_SIZE + UDP_SIZE + data_len;

    if (size % 2)
            size += 1;

    buffer = malloc(size);
    if (!buffer)
     {
            perror("malloc");
            return 0;
     }

    ps = create_pseudo_hdr(ip, u);
    if (!ps)
     {
            free(buffer);
            perror("malloc");
            return 0;
     }

    memset(buffer, 0, size);
    memcpy(buffer, ps, PS_SIZE);
    memcpy(buffer + PS_SIZE, u, UDP_SIZE);
    memcpy(buffer + PS_SIZE + UDP_SIZE, data, data_len);

    arr = (uint16_t *) buffer;

    int i = size;
    while (i > 1)
     {
            sum += *arr++;
            i -= 2;
     }

    sum = (sum & 0xFFFF) + (sum >> 16);
    return ~sum;

}

正如我所说,当我将数据包发送到网络时,Wireshark 报告(在接收端)校验和不正确。任何帮助将不胜感激。

谢谢。

【问题讨论】:

  • 1) 你没有在 1 的补码中处理你的短裤。你可能需要使用 htons。 2)您可能会丢失while循环中的最后一个字节总和,而且您的总和假设它在一次通过后最终将成为16位。不知道你是如何添加 IP 地址信息的(不知道你的 UDP * 是什么样子),你也没有将数据长度添加到总和中(必须是 1s 补码)所以是的。
  • "Wireshark 报告(在接收端)校验和不正确。"发布报告和您的代码结果以及预期结果将比简单地描述错误有用。

标签: c udp checksum


【解决方案1】:

由于我真的不知道你用你所有的结构在做什么,我会给你一个参考校验和实现,希望它能帮助你弄清楚你的事情:

#include <stdint.h>
#include <netinet/in.h>

struct udp {
      uint16_t u_sport; /* source port */
      uint16_t u_dport; /* dest port */
      uint16_t u_len; /* length */
      uint16_t u_chksum; /* checksum */
} __attribute__((packed));

uint16_t udp_checksum(const void *buffer, size_t length, in_addr_t src_addr, in_addr_t dest_addr)
{
    const uint16_t *buf = buffer; /* treat input as bunch of uint16_t's */
    uint16_t *src_ip = (void *) &src_addr; 
    uint16_t *dest_ip = (void *)&dest_addr;
    uint32_t sum;
    size_t len = length;

    sum = 0; 

    /* fold the carry bits for the buffer */
    while (length > 1) {
        sum += *buf++;
        if (sum & 0x80000000)
            sum = (sum & 0xFFFF) + (sum >> 16); /* fold  carries */
        length -= 2;
    }

    if(length & 1)
        sum += *((uint8_t *)buf); // add the padding if packet length is odd */

    /* inject checksum of the pseudo-header */
    sum += *(src_ip++);
    sum += *(src_ip);

    sum += *(dest_ip++);
    sum += *(dest_ip);

    sum += htons(IPPROTO_UDP); /* protocol info */
    sum += htons(len); /* original length! */

    /* fold any carry bits created by adding header sums */
    while(sum >> 16)
        sum = (sum & 0xFFFF) + (sum >> 16);

    return (uint16_t)(~sum);
}

【讨论】:

  • 在 big-endian 和 little-endian 平台上是否都能正确处理最终字节?
猜你喜欢
  • 2010-12-01
  • 2014-08-16
  • 2010-12-18
  • 1970-01-01
  • 1970-01-01
  • 2015-08-31
  • 2015-01-30
  • 2016-03-09
  • 2015-12-21
相关资源
最近更新 更多