diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..109181f --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "alibaba-cloud.tongyi-lingma" + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 4248061..9e9a0f5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,13 +1,9 @@ { "C_Cpp.errorSquiggles": "disabled", "files.associations": { - "string.h": "c", - "stdlib.h": "c", - "ip2region.h": "c", "common.h": "c", "prctl.h": "c", - "resource.h": "c", - "wait.h": "c", - "stdio.h": "c" + "algorithm": "c", + "cstdlib": "c" } } \ No newline at end of file diff --git a/IP_region_query/ipquery b/IP_region_query/ipquery index 54cdc09..15a0f0e 100644 Binary files a/IP_region_query/ipquery and b/IP_region_query/ipquery differ diff --git a/IP_region_query/main.go b/IP_region_query/main.go index 29e29a0..e20b043 100644 --- a/IP_region_query/main.go +++ b/IP_region_query/main.go @@ -5,18 +5,22 @@ import ( "fmt" "io" "log" + "net" "net/http" "os" + "time" ) type IPInfo struct { - Code string `json:"code"` + Msg string `json:"msg"` Data struct { Continent string `json:"continent"` Country string `json:"country"` } `json:"data"` - IP string `json:"ip"` - Msg string `json:"msg"` +} + +func isValidIP(ip string) bool { + return net.ParseIP(ip) != nil } func main() { @@ -24,16 +28,29 @@ func main() { log.Fatalf("用法: %s ", os.Args[0]) } + ip := os.Args[1] + if !isValidIP(ip) { + log.Fatalf("无效的 IP 地址: %s", ip) + } + // 目标 URL - url := "https://qifu.baidu.com/ip/geo/v1/district?ip=" + os.Args[1] + url := "https://qifu.baidu.com/ip/geo/v1/district?ip=" + ip + + // 创建 HTTP 客户端并设置超时时间 + client := &http.Client{Timeout: 10 * time.Second} // 发送 GET 请求 - resp, err := http.Get(url) + resp, err := client.Get(url) if err != nil { log.Fatalf("发送 GET 请求时出错: %v", err) } defer resp.Body.Close() + // 检查 HTTP 响应状态码 + if resp.StatusCode != http.StatusOK { + log.Fatalf("HTTP 请求失败,状态码: %d", resp.StatusCode) + } + // 读取响应体 body, err := io.ReadAll(resp.Body) if err != nil { diff --git a/Makefile b/Makefile index 0d96a7e..5c96863 100644 --- a/Makefile +++ b/Makefile @@ -1,21 +1,26 @@ CROSS_COMPILE ?= CC := $(CROSS_COMPILE)gcc STRIP := $(CROSS_COMPILE)strip -CFLAGS += -g -Os -Wall -Iip2region -Iqqwry -LIBS = -lm -static -BIN := denyip +CFLAGS += -g -Wall -Iip2region +LIBS = +BIN := a.out + +# 使用shell命令获取库的链接选项 +LIBPCAP := $(shell pkg-config --libs --static libpcap) +LIBCAP := $(shell pkg-config --libs --static libcap) +LIBIPSET := $(shell pkg-config --libs --static libipset) all: $(BIN) # 默认目标 ipquery: # Go 构建目标 cd IP_region_query && CGO_ENABLED=0 go build -ldflags '-w -s' -$(BIN): main.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o qqwry/qqwry.o - $(CC) $(CFLAGS) -o $(BIN) $^ $(LIBS) +$(BIN): cap.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o libipset.o + $(CC) $(CFLAGS) -o $(BIN) $^ $(LIBPCAP) $(LIBCAP) $(LIBIPSET) $(LIBS) %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ clean: rm -rf $(BIN) ipquery - rm -rf main.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o qqwry/qqwry.o + rm -rf cap.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o libipset.o diff --git a/README.md b/README.md index cf26cc4..5c83295 100644 --- a/README.md +++ b/README.md @@ -8,17 +8,17 @@ # Debian System apt install build-essential apt install golang -apt install tcpdump procps iptables ipset +apt install libpcap-dev libcap-dev libsystemd-dev root@NIUYULING:/mnt/c/Users/root/Desktop/git.aixiao.me/DenyIP# make clean; make -rm -rf denyip ipquery -rm -rf main.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o qqwry/qqwry.o -gcc -g -Os -Wall -Iip2region -Iqqwry -c main.c -o main.o -gcc -g -Os -Wall -Iip2region -Iqqwry -c common.c -o common.o -gcc -g -Os -Wall -Iip2region -Iqqwry -c ip2region/ip2region.c -o ip2region/ip2region.o -gcc -g -Os -Wall -Iip2region -Iqqwry -c ip2region/xdb_searcher.c -o ip2region/xdb_searcher.o -gcc -g -Os -Wall -Iip2region -Iqqwry -c qqwry/qqwry.c -o qqwry/qqwry.o -gcc -g -Os -Wall -Iip2region -Iqqwry -o denyip main.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o qqwry/qqwry.o -lm -static +rm -rf a.out ipquery +rm -rf cap.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o libipset.o +gcc -g -Wall -Iip2region -c cap.c -o cap.o +gcc -g -Wall -Iip2region -c common.c -o common.o +gcc -g -Wall -Iip2region -c ip2region/ip2region.c -o ip2region/ip2region.o +gcc -g -Wall -Iip2region -c ip2region/xdb_searcher.c -o ip2region/xdb_searcher.o +gcc -g -Wall -Iip2region -c libipset.c -o libipset.o +gcc -g -Wall -Iip2region -o a.out cap.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o libipset.o -lpcap -ldbus-1 -lsystemd -L/usr/lib64 -lcap -lipset -lmnl root@NIUYULING:/mnt/c/Users/root/Desktop/git.aixiao.me/DenyIP# ~~~ @@ -26,22 +26,22 @@ root@NIUYULING:/mnt/c/Users/root/Desktop/git.aixiao.me/DenyIP# ~~~bash -root@NIUYULING:/mnt/c/Users/root/Desktop/git.aixiao.me/DenyIP# ./denyip -h - DenyIp -Linux system firewall, reject non-Chinese IP -Email: aixiao@aixiao.me -Version: 0.1 -Usage: ./denyip [-i eth0|-h|-?] [start|stop] -Options: - stop Enable firewall rules - start Disable firewall rules -Parameters: - -h|? Help info - -i interface name +root@NIUYULING:/mnt/c/Users/root/Desktop/git.aixiao.me/DenyIP# ./a.out -h +DenyIP version 0.2 +拒绝Linux服务器非大陆IP工具 +MAIL: aixiao@aixiao.me +Date: 20241024 + Usage: denyip [-d] [-i ] [-s ] [-h|-?] + -d Daemon mode + -i interface (default eth0) + -s regular signal (default start|stop) + start Enable Iptables rule + stop Disable Iptables rule + -h|-? Help Information -root@niuyuling:~/DenyIP# killall denyip # 关闭 -root@niuyuling:~/DenyIP# ./denyip -i eth0 # 启动 -root@niuyuling:~/DenyIP# ./denyip start # Iptables 规则打开 -root@niuyuling:~/DenyIP# ./denyip stop # Iptables 规则关闭 +root@niuyuling:~/DenyIP# killall -15 denyip # 关闭 +root@niuyuling:~/DenyIP# ./denyip -i eth0 # 启动 +root@niuyuling:~/DenyIP# ./denyip -s start # Iptables 规则打开 +root@niuyuling:~/DenyIP# ./denyip -s stop # Iptables 规则关闭 ~~~ diff --git a/a.out b/a.out new file mode 100644 index 0000000..fb8d58f Binary files /dev/null and b/a.out differ diff --git a/cap.c b/cap.c new file mode 100644 index 0000000..54297ba --- /dev/null +++ b/cap.c @@ -0,0 +1,439 @@ +#include "cap.h" +#include "common.h" +#include "libipset.h" + +#define CACHE_TTL 600 // 设定缓存的存活时间为 600 秒 (10 分钟) +#define MAX_CACHE_SIZE 100 // 缓存最多存储 100 个 IP 地址 + +struct ip_cache_node *ip_cache_head = NULL; // 缓存链表的头节点 +int cache_size = 0; // 当前缓存中的 IP 数量 + +pid_t pid = -1; + +#define SHM_SIZE 1024 // 共享内存大小 +#define SHM_KEY 1234 // 共享内存键值 +int shmid = -1; +int RULE_NAME_NUMBER = 0; +char *RULE_NAME = NULL; + +char *ip2region_area = NULL; // ip2region 解析结果 +char *command_result = NULL; // 执行命令的结果 + +// 定义链表结构,用于缓存 IP 地址 +struct ip_cache_node { + char ip[INET_ADDRSTRLEN]; // 存储 IP 地址 + time_t timestamp; // 记录缓存时间 + struct ip_cache_node *next; // 指向下一个节点 +}; + +// 检查 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) +{ + // 如果缓存大小超过限制,移除最早的 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++; +} + +// 清理缓存链表,释放所有节点的内存 +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; + + int r = 0; + //char *t = _time(); + + inet_ntop(AF_INET, &(ip_header->ip_src), src_ip, INET_ADDRSTRLEN); + //_printf("%s\n", src_ip); + + + // 如果 IP 地址已在缓存中且未过期,则跳过查询 + if (is_ip_in_cache(src_ip)) { + printf(RED "IP:%s 已在缓存中,跳过查询\n" REDEND, src_ip); + return; + } + + + // 执行查询并添加到缓存 + ip2region_area = ip2region("ip2region/ip2region.xdb", src_ip); + if (ip2region_area == NULL) { + printf(RED "ip2region 解析地域错误\n" REDEND); + return; + } + // 取环境变量 + REGION_ENV = getenv("REGION"); + if (REGION_ENV != NULL) { + printf("REGION: %s\n", REGION_ENV); + strcpy(_REGION_LIST, REGION_ENV); + } else { + strcpy(_REGION_LIST, "局域网 内网 中国 "); + } + + split_string(_REGION_LIST, " ", _region_list); + if (isregion(ip2region_area, _region_list) == 1) { // 返回1表示在白名单列表 + ; + } else { + //puts(ip2region_area); + + char ip_query_command[256] = { 0 }; + snprintf(ip_query_command, sizeof(ip_query_command), "./IP_region_query/ipquery %s", src_ip); + if (cache_size < MAX_CACHE_SIZE) // 缓存IP数不够预备设定值 + { + sleep(1); + printf("缓存IP数 %d\n", cache_size); + } + 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 %d\n", r); + } + + free(command_result); + command_result = NULL; + } else { + ; + } + + if (command_result != NULL) + free(command_result); + } + + if (ip2region_area != NULL) + { + free(ip2region_area); + ip2region_area = NULL; + } + return ; +} + +void usage() +{ + printf("DenyIP version %s\n", _VERSION); + puts("拒绝Linux服务器非大陆IP工具"); + puts("MAIL: aixiao@aixiao.me"); + puts("Date: 20241024"); + puts(" Usage: denyip [-d] [-i ] [-s ] [-h|-?]"); + puts(" -d Daemon mode"); + puts(" -i interface (default eth0)"); + puts(" -s regular signal (default start|stop) "); + puts(" start Enable Iptables rule"); + puts(" stop Disable Iptables rule"); + puts(" -h|-? Help Information"); + puts(""); + + exit(0); +} + + pcap_if_t *alldevs, *device; + pcap_t *handle; // 会话句柄 + struct bpf_program fp; // 编译后的过滤器 + +void cleanup_(int signum) +{ + + printf("Received signal %d, cleaning up...\n", signum); + + // 释放共享内存 + if (RULE_NAME != NULL) { + shmdt(RULE_NAME); + shmctl(shmid, IPC_RMID, NULL); + } + + // 在程序结束时,清理缓存链表 + free_ip_cache(); + if (ip2region_area != NULL) { + free(ip2region_area); + ip2region_area = NULL; + } + if (command_result != NULL) { + free(command_result); + command_result = NULL; + } + + // 清理 + pcap_freecode(&fp); + pcap_freealldevs(alldevs); // 释放设备列表 + pcap_close(handle); // 关闭会话句柄 + + // 终止子进程 + if (pid > 0) { + kill(pid, SIGTERM); + } + + // 退出主进程 + exit(0); + + return; +} + +int main(int argc, char **argv) +{ + // 注册 SIGTERM 信号处理函数 + signal(SIGTERM, cleanup_); + + + int opt; + char errbuf[PCAP_ERRBUF_SIZE]; // 错误缓冲区 + + + char protocol[] = "tcp"; + + char interface[256] = "{ 0 }"; + strcpy(interface, "eth0"); + + memset(&alldevs, 0, sizeof(alldevs)); + memset(&device, 0, sizeof(device)); + memset(errbuf, 0, PCAP_ERRBUF_SIZE); + + char Ipset_Command[BUFFER]; + + while ((opt = getopt(argc, argv, "di:s:h?")) != -1) { + switch (opt) { + case 'd': + if (daemon(1, 1)) { + perror("daemon"); + } + break; + case 'i': + strcpy(interface, optarg); + break; + case 's': + if (strcmp(optarg, "start") == 0) { + memset(Ipset_Command, 0, BUFFER); + // 将 MAXIPSET_RULT_NAME_NUM 替换为实际值 + 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); + system(Ipset_Command); + + //system("for n in $(seq 0 MAXIPSET_RULT_NAME_NUM); do iptables -A INPUT -p tcp -m set --match-set root$n src -j DROP 2> /dev/null; done"); + exit(0); + } else if (strcmp(optarg, "stop") == 0) { + memset(Ipset_Command, 0, BUFFER); + // 将 MAXIPSET_RULT_NAME_NUM 替换为实际值 + 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); + system(Ipset_Command); + + //system("for n in $(seq 0 MAXIPSET_RULT_NAME_NUM); do iptables -D INPUT -p tcp -m set --match-set root$n src -j DROP 2> /dev/null; done"); + exit(0); + } else { + usage(); + exit(0); + } + + break; + case 'h': + case '?': + usage(); + exit(0); + break; + default: + usage(); + exit(0); + break; + } + } + + + // 创建共享内存 + shmid = shmget(SHM_KEY, SHM_SIZE, IPC_CREAT | 0666); + if (shmid < 0) { + perror("shmget"); + exit(1); + } + // 连接共享内存到进程地址空间 + RULE_NAME = (char *)shmat(shmid, NULL, 0); + if (RULE_NAME == (char *)-1) { + perror("shmat"); + exit(1); + } + + pid = fork(); // 创建子进程 + if (pid == 0) // 子进程 + { + + int count = 0; + snprintf(RULE_NAME, BUFFER, "root%d", RULE_NAME_NUMBER); + + if (create_ipset(RULE_NAME) != 0) { + fprintf(stderr, "创建 IPSet %s 失败\n", RULE_NAME); + } + while (1) { + + printf("子进程当前Ipset Rule 名 %s\n", RULE_NAME); + + count = get_ip_count_in_ipset(RULE_NAME); + if (count >= 0) { + printf("IPSet %s 中的 IP 数量: %d\n", RULE_NAME, count); + if (count >= MAXIPSET && RULE_NAME_NUMBER <= MAXIPSET_RULT_NAME_NUM) // RULE_中的IP数量不超过MAXIPSET,并且集合不能超过 MAXIPSET_RULT_NAME_NUM 个 + { + RULE_NAME_NUMBER++; + + snprintf(RULE_NAME, BUFFER, "root%d", RULE_NAME_NUMBER); // 更新规则名称 + // 创建新的 IPSet + if (create_ipset(RULE_NAME) != 0) { + printf("创建 IPSet %s 失败\n", RULE_NAME); + } else { + char iptables_command[256]; + 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) { + printf("已达到最大规则数限制,停止创建新规则。\n"); + printf("请手动清理Ipset规则\n"); + } + } + + sleep(3); // 每 3 秒检查一次 + } + } + + + // 查找可用的网络设备 + if (pcap_findalldevs(&alldevs, errbuf) == -1) { + fprintf(stderr, "无法找到设备: %s\n", errbuf); + return 1; + } + + // 打印可用设备列表 + printf("可用的设备:\n"); + for (device = alldevs; device != NULL; device = device->next) { + printf("设备: %s\n", device->name); + } + + // 打开设备以进行数据包捕获 + handle = pcap_open_live(interface, BUFSIZ, 1, 1000, errbuf); + if (handle == NULL) { + fprintf(stderr, "无法打开设备 %s: %s\n", interface, errbuf); + pcap_freealldevs(alldevs); + return 1; + } + + // 编译过滤器 + if (pcap_compile(handle, &fp, protocol, 0, PCAP_NETMASK_UNKNOWN) == -1) { + fprintf(stderr, "无法编译过滤器 %s: %s\n", protocol, pcap_geterr(handle)); + pcap_close(handle); + pcap_freealldevs(alldevs); + return 1; + } + + // 设置过滤器 + if (pcap_setfilter(handle, &fp) == -1) { + fprintf(stderr, "无法设置过滤器 %s: %s\n", protocol, pcap_geterr(handle)); + pcap_freecode(&fp); + pcap_close(handle); + pcap_freealldevs(alldevs); + return 1; + } + + + // 开始捕获数据包 + if (pcap_loop(handle, 0, packet_handler, NULL) < 0) { + fprintf(stderr, "捕获数据包时出错: %s\n", pcap_geterr(handle)); + pcap_freecode(&fp); + pcap_close(handle); + pcap_freealldevs(alldevs); + return 1; + } + + // 在程序结束时,清理缓存链表 + free_ip_cache(); + + // 清理 + pcap_freecode(&fp); + pcap_freealldevs(alldevs); // 释放设备列表 + pcap_close(handle); // 关闭会话句柄 + + return 0; +} diff --git a/cap.h b/cap.h new file mode 100644 index 0000000..5c04d32 --- /dev/null +++ b/cap.h @@ -0,0 +1,31 @@ +#ifndef CAP_H +#define CAP_H + +#include +#include +#include +#include +#include +#include // IP header +#include // TCP header +#include +#include + +#include +#include +#include +#include +#include + +#include "ip2region/ip2region.h" +#include "qqwry/qqwry.h" + +#define RED "\033[31m" +#define REDEND "\033[0m" + +#define MAXIPSET 65535 +#define MAXIPSET_RULT_NAME_NUM 26 + +#define _VERSION "0.2" + +#endif diff --git a/cap.o b/cap.o new file mode 100644 index 0000000..da9de13 Binary files /dev/null and b/cap.o differ diff --git a/common.c b/common.c index f977bf4..725bdf8 100644 --- a/common.c +++ b/common.c @@ -17,7 +17,7 @@ int _strlen(char *str) } // 自定义 printf 函数 -void my_printf(const char *format, ...) +void _printf(const char *format, ...) { va_list args; va_start(args, format); @@ -51,6 +51,7 @@ void my_printf(const char *format, ...) perror("Unable to open log file"); } + va_end(args); // 结束对变参列表的处理 } @@ -117,7 +118,7 @@ int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM]) return 0; // 没有匹配,返回0 } -int8_t copy_new_mem(char *src, int src_len, char **dest) +int8_t _copy_new_mem(char *src, int src_len, char **dest) { *dest = (char *)malloc(src_len + 1); if (*dest == NULL) @@ -152,7 +153,7 @@ int is_valid_ip(const char *ip) return result != 0; } -int nice_(int increment) +int _nice(int increment) { int oldprio = getpriority(PRIO_PROCESS, getpid()); printf("%d\n", oldprio); @@ -161,11 +162,61 @@ int nice_(int increment) } // 判断命令是否存在 -int command_exists(const char *command) +int _command_exists(const char *command) { char buffer[BUFFER]; snprintf(buffer, sizeof(buffer), "%s > /dev/null 2>&1", command); int status = system(buffer); return (status == 0); -} \ No newline at end of file +} + +// 定义一个函数,执行命令并返回输出 +char *_execute_command(const char *command) { + FILE *fp; + char buffer[1024]; + char *output = NULL; + size_t output_size = 0; + size_t total_read = 0; + + // 打开管道,执行命令 + fp = popen(command, "r"); + if (fp == NULL) { + perror("popen"); + return NULL; + } + + // 读取命令的输出 + while (fgets(buffer, sizeof(buffer), fp) != NULL) { + size_t len = strlen(buffer); + if (total_read + len + 1 > output_size) { + output_size = output_size == 0 ? 128 : output_size * 2; + char *new_output = realloc(output, output_size); + if (new_output == NULL) { + perror("realloc"); + free(output); // 释放已分配的内存 + pclose(fp); // 关闭管道 + return NULL; + } + output = new_output; + } + // 复制内容并增加总计读取的长度 + strcpy(output + total_read, buffer); + total_read += len; + } + + // 确保输出以 null 结尾 + if (output_size > 0) { + output[total_read] = '\0'; + } + + // 关闭管道 + if (pclose(fp) == -1) { + perror("pclose"); + free(output); // pclose 失败时释放内存 + return NULL; + } + + return output; +} + diff --git a/common.h b/common.h index f83c665..d77bfbe 100644 --- a/common.h +++ b/common.h @@ -22,21 +22,24 @@ #include #include -#define PRINT_LOG_FILE "Gateway.log" +#define PRINT_LOG_FILE "denyip.log" #define BUFFER 1024 #define WHITELIST_IP_NUM 1024 + +extern char *_time(); extern int _strlen(char *str); -extern void my_printf(const char *format, ...); +extern void _printf(const char *format, ...); +extern int _nice(int increment); + extern void split_string(char string[], char delims[], char (*whitelist_ip)[WHITELIST_IP_NUM]); extern int whitelist(char *client_ip, char (*whitelist_ip)[WHITELIST_IP_NUM]); -extern char *_time(); extern int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM]); -extern int8_t copy_new_mem(char *src, int src_len, char **dest); +extern int8_t _copy_new_mem(char *src, int src_len, char **dest); extern int is_valid_ip(const char *ip); -extern int nice_(int increment); -extern int command_exists(const char *command); +extern int _command_exists(const char *command); +extern char *_execute_command(const char *command); #endif diff --git a/common.o b/common.o index 2193475..3035047 100644 Binary files a/common.o and b/common.o differ diff --git a/denyip b/denyip index 5c569af..9b725cd 100644 Binary files a/denyip and b/denyip differ diff --git a/ip2region/ip2region.o b/ip2region/ip2region.o index 5d056bc..2aaf2aa 100644 Binary files a/ip2region/ip2region.o and b/ip2region/ip2region.o differ diff --git a/ip2region/main.c b/ip2region/main.c new file mode 100644 index 0000000..b53eb39 --- /dev/null +++ b/ip2region/main.c @@ -0,0 +1,20 @@ +#include "ip2region.h" +#include +#include +#include + +int main() +{ + // 执行查询并添加到缓存 + char *area = ip2region("ip2region.xdb", "1.1.1.1"); + if (area == NULL) { + return -1; + } + puts(area); + + + free(area); + + return 0; +} + diff --git a/ip2region/xdb_searcher.o b/ip2region/xdb_searcher.o index 1ffbf25..599b21e 100644 Binary files a/ip2region/xdb_searcher.o and b/ip2region/xdb_searcher.o differ diff --git a/libipset.c b/libipset.c new file mode 100644 index 0000000..22e7686 --- /dev/null +++ b/libipset.c @@ -0,0 +1,246 @@ +#include "libipset.h" + +// 自定义输出处理函数 +int custom_output_handler(struct ipset_session *session, void *p, const char *msg, ...) +{ + int *ip_count = (int *)p; + char buffer[BUFFER]; + + // 格式化输出消息 + va_list args; + va_start(args, msg); + vsnprintf(buffer, sizeof(buffer), msg, args); + va_end(args); + + // 输出调试信息 + //printf("Buffer: %s\n", buffer); // 调试输出 + + if (strlen(buffer) > 1) { + char temp[BUFFER]; + char *p1 = strstr(buffer, "Number of entries:"); + if (p1 != NULL) { + char *p2 = strstr(p1, "\n"); + if (p2 != NULL) { + size_t len = p2 - p1; // 计算长度 + if (len < BUFFER) { + strncpy(temp, p1, len); + temp[len] = '\0'; // 确保字符串结束 + //puts(temp); + + // 查找冒号并提取数量 + char *p3 = strstr(temp, ":"); + if (p3 != NULL) { + // 提取数字 + int count = atoi(p3 + 1); // 从冒号后面开始转换 + *ip_count += count; // 更新计数 + } + } + } + } + } + + return 0; +} + +int custom_output_handler_(struct ipset_session *session, void *p, const char *msg, ...) +{ + char buffer[BUFFER]; + + // 格式化输出消息 + va_list args; + va_start(args, msg); + vsnprintf(buffer, sizeof(buffer), msg, args); + va_end(args); + + // 输出调试信息 + //printf("Buffer: %s\n", buffer); // 调试输出 + + return 0; +} + +// 自定义错误处理函数 +int custom_error_handler(struct ipset *ipset, void *p, int errnum, const char *msg, ...) +{ + va_list args; + va_start(args, msg); + fprintf(stderr, "自定义错误: "); + vfprintf(stderr, msg, args); + va_end(args); + return 0; // 返回0表示处理成功 +} + +// 创建 IPSet,如果它不存在 +int create_ipset(char *set_name) +{ + struct ipset *ipset = ipset_init(); + if (!ipset) { + fprintf(stderr, "Failed to initialize IPSet\n"); + return -1; + } + + ipset_load_types(); + + struct ipset_session *session = ipset_session(ipset); + if (!session) { + fprintf(stderr, "Failed to create IPSet session\n"); + ipset_fini(ipset); + return -1; + } + + // 设置自定义错误和输出处理函数 + if (ipset_custom_printf(ipset, custom_error_handler, NULL, custom_output_handler_, NULL) != 0) { + fprintf(stderr, "设置自定义打印函数失败。\n"); + ipset_fini(ipset); + return -1; + } + + // 创建集合 + char *args[] = { "ipset", "create", set_name, "hash:ip", NULL }; + if (ipset_parse_argv(ipset, 4, args) != 0) { + ipset_fini(ipset); + return -1; + } + + + ipset_fini(ipset); + + return 0; +} + +// 向指定的 ipset 添加 IP +int add_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", "add", set_name, ip, NULL }; + if (ipset_parse_argv(ipset, 4, args) != 0) { + ipset_fini(ipset); + return -1; + } + + + ipset_fini(ipset); + + return 0; // 始终返回 0,表示执行成功 +} + +// 定义一个函数来清空指定名称的 ipset 集合 +int flush_ipset(char *set_name) +{ + struct ipset *ipset = ipset_init(); + if (!ipset) { + fprintf(stderr, "Failed to initialize IPSet\n"); + return -1; + } + + ipset_load_types(); + + // 设置自定义错误和输出处理函数 + if (ipset_custom_printf(ipset, custom_error_handler, NULL, custom_output_handler_, NULL) != 0) { + fprintf(stderr, "设置自定义打印函数失败。\n"); + ipset_fini(ipset); + return -1; + } + + // 清空集合 + char *args[] = { "ipset", "flush", set_name, NULL }; + if (ipset_parse_argv(ipset, 3, args) != 0) { + ipset_fini(ipset); + return -1; + } + + printf("IPSet %s flushed successfully\n", set_name); + ipset_fini(ipset); + return 0; +} + +// 获取指定 IPSet 中的 IP 数量 +int get_ip_count_in_ipset(char *set_name) +{ + int ip_count = 0; + struct ipset *ipset = ipset_init(); + if (!ipset) { + fprintf(stderr, "初始化 ipset 失败。\n"); + return -1; + } + + ipset_load_types(); + + // 设置自定义错误和输出处理函数 + if (ipset_custom_printf(ipset, custom_error_handler, NULL, custom_output_handler, &ip_count) != 0) { + fprintf(stderr, "设置自定义打印函数失败。\n"); + ipset_fini(ipset); + return -1; + } + + // 列出集合 + char *args[] = { "ipset", "list", set_name, NULL }; + if (ipset_parse_argv(ipset, 3, args) != 0) { + ipset_fini(ipset); + return -1; + } + + // 释放资源 + ipset_fini(ipset); + return ip_count; +} + +/* +int main() +{ + int r; + char *set_name = "root"; + char *ip = "1.1.1.2"; + + // 确保 IPSet 已存在 + r = create_ipset(set_name); + printf("create_ipset %d\n", r); + + r = flush_ipset(set_name); + printf("flush_ipset %d\n", r); + + // 尝试添加 IP + r = add_ip_to_ipset(set_name, ip); + printf("add_ip_to_ipset %d\n", r); + + // 获取并打印 IPSet 中的 IP 数量 + int count = get_ip_count_in_ipset(set_name); + if (count >= 0) { + printf("IPSet %s 中的 IP 数量: %d\n", set_name, count); + } + + return 0; +} +*/ diff --git a/libipset.h b/libipset.h new file mode 100644 index 0000000..a05d001 --- /dev/null +++ b/libipset.h @@ -0,0 +1,17 @@ +#ifndef LIBIPSET_H +#define LIBIPSET_H + +#include "common.h" +#include +#include +#include +#include // 包含 inet_pton 函数 + +#define BUFFER 1024 +#define MAX_CMD_LENGTH 256 // 或者根据需要调整 + +extern int create_ipset( char *set_name); +extern int add_ip_to_ipset(char *set_name, char *ip); +extern int get_ip_count_in_ipset(char *set_name); + +#endif diff --git a/libipset.o b/libipset.o new file mode 100644 index 0000000..b63e6eb Binary files /dev/null and b/libipset.o differ diff --git a/main.c b/main.c index 686dcee..804818e 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,6 @@ #include "main.h" +char IPSET_LIST[256] = {0}; void denyip_help() { @@ -171,6 +172,7 @@ int main(int argc, char *argv[]) pid1 = fork(); // 创建子进程 if (pid1 == 0) { while (1) { + FILE *fp = popen("ipset list root | grep \"Number of entries\" | cut -d : -f 2 | xargs", "r"); char line[BUFFER] = { 0 }; while (fgets(line, sizeof(line), fp) != NULL) { diff --git a/main.h b/main.h index d5fe63e..f006f2c 100644 --- a/main.h +++ b/main.h @@ -20,6 +20,7 @@ #define WHITELIST_IP_NUM 1024 #define MAXIPSET 65534 + char *xdb_path = "ip2region.xdb"; pid_t pid1, pid2; // 保存子进程的 PID diff --git a/main.o b/main.o index 21c008a..c951df2 100644 Binary files a/main.o and b/main.o differ diff --git a/qqwry/main.c b/qqwry/main.c new file mode 100644 index 0000000..b4b190a --- /dev/null +++ b/qqwry/main.c @@ -0,0 +1,18 @@ +# +#include +#include +#include "qqwry.h" + +int main() +{ + char *qqwry_region = qqwry_("qqwry.dat", "1.1.1.1"); + if (qqwry_region == NULL) { + printf("qqwry 解析地域错误\n"); + } + puts(qqwry_region); + + free(qqwry_region); + return 0; + + +} diff --git a/qqwry/qqwry.c b/qqwry/qqwry.c index 7c1e02d..e543060 100644 --- a/qqwry/qqwry.c +++ b/qqwry/qqwry.c @@ -52,7 +52,8 @@ int qqwry_match(char *pattern, char *subject) return ret; } -iconv_t initialize_iconv(const char *target, const char *src) { +iconv_t initialize_iconv(const char *target, const char *src) +{ // 创建转换描述符 iconv_t iconvDesc = iconv_open(target, src); @@ -60,9 +61,8 @@ iconv_t initialize_iconv(const char *target, const char *src) { if (iconvDesc == (iconv_t) - 1) { // 如果失败,打印错误信息并返回 NULL fprintf(stderr, "Error: Conversion from '%s' to '%s' is not available.\n", src, target); - return (iconv_t)NULL; + return (iconv_t) NULL; } - // 成功时返回 iconv_t 描述符 return iconvDesc; } @@ -165,23 +165,18 @@ void qqwry_back(unsigned int byte) qqwry_seek(currPos - byte); } - -char *long2ip(int ip) { +char *long2ip(int ip) +{ // 分配16字节内存用于存储IP字符串 char *ip_str = malloc(16 * sizeof(char)); - + if (ip_str == NULL) { // 如果内存分配失败,返回NULL fprintf(stderr, "Memory allocation failed\n"); return NULL; } - // 将IP转换为字符串 - snprintf(ip_str, 16, "%d.%d.%d.%d", - (ip >> 24) & 0xFF, - (ip >> 16) & 0xFF, - (ip >> 8) & 0xFF, - ip & 0xFF); + snprintf(ip_str, 16, "%d.%d.%d.%d", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF); return ip_str; } @@ -341,24 +336,15 @@ int get_location(char *ip) unsigned int offset = search_record(ip); unsigned int tmp_offset; qqwry_seek(offset + 4); // skip 4 byte to get the offset value pointing to record data - readvalue(3, (int *)(&tmp_offset)); // the offset pointing to the data + readvalue(3, (int *)(&tmp_offset)); // the offset pointing to the data get_data(tmp_offset); return 0; } -char *qqwry_(char *ip) +char *qqwry_(char *dat, char *ip) { - char *qqdb_path = "qqwry.dat"; - if (access(qqdb_path, F_OK) == -1) { // 判断 ip2region 地址定位库是否存在 - qqdb_path = "qqwry/qqwry.dat"; - if (access(qqdb_path, F_OK) == -1) { - printf("qqwry.dat DOESN'T EXIST!\n"); - return NULL; - } - } - qqwry_init(qqdb_path); - + qqwry_init(dat); get_location(ip); //printf("%s-%s %d\n", ip_defaults.parent_data, ip_defaults.child_data, ip_defaults.isp); diff --git a/qqwry/qqwry.h b/qqwry/qqwry.h index 52f495f..6c0995c 100644 --- a/qqwry/qqwry.h +++ b/qqwry/qqwry.h @@ -28,4 +28,4 @@ void qqwry_back(unsigned int byte); int get_location(char *ip); int gbk2utf8(char *utf8_str, char *gbk_str); -extern char *qqwry_(char *ip); \ No newline at end of file +extern char *qqwry_(char *dat, char *ip); diff --git a/qqwry/qqwry.o b/qqwry/qqwry.o index d26f95a..fdb87a4 100644 Binary files a/qqwry/qqwry.o and b/qqwry/qqwry.o differ