This commit is contained in:
sushen339
2025-11-19 00:12:11 +08:00
parent 6a9ee37598
commit fb523a842b
7 changed files with 214 additions and 13 deletions
BIN
View File
Binary file not shown.
Binary file not shown.
+14
View File
@@ -21,6 +21,8 @@
#define MAX_LOG_SIZE 10485760 // 10MB #define MAX_LOG_SIZE 10485760 // 10MB
#define DEFAULT_MAX_RETRIES 3 #define DEFAULT_MAX_RETRIES 3
#define DEFAULT_BAN_TIME "24h" #define DEFAULT_BAN_TIME "24h"
#define DEFAULT_RATE_LIMIT 20
#define DEFAULT_RATE_BAN_TIME "10m"
#define RECORD_DIR CONFIG_DIR "/counts" #define RECORD_DIR CONFIG_DIR "/counts"
#define PERSIST_FILE CONFIG_DIR "/blacklist" #define PERSIST_FILE CONFIG_DIR "/blacklist"
#define WHITELIST_FILE CONFIG_DIR "/whitelist" #define WHITELIST_FILE CONFIG_DIR "/whitelist"
@@ -79,4 +81,16 @@ int save_max_retries_to_config(int max_retries);
/* 获取SSH端口 */ /* 获取SSH端口 */
int get_ssh_port(void); int get_ssh_port(void);
/* 获取SSH端口速率 */
int get_rate_limit_from_config(void);
/* 保存SSH端口速率 */
int save_rate_limit_to_config(int rate_limit);
/* 获取速率限制封禁时间 */
const char* get_rate_ban_time_from_config(void);
/* 保存速率限制封禁时间 */
int save_rate_ban_time_to_config(const char *ban_time);
#endif /* COMMON_H */ #endif /* COMMON_H */
+116
View File
@@ -255,3 +255,119 @@ int get_ssh_port(void) {
return port; return port;
} }
/* 通用配置读取函数(整数) */
static int get_config_int(const char *key, int default_value, int min_val, int max_val) {
FILE *fp = fopen(CONFIG_FILE, "r");
if (!fp) return default_value;
char line[MAX_LINE_LEN];
size_t key_len = strlen(key);
while (fgets(line, sizeof(line), fp)) {
if (line[0] == '#' || line[0] == '\n') continue;
if (strncmp(line, key, key_len) == 0 && line[key_len] == '=') {
int value = atoi(line + key_len + 1);
fclose(fp);
return (value >= min_val && value <= max_val) ? value : default_value;
}
}
fclose(fp);
return default_value;
}
/* 通用配置读取函数(字符串) */
static const char* get_config_str(const char *key, const char *default_value, char *buffer, size_t buf_size) {
FILE *fp = fopen(CONFIG_FILE, "r");
if (!fp) return default_value;
char line[MAX_LINE_LEN];
size_t key_len = strlen(key);
while (fgets(line, sizeof(line), fp)) {
if (line[0] == '#' || line[0] == '\n') continue;
if (strncmp(line, key, key_len) == 0 && line[key_len] == '=') {
char *value = line + key_len + 1;
char *p = value;
while (*p && *p != '\n' && *p != '\r') p++;
*p = '\0';
while (*value == ' ' || *value == '\t') value++;
size_t len = strlen(value);
if (len > 0) {
if (len >= buf_size) len = buf_size - 1;
memcpy(buffer, value, len);
buffer[len] = '\0';
fclose(fp);
return buffer;
}
}
}
fclose(fp);
return default_value;
}
/* 通用配置保存函数 */
static int save_config_value(const char *key, const char *value) {
mkdir(CONFIG_DIR, 0700);
FILE *fp = fopen(CONFIG_FILE, "r");
char temp_file[MAX_PATH_LEN];
snprintf(temp_file, sizeof(temp_file), "%s.tmp", CONFIG_FILE);
FILE *temp_fp = fopen(temp_file, "w");
if (!temp_fp) {
if (fp) fclose(fp);
return ERROR_FILE;
}
bool found = false;
size_t key_len = strlen(key);
if (fp) {
char line[MAX_LINE_LEN];
while (fgets(line, sizeof(line), fp)) {
if (strncmp(line, key, key_len) == 0 && line[key_len] == '=') {
fprintf(temp_fp, "%s=%s\n", key, value);
found = true;
} else {
fputs(line, temp_fp);
}
}
fclose(fp);
}
if (!found) {
fprintf(temp_fp, "%s=%s\n", key, value);
}
fclose(temp_fp);
chmod(temp_file, 0600);
rename(temp_file, CONFIG_FILE);
return SUCCESS;
}
int get_rate_limit_from_config(void) {
return get_config_int("RATE_LIMIT", DEFAULT_RATE_LIMIT, 1, 1000);
}
int save_rate_limit_to_config(int rate_limit) {
if (rate_limit <= 0 || rate_limit > 1000) {
return ERROR_INVALID_ARG;
}
char buf[32];
snprintf(buf, sizeof(buf), "%d", rate_limit);
return save_config_value("RATE_LIMIT", buf);
}
const char* get_rate_ban_time_from_config(void) {
static char ban_time[32] = {0};
return get_config_str("RATE_BAN_TIME", DEFAULT_RATE_BAN_TIME, ban_time, sizeof(ban_time));
}
int save_rate_ban_time_to_config(const char *ban_time) {
if (!ban_time) {
return ERROR_INVALID_ARG;
}
return save_config_value("RATE_BAN_TIME", ban_time);
}
+3
View File
@@ -155,6 +155,9 @@ int install_service(void) {
/* 创建默认配置文件 */ /* 创建默认配置文件 */
if (access(CONFIG_FILE, F_OK) != 0) { if (access(CONFIG_FILE, F_OK) != 0) {
save_ban_time_to_config(DEFAULT_BAN_TIME); save_ban_time_to_config(DEFAULT_BAN_TIME);
save_max_retries_to_config(DEFAULT_MAX_RETRIES);
save_rate_limit_to_config(DEFAULT_RATE_LIMIT);
save_rate_ban_time_to_config(DEFAULT_RATE_BAN_TIME);
msg(C_GREEN, " ✓ 已创建默认配置文件"); msg(C_GREEN, " ✓ 已创建默认配置文件");
} }
+47 -4
View File
@@ -21,10 +21,12 @@ void show_help(void) {
printf(" bip vip add <IP> 添加IP到白名单 (支持IPv4/IPv6/CIDR)\n"); printf(" bip vip add <IP> 添加IP到白名单 (支持IPv4/IPv6/CIDR)\n");
printf(" bip vip del <IP> 从白名单移除IP\n"); printf(" bip vip del <IP> 从白名单移除IP\n");
printf(" bip vip list 显示白名单列表\n"); printf(" bip vip list 显示白名单列表\n");
printf(" bip config 显示当前配置\n"); printf(" bip config 显示当前配置\n");
printf(" bip config time <time> 设置封禁时间 (如: 7d, 24h, \"\" 为永久)\n"); printf(" bip config time <time> 设置封禁时间 (如: 7d, 24h, \"\" 为永久)\n");
printf(" bip config retries <N> 设置最大重试次数 (1-10)\n"); printf(" bip config retries <N> 设置最大重试次数 (1-10)\n");
printf(" bip restore 从持久化文件恢复黑白名单\n"); printf(" bip config ratelimit <N> 设置SSH端口速率 (1-1000/分钟)\n");
printf(" bip config rateban <time> 设置超速封禁时长 (如: 10m, 1h)\n");
printf(" bip restore 从持久化文件恢复黑白名单\n");
printf(" bip install 安装/重装服务\n"); printf(" bip install 安装/重装服务\n");
printf(" bip uninstall 卸载服务\n"); printf(" bip uninstall 卸载服务\n");
printf("--------------------------------------------------------\n"); printf("--------------------------------------------------------\n");
@@ -138,7 +140,10 @@ int main(int argc, char *argv[]) {
/* 显示当前配置 */ /* 显示当前配置 */
const char *ban_time = get_ban_time_from_config(); const char *ban_time = get_ban_time_from_config();
int max_retries = get_max_retries_from_config(); int max_retries = get_max_retries_from_config();
int rate_limit = get_rate_limit_from_config();
const char *rate_ban_time = get_rate_ban_time_from_config();
printf("%s当前配置%s\n", C_CYAN, C_RESET); printf("%s当前配置%s\n", C_CYAN, C_RESET);
printf("====防爆破===\n");
printf("封禁时间: %s%s%s", C_GREEN, ban_time, C_RESET); printf("封禁时间: %s%s%s", C_GREEN, ban_time, C_RESET);
if (strlen(ban_time) == 0) { if (strlen(ban_time) == 0) {
printf(" (永久封禁)\n"); printf(" (永久封禁)\n");
@@ -146,6 +151,9 @@ int main(int argc, char *argv[]) {
printf("\n"); printf("\n");
} }
printf("最大重试次数: %s%d%s\n", C_GREEN, max_retries, C_RESET); printf("最大重试次数: %s%d%s\n", C_GREEN, max_retries, C_RESET);
printf("====防洪水攻击===\n");
printf("SSH端口速率: %s%d/分钟%s\n", C_GREEN, rate_limit, C_RESET);
printf("超速封禁时长: %s%s%s\n", C_GREEN, rate_ban_time, C_RESET);
printf("配置文件: %s\n", CONFIG_FILE); printf("配置文件: %s\n", CONFIG_FILE);
return SUCCESS; return SUCCESS;
} else if (argc == 4 && strcmp(argv[2], "time") == 0) { } else if (argc == 4 && strcmp(argv[2], "time") == 0) {
@@ -176,10 +184,45 @@ int main(int argc, char *argv[]) {
} }
msg(C_RED, "❌ 设置失败: 请使用1-10之间的整数"); msg(C_RED, "❌ 设置失败: 请使用1-10之间的整数");
return ERROR_INVALID_ARG; return ERROR_INVALID_ARG;
} else if (argc == 4 && strcmp(argv[2], "ratelimit") == 0) {
/* 设置SSH端口速率 */
int rate = atoi(argv[3]);
if (save_rate_limit_to_config(rate) == SUCCESS) {
char msg_buf[MAX_LINE_LEN];
snprintf(msg_buf, sizeof(msg_buf), "✅ SSH端口速率已设置为: %d/分钟", rate);
msg(C_GREEN, msg_buf);
/* 自动重新加载nftables规则 */
if (init_nftables_rules() == SUCCESS) {
msg(C_GREEN, "✅ 已自动应用新的速率限制规则");
} else {
msg(C_YELLOW, "⚠️ 规则应用失败,请手动运行: sudo bip install");
}
return SUCCESS;
}
msg(C_RED, "❌ 设置失败: 请使用1-1000之间的整数");
return ERROR_INVALID_ARG;
} else if (argc == 4 && strcmp(argv[2], "rateban") == 0) {
/* 设置超速封禁时间 */
const char *new_time = argv[3];
if (save_rate_ban_time_to_config(new_time) == SUCCESS) {
char msg_buf[MAX_LINE_LEN];
snprintf(msg_buf, sizeof(msg_buf), "✅ 超速封禁时长已设置为: %s", new_time);
msg(C_GREEN, msg_buf);
/* 自动重新加载nftables规则 */
if (init_nftables_rules() == SUCCESS) {
msg(C_GREEN, "✅ 已自动应用新的封禁时长规则");
} else {
msg(C_YELLOW, "⚠️ 规则应用失败,请手动运行: sudo bip install");
}
return SUCCESS;
}
return ERROR_FILE;
} else { } else {
msg(C_RED, "用法: bip config"); msg(C_RED, "用法: bip config");
msg(C_RED, " bip config time <time>"); msg(C_RED, " bip config time <time>");
msg(C_RED, " bip config retries <count>"); msg(C_RED, " bip config retries <count>");
msg(C_RED, " bip config ratelimit <rate>");
msg(C_RED, " bip config rateban <time>");
return ERROR_INVALID_ARG; return ERROR_INVALID_ARG;
} }
} }
+34 -9
View File
@@ -95,15 +95,6 @@ int init_nftables_rules(void) {
NFT_TABLE, NFT_WHITELIST, NFT_TABLE, NFT_WHITELIST); NFT_TABLE, NFT_WHITELIST, NFT_TABLE, NFT_WHITELIST);
system(command); system(command);
/* 1b. SSH连接速率限制(每IP每分钟最多20次新连接,防止TCP洪水) */
int ssh_port = get_ssh_port();
snprintf(command, sizeof(command),
"nft list chain %s input | grep -q 'limit rate' || "
"nft add rule %s input tcp dport %d ct state new "
"meter ssh-ratelimit '{ ip saddr limit rate over 20/minute burst 5 packets }' drop",
NFT_TABLE, NFT_TABLE, ssh_port);
system(command);
/* 2. IPv6白名单 accept */ /* 2. IPv6白名单 accept */
snprintf(command, sizeof(command), snprintf(command, sizeof(command),
"nft list chain %s input | grep -q '@%s' || nft add rule %s input ip6 saddr @%s accept", "nft list chain %s input | grep -q '@%s' || nft add rule %s input ip6 saddr @%s accept",
@@ -122,6 +113,40 @@ int init_nftables_rules(void) {
NFT_TABLE, NFT_SET_V6, NFT_TABLE, NFT_SET_V6); NFT_TABLE, NFT_SET_V6, NFT_TABLE, NFT_SET_V6);
system(command); system(command);
/* 5. SSH端口速率(防止TCP洪水,超速临时封禁) */
int ssh_port = get_ssh_port();
int rate_limit = get_rate_limit_from_config();
const char *rate_ban_time = get_rate_ban_time_from_config();
/* 创建SSH端口速率动态集合 */
snprintf(command, sizeof(command),
"nft add set %s ssh-ratelimit '{ type ipv4_addr; size 65535; flags dynamic,timeout; }' 2>/dev/null",
NFT_TABLE);
system(command);
snprintf(command, sizeof(command),
"nft add set %s ssh-ratelimit_v6 '{ type ipv6_addr; size 65535; flags dynamic,timeout; }' 2>/dev/null",
NFT_TABLE);
system(command);
/* 删除旧的限速规则(如果存在) */
snprintf(command, sizeof(command),
"nft -a list chain %s input 2>/dev/null | grep -E 'ssh-ratelimit.*tcp dport' | awk '{print $NF}' | "
"xargs -r -I {} nft delete rule %s input handle {}",
NFT_TABLE, NFT_TABLE);
system(command);
/* 添加新的限速规则:超速IP加入临时封禁集合 */
snprintf(command, sizeof(command),
"nft add rule %s input tcp dport %d ct state new "
"add @ssh-ratelimit { ip saddr timeout %s limit rate over %d/minute burst 5 packets } drop",
NFT_TABLE, ssh_port, rate_ban_time, rate_limit);
system(command);
snprintf(command, sizeof(command),
"nft add rule %s input tcp dport %d ct state new "
"add @ssh-ratelimit_v6 { ip6 saddr timeout %s limit rate over %d/minute burst 5 packets } drop",
NFT_TABLE, ssh_port, rate_ban_time, rate_limit);
system(command);
return SUCCESS; return SUCCESS;
} }