我正在尝试构建一个在以太网级别上工作的简单echo服务器/客户端(使用原始套接字)。 服务器端本身工作并显示eth0上的所有传入数据包。 客户端工作并在eth0上发送以太网数据包(我使用wireshark检查了这个数据包,可以看到数据包已经发出。) 我现在想要制作一个过滤器,只查看我感兴趣的数据包。 (这取决于目的地/源地址。)
在下面的代码中,有人可以向我解释为什么strncmp返回零(意味着字符串匹配)但是“if(ethernet_header-> h_dest == mac)”无法执行(不匹配)。 变量“mac”和“ethernet_header-> h_dest”都是相同的类型和长度。
更多背景资料: - 这是在linux 64bit(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 *) ðernet_header->h_proto, 2);
printf("\n\n");
printf("Length: %d\n",len);
}
} else {
printf("Packet size too small (length: %d)!\n",len);
}
}
答案 0 :(得分:9)
不应使用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
结尾,另一个以{{}结尾1}}。
您应该使用7c
,因为它会比较原始内存字节而不会在早期零字节处停止:
memcmp
答案 1 :(得分:1)
您无法使用==运算符测试字符串相等性。这就是strcmp()函数首先存在的原因。
答案 2 :(得分:1)
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
相等,因为它们都指向内存中的相同const字符串。 asdf\0
复制到这些位置。s1
和s2
是两个不同的指针,指向堆中恰好包含相同值的两个不同的5字节序列块。答案 3 :(得分:0)
这段代码是什么?
if(ethernet_header->h_dest == mac)
在C中不进行字符串比较,只是指针比较,在你的情况下总是假的。
答案 4 :(得分:0)
if(ethernet_header->h_dest == mac)
只是比较原始指针值。这意味着它检查两个字符串是否从相同的内存地址开始。通常,这不是你想要的。
要比较两个c字符串的内容,请始终使用strncmp()
。
答案 5 :(得分:0)
在C语言中,==
对字符串不起作用。您必须改为使用strncmp()
。
只需更改
if(ethernet_header->h_dest == mac) {
到
if(result == 0) {