diff --git a/.vscode/settings.json b/.vscode/settings.json index 49964e7..c10cf8a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,6 +5,11 @@ "prctl.h": "c", "algorithm": "c", "cstdlib": "c", - "libipset.h": "c" + "libipset.h": "c", + "array": "c", + "cache.h": "c", + "errno.h": "c", + "stdlib.h": "c", + "string.h": "c" } } \ No newline at end of file diff --git a/Makefile b/Makefile index b6af680..d21455e 100644 --- a/Makefile +++ b/Makefile @@ -68,11 +68,11 @@ ipquery: cd IP_region_query && CGO_ENABLED=0 go build -ldflags '-w -s' && upx -9 ipquery # 动态链接目标 -$(BIN): cap.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o libipset.o libcurl.o +$(BIN): cap.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o libipset.o libcurl.o cache.o $(CC) $(CFLAGS) -o $(BIN) $^ -lpcap -lipset -lcurl -lcjson # 静态链接目标 -static: cap.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o libipset.o libcurl.o +static: cap.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o libipset.o libcurl.o cache.o $(CC) $(CFLAGS) $(CFLAGS_LIBCURL) $(CFLAGS_LIBCJSON) -o $(BIN) $^ $(LIBPCAP) $(LIBCAP) $(LIBIPSET) $(LIBCJSON) $(LIBCURL) $(LIBS) -static %.o: %.c @@ -81,4 +81,4 @@ static: cap.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o libipset.o # 清理目标 clean: rm -rf $(BIN) IP_region_query/ipquery - rm -rf cap.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o libipset.o libcurl.o + rm -rf cap.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o libipset.o libcurl.o cache.o diff --git a/cache.c b/cache.c new file mode 100644 index 0000000..27d7ef4 --- /dev/null +++ b/cache.c @@ -0,0 +1,150 @@ +#include "cache.h" + +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); + } + + return; +} + +// 保存字符串到文件 +int append_string_to_file(const char *filepath, const char *str) +{ + // 检查输入是否为空 + if (filepath == NULL || str == NULL) { + fprintf(stderr, "Invalid argument(s).\n"); + return -1; + } + // 打开文件以追加模式 + FILE *file = fopen(filepath, "a"); + if (file == NULL) { + perror("Error opening file"); + return -1; + } + // 追加字符串到文件 + if (fprintf(file, "%s\n", str) < 0) { + perror("Error writing to file"); + fclose(file); + return -1; + } + // 刷新缓冲区确保数据写入磁盘 + if (fflush(file) != 0) { + perror("Error flushing file"); + fclose(file); + return -1; + } + // 关闭文件 + if (fclose(file) != 0) { + perror("Error closing file"); + return -1; + } + // 成功返回 + return 0; +} + +int read_file_to_array(const char *filepath, char cn_ip[MAXIPSET_][MAXIPLEN], int *line_count) +{ + // 参数校验 + if (filepath == NULL || cn_ip == NULL || line_count == NULL) { + fprintf(stderr, "Invalid argument(s).\n"); + return -1; + } + + FILE *file = fopen(filepath, "r"); + if (file == NULL) { + fprintf(stderr, "Error opening file '%s': %s\n", filepath, strerror(errno)); + return -2; + } + + int count = 0; + while (fgets(cn_ip[count], MAXIPLEN, file)) { + // 去掉行尾的换行符 + size_t len = strlen(cn_ip[count]); + if (len > 0 && cn_ip[count][len - 1] == '\n') { + cn_ip[count][len - 1] = '\0'; + } + count++; + if (count >= MAXIPSET_) { + fprintf(stderr, "Exceeded maximum number of lines (%d).\n", MAXIPSET_); + fclose(file); + return -3; + } + } + + if (ferror(file)) { + fprintf(stderr, "Error reading file '%s'.\n", filepath); + fclose(file); + return -4; + } + + fclose(file); + *line_count = count; + return 0; +} + +// 判断文件是否存在,返回 1 表示存在,0 表示不存在 +int file_exists_access(const char *filepath) +{ + if (filepath == NULL) { + fprintf(stderr, "Invalid argument.\n"); + return 0; + } + + return access(filepath, F_OK) == 0; +} diff --git a/cache.h b/cache.h new file mode 100644 index 0000000..3b5ce90 --- /dev/null +++ b/cache.h @@ -0,0 +1,26 @@ +#ifndef CACHE_H +#define CACHE_H + +#include +#include +#include +#include +#include + +#define MAXIPSET_ 256 +#define MAXIPLEN 32 + +extern char cn_ip[MAXIPSET_][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]); +extern void clear_ip_set(char cn_ip[MAXIPSET_][MAXIPLEN]); +extern int is_ip_in_cache(const char *ip); + +extern int append_string_to_file(const char *filepath, const char *str); +extern int read_file_to_array(const char *filepath, char cn_ip[MAXIPSET_][MAXIPLEN], int *line_count); + +extern int file_exists_access(const char *filepath); + +#endif diff --git a/cap.c b/cap.c index dae9447..106c57f 100644 --- a/cap.c +++ b/cap.c @@ -2,6 +2,8 @@ #include "common.h" #include "libipset.h" #include "libcurl.h" +#include "cache.h" + pcap_if_t *alldevs, *device; pcap_t *handle; // 会话句柄 @@ -29,100 +31,6 @@ struct ip_cache_node { 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 是否已在缓存中并是否过期 -int is_ip_in_cache(const char *ip) -{ - time_t now = time(NULL); // 获取当前时间 - struct ip_cache_node *current = ip_cache_head; - struct ip_cache_node *prev = NULL; - - while (current != NULL) { - // 如果 IP 匹配并且未过期 - if (strcmp(current->ip, ip) == 0) { - if (now - current->timestamp <= CACHE_TTL) { - return 1; // IP 在缓存中,且未过期 - } else { - // 如果过期,从链表中移除这个节点 - if (prev == NULL) { - ip_cache_head = current->next; - } else { - prev->next = current->next; - } - - free(current); - cache_size--; - return 0; // IP 过期,不再缓存 - } - } - - prev = current; - current = current->next; - } - return 0; // IP 不在缓存中 -} // 将新 IP 添加到缓存,若缓存过大则移除最早的 IP void add_ip_to_cache(const char *ip) @@ -161,6 +69,38 @@ void add_ip_to_cache(const char *ip) cache_size++; } +// 检查 IP 是否已在缓存中并是否过期 +int is_ip_in_cache(const char *ip) +{ + time_t now = time(NULL); // 获取当前时间 + struct ip_cache_node *current = ip_cache_head; + struct ip_cache_node *prev = NULL; + + while (current != NULL) { + // 如果 IP 匹配并且未过期 + if (strcmp(current->ip, ip) == 0) { + if (now - current->timestamp <= CACHE_TTL) { + return 1; // IP 在缓存中,且未过期 + } else { + // 如果过期,从链表中移除这个节点 + if (prev == NULL) { + ip_cache_head = current->next; + } else { + prev->next = current->next; + } + + free(current); + cache_size--; + return 0; // IP 过期,不再缓存 + } + } + + prev = current; + current = current->next; + } + return 0; // IP 不在缓存中 +} + // 清理缓存链表,释放所有节点的内存 void free_ip_cache() { @@ -175,6 +115,7 @@ void free_ip_cache() cache_size = 0; } + // 回调函数,在捕获到每个数据包时调用 void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) { @@ -264,6 +205,10 @@ void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char } else { // 这时是国内IP add_cn_ip(cn_ip, src_ip); // 添加国内IP到缓存 _printf("IP: %s 离线库为国外, API 判断为国内, 标记为已处理!!!\n", src_ip); + + if (append_string_to_file("cn.txt", src_ip) != 0) { + _printf("append_string_to_file() Error!!!\n"); + } } } else { @@ -427,6 +372,21 @@ int main(int argc, char **argv) exit(1); } + // 读取缓存 + if (1 == file_exists_access("cn.txt")) { + int line_count = 0; + int result = read_file_to_array("cn.txt", cn_ip, &line_count); + if (result != 0) { + fprintf(stderr, "Failed to read file with error code: %d\n", result); + return 1; + } + + printf("Read %d lines from file:\n", line_count); + for (int i = 0; i < line_count; i++) { + printf("Line %d: %s\n", i + 1, cn_ip[i]); + } + } + pid = fork(); // 创建子进程 if (pid == 0) // 子进程 { diff --git a/common.c b/common.c index a4acd09..f34972a 100644 --- a/common.c +++ b/common.c @@ -189,7 +189,7 @@ int _nice(int increment) { } // 判断命令是否存在 -int command_exists(const char *command) { +int _command_exists(const char *command) { const char *path_env = getenv("PATH"); if (!path_env) { return 0; // 如果 PATH 不存在,返回不存在 @@ -221,7 +221,7 @@ int command_exists(const char *command) { return 0; // 命令不存在 } -// 定义一个函数,执行命令并返回输出 +// 执行命令并返回输出 char *_execute_command(const char *command) { FILE *fp; char buffer[1024];