C-CRC32校验和与以太网帧校验序列上的Wireshark不匹配

问题描述 投票:0回答:3

我正在使用在线CRC-32计算器检查我的输出是否正确,但是似乎Wireshark对于以太网数据包具有不同的预期FCS。

message2是以太网帧减去FCS,如Wireshark所示

#include <stdio.h>
#include <stdint.h>

unsigned int crc32b(unsigned char *message) {
   int i, j;
   unsigned int byte, crc, mask;

   i = 0;
   crc = 0xFFFFFFFF;
   while (message[i] != 0) {
      //printf("%i %x \n\n", i, message[i]);
      byte = message[i];            
      crc = crc ^ byte;
      for (j = 7; j >= 0; j--) {  
         mask = -(crc & 1);
         crc = (crc >> 1) ^ (0xEDB88320 & mask);
      }
      i = i + 1;
   }
   return ~crc;
}

int main(void)
{
    unsigned char * message = "hello test";
    unsigned char * message2 = "aabbccddeeff5cb9017c5a53080000000000000000000000000000";
    unsigned int res = crc32b(message2);
    printf("%x\n", res);
    return 0;
}

我尝试使用[1-CRC-32 IEEE 802.3小节中定义的不同多项式,但是结果与Wireshark不匹配。

使用0xED多项式的输出:0xd81e4af3

Wireshark FCS预期:0xa8cd3084

我真的很想为我的ethhdr数据包在FCS中编码,我想在创建软件数据包时,NIC不会输入FCS ...

来源:

[1]-http://crppit.epfl.ch/documentation/Hash_Function/WiKi/Cyclic_redundancy_check.htm

c network-programming wireshark ethernet
3个回答
1
投票

您的代码有很多问题。您还可以比较许多现有的实现(例如,从CRC的实际Wikipedia页面上链接的this one)。

  1. unsigned char * message2 = "aabbccddeeff5cb9017c5a53080000000000000000000000000000";

    您是否希望这将是在Wireshark中看到的八位位组序号0xAA 0xBB 0xCC ...?因为那根本不是您所拥有的。

    此字符串实际上包含0x61 0x61 0x62 0x62 ...(假设您的平台使用ASCII编码)因为它是字符串而不是八位字节字符串。

    • 特别是,这里:byte = message[i];,您假设消息的前8位是一个八位位组,由于没有说,我再次假定,您希望它是0xAA。实际上是0x61

    如果要使其正常工作,请使用strtoul(pair, NULL, 16)或类似字符将每对字符转换为整数值。

  2. 您有一个循环for (j = 7; j >= 0; j--),但切勿在其中使用j。您do以一种奇怪的方式使用整数常数1:应该存在(1 << j)还是什么?

我建议您修复明显的错误,然后在尝试将所有框架与Wireshark进行比较之前编写一些自包含的测试。您发布的代码有一些基本错误,应该进行测试,识别和修复,直到现在[[before。


0
投票
不确定您的问题,但是如果您要计算网络数据包的校验和,则必须以适当的结构来部署数据。

请确保您的问题与字节序无关。网络字节顺序是大字节序,这是事情变得有点困难的地方。

Little-Endian主要用于PC,但可能因硬件和制造商而异。

2个字节的整数(16位整数),值为255。

    小尾数:FF00
  • [大尾数:00FF
  • 我不确定您要匹配哪种校验和,但是校验和不仅针对数据字段,而且大多数情况下它都包含所有标志和选项,这些都是在最后一步发出的,这就是为什么实现需要相应的数据结构。

    关于校验和,在很多情况下,当您使用wireshark获得无效的校验和时,可能会导致内核,虚拟适配器,加速的网络,NIC中的专用CPU等...

    TCP头示例:

    /* include/linux/tcp.h */ struct tcphdr { __u16 source; __u16 dest; __u32 seq; __u32 ack_seq; #if defined(__LITTLE_ENDIAN_BITFIELD) __u16 res1:4, doff:4, fin:1, syn:1, rst:1, psh:1, ack:1, urg:1, ece:1, cwr:1; #elif defined(__BIG_ENDIAN_BITFIELD) __u16 doff:4, res1:4, cwr:1, ece:1, urg:1, ack:1, psh:1, rst:1, syn:1, fin:1; #else #error "Adjust your <asm/byteorder.h> defines" #endif __u16 window; __u16 check; __u16 urg_ptr; };


  • 0
    投票
    您的实现绝对正确(对于NUL终止的C字符串)。这可能是网络接口的错误配置。在默认模式下,Wireshark不会从网络驱动程序获取FCS。如果使用Linux,并且驱动程序支持此功能,则必须使用

    ethtool启用它才能获取FCS。

    不幸的是,在我的系统上,这仅适用于接收帧:

    $ ethtool -K eth0 rx-fcs on

    有关详细信息,请参见this

    我在我的嵌入式(对于AVR微控制器)项目中使用了略有不同的算法,并且对我来说非常有效:]

    #define CRC_POLY 0xEDB88320 uint32_t crc32_calc(uint8_t *data, int len) { int i, j; uint32_t crc; if (!data) return 0; if (len < 1) return 0; crc = 0xFFFFFFFF; for (j = 0; j < len; j++) { crc ^= data[j]; for (i = 0; i < 8; i++) { crc = (crc & 1) ? ((crc >> 1) ^ CRC_POLY) : (crc >> 1); } } return (crc ^ 0xFFFFFFFF); }

    一个真实的例子:

    Wireshark中的以太网帧(启用ethtool rx-fcs:

    wireshark frame

    我使用的实现的测试:

    uint8_t frame[] = { 0x20, 0xcf, 0x30, 0x1a, 0xce, 0xa1, 0x62, 0x38, 0xe0, 0xc2, 0xbd, 0x30, 0x08, 0x06, 0x00, 0x01, 0x08, 0x00 ,0x06 ,0x04 ,0x00 ,0x01 ,0x62 ,0x38, 0xe0 ,0xc2 ,0xbd ,0x30 ,0x0a, 0x2a, 0x2a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x2a, 0x2a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; printf("0x%x\n", crc32_calc(frame, sizeof(frame)));

    输出:

    $ ./fcs-test 0x6026b722 $
    您可以看到,Wireshark报告

    0x22bf2660

    为正确的FCS。由于字节顺序,这里只是一个不同的输出。但是CRC计算算法是正确的。

    编辑:

    我已经修改了您的代码:

    uint32_t crc32b(uint8_t *message, int len) { int i, j; uint32_t crc, mask; uint8_t byte; crc = 0xFFFFFFFF; for (j = 0; j < len; j++) { byte = message[j]; crc = crc ^ byte; for (i = 7; i >= 0; i--) { mask = -(crc & 1); crc = (crc >> 1) ^ (0xEDB88320 & mask); } } return ~crc; }

    我添加了一个长度参数,因为只有当消息是NUL终止的C字符串时,您的实现才可以正确运行。如果您的输入是字节数组,那么您将得到错误的CRC值。

    查看差异(数组和C字符串):

    uint8_t msg_arr[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x5c, 0xb9, 0x01, 0x7c, 0x5a, 0x53, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; char *msg_str = "aabbccddeeff5cb9017c5a53080000000000000000000000000000"; printf("0x%x\n", crc32b(msg_arr, sizeof(msg_arr))); printf("0x%x\n", crc32b(msg_str, strlen(msg_str)));

    输出:

    $ 0x3422dd71 0xd81e4af3 $
    © www.soinside.com 2019 - 2024. All rights reserved.