strncmp()和if()不同意...我在想什么? (原始套接字)

strncmp()和if()不同意...我在想什么? (原始套接字)

问题描述:

我想构建一个简单的echo服务器/客户端工作在以太网级别(使用原始套接字)。 服务器端本身工作并显示eth0上的所有传入数据包。 客户端在eth0上工作并发送以太网数据包(我用wireshark检查过这个数据包,可以看到数据包发送出去)。 我现在想做一个过滤器,只查看我感兴趣的数据包。 (这是基于目的地/源地址。)strncmp()和if()不同意...我在想什么? (原始套接字)

在下面的代码中,有人请向我解释为什么strncmp返回零(意味着字符串匹配),但“if(ethernet_header-> h_dest == mac )“执行失败(不匹配)。 变量“mac”和“ethernet_header-> h_dest”是相同的类型和长度。

一些更多的背景: - 这是Linux 64位完成(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); 
} 

} 
+0

啊,不错!真正!真正!简单的错误!谢谢大家! – NomadAlien 2010-07-29 10:13:22

strncmpif都不应该用于比较MAC地址。

如果第一个嵌入的零字节可能会导致strncmp在实际不相等时表示它们相等,则它们将无法正常工作。这是因为以下两个值的strncmp

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

将是真实的(只检查到第一个零字节)。因为你比较指针而非内容的指针指向

第二个将无法工作。如果你有以下的内存布局:

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

然后用ethif (mac == eth)比较mac会给你false,因为它们是不同的指针,一个在78结束,另一个在7c

您应该使用memcmp,而不是因为它比较原始内存字节没有在早期零字节停止:

int result = memcmp (ethernet_header->h_dest, mac, ETH_ALEN); 
+0

请注意,这种错误(使用'strcmp()',其中'memcmp()'是有保证的)过去一直是一个安全问题,例如。当比较散列值时。 – caf 2010-07-29 13:40:36

什么是该代码?

if(ethernet_header->h_dest == mac) 

不在C中做字符串比较,只是一个指针比较,它总是在你的情况下是错误的。

if(ethernet_header->h_dest == mac)只比较原始指针值。这意味着它检查,如果两个字符串在相同的内存地址开始。通常情况下,这不是你想要的。

要比较两个C字符串的内容,请始终使用strncmp()

您不能测试使用==操作符串平等。这就是为什么strcmp()函数首先存在的原因。

strncmp需要指向char作为其首两个参数。

strncmp回报为零,因为在这些两个位置的字符串是同为ETH_ALEN字符 - 这并不意味着ethernet_header->h_destmac是相等的。他们是两个不同的指针

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 
  • p1p2相等,因为它们两者都指向在存储器中的相同的常量字符串。
  • 在数组的情况下,为每个数组变量(堆栈中)分配一个5字节的连续块,并将字符串asdf\0复制到这些位置。
  • s1s2是两个不同的指针,指向堆中恰好包含相同值的两个不同的5字节序列块。

在C中,==对字符串不起作用。您必须改用strncmp()

只要改变

if(ethernet_header->h_dest == mac) { 

if(result == 0) {