新版本采用libipset库操作ipset集合,采用libpcap、libcap抓包获取源IP

This commit is contained in:
2024-10-28 11:15:54 +08:00
parent 866043b976
commit b97b4b212e
27 changed files with 915 additions and 78 deletions

5
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"recommendations": [
"alibaba-cloud.tongyi-lingma"
]
}

View File

@@ -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"
}
}

Binary file not shown.

View File

@@ -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 <IP>", 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 {

View File

@@ -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

View File

@@ -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 <interface>] [-s <start|stop>] [-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 规则关闭
~~~

BIN
a.out Normal file

Binary file not shown.

439
cap.c Normal file
View File

@@ -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 <interface>] [-s <start|stop>] [-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;
}

31
cap.h Normal file
View File

@@ -0,0 +1,31 @@
#ifndef CAP_H
#define CAP_H
#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h> // IP header
#include <netinet/tcp.h> // TCP header
#include <sys/types.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <string.h>
#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

BIN
cap.o Normal file

Binary file not shown.

View File

@@ -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,7 +162,7 @@ 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);
@@ -169,3 +170,53 @@ int command_exists(const char *command)
return (status == 0);
}
// 定义一个函数,执行命令并返回输出
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;
}

View File

@@ -22,21 +22,24 @@
#include <signal.h>
#include <sys/prctl.h>
#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

BIN
common.o

Binary file not shown.

BIN
denyip

Binary file not shown.

Binary file not shown.

20
ip2region/main.c Normal file
View File

@@ -0,0 +1,20 @@
#include "ip2region.h"
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
// 执行查询并添加到缓存
char *area = ip2region("ip2region.xdb", "1.1.1.1");
if (area == NULL) {
return -1;
}
puts(area);
free(area);
return 0;
}

Binary file not shown.

246
libipset.c Normal file
View File

@@ -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;
}
*/

17
libipset.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef LIBIPSET_H
#define LIBIPSET_H
#include "common.h"
#include <libipset/ipset.h>
#include <stdio.h>
#include <stdarg.h>
#include <arpa/inet.h> // 包含 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

BIN
libipset.o Normal file

Binary file not shown.

2
main.c
View File

@@ -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) {

1
main.h
View File

@@ -20,6 +20,7 @@
#define WHITELIST_IP_NUM 1024
#define MAXIPSET 65534
char *xdb_path = "ip2region.xdb";
pid_t pid1, pid2; // 保存子进程的 PID

BIN
main.o

Binary file not shown.

18
qqwry/main.c Normal file
View File

@@ -0,0 +1,18 @@
#
#include <stdio.h>
#include <stdlib.h>
#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;
}

View File

@@ -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,8 +165,8 @@ 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));
@@ -175,13 +175,8 @@ char *long2ip(int ip) {
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);

View File

@@ -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);
extern char *qqwry_(char *dat, char *ip);

Binary file not shown.