fix: IP blacklist and whitelist logic, optimize performance.

This commit is contained in:
dqzboy
2024-09-03 17:39:06 +08:00
parent c510e23942
commit df5027cb98
2 changed files with 364 additions and 164 deletions

View File

@@ -3064,172 +3064,372 @@ esac
# IP 黑白名单
function IP_BLACKWHITE_LIST() {
if ! command -v iptables &> /dev/null
then
WARN "iptables 未安装. 请安装后再运行此脚本."
exit 1
fi
IPTABLES=$(which iptables)
BLACKLIST_CHAIN="IP_BLACKLIST"
WHITELIST_CHAIN="IP_WHITELIST"
get_chain_name() {
local chain=$1
case $chain in
$BLACKLIST_CHAIN) echo "黑名单" ;;
$WHITELIST_CHAIN) echo "白名单" ;;
*) echo "未知名单" ;;
esac
}
create_chains() {
$IPTABLES -N $BLACKLIST_CHAIN 2>/dev/null
$IPTABLES -N $WHITELIST_CHAIN 2>/dev/null
}
create_chains
check_ip() {
local ip=$1
local ipv4_regex='^([0-9]{1,3}\.){3}[0-9]{1,3}$'
local ipv6_regex='^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$'
if [[ $ip =~ $ipv4_regex ]] || [[ $ip =~ $ipv6_regex ]]; then
return 0
else
return 1
fi
}
ip_exists_in_chain() {
local ip=$1
local chain=$2
local action=$3
$IPTABLES -C $chain -s $ip -j $action &>/dev/null
return $?
}
clear_chain() {
local chain=$1
$IPTABLES -F $chain
}
add_ip_to_chain() {
local ip=$1
local chain=$2
local action=$3
local chain_name=$(get_chain_name $chain)
if ! ip_exists_in_chain $ip $chain $action; then
$IPTABLES -A $chain -s $ip -j $action
INFO "${LIGHT_BLUE}$ip${RESET} ${LIGHT_GREEN}已添加${RESET}$(get_chain_name $chain)"
else
WARN "${LIGHT_BLUE}$ip${RESET} ${LIGHT_YELLOW}已存在${RESET}$(get_chain_name $chain),跳过添加"
fi
}
# 白名单
handle_whitelist() {
if ! $IPTABLES -L $WHITELIST_CHAIN >/dev/null 2>&1; then
$IPTABLES -N $WHITELIST_CHAIN
fi
if $IPTABLES -C INPUT -j $BLACKLIST_CHAIN >/dev/null 2>&1; then
read -e -p "$(WARN "${LIGHT_YELLOW}当前使用黑名单模式${RESET},${LIGHT_CYAN}是否切换到白名单模式?(y/n)${RESET}: ")" switch
if [[ $switch == "y" ]]; then
$IPTABLES -D INPUT -j $BLACKLIST_CHAIN
clear_chain $BLACKLIST_CHAIN
$IPTABLES -D INPUT -j $WHITELIST_CHAIN 2>/dev/null
else
return
fi
fi
clear_chain $WHITELIST_CHAIN
add_ip_to_chain 127.0.0.1 $WHITELIST_CHAIN ACCEPT
read -e -p "$(INFO "${LIGHT_CYAN}请输入白名单IP (用逗号分隔多个IP)${RESET}: ")" ips
IFS=',' read -ra ip_array <<< "$ips"
for ip in "${ip_array[@]}"; do
if check_ip $ip; then
add_ip_to_chain $ip $WHITELIST_CHAIN ACCEPT
else
WARN "无效IP: $ip"
fi
done
$IPTABLES -A $WHITELIST_CHAIN -j DROP
$IPTABLES -D INPUT -j $WHITELIST_CHAIN 2>/dev/null
$IPTABLES -I INPUT 1 -j $WHITELIST_CHAIN
INFO "${LIGHT_YELLOW}白名单已更新${RESET}只有指定的IP和本地回环可以访问"
IP_BLACKWHITE_LIST
}
# 黑名单
handle_blacklist() {
if ! $IPTABLES -L $BLACKLIST_CHAIN >/dev/null 2>&1; then
$IPTABLES -N $BLACKLIST_CHAIN
fi
if $IPTABLES -C INPUT -j $WHITELIST_CHAIN >/dev/null 2>&1; then
read -e -p "$(WARN "${LIGHT_YELLOW}当前使用白名单模式${RESET},${LIGHT_CYAN}是否切换到黑名单模式?(y/n)${RESET}: ")" switch
if [[ $switch == "y" ]]; then
$IPTABLES -D INPUT -j $WHITELIST_CHAIN
clear_chain $WHITELIST_CHAIN
$IPTABLES -D INPUT -j $BLACKLIST_CHAIN 2>/dev/null
else
return
fi
fi
read -e -p "$(INFO "${LIGHT_CYAN}请输入黑名单IP (用逗号分隔多个IP)${RESET}: ")" ips
IFS=',' read -ra ip_array <<< "$ips"
for ip in "${ip_array[@]}"; do
if check_ip $ip; then
add_ip_to_chain $ip $BLACKLIST_CHAIN DROP
else
WARN "无效IP: $ip"
fi
done
$IPTABLES -D INPUT -j $BLACKLIST_CHAIN 2>/dev/null
$IPTABLES -I INPUT 1 -j $BLACKLIST_CHAIN
INFO "${LIGHT_YELLOW}黑名单已更新${RESET}黑名单里的IP将无法访问"
IP_BLACKWHITE_LIST
}
SEPARATOR "设置IP黑白名单"
echo -e "1) ${BOLD}设置${LIGHT_GREEN}白名单${RESET}"
echo -e "2) ${BOLD}设置${LIGHT_CYAN}黑名单${RESET}"
echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
echo -e "0) ${BOLD}退出脚本${RESET}"
echo "---------------------------------------------------------------"
read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" ipblack_choice
case $ipblack_choice in
1)
handle_whitelist
;;
2)
handle_blacklist
;;
3)
main_menu
;;
0)
if ! command -v iptables &> /dev/null
then
WARN "iptables 未安装. 请安装后再运行此脚本."
exit 1
;;
*)
WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
IP_BLACKWHITE_LIST
;;
esac
fi
IPTABLES=$(which iptables)
BLACKLIST_CHAIN="IP_BLACKLIST"
WHITELIST_CHAIN="IP_WHITELIST"
WHITELIST_FILE="/etc/firewall/whitelist.txt"
BLACKLIST_FILE="/etc/firewall/blacklist.txt"
# 确保文件存在
mkdir -p /etc/firewall
touch $WHITELIST_FILE $BLACKLIST_FILE
get_chain_name() {
local chain=$1
case $chain in
$BLACKLIST_CHAIN) echo "黑名单" ;;
$WHITELIST_CHAIN) echo "白名单" ;;
*) echo "未知名单" ;;
esac
}
create_chains() {
$IPTABLES -N $BLACKLIST_CHAIN 2>/dev/null
$IPTABLES -N $WHITELIST_CHAIN 2>/dev/null
}
check_ip() {
local ip=$1
local ipv4_regex='^([0-9]{1,3}\.){3}[0-9]{1,3}$'
local ipv6_regex='^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$'
if [[ $ip =~ $ipv4_regex ]] || [[ $ip =~ $ipv6_regex ]]; then
return 0
else
return 1
fi
}
ip_exists_in_file() {
local ip=$1
local file=$2
grep -q "^$ip$" "$file"
return $?
}
add_ips_to_file() {
local ips=("$@")
local file="${ips[-1]}"
unset 'ips[-1]'
local chain_name=$(get_chain_name $([[ $file == $WHITELIST_FILE ]] && echo $WHITELIST_CHAIN || echo $BLACKLIST_CHAIN))
local added=()
local skipped=()
for ip in "${ips[@]}"; do
if ! ip_exists_in_file $ip $file; then
echo $ip >> "$file"
added+=("$ip")
else
skipped+=("$ip")
fi
done
if [ ${#added[@]} -gt 0 ]; then
INFO "${LIGHT_BLUE}${added[*]}${RESET} ${LIGHT_GREEN}已添加${RESET}$chain_name"
fi
if [ ${#skipped[@]} -gt 0 ]; then
WARN "${LIGHT_BLUE}${skipped[*]}${RESET} ${LIGHT_YELLOW}已存在${RESET}$chain_name,跳过添加"
fi
}
remove_ips_from_file() {
local ips=("$@")
local file="${ips[-1]}"
unset 'ips[-1]'
local chain_name=$(get_chain_name $([[ $file == $WHITELIST_FILE ]] && echo $WHITELIST_CHAIN || echo $BLACKLIST_CHAIN))
local removed=()
local not_found=()
for ip in "${ips[@]}"; do
if ip_exists_in_file $ip $file; then
sed -i "/^$ip$/d" "$file"
removed+=("$ip")
else
not_found+=("$ip")
fi
done
if [ ${#removed[@]} -gt 0 ]; then
INFO "${LIGHT_BLUE}${removed[*]}${RESET} ${LIGHT_RED}已从${RESET}$chain_name${LIGHT_RED}移除${RESET}"
fi
if [ ${#not_found[@]} -gt 0 ]; then
WARN "${LIGHT_BLUE}${not_found[*]}${RESET} ${LIGHT_YELLOW}不存在${RESET}$chain_name,无需移除"
fi
}
list_ips_in_file() {
local file=$1
local chain_name=$(get_chain_name $([[ $file == $WHITELIST_FILE ]] && echo $WHITELIST_CHAIN || echo $BLACKLIST_CHAIN))
echo "---------------------------------------------------------------"
echo "当前${chain_name}中的IP列表"
cat "$file"
}
apply_ip_list() {
local chain=$1
local file=$2
local action=$3
# 清空链
$IPTABLES -F $chain
# 使用 iptables-restore 批量应用规则
{
echo "*filter"
echo ":$chain - [0:0]"
while IFS= read -r ip; do
echo "-A $chain -s $ip -j $action"
done < "$file"
echo "COMMIT"
} | $IPTABLES-restore -n
}
ensure_default_deny_for_whitelist() {
if ! $IPTABLES -C $WHITELIST_CHAIN -j DROP &>/dev/null; then
$IPTABLES -A $WHITELIST_CHAIN -j DROP
fi
}
whitelist_is_empty() {
[ ! -s "$WHITELIST_FILE" ]
}
apply_whitelist() {
if whitelist_is_empty; then
WARN "白名单为空,不应用白名单规则以避免锁定系统。"
return 1
fi
if ! $IPTABLES -C INPUT -j $WHITELIST_CHAIN &>/dev/null; then
$IPTABLES -I INPUT 1 -j $WHITELIST_CHAIN
INFO "已将白名单规则应用到 INPUT 链"
else
INFO "白名单规则已经应用到 INPUT 链"
fi
apply_ip_list $WHITELIST_CHAIN $WHITELIST_FILE ACCEPT
ensure_default_deny_for_whitelist
return 0
}
switch_to_whitelist() {
$IPTABLES -D INPUT -j $BLACKLIST_CHAIN 2>/dev/null
INFO "${LIGHT_YELLOW}已切换到白名单模式请注意请在添加IP后手动应用规则${RESET}"
}
switch_to_blacklist() {
$IPTABLES -D INPUT -j $WHITELIST_CHAIN 2>/dev/null
$IPTABLES -I INPUT 1 -j $BLACKLIST_CHAIN
apply_ip_list $BLACKLIST_CHAIN $BLACKLIST_FILE DROP
INFO "${LIGHT_YELLOW}已切换到黑名单模式${RESET}"
}
handle_whitelist() {
create_chains
local whitelist_mode_active=false
local whitelist_rules_applied=false
if $IPTABLES -C INPUT -j $WHITELIST_CHAIN &>/dev/null; then
whitelist_mode_active=true
whitelist_rules_applied=true
elif $IPTABLES -C INPUT -j $BLACKLIST_CHAIN &>/dev/null; then
read -e -p "$(WARN "${LIGHT_YELLOW}当前使用黑名单模式${RESET},${LIGHT_CYAN}是否切换到白名单模式?(y/n)${RESET}: ")" switch
if [[ $switch == "y" ]]; then
switch_to_whitelist
whitelist_mode_active=true
whitelist_rules_applied=false
else
WARN "保持在黑名单模式,返回主菜单。"
return
fi
else
switch_to_whitelist
whitelist_mode_active=true
whitelist_rules_applied=false
fi
while true; do
echo "---------------------------------------------------------------"
echo -e "1) ${BOLD}添加IP到白名单${RESET}"
echo -e "2) ${BOLD}从白名单移除IP${RESET}"
echo -e "3) ${BOLD}查看当前白名单${RESET}"
echo -e "4) ${BOLD}应用白名单规则${RESET}"
echo -e "5) ${BOLD}返回上一级${RESET}"
echo "---------------------------------------------------------------"
read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" whitelist_choice
case $whitelist_choice in
1)
read -e -p "$(INFO "${LIGHT_CYAN}请输入要添加到白名单的IP (用逗号分隔多个IP)${RESET}: ")" ips
IFS=',' read -ra ip_array <<< "$ips"
valid_ips=()
for ip in "${ip_array[@]}"; do
if check_ip $ip; then
valid_ips+=("$ip")
else
WARN "无效IP: $ip"
fi
done
if [ ${#valid_ips[@]} -gt 0 ]; then
add_ips_to_file "${valid_ips[@]}" "$WHITELIST_FILE"
whitelist_rules_applied=false
fi
;;
2)
read -e -p "$(INFO "${LIGHT_CYAN}请输入要从白名单移除的IP (用逗号分隔多个IP)${RESET}: ")" ips
IFS=',' read -ra ip_array <<< "$ips"
valid_ips=()
for ip in "${ip_array[@]}"; do
if check_ip $ip; then
valid_ips+=("$ip")
else
WARN "无效IP: $ip"
fi
done
if [ ${#valid_ips[@]} -gt 0 ]; then
remove_ips_from_file "${valid_ips[@]}" "$WHITELIST_FILE"
whitelist_rules_applied=false
fi
;;
3)
list_ips_in_file $WHITELIST_FILE
;;
4)
if apply_whitelist; then
whitelist_rules_applied=true
INFO "${LIGHT_GREEN}白名单规则已成功应用${RESET}"
else
WARN "${LIGHT_YELLOW}无法应用白名单规则${RESET}"
fi
;;
5)
if ! $whitelist_rules_applied; then
read -e -p "$(WARN "${LIGHT_YELLOW}白名单规则尚未应用。您确定要退出吗?${RESET} (y/n): ")" confirm
if [[ $confirm != "y" ]]; then
continue
fi
fi
return
;;
*)
WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择1-5${RESET}的选项."
;;
esac
done
}
handle_blacklist() {
create_chains
local blacklist_mode_active=false
if $IPTABLES -C INPUT -j $BLACKLIST_CHAIN &>/dev/null; then
blacklist_mode_active=true
elif $IPTABLES -C INPUT -j $WHITELIST_CHAIN &>/dev/null; then
read -e -p "$(WARN "${LIGHT_YELLOW}当前使用白名单模式${RESET},${LIGHT_CYAN}是否切换到黑名单模式?(y/n)${RESET}: ")" switch
if [[ $switch == "y" ]]; then
switch_to_blacklist
blacklist_mode_active=true
else
WARN "保持在白名单模式,返回主菜单。"
return
fi
else
switch_to_blacklist
blacklist_mode_active=true
fi
while true; do
echo "---------------------------------------------------------------"
echo -e "1) ${BOLD}添加IP到黑名单${RESET}"
echo -e "2) ${BOLD}从黑名单移除IP${RESET}"
echo -e "3) ${BOLD}查看当前黑名单${RESET}"
echo -e "4) ${BOLD}返回上一级${RESET}"
echo "---------------------------------------------------------------"
read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" blacklist_choice
case $blacklist_choice in
1)
read -e -p "$(INFO "${LIGHT_CYAN}请输入要添加到黑名单的IP (用逗号分隔多个IP)${RESET}: ")" ips
IFS=',' read -ra ip_array <<< "$ips"
valid_ips=()
for ip in "${ip_array[@]}"; do
if check_ip $ip; then
valid_ips+=("$ip")
else
WARN "无效IP: $ip"
fi
done
if [ ${#valid_ips[@]} -gt 0 ]; then
add_ips_to_file "${valid_ips[@]}" "$BLACKLIST_FILE"
apply_ip_list $BLACKLIST_CHAIN $BLACKLIST_FILE DROP
fi
;;
2)
read -e -p "$(INFO "${LIGHT_CYAN}请输入要从黑名单移除的IP (用逗号分隔多个IP)${RESET}: ")" ips
IFS=',' read -ra ip_array <<< "$ips"
valid_ips=()
for ip in "${ip_array[@]}"; do
if check_ip $ip; then
valid_ips+=("$ip")
else
WARN "无效IP: $ip"
fi
done
if [ ${#valid_ips[@]} -gt 0 ]; then
remove_ips_from_file "${valid_ips[@]}" "$BLACKLIST_FILE"
apply_ip_list $BLACKLIST_CHAIN $BLACKLIST_FILE DROP
fi
;;
3)
list_ips_in_file $BLACKLIST_FILE
;;
4)
return
;;
*)
WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择1-4${RESET}的选项."
;;
esac
done
}
while true; do
SEPARATOR "设置IP黑白名单"
echo -e "1) ${BOLD}管理${LIGHT_GREEN}白名单${RESET}"
echo -e "2) ${BOLD}管理${LIGHT_CYAN}黑名单${RESET}"
echo -e "3) ${BOLD}返回${LIGHT_RED}主菜单${RESET}"
echo -e "0) ${BOLD}退出脚本${RESET}"
echo "---------------------------------------------------------------"
read -e -p "$(INFO "输入${LIGHT_CYAN}对应数字${RESET}并按${LIGHT_GREEN}Enter${RESET}键 > ")" ipblack_choice
case $ipblack_choice in
1)
handle_whitelist
;;
2)
handle_blacklist
;;
3)
main_menu
;;
0)
exit 0
;;
*)
WARN "输入了无效的选择。请重新${LIGHT_GREEN}选择0-3${RESET}的选项."
;;
esac
done
}
# 其他工具
function OtherTools() {
echo -e "1) 设置${BOLD}${YELLOW}系统命令${RESET}"