This commit is contained in:
2025-01-16 16:32:39 +08:00
parent a79a59bd97
commit a3712fde22
5 changed files with 133 additions and 97 deletions

View File

@@ -6,3 +6,4 @@
{"code":"Success","data":{"continent":"北美洲","country":"美国","zipcode":"","owner":"","isp":"Cloudflare, Inc.","adcode":"","prov":"","city":"","district":""},"ip":"1.1.1.6"}
{"code":"Success","data":{"continent":"北美洲","country":"美国","zipcode":"","owner":"","isp":"Cloudflare, Inc.","adcode":"","prov":"","city":"","district":""},"ip":"1.1.1.7"}
{"code":"Success","data":{"continent":"北美洲","country":"美国","zipcode":"","owner":"","isp":"Cloudflare, Inc.","adcode":"","prov":"","city":"","district":""},"ip":"1.1.1.8"}
{"code":"Success","data":{"continent":"亚洲","country":"中国","zipcode":"999077","owner":"Censys, Inc.","isp":"Censys, Inc.","adcode":"810000","prov":"中国香港","city":"中国香港","district":""},"ip":"199.45.154.152"}

224
cap.c
View File

@@ -3,33 +3,94 @@
#include "libipset.h"
#include "libcurl.h"
pcap_if_t *alldevs, *device;
pcap_t *handle; // 会话句柄
struct bpf_program fp; // 编译后的过滤器
pcap_t *handle; // 会话句柄
struct bpf_program fp; // 编译后的过滤器
pid_t pid = -1; // 子进程全局PID
pid_t pid = -1; // 子进程全局PID
#define SHM_SIZE 1024 // 共享内存大小
#define SHM_KEY 0124 // 共享内存键值
#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; // 执行命令的结果
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 数量
#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; // 指向下一个节点
char ip[INET_ADDRSTRLEN]; // 存储 IP 地址
time_t timestamp; // 记录缓存时间
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)
@@ -117,14 +178,14 @@ void free_ip_cache()
// 回调函数,在捕获到每个数据包时调用
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 };
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 _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 };
//char ip_query_command[256] = { 0 };
@@ -132,12 +193,7 @@ void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char
// 定义 Response 结构体
Response response;
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)) {
@@ -152,6 +208,25 @@ void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char
return;
}
if (1 == is_ip_in_set(cn_ip, src_ip)) {
_printf(RED "IP:%s 已经标记为国内,跳过!!!\n" REDEND, src_ip);
for (int i = 0; i < MAXIPSET_; i++) {
if (cn_ip[i][0] != '\0') {
printf("%s ", cn_ip[i]);
}
}
if (cn_ip_len(cn_ip) >= 100) { // 清理集合
clear_ip_set(cn_ip);
}
printf("cn_ip_len(cn_ip): %d\n", cn_ip_len(cn_ip));
return;
}
// 执行查询并添加到缓存
ip2region_area = ip2region("ip2region/ip2region.xdb", src_ip);
if (ip2region_area == NULL) {
@@ -172,32 +247,24 @@ void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char
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 = curl_get_area(src_ip);
//puts(p);
if (parse_json_to_struct(p, &response) == 0) { // 解析 JSON 到结构体
// 输出解析结果
/*
printf("Code: %s\n", response.code);
printf("IP: %s\n", response.ip);
printf("Continent: %s\n", response.data.continent);
printf("Country: %s\n", response.data.country);
printf("ISP: %s\n", response.data.isp);
printf("Region: %s\n", response.data.region);
*/
char *p1 = strstr(response.continent_country, "中国");
if (p1 == NULL) {
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);
r = add_ip_to_ipset(RULE_NAME, src_ip);
//_printf("add_ip_to_ipset() return %d\n", r);
add_ip_to_ipset(RULE_NAME, src_ip);
} else { // 这时是国内IP
add_cn_ip(cn_ip, src_ip); // 添加国内IP到缓存
_printf("IP: %s 离线库为国外, API 判断为国内, 标记为已处理!!!\n", src_ip);
}
} else {
@@ -206,38 +273,13 @@ void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char
free(p);
/*
//go 执行命令方法
snprintf(ip_query_command, sizeof(ip_query_command), "./IP_region_query/ipquery %s", src_ip);
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() return %d\n", r);
}
free(command_result);
command_result = NULL;
} else {
;
}
if (command_result != NULL)
free(command_result);
*/
}
if (ip2region_area != NULL)
{
if (ip2region_area != NULL) {
free(ip2region_area);
ip2region_area = NULL;
}
return ;
return;
}
void usage()
@@ -268,7 +310,7 @@ void cleanup_(int signum)
if (pid > 0) {
kill(pid, SIGTERM);
}
// 释放共享内存
if (RULE_NAME != NULL) {
shmdt(RULE_NAME);
@@ -292,7 +334,6 @@ void cleanup_(int signum)
pcap_freealldevs(alldevs); // 释放设备列表
//pcap_close(handle); // 关闭会话句柄
// 退出主进程
exit(0);
@@ -304,11 +345,11 @@ int main(int argc, char **argv)
// 注册 SIGTERM 信号处理函数
signal(SIGTERM, cleanup_);
int opt;
char errbuf[PCAP_ERRBUF_SIZE] = { 0 }; // 错误缓冲区
char protocol[] = "tcp";
char interface[256] = "{ 0 }";
char Ipset_Command[BUFFER] = { 0 };
int opt;
char errbuf[PCAP_ERRBUF_SIZE] = { 0 }; // 错误缓冲区
char protocol[] = "tcp";
char interface[256] = "{ 0 }";
char Ipset_Command[BUFFER] = { 0 };
strcpy(interface, "eth0");
memset(&alldevs, 0, sizeof(alldevs));
@@ -327,8 +368,7 @@ int main(int argc, char **argv)
{ 0, 0, 0, 0 }
};
while (-1 != (opt = getopt_long(argc, argv, optstring, longopts, &longindex)))
{
while (-1 != (opt = getopt_long(argc, argv, optstring, longopts, &longindex))) {
switch (opt) {
case 'd':
if (daemon(1, 1)) {
@@ -346,17 +386,13 @@ int main(int argc, char **argv)
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);
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);
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);
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);
exit(0);
} else {
@@ -377,7 +413,6 @@ int main(int argc, char **argv)
}
}
// 创建共享内存
shmid = shmget(SHM_KEY, SHM_SIZE, IPC_CREAT | 0666);
if (shmid < 0) {
@@ -392,25 +427,23 @@ int main(int argc, char **argv)
exit(1);
}
pid = fork(); // 创建子进程
if (pid == 0) // 子进程
{
int count = 0;
int count = 0;
snprintf(RULE_NAME, BUFFER, "root%d", RULE_NAME_NUMBER);
if (create_ipset(RULE_NAME) != 0) {
_printf("创建 IPSet %s 失败\n", RULE_NAME);
}
while (1)
{
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);
_printf("子进程当前 Ipset Rule 名 %s, 数量: %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++;
@@ -436,7 +469,6 @@ int main(int argc, char **argv)
sleep(9); // 每 3 秒检查一次
}
}
// 查找可用的网络设备
if (pcap_findalldevs(&alldevs, errbuf) == -1) {

3
cap.h
View File

@@ -28,4 +28,7 @@
#define _VERSION "0.2"
#endif

Binary file not shown.

View File

@@ -6,7 +6,7 @@
int main()
{
// 执行查询并添加到缓存
char *area = ip2region("ip2region.xdb", "1.1.1.1");
char *area = ip2region("ip2region.xdb", "199.45.154.152");
if (area == NULL) {
return -1;
}