C - контрольная сумма CRC32 не соответствует Wireshark на Ethe rnet Последовательность проверки кадра - PullRequest
0 голосов
/ 14 марта 2020

Я использую онлайн-калькулятор CR C -32, чтобы проверить правильность моего вывода, однако кажется, что Wireshark имеет другую ожидаемую FCS для пакета ethe rnet.

message2 - это сообщение ethe rnet frame минус 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 - подраздел CR C -32 IEEE 802.3], однако результат не дает match Wireshark.

Вывод с использованием полинома 0xED: 0xd81e4af3

Ожидается FCS Wireshark: 0xa8cd3084

Я бы очень хотел кодировать в FCS для моего пакета ethhdr, я думаю, когда При создании программного пакета FCS не вводится NI C ...

Источники:

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

Ответы [ 3 ]

3 голосов
/ 22 марта 2020

Ваша реализация определенно верна (для 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);
}

Пример из реального мира:

Рамка Ethe rnet в 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. Вот только другой вывод из-за порядка следования байтов. Но алгоритм расчета CR C правильный.

РЕДАКТИРОВАТЬ:

Я изменил ваш код:

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 строкой. Если ваш ввод представляет собой байтовый массив, то вы получите неправильное значение CR C.

См. Различия (массив и 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
$
1 голос
/ 17 марта 2020

Есть ряд проблем с вашим кодом. Существует также множество существующих реализаций, которые вы можете сравнить (например, эта связана со страницей реальной Википедии на CR C).

  1. unsigned char * message2 = "aabbccddeeff5cb9017c5a53080000000000000000000000000000";

    Вы надеетесь, что это будет последовательность октетов 0xAA 0xBB 0xCC ..., как вы видите их в Wireshark? Потому что это совсем не то, что у вас есть.

    Эта строка на самом деле содержит 0x61 0x61 0x62 0x62 ... (при условии, что ваша платформа использует кодировку ASCII) , потому что это строка символов , а не строка октетов.

    • в частности, здесь: byte = message[i]; вы предполагаете, что первые 8 бит вашего сообщения являются октетом, и снова я предполагаю , поскольку вы не сказали, что ожидали этого быть 0xAA. На самом деле это будет 0x61.

    Если вы хотите, чтобы это работало правильно, переведите каждую пару символов в целочисленное значение, используя strtoul(pair, NULL, 16) или подобное.

  2. У вас есть все oop for (j = 7; j >= 0; j--), но никогда не используйте j внутри. Вы делаете используете целочисленную константу 1 странным образом: должно быть (1 << j) или что-то еще?

Я предлагаю исправить очевидные ошибки, а затем написание некоторых автономных тестов, прежде чем пытаться сравнивать целые кадры с Wireshark. В коде, который вы опубликовали, есть некоторые базовые c ошибки, которые должны быть проверены, идентифицированы и исправлены до того, как вы доберетесь до этой точки.

0 голосов
/ 19 марта 2020

Я не уверен в вашем вопросе, но если вы хотите вычислить контрольную сумму сетевого пакета, вы должны развернуть данные в правильной структуре.

Пожалуйста, убедитесь, что ваша проблема не связана с порядком байтов. Порядок байтов в сети имеет порядковый порядок байтов, здесь дело в том, что все становится немного сложнее.

Little-Endian в основном используется в ПК, но может варьироваться в зависимости от оборудования и производителя.

2-байтовое целое (16-битное целое) со значением 255.

  • Little Endian: FF00
  • Big Endian: 00FF

Im не уверен, с какой контрольной суммой вы пытаетесь сопоставить, но контрольная сумма не только для поля данных, в основном она содержит все флаги и опции, выданные на последнем шаге, поэтому для реализации требуется соответствующая структура данных.

О программе контрольные суммы, есть много случаев, когда вы получаете неверную контрольную сумму с Wireshark, это может привести к ядру, виртуальному адаптеру, ускоренной сети, выделенному ЦП в вашем NI C, et c ...

Пример для заголовка 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;
};
...