strncmp () и if () не согласны ... что мне не хватает ??(сырые розетки) - PullRequest
0 голосов
/ 29 июля 2010

Я пытаюсь создать простой эхо-сервер / клиент, который работает на уровне Ethernet (используя сырые сокеты).Серверная сторона сама по себе работает и показывает все входящие пакеты на eth0.Клиент работает и отправляет пакеты Ethernet по eth0 (я проверил это с помощью wireshark и могу видеть, что пакеты выходят.) Теперь я хочу создать фильтр, чтобы посмотреть только те пакеты, которые мне интересны.(Это основано на адресах назначения / источника.)

В приведенном ниже коде кто-то может объяснить мне, почему strncmp возвращает ноль (что означает совпадение строк), но все же "if (ethernet_header-> h_dest == mac) "не удалось выполнить (не соответствует).Обе переменные "mac" и "ethernet_header-> h_dest" имеют одинаковый тип и длину.

Еще немного предыстории: - Это сделано на 64-битной Linux (Ubuntu) - я использую eth0 на той же машинедля отправки / получения .... Я не думаю, что это должно быть проблемой?

Я просто не понимаю, почему strcmp возвращает совпадение, а если нет.Чего мне не хватает ??

void ParseEthernetHeader(unsigned char *packet, int len) {
    struct ethhdr *ethernet_header;
 unsigned char mac[ETH_ALEN] = {0x01, 0x55, 0x56, 0x88, 0x32, 0x7c}; 

 if (len > sizeof(struct ethhdr)) {
  ethernet_header = (struct ethhdr *) packet;

  int result = strncmp(ethernet_header->h_dest, mac, ETH_ALEN);
  printf("Result: %d\n", result);

  if(ethernet_header->h_dest == mac) {
   /* First set of 6 bytes are Destination MAC */
   PrintInHex("Destination MAC: ", ethernet_header->h_dest, 6);
   printf("\n");

   /* Second set of 6 bytes are Source MAC */
   PrintInHex("Source MAC: ", ethernet_header->h_source, 6);
   printf("\n");

   /* Last 2 bytes in the Ethernet header are the protocol it carries */
   PrintInHex("Protocol: ", (void *) &ethernet_header->h_proto, 2);
   printf("\n\n");
   printf("Length: %d\n",len);
  }

 } else {
  printf("Packet size too small (length: %d)!\n",len);
 }

}

Ответы [ 6 ]

9 голосов
/ 29 июля 2010

Ни strncmp, ни голый if не должны использоваться для сравнения MAC-адресов.

Первое не будет работать должным образом в тех случаях, когда они могут иметь встроенный нулевой байт, что приведет к strncmpзаявить, что они равны, когда они на самом деле нет.Это потому, что strncmp из следующих двух значений:

ff ff 00 ff ff ff
ff ff 00 aa aa aa

будет истинным (проверяется только до первого нулевого байта).

Второе не будет работать, потому что выВы сравниваете указатели , а не содержимое , на которое указывают указатели.Если у вас есть следующая схема памяти:

0x12345678 (mac) | 0x11111111 |
0x1234567c (eth) | 0x11111111 |

, тогда сравнение mac с eth с if (mac == eth) даст вам false, так как они являются разными указателями, один из которых заканчивается на 78,other в 7c.

Вместо этого следует использовать memcmp, поскольку он будет сравнивать необработанные байты памяти без остановки на раннем нулевом байте:

int result = memcmp (ethernet_header->h_dest, mac, ETH_ALEN);
1 голос
/ 29 июля 2010

strncmp принимает указатели на char в качестве первых двух аргументов.

strncmp возвращает ноль, потому что строки в этих двух местах одинаковы для ETH_ALEN символов - это не означает, что ethernet_header->h_dest и mac равны.Это два разных указателя .

int main()
{
        char a1[] = "asdf";
        char a2[] = "asdf";
        char *p1 = "asdf";
        char *p2 = "asdf";
        char *s1 = malloc(5);
        char *s2 = malloc(5);
        strcpy(s1, "asdf");
        strcpy(s2, "asdf");
        printf("a1 and a2: strcmp gives %d and they are %s\n", strcmp(a1, a2), a1 == a2 ? "equal" : "different");
        printf("p1 and p2: strcmp gives %d and they are %s\n", strcmp(p1, p2), p1 == p2 ? "equal" : "different");
        printf("s1 and s2: strcmp gives %d and they are %s\n", strcmp(s1, s2), s1 == s2 ? "equal" : "different");
        return 0;
}

Вывод:

a1 and a2: strcmp gives 0 and they are different  
p1 and p2: strcmp gives 0 and they are equal  
s1 and s2: strcmp gives 0 and they are different
  • p1 и p2 равны, поскольку они оба указывают на одну и ту же строку констант в памяти.
  • В случае массивов, непрерывный блок из 5 байтов выделяется для каждой переменной массива (в стеке), и строка asdf\0 копируется в эти места.
  • s1 иs2 - это два разных указателя, которые указывают на два разных блока из 5-байтовых последовательностей в куче, в которой содержится одно и то же значение.
1 голос
/ 29 июля 2010

Вы не можете проверить на равенство строк, используя оператор ==.Вот почему функции strcmp () существуют в первую очередь.

0 голосов
/ 29 июля 2010

В C == не работает со строками, как вы думаете. Вместо этого вы должны использовать strncmp().

Просто изменить

 if(ethernet_header->h_dest == mac) {

до

if(result == 0) {
0 голосов
/ 29 июля 2010

if(ethernet_header->h_dest == mac) просто сравнивает необработанные значения указателя.Это означает, что он проверяет, начинаются ли обе строки с одного и того же адреса памяти.Обычно это не то, что вам нужно.

Для сравнения содержимого двух c-строк всегда используйте strncmp().

0 голосов
/ 29 июля 2010

Что это за код?

if(ethernet_header->h_dest == mac)

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

...