Skip to content

Commit

Permalink
iplimit - accept all email format
Browse files Browse the repository at this point in the history
  • Loading branch information
MHSanaei committed Oct 28, 2024
1 parent ac84553 commit 569d995
Showing 1 changed file with 46 additions and 55 deletions.
101 changes: 46 additions & 55 deletions web/job/check_client_ip_job.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"os/exec"
"regexp"
"sort"
"strings"
"time"

"x-ui/database"
Expand Down Expand Up @@ -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) {
Expand All @@ -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()
Expand Down Expand Up @@ -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: (.+)$`)

accessLogPath, _ := xray.GetAccessLogPath()
file, _ := os.Open(accessLogPath)
defer file.Close()

InboundClientIps := make(map[string][]string)
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+)$`)
ipMatches := ipRegex.FindStringSubmatch(line)
if len(ipMatches) < 2 {
continue
}

matches := ipRegx.FindStringSubmatch(line)
if len(matches) > 1 {
ip := matches[1]
if ip == "127.0.0.1" || ip == "::1" {
continue
}
ip := ipMatches[1]

matchesEmail := emailRegx.FindString(line)
if matchesEmail == "" {
continue
}
matchesEmail = strings.Split(matchesEmail, "email: ")[1]
if ip == "127.0.0.1" || ip == "::1" {
continue
}

if InboundClientIps[matchesEmail] != nil {
if j.contains(InboundClientIps[matchesEmail], ip) {
continue
}
InboundClientIps[matchesEmail] = append(InboundClientIps[matchesEmail], ip)
} else {
InboundClientIps[matchesEmail] = append(InboundClientIps[matchesEmail], ip)
}
emailMatches := emailRegex.FindStringSubmatch(line)
if len(emailMatches) < 2 {
continue
}
}
email := emailMatches[1]

j.checkError(scanner.Err())
file.Close()
if _, exists := inboundClientIps[email]; !exists {
inboundClientIps[email] = make(map[string]struct{})
}
inboundClientIps[email][ip] = struct{}{}
}

shouldCleanLog := false
for email, uniqueIps := range inboundClientIps {

for clientEmail, ips := range InboundClientIps {
inboundClientIps, err := j.getInboundClientIps(clientEmail)
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(clientEmail, ips)
} else {
shouldCleanLog = j.updateInboundClientIps(inboundClientIps, clientEmail, ips)
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 {
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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
Expand Down

0 comments on commit 569d995

Please sign in to comment.