iplimit - accept all email format

This commit is contained in:
mhsanaei 2024-10-28 20:13:42 +01:00
parent ac84553a68
commit 569d99512c
No known key found for this signature in database
GPG Key ID: 4DACC0663B5986F5

View File

@ -9,7 +9,6 @@ import (
"os/exec"
"regexp"
"sort"
"strings"
"time"
"x-ui/database"
@ -37,11 +36,17 @@ func (j *CheckClientIpJob) Run() {
shouldClearAccessLog := false
iplimitActive := j.hasLimitIp()
f2bInstalled := j.checkFail2BanInstalled(iplimitActive)
f2bInstalled := j.checkFail2BanInstalled()
isAccessLogAvailable := j.checkAccessLogAvailable(iplimitActive)
if iplimitActive && f2bInstalled && isAccessLogAvailable {
shouldClearAccessLog = j.processLogFile()
if iplimitActive {
if f2bInstalled && isAccessLogAvailable {
shouldClearAccessLog = j.processLogFile()
} else {
if !f2bInstalled {
logger.Warning("[LimitIP] Fail2Ban is not installed, Please install Fail2Ban from the x-ui bash menu.")
}
}
}
if shouldClearAccessLog || (isAccessLogAvailable && time.Now().Unix()-j.lastClear > 3600) {
@ -53,23 +58,18 @@ func (j *CheckClientIpJob) clearAccessLog() {
logAccessP, err := os.OpenFile(xray.GetAccessPersistentLogPath(), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644)
j.checkError(err)
// get access log path to open it
accessLogPath, err := xray.GetAccessLogPath()
j.checkError(err)
// reopen the access log file for reading
file, err := os.Open(accessLogPath)
j.checkError(err)
// copy access log content to persistent file
_, err = io.Copy(logAccessP, file)
j.checkError(err)
// close the file after copying content
logAccessP.Close()
file.Close()
// clean access log
err = os.Truncate(accessLogPath, 0)
j.checkError(err)
j.lastClear = time.Now().Unix()
@ -105,74 +105,69 @@ func (j *CheckClientIpJob) hasLimitIp() bool {
}
func (j *CheckClientIpJob) processLogFile() bool {
accessLogPath, err := xray.GetAccessLogPath()
j.checkError(err)
file, err := os.Open(accessLogPath)
j.checkError(err)
ipRegex := regexp.MustCompile(`from \[?([0-9a-fA-F:.]+)\]?:\d+ accepted`)
emailRegex := regexp.MustCompile(`email: (.+)$`)
InboundClientIps := make(map[string][]string)
accessLogPath, _ := xray.GetAccessLogPath()
file, _ := os.Open(accessLogPath)
defer file.Close()
inboundClientIps := make(map[string]map[string]struct{}, 100)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
ipRegx, _ := regexp.Compile(`from \[?([0-9a-fA-F:.]+)\]?:\d+ accepted`)
emailRegx, _ := regexp.Compile(`email: (\S+)$`)
matches := ipRegx.FindStringSubmatch(line)
if len(matches) > 1 {
ip := matches[1]
if ip == "127.0.0.1" || ip == "::1" {
continue
}
matchesEmail := emailRegx.FindString(line)
if matchesEmail == "" {
continue
}
matchesEmail = strings.Split(matchesEmail, "email: ")[1]
if InboundClientIps[matchesEmail] != nil {
if j.contains(InboundClientIps[matchesEmail], ip) {
continue
}
InboundClientIps[matchesEmail] = append(InboundClientIps[matchesEmail], ip)
} else {
InboundClientIps[matchesEmail] = append(InboundClientIps[matchesEmail], ip)
}
ipMatches := ipRegex.FindStringSubmatch(line)
if len(ipMatches) < 2 {
continue
}
ip := ipMatches[1]
if ip == "127.0.0.1" || ip == "::1" {
continue
}
emailMatches := emailRegex.FindStringSubmatch(line)
if len(emailMatches) < 2 {
continue
}
email := emailMatches[1]
if _, exists := inboundClientIps[email]; !exists {
inboundClientIps[email] = make(map[string]struct{})
}
inboundClientIps[email][ip] = struct{}{}
}
j.checkError(scanner.Err())
file.Close()
shouldCleanLog := false
for email, uniqueIps := range inboundClientIps {
for clientEmail, ips := range InboundClientIps {
inboundClientIps, err := j.getInboundClientIps(clientEmail)
sort.Strings(ips)
if err != nil {
j.addInboundClientIps(clientEmail, ips)
} else {
shouldCleanLog = j.updateInboundClientIps(inboundClientIps, clientEmail, ips)
ips := make([]string, 0, len(uniqueIps))
for ip := range uniqueIps {
ips = append(ips, ip)
}
sort.Strings(ips)
inboundClientIps, err := j.getInboundClientIps(email)
if err != nil {
j.addInboundClientIps(email, ips)
continue
}
shouldCleanLog = j.updateInboundClientIps(inboundClientIps, email, ips) || shouldCleanLog
}
return shouldCleanLog
}
func (j *CheckClientIpJob) checkFail2BanInstalled(iplimitActive bool) bool {
func (j *CheckClientIpJob) checkFail2BanInstalled() bool {
cmd := "fail2ban-client"
args := []string{"-h"}
err := exec.Command(cmd, args...).Run()
if iplimitActive && err != nil {
logger.Warning("[LimitIP] Fail2Ban is not installed, Please install Fail2Ban from the x-ui bash menu.")
return false
}
return true
return err == nil
}
func (j *CheckClientIpJob) checkAccessLogAvailable(iplimitActive bool) bool {
@ -253,7 +248,6 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
inboundClientIps.ClientEmail = clientEmail
inboundClientIps.Ips = string(jsonIps)
// Fetch inbound settings by client email
inbound, err := j.getInboundByEmail(clientEmail)
if err != nil {
logger.Errorf("failed to fetch inbound settings for email %s: %s", clientEmail, err)
@ -265,14 +259,12 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
return false
}
// Unmarshal settings to get client limits
settings := map[string][]model.Client{}
json.Unmarshal([]byte(inbound.Settings), &settings)
clients := settings["clients"]
shouldCleanLog := false
j.disAllowedIps = []string{}
// Open log file for IP limits
logIpFile, err := os.OpenFile(xray.GetIPLimitLogPath(), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
logger.Errorf("failed to open IP limit log file: %s", err)
@ -282,7 +274,6 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
log.SetOutput(logIpFile)
log.SetFlags(log.LstdFlags)
// Check client IP limits
for _, client := range clients {
if client.Email == clientEmail {
limitIp := client.LimitIP