【问题标题】:UDP checksum error c++UDP校验和错误c ++
【发布时间】:2010-10-25 08:01:26
【问题描述】:

我正在使用以下函数计算 UDP 校验和(在某处找到):

   uint16_t udp_checksum(const void *buff, size_t len, in_addr_t src_addr, in_addr_t dest_addr)
     {
             const uint16_t *buf=(const uint16_t *)buff;
             uint16_t *ip_src=(uint16_t *)&src_addr,
                      *ip_dst=(uint16_t *)&dest_addr;
             uint32_t sum;
             size_t length=len;


         // Calculate the sum                                      
         sum = 0;
         while (len > 1)
         {
                 sum += *buf++;
                 if (sum & 0x80000000)
                         sum = (sum & 0xFFFF) + (sum >> 16);
                 len -= 2;
         }

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

         // Add the pseudo-header                                       
         sum += *(ip_src++);
         sum += *ip_src;

         sum += *(ip_dst++);
         sum += *ip_dst;

         sum += htons(IPROTO_UDP);
         sum += htons(length);

     // Add the carries                                              
         while (sum >> 16)
                 sum = (sum & 0xFFFF) + (sum >> 16);

         // Return the one's complement of sum                           
         return ( (uint16_t)(~sum)  );
 }



    int form_checksums(char * buff)
    {
      // Get IP and UDP headers
      IP_Header* ipHdr  = (IP_Header*)(buff);
      struct UDP_Header* udpHdr = (struct UDP_Header*) (buff + 4*ipHdr->ihl);

      //---- Form and fill IP checksum now--------------------------------------
      ipHdr->check = 0;
      ipHdr->check = in_cksum((unsigned short *)ipHdr, sizeof(*ipHdr));


      //---- calculate and fill udp checksum now ---
      udpHdr->checksum = 0;

      udpHdr->checksum = udp_checksum(buff + 4*ipHdr->ihl, udpHdr->length, ipHdr->saddr, ipHdr->daddr); 

      return 0;
    }

Wireshark 显示计算了错误的 UDP 校验和。我在函数中没有看到任何问题。可能出了什么问题?

【问题讨论】:

  • 我试图找出这个函数本身的错误。谢谢。

标签: c++ udp checksum wireshark


【解决方案1】:

UDP 校验和计算需要 UDP pseudo-header

以下是我的库中可能有帮助的一些代码示例:

// SmartBuffer is a stream-like buffer class
uint16_t SmartBuffer::checksum(const void* buf, size_t buflen)
{
    assert(buf);

    uint32_t r = 0;
    size_t len = buflen;

    const uint16_t* d = reinterpret_cast<const uint16_t*>(buf);

    while (len > 1)
    {
        r += *d++;
        len -= sizeof(uint16_t);
    }

    if (len)
    {
        r += *reinterpret_cast<const uint8_t*>(d);
    }

    while (r >> 16)
    {
        r = (r & 0xffff) + (r >> 16);
    }

    return static_cast<uint16_t>(~r);
}

UDPFrame校验和计算:

uint16_t UDPFrame::computeChecksum(const ipv4_header& ih) const
{
    udp_pseudo_header uph;

    memset(&uph, 0x00, sizeof(uph));

    uph.source = ih.source;
    uph.destination = ih.destination;
    uph.mbz = 0x00;
    uph.type = ih.protocol;
    uph.length = getData()->length;

    systools::SmartBuffer tmp(sizeof(uph) + d_data.size());

    tmp.appendValue(uph);
    tmp.append(d_data); // d_data is the UDP frame payload

    return tmp.checksum();
}

无论如何,请记住,wireshark 通常会警告您,由于UDP checksum offload,可能会计算出错误的校验和值。

也许您的校验和函数确实是错误的,但一种可靠的确定方法是尝试接收您的 UDP 帧。

【讨论】:

  • 谢谢。我希望找出我已经在使用的函数出了什么问题。
  • @SkypeMeSM:理解是一件好事,但校验和函数很难理解。它们主要由数学家设计。如果让您卡住太久,请尝试按原样使用我的功能。知道工作。 ;)
  • 嗨,您能否更新您的答案,更完整地实现SmartBufferudp_pseudo_header
【解决方案2】:

UDP 校验和通常使用UDP pseudo header 计算。这包括已经在网络顺序中的协议 id (17)。我认为您必须将sum = htons(17) 替换为sum += 17

【讨论】:

  • 我把它改成了更标准的 htons(IPPROTO_UDP)。我们需要 hton,因为我们想按字节顺序添加协议。但是函数中还有其他问题。我找不到它。
  • 当您从伪标头中添加单独的项目时,您应该使用 UDP 伪标头方法或正确的 endianess。协议 ID IPPROTO_UDP 必须用 htons() 处理。
【解决方案3】:

就我而言,它运行不佳,因为我没有正确填写源地址和目标地址参数(字节序问题),但该函数运行良好,正如在这个问题中发布的那样。 如果函数返回零,则必须将校验和设置为 0xFFFF。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    • 2014-06-15
    • 1970-01-01
    • 2014-08-16
    • 2010-12-18
    • 1970-01-01
    相关资源
    最近更新 更多