我正在使用在线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
您的代码有很多问题。您还可以比较许多现有的实现(例如,从CRC的实际Wikipedia页面上链接的this one)。
unsigned char * message2 = "aabbccddeeff5cb9017c5a53080000000000000000000000000000";
您是否希望这将是在Wireshark中看到的八位位组序号0xAA 0xBB 0xCC ...
?因为那根本不是您所拥有的。
此字符串实际上包含0x61 0x61 0x62 0x62 ...
(假设您的平台使用ASCII编码)因为它是字符串而不是八位字节字符串。
byte = message[i];
,您假设消息的前8位是一个八位位组,由于没有说,我再次假定,您希望它是0xAA
。实际上是0x61
。如果要使其正常工作,请使用strtoul(pair, NULL, 16)
或类似字符将每对字符转换为整数值。
您有一个循环for (j = 7; j >= 0; j--)
,但切勿在其中使用j
。您do以一种奇怪的方式使用整数常数1
:应该存在(1 << j)
还是什么?
我建议您修复明显的错误,然后在尝试将所有框架与Wireshark进行比较之前编写一些自包含的测试。您发布的代码有一些基本错误,应该进行测试,识别和修复,直到现在[[before。
请确保您的问题与字节序无关。网络字节顺序是大字节序,这是事情变得有点困难的地方。
Little-Endian主要用于PC,但可能因硬件和制造商而异。
2个字节的整数(16位整数),值为255。
关于校验和,在很多情况下,当您使用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;
};
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:
我使用的实现的测试:
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报告为正确的FCS。由于字节顺序,这里只是一个不同的输出。但是CRC计算算法是正确的。0x22bf2660
编辑:
我已经修改了您的代码: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
$