mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-03-01 01:20:49 +03:00
[IPLimit] Optimize + Debian 12 compability
This commit is contained in:
parent
6563d23f38
commit
5ba9d6e118
@ -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 || 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
6
x-ui.sh
6
x-ui.sh
@ -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}
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user