C 快速比较IP地址的最智能方法?
我有一个IP地址列表,存储方式如下:C 快速比较IP地址的最智能方法?,c,linux,networking,ip,libpcap,C,Linux,Networking,Ip,Libpcap,我有一个IP地址列表,存储方式如下: char IP_addresses_list[] = { "157.55.130", /* 157.55.130.0/24 */ "157.56.52", /* 157.56.52.0/24 */ "157.12.53", /* 157.12.53.0/24 */ ... }; 我从嗅探的数据包中获取IP地址(将其转换为struct iphdr*iph=(struct iphdr*)(数据包+sizeof(struct
char IP_addresses_list[] = {
"157.55.130", /* 157.55.130.0/24 */
"157.56.52", /* 157.56.52.0/24 */
"157.12.53", /* 157.12.53.0/24 */
...
};
我从嗅探的数据包中获取IP地址(将其转换为struct iphdr*iph=(struct iphdr*)(数据包+sizeof(struct ether_header));
我使用inet_ntop
将其转换为字符串;最后,我将数据包中的IP地址与列表中的IP地址进行比较,并使用以下代码:
/*
* input: IP address to search in the list
* output: 1 if IP address is found in the list, 0 otherwise
*/
int find_IP_addr(char *server) {
int ret = 0;
int i, string_size1, string_size2;
char *copied_server, *copied_const_char;
char *save_ptr1, *save_ptr2;
char dot[2] = ".";
/* Here I store the IP address from the packet */
char first_IPaddr_pkt[4], second_IPaddr_pkt[4], third_IPaddr_pkt[4];
/* Here I store the IP address from the list */
char first_IPaddr_list[4], second_IPaddr_list[4], third_IPaddr_list[4];
string_size1 = strlen(server)+1;
copied_server = (char *)malloc(string_size1 * sizeof(char));
strcpy(copied_server, server);
/* I store and compare the first three bits of the IP address */
strcpy(first_IPaddr_pkt, strtok_r(copied_server, dot, &save_ptr1));
strcpy(second_IPaddr_pkt, strtok_r(NULL, dot, &save_ptr1));
strcpy(third_IPaddr_pkt, strtok_r(NULL, dot, &save_ptr1));
printf("tokenized %s, %s and %s\n", first_IPaddr_pkt, second_IPaddr_pkt, third_IPaddr_pkt);
/* Now I scan the list */
for (i=0; i<LIST_LENGTH; i++) {
/* I copy an address from the list */
string_size2 = strlen(IP_addresses_list[i])+1; // +1 for null character
copied_const_char = (char *)malloc(string_size2 * sizeof(char));
strcpy(copied_const_char, IP_addresses_list[i]);
/* Let's split the address from the list */
strcpy(first_IPaddr_list, strtok_r(copied_const_char, dot, &save_ptr2));
strcpy(second_IPaddr_list, strtok_r(NULL, dot, &save_ptr2));
strcpy(third_IPaddr_list, strtok_r(NULL, dot, &save_ptr2));
printf("tokenized %s, %s and %s\n", first_IPaddr_list, second_IPaddr_list, third_IPaddr_list);
/* I compare the first byte of the address from the packet I got and
the first byte of the address from the list:
if they are different, there's no reason to continue comparing
the other bytes of the addresses */
if (strcmp(first_IPaddr_pkt, first_IPaddr_list) != 0) {
continue;
}
else {
if (strcmp(second_IPaddr_pkt, second_IPaddr_list) != 0) {
continue;
}
else {
if (strcmp(third_IPaddr_pkt, third_IPaddr_list) != 0) {
continue;
}
else
/* All the bytes are the same! */
ret = 1;
}
}
free(copied_const_char);
}
free(copied_server);
return ret;
}
是否可以在不使用
inet\u ntop
的情况下进行比较,可能只是在两个地址仍然是u\u int32\t
时进行比较
编辑:下面是一个解决方案示例,供阅读此问题的人参考
#include <stdio.h>
#include <sys/types.h>
int main() {
// In the list I have: 104.40.0.0./13
int cidr = 13;
u_int32_t ipaddr_from_pkt = 1747488105; // pkt coming from 104.40.141.105
u_int32_t ipaddr_from_list = 1747451904; // 104.40.0.0
int mask = (-1) << (32 - cidr);
if ((ipaddr_from_pkt & mask) == ipaddr_from_list)
printf("IP address belongs to the given range!!!\n");
else printf ("failure\n");
return 0;
}
#包括
#包括
int main(){
//在列表中我有:104.40.0.0./13
int-cidr=13;
u_int32_t ipaddr_from_pkt=1747488105;//pkt from 104.40.141.105
u_int32_t ipaddr_from_list=1747451904;//104.40.0.0
int mask=(-1)性能问题与strcmp()无关,malloc()
,但是没有必要
如果只使用IPv4地址,则只需16个字符即可存储该地址,这样就可以删除malloc()
,并将临时存储声明为数组
但是,如果列表中有许多ip地址,则有一个重要的改进
首先,您需要对IP地址列表进行排序,然后使用bsearch()
搜索正确的IP。这样,代码将在O(log(2n))时间内运行,比O(N)快得多,特别是对于大的N
最快的方法是在字典中存储地址,请参见我的方法是:
只需将strncat
与“.0”
一起使用,即可构建有效的IPv4地址
使用带有套接字类型等常量值的getaddrinfo
来构建addrinfo
结构
比较addrinfo
的相关字段
基本上,中的示例可以避免将二进制数据转换为字符串。如果将它们保持为二进制,则比较起来非常容易:
match = (ip & listed_mask) == listed_ip;
“/24”是一个掩码。表示只有24个最高位是相关的。您可以将其转换为二进制掩码,如下所示:
listed_mask = (-1) << (32 - 24);
listed\u mask=(-1)这些地址都不是有效的IPv4地址,所以我先将它们转换成类似的地址,然后使用标准网络库。这有很多代码只用于ip地址比较。是的,不要使用malloc()
/free()
,也没有合理的理由需要strtok()
。“是否可以在不使用inet\u ntop
的情况下进行比较,可能只是在两个地址仍然是u\u int32\t
时进行比较?”?“为什么与32位无符号的int
值相比无效?当新程序员开始关心可读性时,你让我认为你的代码是错误的,因此给出了错误的答案。strlen(服务器)+1
我没有看到+1
,因为它与其他字符太接近,因此看起来像一个单独的对象。中没有字典。不建议使用仅链接的答案。呃,但是链接描述了如何实现字典?您不会将链接保留为答案。这就是我的答案。我写了“157.55.130”因为我的意思是“157.55.130.0/24”:我不想写从157.55.130.0到157.55.130.255的整个地址范围。如果我得到一个来自157.55.130.45的数据包,我只比较地址的前三个字节(157.55.130)你不必听从我的建议,但是让一个标准的库函数来完成你的工作,形成一个格式良好的地址绝对是我喜欢你的长手比较解决方案。我考虑使用为工作而设计的工具,在这种情况下,使用一个标准的库函数来设计。理解表示IP地址的字符串比编写自己的、可能存在错误的版本要聪明得多。假设你不必每秒解析数百万个地址,那么在我能想到的任何机器上,开销都可以忽略不计。我不擅长使用掩码和逻辑运算符:你能解释一下你的代码吗?/24是一个mask。您使用它来计算“列出的\u掩码”-见上文。然后您使用掩码用&操作屏蔽掉ip中不相关的8位。这将用零替换不相关的位。您将结果压缩到列表中列出的\u ip(已屏蔽)如果相等的话,你已经找到了匹配项。我的列表确实会很长,超过150个IP地址。b搜索
可能是一个不错的策略!
listed_mask = (-1) << (32 - 24);