diff --git a/a.out b/a.out new file mode 100644 index 0000000..f6d4755 Binary files /dev/null and b/a.out differ diff --git a/cache.c b/cache.c index 27d7ef4..77ea9dd 100644 --- a/cache.c +++ b/cache.c @@ -1,5 +1,94 @@ #include "cache.h" + +struct ip_cache_node *ip_cache_head = NULL; // 缓存链表的头节点 +int cache_size = 0; // 当前缓存中的 IP 数量 + +// 将新 IP 添加到缓存,若缓存过大则移除最早的 IP +void add_ip_to_cache(const char *ip) +{ + // 如果缓存大小超过限制,移除最早的 IP + if (cache_size >= MAX_CACHE_SIZE) { + struct ip_cache_node *current = ip_cache_head; + struct ip_cache_node *prev = NULL; + + // 找到链表的最后一个节点 + while (current->next != NULL) { + prev = current; + current = current->next; + } + + // 移除最后一个节点(最早的 IP) + if (prev != NULL) { + prev->next = NULL; + } else { + ip_cache_head = NULL; + } + free(current); + cache_size--; + } + + // 创建新的缓存节点并添加到链表头部 + struct ip_cache_node *new_node = (struct ip_cache_node *)malloc(sizeof(struct ip_cache_node)); + if (new_node == NULL) { + perror("malloc"); + return; + } + strncpy(new_node->ip, ip, INET_ADDRSTRLEN); + new_node->timestamp = time(NULL); // 记录当前时间 + new_node->next = ip_cache_head; + ip_cache_head = new_node; + 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() +{ + struct ip_cache_node *current = ip_cache_head; + while (current != NULL) { + struct ip_cache_node *next = current->next; + free(current); + current = next; + } + + ip_cache_head = NULL; + cache_size = 0; +} + + + char cn_ip[MAXIPSET_][MAXIPLEN] = { 0 }; // 添加一个 IP 到集合(如果已存在则不添加) diff --git a/cache.h b/cache.h index 3b5ce90..514f128 100644 --- a/cache.h +++ b/cache.h @@ -6,12 +6,44 @@ #include #include #include +#include -#define MAXIPSET_ 256 +#include +#include +#include +#include +#include +#include // IP header +#include // TCP header +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MAXIPSET_ 10240 #define MAXIPLEN 32 -extern char cn_ip[MAXIPSET_][MAXIPLEN]; +#define CACHE_TTL 180 // 设定缓存的存活时间为 600 秒 (10 分钟) +#define MAX_CACHE_SIZE 100 // 缓存最多存储 100 个 IP 地址 +extern int cache_size; // 当前缓存中的 IP 数量 +// 定义链表结构,用于缓存 IP 地址 +struct ip_cache_node { + char ip[INET_ADDRSTRLEN]; // 存储 IP 地址 + time_t timestamp; // 记录缓存时间 + struct ip_cache_node *next; // 指向下一个节点 +}; + +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 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 106c57f..35c5988 100644 --- a/cap.c +++ b/cap.c @@ -10,131 +10,27 @@ pcap_t *handle; // 会话句柄 struct bpf_program fp; // 编译后的过滤器 pid_t pid = -1; // 子进程全局PID - #define SHM_SIZE 1024 // 共享内存大小 #define SHM_KEY 0124 // 共享内存键值 int shmid = -1; int RULE_NAME_NUMBER = 0; // ipset 集合集合数 char *RULE_NAME = NULL; // 共享内存 + + char *ip2region_area = NULL; // ip2region 解析结果 char *command_result = NULL; // 执行命令的结果 -#define CACHE_TTL 180 // 设定缓存的存活时间为 600 秒 (10 分钟) -#define MAX_CACHE_SIZE 100 // 缓存最多存储 100 个 IP 地址 -struct ip_cache_node *ip_cache_head = NULL; // 缓存链表的头节点 -int cache_size = 0; // 当前缓存中的 IP 数量 -// 定义链表结构,用于缓存 IP 地址 -struct ip_cache_node { - char ip[INET_ADDRSTRLEN]; // 存储 IP 地址 - time_t timestamp; // 记录缓存时间 - struct ip_cache_node *next; // 指向下一个节点 -}; - - -// 将新 IP 添加到缓存,若缓存过大则移除最早的 IP -void add_ip_to_cache(const char *ip) +void Processing_IP_addresses(char *src_ip) { - // 如果缓存大小超过限制,移除最早的 IP - if (cache_size >= MAX_CACHE_SIZE) { - struct ip_cache_node *current = ip_cache_head; - struct ip_cache_node *prev = NULL; - - // 找到链表的最后一个节点 - while (current->next != NULL) { - prev = current; - current = current->next; - } - - // 移除最后一个节点(最早的 IP) - if (prev != NULL) { - prev->next = NULL; - } else { - ip_cache_head = NULL; - } - free(current); - cache_size--; - } - - // 创建新的缓存节点并添加到链表头部 - struct ip_cache_node *new_node = (struct ip_cache_node *)malloc(sizeof(struct ip_cache_node)); - if (new_node == NULL) { - perror("malloc"); - return; - } - strncpy(new_node->ip, ip, INET_ADDRSTRLEN); - new_node->timestamp = time(NULL); // 记录当前时间 - new_node->next = ip_cache_head; - ip_cache_head = new_node; - 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() -{ - struct ip_cache_node *current = ip_cache_head; - while (current != NULL) { - struct ip_cache_node *next = current->next; - free(current); - current = next; - } - - ip_cache_head = NULL; - cache_size = 0; -} - - -// 回调函数,在捕获到每个数据包时调用 -void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) -{ - int ethernet_header_len = 14; - struct ip *ip_header = (struct ip *)(packet + ethernet_header_len); - char src_ip[INET_ADDRSTRLEN] = { 0 }; - // 地域白名单 char _region_list[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } }; char _REGION_LIST[BUFFER] = { 0 }; const char *REGION_ENV = NULL; - char ipset_query_command[256] = { 0 }; - // 定义 Response 结构体 Response response; - inet_ntop(AF_INET, &(ip_header->ip_src), src_ip, INET_ADDRSTRLEN); - // 如果 IP 地址已在缓存中且未过期,则跳过查询 if (is_ip_in_cache(src_ip)) { _printf(RED "IP:%s 已在缓存中,跳过查询\n" REDEND, src_ip); @@ -156,14 +52,12 @@ void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char printf("%s ", cn_ip[i]); } } - - if (cn_ip_len(cn_ip) >= 100) { // 清理集合 + if (cn_ip_len(cn_ip) >= 1024) { // 清理集合 clear_ip_set(cn_ip); } printf("cn_ip_len(cn_ip): %d\n", cn_ip_len(cn_ip)); - return; } @@ -196,34 +90,47 @@ void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char add_ip_to_cache(src_ip); // 添加到缓存 - char *p = curl_get_area(src_ip); + char *p = CurlGetIpArea(src_ip); if (parse_json_to_struct(p, &response) == 0) { // 解析 JSON 到结构体 if (NULL == strstr(response.continent_country, "中国")) { // 这时是国外IP - _printf(RED "%s %s\n" REDEND, src_ip, response.continent_country); + _printf(RED "CurlGetIpArea(): %s %s\n" REDEND, src_ip, response.continent_country); add_ip_to_ipset(RULE_NAME, src_ip); - } else { // 这时是国内IP - add_cn_ip(cn_ip, src_ip); // 添加国内IP到缓存 + } 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 { fprintf(stderr, "Failed to parse JSON.\n"); } if (p != NULL) free(p); - } + if (ip2region_area != NULL) { free(ip2region_area); ip2region_area = NULL; } + + return ; +} + +// 回调函数,在捕获到每个数据包时调用 +void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) +{ + int ethernet_header_len = 14; + struct ip *ip_header = (struct ip *)(packet + ethernet_header_len); + char src_ip[INET_ADDRSTRLEN] = { 0 }; + + inet_ntop(AF_INET, &(ip_header->ip_src), src_ip, INET_ADDRSTRLEN); + Processing_IP_addresses(src_ip); + return; } @@ -236,6 +143,7 @@ void usage() puts(" Usage: denyip [-d] [-i ] [-s ] [-h|-?]"); puts(" -d --daemon Daemon mode"); puts(" -i --interface interface (default eth0)"); + puts(" -f --protocol 过滤器 [\"tcp\" | \"udp\" | \"tcp or udp\"] (default \"tcp\")"); puts(" -l print iptables rule"); puts(" -s --signal regular signal (default start|stop) "); puts(" start Enable Iptables rule"); @@ -292,7 +200,7 @@ int main(int argc, char **argv) int opt; char errbuf[PCAP_ERRBUF_SIZE] = { 0 }; // 错误缓冲区 - char protocol[] = "tcp"; + char protocol[256] = "tcp"; char interface[256] = "{ 0 }"; char Ipset_Command[BUFFER] = { 0 }; @@ -302,9 +210,10 @@ int main(int argc, char **argv) memset(errbuf, 0, PCAP_ERRBUF_SIZE); int longindex = 0; - char optstring[] = "di:s:lh?"; + char optstring[] = "di:f:s:lh?"; static struct option longopts[] = { { "interface", required_argument, 0, 'i' }, + { "protocol", required_argument, 0, 'f' }, { "signal", required_argument, 0, 's' }, { "daemon", no_argument, 0, 'd' }, { "l", no_argument, 0, 'l' }, @@ -323,6 +232,9 @@ int main(int argc, char **argv) case 'i': strcpy(interface, optarg); break; + case 'f': + strcpy(protocol, optarg); + break; case 'l': system("iptables -L -v -n --line-numbers"); exit(0); @@ -381,16 +293,25 @@ int main(int argc, char **argv) return 1; } + char *local_addr = GetLocalAddr("https://inet-ip.aixiao.me/"); + if (local_addr == NULL) { + perror("GetLocalAddr()"); + return 1; + } + remove_char(local_addr, '\n'); + printf("Local Address: %s\n", local_addr); + 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]); } + + free(local_addr); } pid = fork(); // 创建子进程 if (pid == 0) // 子进程 { - int count = 0; snprintf(RULE_NAME, BUFFER, "root%d", RULE_NAME_NUMBER); @@ -400,7 +321,6 @@ int main(int argc, char **argv) while (1) { //_printf("子进程当前 Ipset Rule 名 %s\n", RULE_NAME); - count = get_ip_count_in_ipset(RULE_NAME); if (count >= 0) { _printf("子进程当前 Ipset Rule 名 %s, 数量: %d \n", RULE_NAME, count); @@ -417,7 +337,6 @@ int main(int argc, char **argv) sprintf(iptables_command, "iptables -I INPUT -m set --match-set %s src -j DROP", RULE_NAME); system(iptables_command); } - } if (RULE_NAME_NUMBER == MAXIPSET_RULT_NAME_NUM) { @@ -426,7 +345,7 @@ int main(int argc, char **argv) } } - sleep(9); // 每 3 秒检查一次 + sleep(3); // 每 3 秒检查一次 } } diff --git a/common.c b/common.c index f34972a..d17b26a 100644 --- a/common.c +++ b/common.c @@ -270,3 +270,15 @@ char *_execute_command(const char *command) { return output; } +void remove_char(char *str, char c) +{ + int i = 0, j = 0; + while (str[i]) { + if (str[i] != c) { + str[j++] = str[i]; + } + i++; + } + str[j] = '\0'; +} + diff --git a/common.h b/common.h index 338e5d2..5a05c4e 100644 --- a/common.h +++ b/common.h @@ -43,4 +43,6 @@ extern int is_valid_ip(const char *ip); extern int _command_exists(const char *command); extern char *_execute_command(const char *command); +extern void remove_char(char *str, char c); + #endif diff --git a/libcurl.c b/libcurl.c index 889b019..38bb650 100644 --- a/libcurl.c +++ b/libcurl.c @@ -27,8 +27,76 @@ static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, voi return realsize; } +char *GetLocalAddr(char *url) +{ + CURL *curl_handle; + CURLcode res; + + struct curl_slist *headers = NULL; + struct MemoryStruct chunk; + + chunk.memory = malloc(1); /* 将根据上述再分配的需要增长 */ + chunk.size = 0; /* 此时没有数据 */ + + curl_global_init(CURL_GLOBAL_ALL); + + /* 初始化curl会话 */ + curl_handle = curl_easy_init(); + + char *p = NULL; + char *buff; + + p = strstr(url, "-H"); + if (p) { + + buff = (char *)alloca(p - url + 1); + if (buff == NULL) + perror("out of memory."); + + memset(buff, 0, p - url + 1); + memcpy(buff, url, (int)(p - url - 1)); + + // 赋值header值 + headers = curl_slist_append(headers, p + 3); + + // 设置header + curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl_handle, CURLOPT_URL, buff); + + } else { + /* 指定要获取的URL */ + curl_easy_setopt(curl_handle, CURLOPT_URL, url); + + } + + /* 将所有数据发送到此函数 */ + //对于同一次阻塞的curl_easy_perform而言,在写完获取的数据之前,会多次调用 WriteMemoryCallback + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); + + /* 将"chunk"结构传递给回调函数 */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); + + curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + + //对于同一次阻塞的curl_easy_perform而言,在写完获取的数据之前,会多次调用 WriteMemoryCallback + res = curl_easy_perform(curl_handle); + + if (res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + } else { + //printf("%lu bytes retrieved\n", (unsigned long)chunk.size); + //printf("%s", chunk.memory); + ; + } + + curl_easy_cleanup(curl_handle); + curl_global_cleanup(); + + return chunk.memory; +} + // 获取公网IP -char *curl_get_area(char *ip) +char *CurlGetIpArea(char *ip) { char url[256] = { 0 }; snprintf(url, sizeof(url), "https://qifu.baidu.com/ip/geo/v1/district?ip=%s", ip); @@ -114,7 +182,10 @@ void parse_string_field(cJSON *parent, const char *field_name, char *output, siz // 函数用于从 JSON 字符串解析为结构体 int parse_json_to_struct(const char *json_string, Response *response) { - if (!response) return -1; + if (!json_string || !response) { + fprintf(stderr, "Invalid input parameters!\n"); + return -1; + } // 初始化结构体 memset(response, 0, sizeof(Response)); @@ -152,7 +223,12 @@ int parse_json_to_struct(const char *json_string, Response *response) parse_string_field(data_item, "region", response->data.region, sizeof(response->data.region)); } - snprintf(response->continent_country, 256, "%s%s", response->data.continent, response->data.country); + // ----------- 拼接 continent_country --------------- + if (snprintf(response->continent_country, sizeof(response->continent_country), "%s%s", response->data.continent, response->data.country) >= sizeof(response->continent_country)) { + fprintf(stderr, "continent_country truncated!\n"); + } + + //snprintf(response->continent_country, 256, "%s%s", response->data.continent, response->data.country); // 清理 JSON 对象 cJSON_Delete(root); @@ -186,4 +262,4 @@ int main(int argc, char *argv[]) free(p); } -*/ \ No newline at end of file +*/ diff --git a/libcurl.h b/libcurl.h index 220235e..5cf0f2e 100644 --- a/libcurl.h +++ b/libcurl.h @@ -43,7 +43,8 @@ typedef struct { } Response; -extern char *curl_get_area(char *URL); +extern char *CurlGetIpArea(char *ip); +extern char *GetLocalAddr(char *url); extern int parse_json_to_struct(const char *json_string, Response *response);