[英]Smartest way to compare IP addresses quickly?
I have a list of IP addresses, stored like this: 我有一个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 */
...
};
I get the IP address from the sniffed packet (casting it to struct iphdr *iph = (struct iphdr *)(packet + sizeof(struct ether_header));
I convert it in a character string using inet_ntop
; finally, I compare the IP address from the packet with the ones in the list with the following code: 我从嗅探到的数据包中获得IP地址(将其广播到
struct iphdr *iph = (struct iphdr *)(packet + sizeof(struct ether_header));
我使用inet_ntop
将其转换为字符串;最后,我比较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;
}
I'd like to make this more fast, without using strtok
, strcmp
, malloc
or free
. 我想使它更快,而不使用
strtok
, strcmp
, malloc
或free
。 In /usr/include/netinet/ip.h
I see that addresses are 在
/usr/include/netinet/ip.h
我看到地址是
u_int32_t saddr;
u_int32_t daddr;
is it possible to compare without even using inet_ntop
first, maybe just comparing the two addresses while they still are u_int32_t
? 是否有可能甚至
inet_ntop
先使用inet_ntop
进行比较,也可能只是在两个地址仍然为u_int32_t
时进行比较?
EDIT: here's a solution example for whoever will read this question. 编辑:这是解决方案示例,适合任何人阅读此问题。
#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;
}
Thanks to iharob too for the bsearch
hint. 也感谢iharob提供的
bsearch
提示。
I would avoid converting the binary data to strings. 我会避免将二进制数据转换为字符串。 If you keep them binary then it's quite easy to compare:
如果将它们保留为二进制,则比较起来很容易:
match = (ip & listed_mask) == listed_ip;
"/24" is a mask. “ / 24”是掩码。 Means inly 24 highest bits are relevant.
意味着只有24个最高位是相关的。 You convert it to binary mask as follows:
您将其转换为二进制掩码,如下所示:
listed_mask = (-1) << (32 - 24);
The performance issues have nothing to do with strcmp()
, malloc()
is unnecessary though. 性能问题与
strcmp()
无关,尽管malloc()
是不必要的。
If you are only using IPv4 addresses you only need 16 characters to store it so you can remove malloc()
and declare the temporary storage as an array. 如果仅使用IPv4地址,则只需要16个字符即可存储它,因此可以删除
malloc()
并将临时存储声明为数组。
But there is an important improvement if there are going to be many ip addresses in the list. 但是,如果列表中将有许多ip地址,则有一个重要的改进。
First you need to sort the list of IP addresses, and then use bsearch()
to search for the right IP. 首先,您需要对IP地址列表进行排序,然后使用
bsearch()
搜索正确的IP。 This way the code will run in O(log(2n)) time which is a lot faster than O(N) , specially for large N
这样,代码将以O(log(2n))的时间运行,这比O(N)快很多,特别是对于较大的
N
My approach here would be: 我的方法是:
strncat
with ".0"
to build valid IPv4 addresses. ".0"
的strncat
即可构建有效的IPv4地址。 getaddrinfo
with constant values for socket type etc to build a addrinfo
struct getaddrinfo
来构建addrinfo
结构 addrinfo
. addrinfo
的相关字段。 Basically, the example from man getaddrinfo
does all this . 基本上,来自
man getaddrinfo
的示例完成了所有这一切 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.