[IPLimit] Optimize + Debian 12 compability

[IPLimit] Optimize + Debian 12 compability
This commit is contained in:
somebodywashere 2024-03-05 17:38:47 +03:00 committed by GitHub
commit 2f594ca7c9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 43 additions and 62 deletions

View File

@ -10,10 +10,8 @@ import (
"regexp" "regexp"
"sort" "sort"
"strings" "strings"
"sync"
"time" "time"
"x-ui/config"
"x-ui/database" "x-ui/database"
"x-ui/database/model" "x-ui/database/model"
"x-ui/logger" "x-ui/logger"
@ -21,17 +19,11 @@ import (
) )
type CheckClientIpJob struct { type CheckClientIpJob struct {
lastClear int64
disAllowedIps []string disAllowedIps []string
} }
var job *CheckClientIpJob var job *CheckClientIpJob
var ipFiles = []string{
xray.GetIPLimitLogPath(),
xray.GetIPLimitBannedLogPath(),
xray.GetIPLimitBannedPrevLogPath(),
xray.GetAccessPersistentLogPath(),
xray.GetAccessPersistentPrevLogPath(),
}
func NewCheckClientIpJob() *CheckClientIpJob { func NewCheckClientIpJob() *CheckClientIpJob {
job = new(CheckClientIpJob) job = new(CheckClientIpJob)
@ -39,54 +31,43 @@ func NewCheckClientIpJob() *CheckClientIpJob {
} }
func (j *CheckClientIpJob) Run() { func (j *CheckClientIpJob) Run() {
var wg sync.WaitGroup if j.lastClear == 0 {
j.lastClear = time.Now().Unix()
if j.checkFail2BanInstalled() {
j.openLogFiles(ipFiles)
} }
f2bInstalled := j.checkFail2BanInstalled()
accessLogPath := xray.GetAccessLogPath()
clearAccessLog := false
if j.hasLimitIp() { if j.hasLimitIp() {
if j.checkFail2BanInstalled() && xray.GetAccessLogPath() == "./access.log" { if f2bInstalled && accessLogPath == "./access.log" {
j.processLogFile() clearAccessLog = j.processLogFile()
} else { } else {
if !j.checkFail2BanInstalled() { if !f2bInstalled {
logger.Warning("fail2ban is not installed. IP limiting may not work properly.") logger.Warning("fail2ban is not installed. IP limiting may not work properly.")
} }
switch xray.GetAccessLogPath() { switch accessLogPath {
case "none": case "none":
logger.Warning("Access log is set to 'none', check your Xray Configs") logger.Warning("Access log is set to 'none', check your Xray Configs")
case "": case "":
logger.Warning("Access log doesn't exist in your Xray Configs") logger.Warning("Access log doesn't exist in your Xray Configs")
default:
logger.Warning("Current access.log path is not compatible with IP Limit")
} }
} }
} }
if !j.checkFail2BanInstalled() && xray.GetAccessLogPath() == "./access.log" { if clearAccessLog || accessLogPath == "./access.log" && time.Now().Unix() - j.lastClear > 3600 {
wg.Add(1)
go func() {
defer wg.Done()
j.clearLogTime()
}()
wg.Wait()
}
}
func (j *CheckClientIpJob) clearLogTime() {
ticker := time.NewTicker(time.Hour)
defer ticker.Stop()
for range ticker.C {
j.clearAccessLog() j.clearAccessLog()
} }
} }
func (j *CheckClientIpJob) clearAccessLog() { func (j *CheckClientIpJob) clearAccessLog() {
accessLogPath := xray.GetAccessLogPath() logAccessP, err := os.OpenFile(xray.GetAccessPersistentLogPath(), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
logAccessP, err := os.OpenFile(xray.GetAccessPersistentLogPath(), os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
j.checkError(err) j.checkError(err)
defer logAccessP.Close()
// reopen the access log file for reading // reopen the access log file for reading
accessLogPath := xray.GetAccessLogPath()
file, err := os.Open(accessLogPath) file, err := os.Open(accessLogPath)
j.checkError(err) j.checkError(err)
@ -95,12 +76,13 @@ func (j *CheckClientIpJob) clearAccessLog() {
j.checkError(err) j.checkError(err)
// close the file after copying content // close the file after copying content
logAccessP.Close()
file.Close() file.Close()
// clean access log // clean access log
err = os.Truncate(accessLogPath, 0) err = os.Truncate(accessLogPath, 0)
j.checkError(err) j.checkError(err)
j.lastClear = time.Now().Unix()
} }
func (j *CheckClientIpJob) hasLimitIp() bool { func (j *CheckClientIpJob) hasLimitIp() bool {
@ -139,22 +121,11 @@ func (j *CheckClientIpJob) checkFail2BanInstalled() bool {
return err == nil return err == nil
} }
func (j *CheckClientIpJob) openLogFiles(ipFiles []string) { func (j *CheckClientIpJob) processLogFile() bool {
for i := 0; i < len(ipFiles); i++ {
err := os.MkdirAll(config.GetLogFolder(), 0770)
j.checkError(err)
file, err := os.OpenFile(ipFiles[i], os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
j.checkError(err)
defer file.Close()
}
}
func (j *CheckClientIpJob) processLogFile() {
accessLogPath := xray.GetAccessLogPath() accessLogPath := xray.GetAccessLogPath()
file, err := os.Open(accessLogPath) file, err := os.Open(accessLogPath)
j.checkError(err) j.checkError(err)
defer file.Close()
InboundClientIps := make(map[string][]string) InboundClientIps := make(map[string][]string)
@ -190,6 +161,7 @@ func (j *CheckClientIpJob) processLogFile() {
} }
j.checkError(scanner.Err()) j.checkError(scanner.Err())
file.Close()
shouldCleanLog := false shouldCleanLog := false
@ -203,12 +175,7 @@ func (j *CheckClientIpJob) processLogFile() {
} }
} }
// added delay before cleaning logs to reduce chance of logging IP that already has been banned return shouldCleanLog
time.Sleep(time.Second * 2)
if shouldCleanLog {
j.clearAccessLog()
}
} }
func (j *CheckClientIpJob) checkError(e error) { func (j *CheckClientIpJob) checkError(e error) {
@ -286,7 +253,7 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
j.disAllowedIps = []string{} j.disAllowedIps = []string{}
// create iplimit log file channel // create iplimit log file channel
logIpFile, err := os.OpenFile(xray.GetIPLimitLogPath(), os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644) logIpFile, err := os.OpenFile(xray.GetIPLimitLogPath(), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil { if err != nil {
logger.Errorf("failed to create or open ip limit log file: %s", err) logger.Errorf("failed to create or open ip limit log file: %s", err)
} }
@ -319,9 +286,8 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
db := database.GetDB() db := database.GetDB()
err = db.Save(inboundClientIps).Error err = db.Save(inboundClientIps).Error
if err != nil { j.checkError(err)
return shouldCleanLog
}
return shouldCleanLog return shouldCleanLog
} }

View File

@ -1,6 +1,7 @@
package job package job
import ( import (
"io"
"os" "os"
"x-ui/logger" "x-ui/logger"
"x-ui/xray" "x-ui/xray"
@ -28,21 +29,23 @@ func (j *ClearLogsJob) Run() {
for i := 0; i < len(logFiles); i++ { for i := 0; i < len(logFiles); i++ {
if i > 0 { if i > 0 {
// copy to previous logs // copy to previous logs
logFilePrev, err := os.OpenFile(logFilesPrev[i-1], os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644) logFilePrev, err := os.OpenFile(logFilesPrev[i-1], os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil { if err != nil {
logger.Warning("clear logs job err:", err) logger.Warning("clear logs job err:", err)
} }
logFile, err := os.ReadFile(logFiles[i]) logFile, err := os.Open(logFiles[i])
if err != nil { if err != nil {
logger.Warning("clear logs job err:", err) logger.Warning("clear logs job err:", err)
} }
_, err = logFilePrev.Write(logFile) _, err = io.Copy(logFilePrev, logFile)
if err != nil { if err != nil {
logger.Warning("clear logs job err:", err) logger.Warning("clear logs job err:", err)
} }
defer logFilePrev.Close()
logFile.Close()
logFilePrev.Close()
} }
err := os.Truncate(logFiles[i], 0) err := os.Truncate(logFiles[i], 0)

View File

@ -953,9 +953,15 @@ create_iplimit_jails() {
# Uncomment 'allowipv6 = auto' in fail2ban.conf # Uncomment 'allowipv6 = auto' in fail2ban.conf
sed -i 's/#allowipv6 = auto/allowipv6 = auto/g' /etc/fail2ban/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 cat << EOF > /etc/fail2ban/jail.d/3x-ipl.conf
[3x-ipl] [3x-ipl]
enabled=true enabled=true
backend=auto
filter=3x-ipl filter=3x-ipl
action=3x-ipl action=3x-ipl
logpath=${iplimit_log_path} logpath=${iplimit_log_path}

View File

@ -202,6 +202,12 @@ func (p *process) Start() (err error) {
if err != nil { if err != nil {
return common.NewErrorf("Failed to generate xray configuration file: %v", err) return common.NewErrorf("Failed to generate xray configuration file: %v", err)
} }
err = os.MkdirAll(config.GetLogFolder(), 0770)
if err != nil {
logger.Warningf("Something went wrong: %s", err)
}
configPath := GetConfigPath() configPath := GetConfigPath()
err = os.WriteFile(configPath, data, fs.ModePerm) err = os.WriteFile(configPath, data, fs.ModePerm)
if err != nil { if err != nil {