mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-04-19 21:42:24 +00:00
Added IP Limit Management to x-ui menu, Tweaked IP Limit to check every 20s (#615)
Co-authored-by: Hamidreza <70919649+hamid-gh98@users.noreply.github.com> Co-authored-by: Ho3ein <ho3ein.sanaei@gmail.com>
This commit is contained in:
parent
85df1301dc
commit
6e22aa59e7
3 changed files with 216 additions and 11 deletions
|
@ -2,6 +2,7 @@ package job
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"x-ui/database"
|
"x-ui/database"
|
||||||
|
@ -31,6 +32,18 @@ func (j *CheckClientIpJob) Run() {
|
||||||
logger.Debug("Check Client IP Job...")
|
logger.Debug("Check Client IP Job...")
|
||||||
|
|
||||||
if hasLimitIp() {
|
if hasLimitIp() {
|
||||||
|
//create log file for Fail2ban IP Limit
|
||||||
|
logIpFile, err := os.OpenFile("/var/log/3xipl.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
|
||||||
|
checkError(err)
|
||||||
|
defer logIpFile.Close()
|
||||||
|
log.SetOutput(logIpFile)
|
||||||
|
log.SetFlags(log.LstdFlags)
|
||||||
|
|
||||||
|
//create file to collect access.log to another file accessp.log (p=persistent)
|
||||||
|
logAccessP, err := os.OpenFile("/usr/local/x-ui/accessp.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
|
||||||
|
checkError(err)
|
||||||
|
defer logAccessP.Close()
|
||||||
|
|
||||||
processLogFile()
|
processLogFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,9 +142,18 @@ func processLogFile() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(time.Second * 5)
|
time.Sleep(time.Second * 3)
|
||||||
//added 5 seconds delay before cleaning logs to reduce chance of logging IP that already has been banned
|
//added 3 seconds delay before cleaning logs to reduce chance of logging IP that already has been banned
|
||||||
if shouldCleanLog {
|
if shouldCleanLog {
|
||||||
|
//copy log
|
||||||
|
logAccessP, err := os.OpenFile("/usr/local/x-ui/accessp.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
|
||||||
|
checkError(err)
|
||||||
|
input, err := os.ReadFile(accessLogPath)
|
||||||
|
checkError(err)
|
||||||
|
if _, err := logAccessP.Write(input); err != nil {
|
||||||
|
checkError(err)
|
||||||
|
}
|
||||||
|
defer logAccessP.Close()
|
||||||
// clean log
|
// clean log
|
||||||
if err := os.Truncate(GetAccessLogPath(), 0); err != nil {
|
if err := os.Truncate(GetAccessLogPath(), 0); err != nil {
|
||||||
checkError(err)
|
checkError(err)
|
||||||
|
@ -239,10 +261,9 @@ func updateInboundClientIps(inboundClientIps *model.InboundClientIps, clientEmai
|
||||||
shouldCleanLog = true
|
shouldCleanLog = true
|
||||||
|
|
||||||
if limitIp < len(ips) && inbound.Enable {
|
if limitIp < len(ips) && inbound.Enable {
|
||||||
|
|
||||||
disAllowedIps = append(disAllowedIps, ips[limitIp:]...)
|
disAllowedIps = append(disAllowedIps, ips[limitIp:]...)
|
||||||
for i := limitIp; i < len(ips); i++ {
|
for i := limitIp; i < len(ips); i++ {
|
||||||
logger.Notice("[LIMIT_IP] Email=", clientEmail, " SRC=", ips[i])
|
log.Printf("[LIMIT_IP] Email = %s || SRC = %s", clientEmail, ips[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -250,8 +250,8 @@ func (s *Server) startTask() {
|
||||||
// Check the inbound traffic every 30 seconds that the traffic exceeds and expires
|
// Check the inbound traffic every 30 seconds that the traffic exceeds and expires
|
||||||
s.cron.AddJob("@every 30s", job.NewCheckInboundJob())
|
s.cron.AddJob("@every 30s", job.NewCheckInboundJob())
|
||||||
|
|
||||||
// check client ips from log file every 30 sec
|
// check client ips from log file every 20 sec
|
||||||
s.cron.AddJob("@every 30s", job.NewCheckClientIpJob())
|
s.cron.AddJob("@every 20s", job.NewCheckClientIpJob())
|
||||||
|
|
||||||
// Make a traffic condition every day, 8:30
|
// Make a traffic condition every day, 8:30
|
||||||
var entry cron.EntryID
|
var entry cron.EntryID
|
||||||
|
|
194
x-ui.sh
194
x-ui.sh
|
@ -518,9 +518,9 @@ install_acme() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ssl_cert_issue_main() {
|
ssl_cert_issue_main() {
|
||||||
echo "1) Get SSL"
|
echo -e "${green}\t1.${plain} Get SSL"
|
||||||
echo "2) Revoke"
|
echo -e "${green}\t2.${plain} Revoke"
|
||||||
echo "3) Force Renew"
|
echo -e "${green}\t3.${plain} Force Renew"
|
||||||
read -p "Choose an option: " choice
|
read -p "Choose an option: " choice
|
||||||
case "$choice" in
|
case "$choice" in
|
||||||
1) ssl_cert_issue ;;
|
1) ssl_cert_issue ;;
|
||||||
|
@ -671,6 +671,186 @@ run_speedtest() {
|
||||||
speedtest
|
speedtest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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} Check Logs"
|
||||||
|
echo -e "${green}\t5.${plain} Uninstall IP Limit"
|
||||||
|
echo -e "${green}\t0.${plain} Back to Main Menu"
|
||||||
|
read -p "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 5]: " NUM
|
||||||
|
if [[ $NUM =~ ^[0-9]+$ ]]; then
|
||||||
|
echo -e "\n[3x-ipl]\nenabled=true\nfilter=3x-ipl\naction=3x-ipl\nlogpath=/var/log/3xipl.log\nmaxretry=3\nfindtime=100\nbantime=${NUM}m" > /etc/fail2ban/jail.d/3x-ipl.conf
|
||||||
|
sudo systemctl restart fail2ban
|
||||||
|
echo -e "${green}Bantime set to ${NUM} minutes successfully.${plain}"
|
||||||
|
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
|
||||||
|
echo -e "${green}All users Unbanned successfully.${plain}"
|
||||||
|
iplimit_main
|
||||||
|
else
|
||||||
|
echo -e "${yellow}Cancelled.${plain}"
|
||||||
|
fi
|
||||||
|
iplimit_main ;;
|
||||||
|
4)
|
||||||
|
if test -f "/var/log/3xipl-banned.log"; then
|
||||||
|
if [[ -s "/var/log/3xipl-banned.log" ]]; then
|
||||||
|
cat /var/log/3xipl-banned.log
|
||||||
|
else
|
||||||
|
echo -e "${red}Log file is empty.${plain}\n"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${red}Log file not found. Please Install Fail2ban and IP Limit first.${plain}\n"
|
||||||
|
iplimit_main
|
||||||
|
fi ;;
|
||||||
|
5)
|
||||||
|
remove_iplimit ;;
|
||||||
|
*) echo "Invalid choice" ;;
|
||||||
|
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|debian)
|
||||||
|
sudo apt-get update && sudo apt-get install fail2ban -y ;;
|
||||||
|
centos)
|
||||||
|
sudo yum -y update && sudo yum -y install fail2ban ;;
|
||||||
|
fedora)
|
||||||
|
sudo dnf -y update && sudo dnf -y install fail2ban ;;
|
||||||
|
*)
|
||||||
|
echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n"
|
||||||
|
exit 1 ;;
|
||||||
|
esac
|
||||||
|
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"
|
||||||
|
|
||||||
|
#Check if [3x-ipl] exists in jail.local (just making sure there's no double config for jail)
|
||||||
|
if grep -qw '3x-ipl' /etc/fail2ban/jail.local || grep -qw '3x-ipl' /etc/fail2ban/jail.conf; then
|
||||||
|
echo -e "${red}Found conflicts in /etc/fail2ban/jail.conf or jail.local file!\nPlease manually remove anything related 3x-ipl in that files and try again.\nInstallation of IP Limit failed.${plain}\n"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#Check if log file exists
|
||||||
|
if ! test -f "/var/log/3xipl-banned.log"; then
|
||||||
|
touch /var/log/3xipl-banned.log
|
||||||
|
fi
|
||||||
|
|
||||||
|
#Check if service log file exists so fail2ban won't return error
|
||||||
|
if ! test -f "/var/log/3xipl.log"; then
|
||||||
|
touch /var/log/3xipl.log
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
echo -e "\n[3x-ipl]\nenabled=true\nfilter=3x-ipl\naction=3x-ipl\nlogpath=/var/log/3xipl.log\nmaxretry=3\nfindtime=100\nbantime=5m" > /etc/fail2ban/jail.d/3x-ipl.conf
|
||||||
|
|
||||||
|
sudo cat > /etc/fail2ban/filter.d/3x-ipl.conf << EOF
|
||||||
|
[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
|
||||||
|
|
||||||
|
sudo cat > /etc/fail2ban/action.d/3x-ipl.conf << 'EOF'
|
||||||
|
[INCLUDES]
|
||||||
|
before = iptables-common.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." >> /var/log/3xipl-banned.log
|
||||||
|
|
||||||
|
actionunban = <iptables> -D f2b-<name> -s <ip> -j <blocktype>
|
||||||
|
echo "$(date +"%%Y/%%m/%%d %%H:%%M:%%S") UNBAN [Email] = <F-USER> [IP] = <ip> unbanned." >> /var/log/3xipl-banned.log
|
||||||
|
|
||||||
|
[Init]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
#Launching fail2ban
|
||||||
|
if ! sudo systemctl is-active --quiet fail2ban; then
|
||||||
|
sudo systemctl start fail2ban
|
||||||
|
else
|
||||||
|
systemctl restart fail2ban
|
||||||
|
fi
|
||||||
|
sudo systemctl enable fail2ban
|
||||||
|
|
||||||
|
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} Abort"
|
||||||
|
read -p "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
|
||||||
|
sudo systemctl restart fail2ban
|
||||||
|
echo -e "${green}IP Limit removed successfully!${plain}\n"
|
||||||
|
before_show_menu ;;
|
||||||
|
2)
|
||||||
|
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
|
||||||
|
sudo systemctl stop fail2ban
|
||||||
|
sudo systemctl disable fail2ban
|
||||||
|
case "${release}" in
|
||||||
|
ubuntu|debian)
|
||||||
|
sudo apt-get remove fail2ban -y ;;
|
||||||
|
centos)
|
||||||
|
sudo yum -y remove fail2ban ;;
|
||||||
|
fedora)
|
||||||
|
sudo dnf -y remove fail2ban ;;
|
||||||
|
*)
|
||||||
|
echo -e "${red}Unsupported operating system. Please uninstall Fail2ban manually.${plain}\n"
|
||||||
|
exit 1 ;;
|
||||||
|
esac
|
||||||
|
rm -rf /etc/fail2ban/*
|
||||||
|
echo -e "${green}Fail2ban and IP Limit removed successfully!${plain}\n"
|
||||||
|
before_show_menu ;;
|
||||||
|
0)
|
||||||
|
echo -e "${yellow}Cancelled.${plain}\n"
|
||||||
|
iplimit_main ;;
|
||||||
|
*)
|
||||||
|
echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
|
||||||
|
remove_iplimit ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
show_usage() {
|
show_usage() {
|
||||||
echo "x-ui control menu usages: "
|
echo "x-ui control menu usages: "
|
||||||
|
@ -718,9 +898,10 @@ show_menu() {
|
||||||
${green}18.${plain} Active Firewall and open ports
|
${green}18.${plain} Active Firewall and open ports
|
||||||
${green}19.${plain} Install WARP
|
${green}19.${plain} Install WARP
|
||||||
${green}20.${plain} Speedtest by Ookla
|
${green}20.${plain} Speedtest by Ookla
|
||||||
|
${green}21.${plain} IP Limit Management
|
||||||
"
|
"
|
||||||
show_status
|
show_status
|
||||||
echo && read -p "Please enter your selection [0-20]: " num
|
echo && read -p "Please enter your selection [0-21]: " num
|
||||||
|
|
||||||
case "${num}" in
|
case "${num}" in
|
||||||
0)
|
0)
|
||||||
|
@ -786,8 +967,11 @@ show_menu() {
|
||||||
20)
|
20)
|
||||||
run_speedtest
|
run_speedtest
|
||||||
;;
|
;;
|
||||||
|
21)
|
||||||
|
iplimit_main
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
LOGE "Please enter the correct number [0-20]"
|
LOGE "Please enter the correct number [0-21]"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue