From c27df40923bec87471bde57c44c6dd8a024f980d Mon Sep 17 00:00:00 2001 From: aixiao Date: Thu, 24 Jul 2025 15:05:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=99=BD=E5=90=8D=E5=8D=95?= =?UTF-8?q?=E6=94=AF=E6=8C=81=EF=BC=8C=E8=BF=98=E6=9C=AA=E5=A4=A7=E9=87=8F?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cache.c | 4 +- cache.h | 2 +- cap.c | 130 +++++++++++++++++++++++++++++++++++++++----------- libipset.c | 47 ++++++++++++++++++ whitelist.txt | 4 ++ 5 files changed, 156 insertions(+), 31 deletions(-) create mode 100644 whitelist.txt diff --git a/cache.c b/cache.c index d617d5e..f640a83 100644 --- a/cache.c +++ b/cache.c @@ -1,5 +1,7 @@ #include "cache.h" + + struct ip_cache_node *ip_cache_head = NULL; // 缓存链表的头节点 int cache_size = 0; // 当前缓存中的 IP 数量 @@ -88,7 +90,7 @@ void free_ip_cache() cache_size = 0; } -char cn_ip[MAXIPSET_][MAXIPLEN] = { 0 }; + // 添加一个 IP 到集合(如果已存在则不添加) int add_cn_ip(char cn_ip[MAXIPSET_][MAXIPLEN], char *ip) diff --git a/cache.h b/cache.h index 42854d0..47a4f76 100644 --- a/cache.h +++ b/cache.h @@ -47,7 +47,7 @@ extern void add_ip_to_cache(const char *ip); extern int is_ip_in_cache(const char *ip); extern void free_ip_cache(); -extern char cn_ip[MAXIPSET_][MAXIPLEN]; +extern char (*cn_ip)[MAXIPLEN]; extern int add_cn_ip(char cn_ip[MAXIPSET_][MAXIPLEN], char *ip); extern int is_ip_in_set(char cn_ip[MAXIPSET_][MAXIPLEN], const char *ip); extern int cn_ip_len(char cn_ip[MAXIPSET_][MAXIPLEN]); diff --git a/cap.c b/cap.c index 9922e44..fcf1476 100644 --- a/cap.c +++ b/cap.c @@ -6,17 +6,22 @@ #include "leak_detector_c/leak_detector_c.h" pcap_if_t *alldevs, *device; -pcap_t *handle; // 会话句柄 -struct bpf_program fp; // 编译后的过滤器 +pcap_t *handle; // 会话句柄 +struct bpf_program fp; // 编译后的过滤器 -pid_t pids[MAX_CHILDREN] = {-1}; // 子进程全局PID -#define SHM_SIZE 1024 // 共享内存大小 -#define SHM_KEY 0124 // 共享内存键值 -int shmid = -1; -int RULE_NAME_NUMBER = 0; // ipset 集合集合数 +pid_t pids[MAX_CHILDREN] = {-1}; // 子进程全局PID + +char *ip2region_area = NULL; // ip2region 解析结果 + +// 共享内存 +#define SHM_SIZE (MAXIPSET_ * MAXIPLEN) +int shmid[3] = {-1}; + +char (*cn_ip)[MAXIPLEN] = NULL; // 用于存储国内 IP 地址 +char (*whitelist_ip)[MAXIPLEN] = NULL; // 最终要这样定义 char *RULE_NAME = NULL; // 共享内存 +int RULE_NAME_NUMBER = 0; // ipset 集合集合数 -char *ip2region_area = NULL; // ip2region 解析结果 void Processing_IP_addresses(char *src_ip) { @@ -28,6 +33,15 @@ void Processing_IP_addresses(char *src_ip) // 定义 Response 结构体 Response response; + + if (1 == is_ip_in_set(whitelist_ip, src_ip)) { + _printf(RED "IP:%s 白名单IP, 跳过!\n" REDEND, src_ip); + //printf("%s %d\n", whitelist_ip[0], cn_ip_len(whitelist_ip)); + + return; + } + + // 如果 IP 地址已在缓存中且未过期,则跳过查询 if (is_ip_in_cache(src_ip)) { _printf(RED "IP:%s 已在缓存中,跳过查询\n" REDEND, src_ip); @@ -37,7 +51,7 @@ void Processing_IP_addresses(char *src_ip) // 如果ipset规则已经存在,则跳过查询 snprintf(ipset_query_command, sizeof(ipset_query_command), "ipset test %s %s 2>/dev/null", RULE_NAME, src_ip); if (system(ipset_query_command) == 0) { - //_printf(RED "Ipset 规则内已经存在 %s\n" REDEND, src_ip); + _printf(RED "Ipset 规则内已经存在 %s\n" REDEND, src_ip); return; } @@ -67,13 +81,13 @@ void Processing_IP_addresses(char *src_ip) if (isregion(ip2region_area, _region_list) == 1) { // 返回1表示在白名单列表 ; } else { - +/* if (cache_size < MAX_CACHE_SIZE) // 缓存IP数不够预备设定值 { sleep(1); _printf("缓存 IP 数 %d\n", cache_size); } - +*/ add_ip_to_cache(src_ip); // 添加到缓存 char *p = CurlGetIpArea(src_ip); @@ -136,6 +150,8 @@ void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char // INET_ADDRSTRLEN: 缓冲区的长度 inet_ntop(AF_INET, &(ip_header->ip_src), src_ip, INET_ADDRSTRLEN); + + Processing_IP_addresses(src_ip); return; @@ -161,6 +177,16 @@ void usage() exit(0); } + +void detach_and_delete_shm(void *addr, int shmid, int delete_flag) { + if (addr && addr != (void *)-1) { + shmdt(addr); + } + if (delete_flag && shmid >= 0) { + shmctl(shmid, IPC_RMID, NULL); + } +} + void cleanup_(int signum) { @@ -178,10 +204,9 @@ void cleanup_(int signum) } // 释放共享内存 - if (RULE_NAME != NULL) { - shmdt(RULE_NAME); - shmctl(shmid, IPC_RMID, NULL); - } + detach_and_delete_shm(RULE_NAME, shmid[0], 1); + detach_and_delete_shm(whitelist_ip, shmid[1], 1); + detach_and_delete_shm(cn_ip, shmid[2], 1); // 在程序结束时,清理缓存链表 free_ip_cache(); @@ -195,7 +220,8 @@ void cleanup_(int signum) // 清理 pcap_freecode(&fp); pcap_freealldevs(alldevs); // 释放设备列表 - //pcap_close(handle); // 关闭会话句柄 + if (handle) + pcap_close(handle); // 退出主进程 exit(0); @@ -203,6 +229,30 @@ void cleanup_(int signum) return; } +void *create_and_attach_shm(const char *path, int proj_id, size_t size, int *shmid_out) { + key_t key = ftok(path, proj_id); + if (key == -1) { + perror("ftok"); + exit(1); + } + + int shmid = shmget(key, size, IPC_CREAT | 0666); + if (shmid < 0) { + perror("shmget"); + exit(1); + } + + void *addr = shmat(shmid, NULL, 0); + if (addr == (void *)-1) { + perror("shmat"); + exit(1); + } + + if (shmid_out) *shmid_out = shmid; + return addr; +} + + int main(int argc, char **argv) { atexit(report_mem_leak); @@ -284,17 +334,24 @@ int main(int argc, char **argv) } // 创建共享内存 - shmid = shmget(SHM_KEY, SHM_SIZE, IPC_CREAT | 0666); - if (shmid < 0) { - perror("shmget"); - exit(1); - } + RULE_NAME = (char *)create_and_attach_shm("/tmp", 'A', 1024, &shmid[0]); + whitelist_ip = (char (*)[MAXIPLEN])create_and_attach_shm("/tmp", 'B', SHM_SIZE, &shmid[1]); + cn_ip = (char (*)[MAXIPLEN])create_and_attach_shm("/tmp", 'C', SHM_SIZE, &shmid[2]); - // 连接共享内存到进程地址空间 - RULE_NAME = (char *)shmat(shmid, NULL, 0); - if (RULE_NAME == (char *)-1) { - perror("shmat"); - exit(1); + + + // 读取白名单 + if (1 == file_exists_access("whitelist.txt")) { + int line_count = 0; + int result = read_file_to_array("whitelist.txt", whitelist_ip, &line_count); + if (result != 0) { + fprintf(stderr, "Failed to read file with error code: %d\n", result); + return 1; + } + + for (int i = 0; i < line_count; i++) { + printf("Line %d: %s\n", i + 1, whitelist_ip[i]); + } } // 读取缓存 @@ -330,6 +387,21 @@ int main(int argc, char **argv) if ( 0 == pids[0] ) // 子进程 { while(1) { + + if (1 == file_exists_access("whitelist.txt")) { + clear_ip_set(whitelist_ip); // 清空白名单IP集合 + int line_count = 0; + int result = read_file_to_array("whitelist.txt", whitelist_ip, &line_count); + if (result != 0) { + fprintf(stderr, "Failed to read file with error code: %d\n", result); + return 1; + } + + for (int i = 0; i < line_count; i++) { + printf("Line %d: %s\n", i + 1, whitelist_ip[i]); + } + } + for (int i = 0; i < MAXIPSET_; i++) { if (cn_ip[i][0] != '\0') { printf("%s ", cn_ip[i]); @@ -342,7 +414,7 @@ int main(int argc, char **argv) truncate_file("cn.txt"); // 清空文件 } - sleep(60); // 每 60 秒检查一次 + sleep(10); // 每 60 秒检查一次 } } @@ -356,8 +428,8 @@ int main(int argc, char **argv) _printf("创建 IPSet %s 失败\n", RULE_NAME); } - while (1) { - //_printf("子进程当前 Ipset Rule 名 %s\n", RULE_NAME); + while (1) + { count = get_ip_count_in_ipset(RULE_NAME); if (count >= 0) { _printf("子进程当前 Ipset Rule 名 %s, 数量: %d \n", RULE_NAME, count); diff --git a/libipset.c b/libipset.c index 529785b..210c25c 100644 --- a/libipset.c +++ b/libipset.c @@ -150,6 +150,53 @@ int add_ip_to_ipset(char *set_name, char *ip) return 0; // 始终返回 0,表示执行成功 } +// 向指定的 ipset 删除 IP +int del_ip_to_ipset(char *set_name, char *ip) +{ + struct ipset *ipset = NULL; + struct ipset_session *session = NULL; + + // 初始化 ipset 和 session + ipset = ipset_init(); + if (!ipset) { + fprintf(stderr, "初始化 IPSet 失败\n"); + return -1; // 返回 -1,但不退出 + } + + ipset_load_types(); + + session = ipset_session(ipset); + if (!session) { + fprintf(stderr, "创建 IPSet 会话失败\n"); + ipset_fini(ipset); + return -1; // 返回 -1,但不退出 + } + // 设置 IPSet 名称 + if (ipset_session_data_set(session, IPSET_SETNAME, set_name) != 0) { + fprintf(stderr, "设置 IPSet 名称失败\n"); + ipset_session_fini(session); + ipset_fini(ipset); + return -1; // 返回 -1,但不退出 + } + // 设置自定义错误和输出处理函数 + if (ipset_custom_printf(ipset, custom_error_handler, NULL, custom_output_handler_, NULL) != 0) { + fprintf(stderr, "设置自定义打印函数失败。\n"); + ipset_fini(ipset); + return -1; + } + // 将ip添加到集合 + char *args[] = { "ipset", "del", set_name, ip, NULL }; + if (ipset_parse_argv(ipset, 4, args) != 0) { + ipset_fini(ipset); + return -1; + } + + ipset_session_fini(session); + ipset_fini(ipset); + + return 0; // 始终返回 0,表示执行成功 +} + // 定义一个函数来清空指定名称的 ipset 集合 int flush_ipset(char *set_name) { diff --git a/whitelist.txt b/whitelist.txt new file mode 100644 index 0000000..622411c --- /dev/null +++ b/whitelist.txt @@ -0,0 +1,4 @@ +127.0.0.1 +13.125.223.189 +158.101.117.243 +52.221.186.101