This commit is contained in:
2025-01-16 16:32:39 +08:00
parent a79a59bd97
commit a3712fde22
5 changed files with 133 additions and 97 deletions

View File

@@ -6,3 +6,4 @@
{"code":"Success","data":{"continent":"北美洲","country":"美国","zipcode":"","owner":"","isp":"Cloudflare, Inc.","adcode":"","prov":"","city":"","district":""},"ip":"1.1.1.6"} {"code":"Success","data":{"continent":"北美洲","country":"美国","zipcode":"","owner":"","isp":"Cloudflare, Inc.","adcode":"","prov":"","city":"","district":""},"ip":"1.1.1.6"}
{"code":"Success","data":{"continent":"北美洲","country":"美国","zipcode":"","owner":"","isp":"Cloudflare, Inc.","adcode":"","prov":"","city":"","district":""},"ip":"1.1.1.7"} {"code":"Success","data":{"continent":"北美洲","country":"美国","zipcode":"","owner":"","isp":"Cloudflare, Inc.","adcode":"","prov":"","city":"","district":""},"ip":"1.1.1.7"}
{"code":"Success","data":{"continent":"北美洲","country":"美国","zipcode":"","owner":"","isp":"Cloudflare, Inc.","adcode":"","prov":"","city":"","district":""},"ip":"1.1.1.8"} {"code":"Success","data":{"continent":"北美洲","country":"美国","zipcode":"","owner":"","isp":"Cloudflare, Inc.","adcode":"","prov":"","city":"","district":""},"ip":"1.1.1.8"}
{"code":"Success","data":{"continent":"亚洲","country":"中国","zipcode":"999077","owner":"Censys, Inc.","isp":"Censys, Inc.","adcode":"810000","prov":"中国香港","city":"中国香港","district":""},"ip":"199.45.154.152"}

214
cap.c
View File

@@ -3,33 +3,94 @@
#include "libipset.h" #include "libipset.h"
#include "libcurl.h" #include "libcurl.h"
pcap_if_t *alldevs, *device; pcap_if_t *alldevs, *device;
pcap_t *handle; // 会话句柄 pcap_t *handle; // 会话句柄
struct bpf_program fp; // 编译后的过滤器 struct bpf_program fp; // 编译后的过滤器
pid_t pid = -1; // 子进程全局PID pid_t pid = -1; // 子进程全局PID
#define SHM_SIZE 1024 // 共享内存大小 #define SHM_SIZE 1024 // 共享内存大小
#define SHM_KEY 0124 // 共享内存键值 #define SHM_KEY 0124 // 共享内存键值
int shmid = -1; int shmid = -1;
int RULE_NAME_NUMBER = 0; // ipset 集合集合数 int RULE_NAME_NUMBER = 0; // ipset 集合集合数
char *RULE_NAME = NULL; // 共享内存 char *RULE_NAME = NULL; // 共享内存
char *ip2region_area = NULL; // ip2region 解析结果 char *ip2region_area = NULL; // ip2region 解析结果
char *command_result = NULL; // 执行命令的结果 char *command_result = NULL; // 执行命令的结果
#define CACHE_TTL 180 // 设定缓存的存活时间为 600 秒 (10 分钟) #define CACHE_TTL 180 // 设定缓存的存活时间为 600 秒 (10 分钟)
#define MAX_CACHE_SIZE 100 // 缓存最多存储 100 个 IP 地址 #define MAX_CACHE_SIZE 100 // 缓存最多存储 100 个 IP 地址
struct ip_cache_node *ip_cache_head = NULL; // 缓存链表的头节点 struct ip_cache_node *ip_cache_head = NULL; // 缓存链表的头节点
int cache_size = 0; // 当前缓存中的 IP 数量 int cache_size = 0; // 当前缓存中的 IP 数量
// 定义链表结构,用于缓存 IP 地址 // 定义链表结构,用于缓存 IP 地址
struct ip_cache_node { struct ip_cache_node {
char ip[INET_ADDRSTRLEN]; // 存储 IP 地址 char ip[INET_ADDRSTRLEN]; // 存储 IP 地址
time_t timestamp; // 记录缓存时间 time_t timestamp; // 记录缓存时间
struct ip_cache_node *next; // 指向下一个节点 struct ip_cache_node *next; // 指向下一个节点
}; };
#define MAXIPSET_ 100
#define MAXIPLEN 32
char cn_ip[MAXIPSET_][MAXIPLEN] = { 0 };
// 添加一个 IP 到集合(如果已存在则不添加)
int add_cn_ip(char cn_ip[MAXIPSET_][MAXIPLEN], char *ip)
{
if (ip == NULL || strlen(ip) >= MAXIPLEN) {
return -1; // 错误:无效的 IP 地址或过长
}
// 检查是否已存在
for (int i = 0; i < MAXIPSET_; i++) {
if (cn_ip[i][0] != '\0' && strcmp(cn_ip[i], ip) == 0) {
return 1; // IP 已存在,返回特殊代码
}
}
// 查找空位并添加
for (int i = 0; i < MAXIPSET_; i++) {
if (cn_ip[i][0] == '\0') { // 检查是否为空
strcpy(cn_ip[i], ip);
return 0; // 成功添加
}
}
return -1; // 错误:集合已满
}
// 判断给定的IP地址是否在集合中
int is_ip_in_set(char cn_ip[MAXIPSET_][MAXIPLEN], const char *ip)
{
if (ip == NULL) {
return 0; // 错误无效的IP地址指针
}
for (int i = 0; i < MAXIPSET_; i++) {
if (cn_ip[i][0] != '\0' && strcmp(cn_ip[i], ip) == 0) {
return 1; // 找到匹配的IP地址
}
}
return 0; // 没有找到匹配的IP地址
}
// 计算集合中非空IP的数量
int cn_ip_len(char cn_ip[MAXIPSET_][MAXIPLEN])
{
int count = 0; // 用于计数非空IP
for (int i = 0; i < MAXIPSET_; i++) {
if (cn_ip[i][0] != '\0') {
count++; // 非空IP计数
}
}
return count;
}
// 安全的清理IP地址集合将所有位置置为空字符串
void clear_ip_set(char cn_ip[MAXIPSET_][MAXIPLEN])
{
if (cn_ip == NULL) {
return; // 如果指针无效,则直接返回
}
for (int i = 0; i < MAXIPSET_; i++) {
memset(cn_ip[i], '\0', MAXIPLEN);
}
}
// 检查 IP 是否已在缓存中并是否过期 // 检查 IP 是否已在缓存中并是否过期
int is_ip_in_cache(const char *ip) int is_ip_in_cache(const char *ip)
@@ -117,14 +178,14 @@ void free_ip_cache()
// 回调函数,在捕获到每个数据包时调用 // 回调函数,在捕获到每个数据包时调用
void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{ {
int ethernet_header_len = 14; int ethernet_header_len = 14;
struct ip *ip_header = (struct ip *)(packet + ethernet_header_len); struct ip *ip_header = (struct ip *)(packet + ethernet_header_len);
char src_ip[INET_ADDRSTRLEN] = { 0 }; char src_ip[INET_ADDRSTRLEN] = { 0 };
// 地域白名单 // 地域白名单
char _region_list[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } }; char _region_list[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } };
char _REGION_LIST[BUFFER] = { 0 }; char _REGION_LIST[BUFFER] = { 0 };
const char *REGION_ENV = NULL; const char *REGION_ENV = NULL;
char ipset_query_command[256] = { 0 }; char ipset_query_command[256] = { 0 };
//char ip_query_command[256] = { 0 }; //char ip_query_command[256] = { 0 };
@@ -132,12 +193,7 @@ void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char
// 定义 Response 结构体 // 定义 Response 结构体
Response response; Response response;
int r = 0;
//char *t = _time();
inet_ntop(AF_INET, &(ip_header->ip_src), src_ip, INET_ADDRSTRLEN); inet_ntop(AF_INET, &(ip_header->ip_src), src_ip, INET_ADDRSTRLEN);
//_printf("%s\n", src_ip);
// 如果 IP 地址已在缓存中且未过期,则跳过查询 // 如果 IP 地址已在缓存中且未过期,则跳过查询
if (is_ip_in_cache(src_ip)) { if (is_ip_in_cache(src_ip)) {
@@ -152,6 +208,25 @@ void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char
return; return;
} }
if (1 == is_ip_in_set(cn_ip, src_ip)) {
_printf(RED "IP:%s 已经标记为国内,跳过!!!\n" REDEND, src_ip);
for (int i = 0; i < MAXIPSET_; i++) {
if (cn_ip[i][0] != '\0') {
printf("%s ", cn_ip[i]);
}
}
if (cn_ip_len(cn_ip) >= 100) { // 清理集合
clear_ip_set(cn_ip);
}
printf("cn_ip_len(cn_ip): %d\n", cn_ip_len(cn_ip));
return;
}
// 执行查询并添加到缓存 // 执行查询并添加到缓存
ip2region_area = ip2region("ip2region/ip2region.xdb", src_ip); ip2region_area = ip2region("ip2region/ip2region.xdb", src_ip);
if (ip2region_area == NULL) { if (ip2region_area == NULL) {
@@ -179,25 +254,17 @@ void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char
_printf("缓存 IP 数 %d\n", cache_size); _printf("缓存 IP 数 %d\n", cache_size);
} }
add_ip_to_cache(src_ip); // 添加到缓存
char *p = curl_get_area(src_ip); char *p = curl_get_area(src_ip);
//puts(p); if (parse_json_to_struct(p, &response) == 0) { // 解析 JSON 到结构体
if (parse_json_to_struct(p, &response) == 0) { // 解析 JSON 到结构体
// 输出解析结果
/*
printf("Code: %s\n", response.code);
printf("IP: %s\n", response.ip);
printf("Continent: %s\n", response.data.continent);
printf("Country: %s\n", response.data.country);
printf("ISP: %s\n", response.data.isp);
printf("Region: %s\n", response.data.region);
*/
char *p1 = strstr(response.continent_country, "中国"); if (NULL == strstr(response.continent_country, "中国")) { // 这时是国外IP
if (p1 == NULL) {
_printf(RED "%s %s\n" REDEND, src_ip, response.continent_country); _printf(RED "%s %s\n" REDEND, src_ip, response.continent_country);
r = add_ip_to_ipset(RULE_NAME, src_ip); add_ip_to_ipset(RULE_NAME, src_ip);
//_printf("add_ip_to_ipset() return %d\n", r); } else { // 这时是国内IP
add_cn_ip(cn_ip, src_ip); // 添加国内IP到缓存
_printf("IP: %s 离线库为国外, API 判断为国内, 标记为已处理!!!\n", src_ip);
} }
} else { } else {
@@ -206,38 +273,13 @@ void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char
free(p); free(p);
/*
//go 执行命令方法
snprintf(ip_query_command, sizeof(ip_query_command), "./IP_region_query/ipquery %s", src_ip);
command_result = _execute_command(ip_query_command);
if (command_result != NULL) {
add_ip_to_cache(src_ip); // 添加 IP 到缓存
char *p = strstr(command_result, "中国");
if (p == NULL) {
_printf(RED "%s %s\n" REDEND, src_ip, command_result);
r = add_ip_to_ipset(RULE_NAME, src_ip);
_printf("add_ip_to_ipset() return %d\n", r);
}
free(command_result);
command_result = NULL;
} else {
;
}
if (command_result != NULL)
free(command_result);
*/
} }
if (ip2region_area != NULL) if (ip2region_area != NULL) {
{
free(ip2region_area); free(ip2region_area);
ip2region_area = NULL; ip2region_area = NULL;
} }
return ; return;
} }
void usage() void usage()
@@ -292,7 +334,6 @@ void cleanup_(int signum)
pcap_freealldevs(alldevs); // 释放设备列表 pcap_freealldevs(alldevs); // 释放设备列表
//pcap_close(handle); // 关闭会话句柄 //pcap_close(handle); // 关闭会话句柄
// 退出主进程 // 退出主进程
exit(0); exit(0);
@@ -304,11 +345,11 @@ int main(int argc, char **argv)
// 注册 SIGTERM 信号处理函数 // 注册 SIGTERM 信号处理函数
signal(SIGTERM, cleanup_); signal(SIGTERM, cleanup_);
int opt; int opt;
char errbuf[PCAP_ERRBUF_SIZE] = { 0 }; // 错误缓冲区 char errbuf[PCAP_ERRBUF_SIZE] = { 0 }; // 错误缓冲区
char protocol[] = "tcp"; char protocol[] = "tcp";
char interface[256] = "{ 0 }"; char interface[256] = "{ 0 }";
char Ipset_Command[BUFFER] = { 0 }; char Ipset_Command[BUFFER] = { 0 };
strcpy(interface, "eth0"); strcpy(interface, "eth0");
memset(&alldevs, 0, sizeof(alldevs)); memset(&alldevs, 0, sizeof(alldevs));
@@ -327,8 +368,7 @@ int main(int argc, char **argv)
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
}; };
while (-1 != (opt = getopt_long(argc, argv, optstring, longopts, &longindex))) while (-1 != (opt = getopt_long(argc, argv, optstring, longopts, &longindex))) {
{
switch (opt) { switch (opt) {
case 'd': case 'd':
if (daemon(1, 1)) { if (daemon(1, 1)) {
@@ -346,17 +386,13 @@ int main(int argc, char **argv)
if (strcmp(optarg, "start") == 0) { if (strcmp(optarg, "start") == 0) {
memset(Ipset_Command, 0, BUFFER); memset(Ipset_Command, 0, BUFFER);
// 将 MAXIPSET_RULT_NAME_NUM 替换为实际值 // 将 MAXIPSET_RULT_NAME_NUM 替换为实际值
snprintf(Ipset_Command, sizeof(Ipset_Command), snprintf(Ipset_Command, sizeof(Ipset_Command), "for n in $(seq 0 %d); do iptables -A INPUT -p tcp -m set --match-set root$n src -j DROP 2> /dev/null; done", MAXIPSET_RULT_NAME_NUM);
"for n in $(seq 0 %d); do iptables -A INPUT -p tcp -m set --match-set root$n src -j DROP 2> /dev/null; done",
MAXIPSET_RULT_NAME_NUM);
system(Ipset_Command); system(Ipset_Command);
exit(0); exit(0);
} else if (strcmp(optarg, "stop") == 0) { } else if (strcmp(optarg, "stop") == 0) {
memset(Ipset_Command, 0, BUFFER); memset(Ipset_Command, 0, BUFFER);
// 将 MAXIPSET_RULT_NAME_NUM 替换为实际值 // 将 MAXIPSET_RULT_NAME_NUM 替换为实际值
snprintf(Ipset_Command, sizeof(Ipset_Command), snprintf(Ipset_Command, sizeof(Ipset_Command), "for n in $(seq 0 %d); do iptables -D INPUT -p tcp -m set --match-set root$n src -j DROP 2> /dev/null; done", MAXIPSET_RULT_NAME_NUM);
"for n in $(seq 0 %d); do iptables -D INPUT -p tcp -m set --match-set root$n src -j DROP 2> /dev/null; done",
MAXIPSET_RULT_NAME_NUM);
system(Ipset_Command); system(Ipset_Command);
exit(0); exit(0);
} else { } else {
@@ -377,7 +413,6 @@ int main(int argc, char **argv)
} }
} }
// 创建共享内存 // 创建共享内存
shmid = shmget(SHM_KEY, SHM_SIZE, IPC_CREAT | 0666); shmid = shmget(SHM_KEY, SHM_SIZE, IPC_CREAT | 0666);
if (shmid < 0) { if (shmid < 0) {
@@ -392,25 +427,23 @@ int main(int argc, char **argv)
exit(1); exit(1);
} }
pid = fork(); // 创建子进程 pid = fork(); // 创建子进程
if (pid == 0) // 子进程 if (pid == 0) // 子进程
{ {
int count = 0; int count = 0;
snprintf(RULE_NAME, BUFFER, "root%d", RULE_NAME_NUMBER); snprintf(RULE_NAME, BUFFER, "root%d", RULE_NAME_NUMBER);
if (create_ipset(RULE_NAME) != 0) { if (create_ipset(RULE_NAME) != 0) {
_printf("创建 IPSet %s 失败\n", RULE_NAME); _printf("创建 IPSet %s 失败\n", RULE_NAME);
} }
while (1) while (1) {
{
//_printf("子进程当前 Ipset Rule 名 %s\n", RULE_NAME); //_printf("子进程当前 Ipset Rule 名 %s\n", RULE_NAME);
count = get_ip_count_in_ipset(RULE_NAME); count = get_ip_count_in_ipset(RULE_NAME);
if (count >= 0) { if (count >= 0) {
_printf("子进程当前 Ipset Rule 名 %s, 数量: %d\n", RULE_NAME, count); _printf("子进程当前 Ipset Rule 名 %s, 数量: %d \n", RULE_NAME, count);
if (count >= MAXIPSET && RULE_NAME_NUMBER <= MAXIPSET_RULT_NAME_NUM) // RULE_中的IP数量不超过MAXIPSET并且集合不能超过 MAXIPSET_RULT_NAME_NUM 个 if (count >= MAXIPSET && RULE_NAME_NUMBER <= MAXIPSET_RULT_NAME_NUM) // RULE_中的IP数量不超过MAXIPSET并且集合不能超过 MAXIPSET_RULT_NAME_NUM 个
{ {
RULE_NAME_NUMBER++; RULE_NAME_NUMBER++;
@@ -437,7 +470,6 @@ int main(int argc, char **argv)
} }
} }
// 查找可用的网络设备 // 查找可用的网络设备
if (pcap_findalldevs(&alldevs, errbuf) == -1) { if (pcap_findalldevs(&alldevs, errbuf) == -1) {
fprintf(stderr, "无法找到设备: %s\n", errbuf); fprintf(stderr, "无法找到设备: %s\n", errbuf);

3
cap.h
View File

@@ -28,4 +28,7 @@
#define _VERSION "0.2" #define _VERSION "0.2"
#endif #endif

Binary file not shown.

View File

@@ -6,7 +6,7 @@
int main() int main()
{ {
// 执行查询并添加到缓存 // 执行查询并添加到缓存
char *area = ip2region("ip2region.xdb", "1.1.1.1"); char *area = ip2region("ip2region.xdb", "199.45.154.152");
if (area == NULL) { if (area == NULL) {
return -1; return -1;
} }