mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-02-28 21:23:01 +00:00
399 lines
13 KiB
Bash
399 lines
13 KiB
Bash
|
|
#!/bin/bash
|
||
|
|
# lib/iplimit.sh - Fail2ban IP limiting management
|
||
|
|
|
||
|
|
# Include guard
|
||
|
|
[[ -n "${__X_UI_IPLIMIT_INCLUDED:-}" ]] && return 0
|
||
|
|
__X_UI_IPLIMIT_INCLUDED=1
|
||
|
|
|
||
|
|
# Source dependencies
|
||
|
|
source "${LIB_DIR}/common.sh"
|
||
|
|
source "${LIB_DIR}/service.sh"
|
||
|
|
|
||
|
|
ip_validation() {
|
||
|
|
ipv6_regex="^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$"
|
||
|
|
ipv4_regex="^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)$"
|
||
|
|
}
|
||
|
|
|
||
|
|
iplimit_main() {
|
||
|
|
echo -e "\n${green}\t1.${plain} Install Fail2ban and configure IP Limit"
|
||
|
|
echo -e "${green}\t2.${plain} Change Ban Duration"
|
||
|
|
echo -e "${green}\t3.${plain} Unban Everyone"
|
||
|
|
echo -e "${green}\t4.${plain} Ban Logs"
|
||
|
|
echo -e "${green}\t5.${plain} Ban an IP Address"
|
||
|
|
echo -e "${green}\t6.${plain} Unban an IP Address"
|
||
|
|
echo -e "${green}\t7.${plain} Real-Time Logs"
|
||
|
|
echo -e "${green}\t8.${plain} Service Status"
|
||
|
|
echo -e "${green}\t9.${plain} Service Restart"
|
||
|
|
echo -e "${green}\t10.${plain} Uninstall Fail2ban and IP Limit"
|
||
|
|
echo -e "${green}\t0.${plain} Back to Main Menu"
|
||
|
|
read -rp "Choose an option: " choice
|
||
|
|
case "$choice" in
|
||
|
|
0)
|
||
|
|
show_menu
|
||
|
|
;;
|
||
|
|
1)
|
||
|
|
confirm "Proceed with installation of Fail2ban & IP Limit?" "y"
|
||
|
|
if [[ $? == 0 ]]; then
|
||
|
|
install_iplimit
|
||
|
|
else
|
||
|
|
iplimit_main
|
||
|
|
fi
|
||
|
|
;;
|
||
|
|
2)
|
||
|
|
read -rp "Please enter new Ban Duration in Minutes [default 30]: " NUM
|
||
|
|
if [[ $NUM =~ ^[0-9]+$ ]]; then
|
||
|
|
create_iplimit_jails ${NUM}
|
||
|
|
if [[ $release == "alpine" ]]; then
|
||
|
|
rc-service fail2ban restart
|
||
|
|
else
|
||
|
|
systemctl restart fail2ban
|
||
|
|
fi
|
||
|
|
else
|
||
|
|
echo -e "${red}${NUM} is not a number! Please, try again.${plain}"
|
||
|
|
fi
|
||
|
|
iplimit_main
|
||
|
|
;;
|
||
|
|
3)
|
||
|
|
confirm "Proceed with Unbanning everyone from IP Limit jail?" "y"
|
||
|
|
if [[ $? == 0 ]]; then
|
||
|
|
fail2ban-client reload --restart --unban 3x-ipl
|
||
|
|
truncate -s 0 "${iplimit_banned_log_path}"
|
||
|
|
echo -e "${green}All users Unbanned successfully.${plain}"
|
||
|
|
iplimit_main
|
||
|
|
else
|
||
|
|
echo -e "${yellow}Cancelled.${plain}"
|
||
|
|
fi
|
||
|
|
iplimit_main
|
||
|
|
;;
|
||
|
|
4)
|
||
|
|
show_banlog
|
||
|
|
iplimit_main
|
||
|
|
;;
|
||
|
|
5)
|
||
|
|
read -rp "Enter the IP address you want to ban: " ban_ip
|
||
|
|
ip_validation
|
||
|
|
if [[ $ban_ip =~ $ipv4_regex || $ban_ip =~ $ipv6_regex ]]; then
|
||
|
|
fail2ban-client set 3x-ipl banip "$ban_ip"
|
||
|
|
echo -e "${green}IP Address ${ban_ip} has been banned successfully.${plain}"
|
||
|
|
else
|
||
|
|
echo -e "${red}Invalid IP address format! Please try again.${plain}"
|
||
|
|
fi
|
||
|
|
iplimit_main
|
||
|
|
;;
|
||
|
|
6)
|
||
|
|
read -rp "Enter the IP address you want to unban: " unban_ip
|
||
|
|
ip_validation
|
||
|
|
if [[ $unban_ip =~ $ipv4_regex || $unban_ip =~ $ipv6_regex ]]; then
|
||
|
|
fail2ban-client set 3x-ipl unbanip "$unban_ip"
|
||
|
|
echo -e "${green}IP Address ${unban_ip} has been unbanned successfully.${plain}"
|
||
|
|
else
|
||
|
|
echo -e "${red}Invalid IP address format! Please try again.${plain}"
|
||
|
|
fi
|
||
|
|
iplimit_main
|
||
|
|
;;
|
||
|
|
7)
|
||
|
|
tail -f /var/log/fail2ban.log
|
||
|
|
iplimit_main
|
||
|
|
;;
|
||
|
|
8)
|
||
|
|
service fail2ban status
|
||
|
|
iplimit_main
|
||
|
|
;;
|
||
|
|
9)
|
||
|
|
if [[ $release == "alpine" ]]; then
|
||
|
|
rc-service fail2ban restart
|
||
|
|
else
|
||
|
|
systemctl restart fail2ban
|
||
|
|
fi
|
||
|
|
iplimit_main
|
||
|
|
;;
|
||
|
|
10)
|
||
|
|
remove_iplimit
|
||
|
|
iplimit_main
|
||
|
|
;;
|
||
|
|
*)
|
||
|
|
echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
|
||
|
|
iplimit_main
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
}
|
||
|
|
|
||
|
|
install_iplimit() {
|
||
|
|
if ! command -v fail2ban-client &>/dev/null; then
|
||
|
|
echo -e "${green}Fail2ban is not installed. Installing now...!${plain}\n"
|
||
|
|
|
||
|
|
# Check the OS and install necessary packages
|
||
|
|
case "${release}" in
|
||
|
|
ubuntu)
|
||
|
|
apt-get update
|
||
|
|
if [[ "${os_version}" -ge 24 ]]; then
|
||
|
|
apt-get install python3-pip -y
|
||
|
|
python3 -m pip install pyasynchat --break-system-packages
|
||
|
|
fi
|
||
|
|
apt-get install fail2ban -y
|
||
|
|
;;
|
||
|
|
debian)
|
||
|
|
apt-get update
|
||
|
|
if [ "$os_version" -ge 12 ]; then
|
||
|
|
apt-get install -y python3-systemd
|
||
|
|
fi
|
||
|
|
apt-get install -y fail2ban
|
||
|
|
;;
|
||
|
|
armbian)
|
||
|
|
apt-get update && apt-get install fail2ban -y
|
||
|
|
;;
|
||
|
|
fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
|
||
|
|
dnf -y update && dnf -y install fail2ban
|
||
|
|
;;
|
||
|
|
centos)
|
||
|
|
if [[ "${VERSION_ID}" =~ ^7 ]]; then
|
||
|
|
yum update -y && yum install epel-release -y
|
||
|
|
yum -y install fail2ban
|
||
|
|
else
|
||
|
|
dnf -y update && dnf -y install fail2ban
|
||
|
|
fi
|
||
|
|
;;
|
||
|
|
arch | manjaro | parch)
|
||
|
|
pacman -Syu --noconfirm fail2ban
|
||
|
|
;;
|
||
|
|
alpine)
|
||
|
|
apk add fail2ban
|
||
|
|
;;
|
||
|
|
*)
|
||
|
|
echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n"
|
||
|
|
exit 1
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
|
||
|
|
if ! command -v fail2ban-client &>/dev/null; then
|
||
|
|
echo -e "${red}Fail2ban installation failed.${plain}\n"
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
echo -e "${green}Fail2ban installed successfully!${plain}\n"
|
||
|
|
else
|
||
|
|
echo -e "${yellow}Fail2ban is already installed.${plain}\n"
|
||
|
|
fi
|
||
|
|
|
||
|
|
echo -e "${green}Configuring IP Limit...${plain}\n"
|
||
|
|
|
||
|
|
# make sure there's no conflict for jail files
|
||
|
|
iplimit_remove_conflicts
|
||
|
|
|
||
|
|
# Check if log file exists
|
||
|
|
if ! test -f "${iplimit_banned_log_path}"; then
|
||
|
|
touch ${iplimit_banned_log_path}
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Check if service log file exists so fail2ban won't return error
|
||
|
|
if ! test -f "${iplimit_log_path}"; then
|
||
|
|
touch ${iplimit_log_path}
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Create the iplimit jail files
|
||
|
|
# we didn't pass the bantime here to use the default value
|
||
|
|
create_iplimit_jails
|
||
|
|
|
||
|
|
# Launching fail2ban
|
||
|
|
if [[ $release == "alpine" ]]; then
|
||
|
|
if [[ $(rc-service fail2ban status | grep -F 'status: started' -c) == 0 ]]; then
|
||
|
|
rc-service fail2ban start
|
||
|
|
else
|
||
|
|
rc-service fail2ban restart
|
||
|
|
fi
|
||
|
|
rc-update add fail2ban
|
||
|
|
else
|
||
|
|
if ! systemctl is-active --quiet fail2ban; then
|
||
|
|
systemctl start fail2ban
|
||
|
|
else
|
||
|
|
systemctl restart fail2ban
|
||
|
|
fi
|
||
|
|
systemctl enable fail2ban
|
||
|
|
fi
|
||
|
|
|
||
|
|
echo -e "${green}IP Limit installed and configured successfully!${plain}\n"
|
||
|
|
before_show_menu
|
||
|
|
}
|
||
|
|
|
||
|
|
remove_iplimit() {
|
||
|
|
echo -e "${green}\t1.${plain} Only remove IP Limit configurations"
|
||
|
|
echo -e "${green}\t2.${plain} Uninstall Fail2ban and IP Limit"
|
||
|
|
echo -e "${green}\t0.${plain} Back to Main Menu"
|
||
|
|
read -rp "Choose an option: " num
|
||
|
|
case "$num" in
|
||
|
|
1)
|
||
|
|
rm -f /etc/fail2ban/filter.d/3x-ipl.conf
|
||
|
|
rm -f /etc/fail2ban/action.d/3x-ipl.conf
|
||
|
|
rm -f /etc/fail2ban/jail.d/3x-ipl.conf
|
||
|
|
if [[ $release == "alpine" ]]; then
|
||
|
|
rc-service fail2ban restart
|
||
|
|
else
|
||
|
|
systemctl restart fail2ban
|
||
|
|
fi
|
||
|
|
echo -e "${green}IP Limit removed successfully!${plain}\n"
|
||
|
|
before_show_menu
|
||
|
|
;;
|
||
|
|
2)
|
||
|
|
rm -rf /etc/fail2ban
|
||
|
|
if [[ $release == "alpine" ]]; then
|
||
|
|
rc-service fail2ban stop
|
||
|
|
else
|
||
|
|
systemctl stop fail2ban
|
||
|
|
fi
|
||
|
|
case "${release}" in
|
||
|
|
ubuntu | debian | armbian)
|
||
|
|
apt-get remove -y fail2ban
|
||
|
|
apt-get purge -y fail2ban -y
|
||
|
|
apt-get autoremove -y
|
||
|
|
;;
|
||
|
|
fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
|
||
|
|
dnf remove fail2ban -y
|
||
|
|
dnf autoremove -y
|
||
|
|
;;
|
||
|
|
centos)
|
||
|
|
if [[ "${VERSION_ID}" =~ ^7 ]]; then
|
||
|
|
yum remove fail2ban -y
|
||
|
|
yum autoremove -y
|
||
|
|
else
|
||
|
|
dnf remove fail2ban -y
|
||
|
|
dnf autoremove -y
|
||
|
|
fi
|
||
|
|
;;
|
||
|
|
arch | manjaro | parch)
|
||
|
|
pacman -Rns --noconfirm fail2ban
|
||
|
|
;;
|
||
|
|
alpine)
|
||
|
|
apk del fail2ban
|
||
|
|
;;
|
||
|
|
*)
|
||
|
|
echo -e "${red}Unsupported operating system. Please uninstall Fail2ban manually.${plain}\n"
|
||
|
|
exit 1
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
echo -e "${green}Fail2ban and IP Limit removed successfully!${plain}\n"
|
||
|
|
before_show_menu
|
||
|
|
;;
|
||
|
|
0)
|
||
|
|
show_menu
|
||
|
|
;;
|
||
|
|
*)
|
||
|
|
echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
|
||
|
|
remove_iplimit
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
}
|
||
|
|
|
||
|
|
show_banlog() {
|
||
|
|
local system_log="/var/log/fail2ban.log"
|
||
|
|
|
||
|
|
echo -e "${green}Checking ban logs...${plain}\n"
|
||
|
|
|
||
|
|
if [[ $release == "alpine" ]]; then
|
||
|
|
if [[ $(rc-service fail2ban status | grep -F 'status: started' -c) == 0 ]]; then
|
||
|
|
echo -e "${red}Fail2ban service is not running!${plain}\n"
|
||
|
|
return 1
|
||
|
|
fi
|
||
|
|
else
|
||
|
|
if ! systemctl is-active --quiet fail2ban; then
|
||
|
|
echo -e "${red}Fail2ban service is not running!${plain}\n"
|
||
|
|
return 1
|
||
|
|
fi
|
||
|
|
fi
|
||
|
|
|
||
|
|
if [[ -f "$system_log" ]]; then
|
||
|
|
echo -e "${green}Recent system ban activities from fail2ban.log:${plain}"
|
||
|
|
grep "3x-ipl" "$system_log" | grep -E "Ban|Unban" | tail -n 10 || echo -e "${yellow}No recent system ban activities found${plain}"
|
||
|
|
echo ""
|
||
|
|
fi
|
||
|
|
|
||
|
|
if [[ -f "${iplimit_banned_log_path}" ]]; then
|
||
|
|
echo -e "${green}3X-IPL ban log entries:${plain}"
|
||
|
|
if [[ -s "${iplimit_banned_log_path}" ]]; then
|
||
|
|
grep -v "INIT" "${iplimit_banned_log_path}" | tail -n 10 || echo -e "${yellow}No ban entries found${plain}"
|
||
|
|
else
|
||
|
|
echo -e "${yellow}Ban log file is empty${plain}"
|
||
|
|
fi
|
||
|
|
else
|
||
|
|
echo -e "${red}Ban log file not found at: ${iplimit_banned_log_path}${plain}"
|
||
|
|
fi
|
||
|
|
|
||
|
|
echo -e "\n${green}Current jail status:${plain}"
|
||
|
|
fail2ban-client status 3x-ipl || echo -e "${yellow}Unable to get jail status${plain}"
|
||
|
|
}
|
||
|
|
|
||
|
|
create_iplimit_jails() {
|
||
|
|
# Use default bantime if not passed => 30 minutes
|
||
|
|
local bantime="${1:-30}"
|
||
|
|
|
||
|
|
# Uncomment 'allowipv6 = auto' in fail2ban.conf
|
||
|
|
sed -i 's/#allowipv6 = auto/allowipv6 = auto/g' /etc/fail2ban/fail2ban.conf
|
||
|
|
|
||
|
|
# On Debian 12+ fail2ban's default backend should be changed to systemd
|
||
|
|
if [[ "${release}" == "debian" && ${os_version} -ge 12 ]]; then
|
||
|
|
sed -i '0,/action =/s/backend = auto/backend = systemd/' /etc/fail2ban/jail.conf
|
||
|
|
fi
|
||
|
|
|
||
|
|
cat << EOF > /etc/fail2ban/jail.d/3x-ipl.conf
|
||
|
|
[3x-ipl]
|
||
|
|
enabled=true
|
||
|
|
backend=auto
|
||
|
|
filter=3x-ipl
|
||
|
|
action=3x-ipl
|
||
|
|
logpath=${iplimit_log_path}
|
||
|
|
maxretry=2
|
||
|
|
findtime=32
|
||
|
|
bantime=${bantime}m
|
||
|
|
EOF
|
||
|
|
|
||
|
|
cat << EOF > /etc/fail2ban/filter.d/3x-ipl.conf
|
||
|
|
[Definition]
|
||
|
|
datepattern = ^%%Y/%%m/%%d %%H:%%M:%%S
|
||
|
|
failregex = \[LIMIT_IP\]\s*Email\s*=\s*<F-USER>.+</F-USER>\s*\|\|\s*SRC\s*=\s*<ADDR>
|
||
|
|
ignoreregex =
|
||
|
|
EOF
|
||
|
|
|
||
|
|
cat << EOF > /etc/fail2ban/action.d/3x-ipl.conf
|
||
|
|
[INCLUDES]
|
||
|
|
before = iptables-allports.conf
|
||
|
|
|
||
|
|
[Definition]
|
||
|
|
actionstart = <iptables> -N f2b-<name>
|
||
|
|
<iptables> -A f2b-<name> -j <returntype>
|
||
|
|
<iptables> -I <chain> -p <protocol> -j f2b-<name>
|
||
|
|
|
||
|
|
actionstop = <iptables> -D <chain> -p <protocol> -j f2b-<name>
|
||
|
|
<actionflush>
|
||
|
|
<iptables> -X f2b-<name>
|
||
|
|
|
||
|
|
actioncheck = <iptables> -n -L <chain> | grep -q 'f2b-<name>[ \t]'
|
||
|
|
|
||
|
|
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>
|
||
|
|
echo "\$(date +"%%Y/%%m/%%d %%H:%%M:%%S") BAN [Email] = <F-USER> [IP] = <ip> banned for <bantime> seconds." >> ${iplimit_banned_log_path}
|
||
|
|
|
||
|
|
actionunban = <iptables> -D f2b-<name> -s <ip> -j <blocktype>
|
||
|
|
echo "\$(date +"%%Y/%%m/%%d %%H:%%M:%%S") UNBAN [Email] = <F-USER> [IP] = <ip> unbanned." >> ${iplimit_banned_log_path}
|
||
|
|
|
||
|
|
[Init]
|
||
|
|
name = default
|
||
|
|
protocol = tcp
|
||
|
|
chain = INPUT
|
||
|
|
EOF
|
||
|
|
|
||
|
|
echo -e "${green}Ip Limit jail files created with a bantime of ${bantime} minutes.${plain}"
|
||
|
|
}
|
||
|
|
|
||
|
|
iplimit_remove_conflicts() {
|
||
|
|
local jail_files=(
|
||
|
|
/etc/fail2ban/jail.conf
|
||
|
|
/etc/fail2ban/jail.local
|
||
|
|
)
|
||
|
|
|
||
|
|
for file in "${jail_files[@]}"; do
|
||
|
|
# Check for [3x-ipl] config in jail file then remove it
|
||
|
|
if test -f "${file}" && grep -qw '3x-ipl' ${file}; then
|
||
|
|
sed -i "/\[3x-ipl\]/,/^$/d" ${file}
|
||
|
|
echo -e "${yellow}Removing conflicts of [3x-ipl] in jail (${file})!${plain}\n"
|
||
|
|
fi
|
||
|
|
done
|
||
|
|
}
|