2023-02-28 19:54:29 +00:00
|
|
|
|
package job
|
|
|
|
|
|
|
|
|
|
import (
|
2024-02-03 10:41:57 +00:00
|
|
|
|
"bufio"
|
2023-04-13 19:37:13 +00:00
|
|
|
|
"encoding/json"
|
2024-02-03 10:41:57 +00:00
|
|
|
|
"io"
|
2023-06-24 20:36:18 +00:00
|
|
|
|
"log"
|
2023-04-13 19:37:13 +00:00
|
|
|
|
"os"
|
2023-09-01 09:53:50 +00:00
|
|
|
|
"os/exec"
|
2023-04-13 19:37:13 +00:00
|
|
|
|
"regexp"
|
2023-07-01 12:26:43 +00:00
|
|
|
|
"sort"
|
|
|
|
|
"time"
|
|
|
|
|
|
2025-03-12 19:13:51 +00:00
|
|
|
|
"slices"
|
2023-02-28 19:54:29 +00:00
|
|
|
|
"x-ui/database"
|
|
|
|
|
"x-ui/database/model"
|
2023-04-13 19:37:13 +00:00
|
|
|
|
"x-ui/logger"
|
|
|
|
|
"x-ui/xray"
|
2023-02-28 19:54:29 +00:00
|
|
|
|
)
|
|
|
|
|
|
2024-01-21 11:09:15 +00:00
|
|
|
|
type CheckClientIpJob struct {
|
2024-03-05 13:39:20 +00:00
|
|
|
|
lastClear int64
|
2024-01-21 11:09:15 +00:00
|
|
|
|
disAllowedIps []string
|
|
|
|
|
}
|
2023-04-13 19:37:13 +00:00
|
|
|
|
|
2023-02-28 19:54:29 +00:00
|
|
|
|
var job *CheckClientIpJob
|
|
|
|
|
|
|
|
|
|
func NewCheckClientIpJob() *CheckClientIpJob {
|
2023-06-03 15:29:32 +00:00
|
|
|
|
job = new(CheckClientIpJob)
|
2023-02-28 19:54:29 +00:00
|
|
|
|
return job
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (j *CheckClientIpJob) Run() {
|
2024-03-05 13:39:20 +00:00
|
|
|
|
if j.lastClear == 0 {
|
|
|
|
|
j.lastClear = time.Now().Unix()
|
2023-07-01 12:26:43 +00:00
|
|
|
|
}
|
2023-06-24 20:36:18 +00:00
|
|
|
|
|
2024-03-10 21:31:24 +00:00
|
|
|
|
shouldClearAccessLog := false
|
2025-05-28 11:48:00 +00:00
|
|
|
|
iplimitActive := j.hasLimitOrDeviceLimit() // 修改:检查LimitIP或MaxDevices
|
2024-10-28 19:13:42 +00:00
|
|
|
|
f2bInstalled := j.checkFail2BanInstalled()
|
2024-09-12 07:44:17 +00:00
|
|
|
|
isAccessLogAvailable := j.checkAccessLogAvailable(iplimitActive)
|
2024-03-05 13:39:20 +00:00
|
|
|
|
|
2024-10-28 19:13:42 +00:00
|
|
|
|
if iplimitActive {
|
|
|
|
|
if f2bInstalled && isAccessLogAvailable {
|
|
|
|
|
shouldClearAccessLog = j.processLogFile()
|
|
|
|
|
} else {
|
|
|
|
|
if !f2bInstalled {
|
2025-05-28 11:48:00 +00:00
|
|
|
|
logger.Warning("[LimitIP/MaxDevices] Fail2Ban is not installed, Please install Fail2Ban from the x-ui bash menu.")
|
2024-10-28 19:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-15 21:38:35 +00:00
|
|
|
|
}
|
2024-02-09 22:22:20 +00:00
|
|
|
|
|
2024-09-09 07:52:29 +00:00
|
|
|
|
if shouldClearAccessLog || (isAccessLogAvailable && time.Now().Unix()-j.lastClear > 3600) {
|
2024-02-09 22:22:20 +00:00
|
|
|
|
j.clearAccessLog()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (j *CheckClientIpJob) clearAccessLog() {
|
2024-03-10 21:31:24 +00:00
|
|
|
|
logAccessP, err := os.OpenFile(xray.GetAccessPersistentLogPath(), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o644)
|
2024-02-10 10:40:39 +00:00
|
|
|
|
j.checkError(err)
|
|
|
|
|
|
2024-03-13 07:54:41 +00:00
|
|
|
|
accessLogPath, err := xray.GetAccessLogPath()
|
|
|
|
|
j.checkError(err)
|
|
|
|
|
|
2024-02-10 10:40:39 +00:00
|
|
|
|
file, err := os.Open(accessLogPath)
|
|
|
|
|
j.checkError(err)
|
|
|
|
|
|
|
|
|
|
_, err = io.Copy(logAccessP, file)
|
|
|
|
|
j.checkError(err)
|
|
|
|
|
|
2024-03-05 13:39:20 +00:00
|
|
|
|
logAccessP.Close()
|
2024-03-02 17:40:12 +00:00
|
|
|
|
file.Close()
|
|
|
|
|
|
2024-02-10 10:40:39 +00:00
|
|
|
|
err = os.Truncate(accessLogPath, 0)
|
2024-02-09 22:22:20 +00:00
|
|
|
|
j.checkError(err)
|
2024-03-05 13:39:20 +00:00
|
|
|
|
j.lastClear = time.Now().Unix()
|
2023-02-28 19:54:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2025-05-28 11:48:00 +00:00
|
|
|
|
func (j *CheckClientIpJob) hasLimitOrDeviceLimit() bool { // 修改函数名和逻辑
|
2023-06-15 21:38:35 +00:00
|
|
|
|
db := database.GetDB()
|
|
|
|
|
var inbounds []*model.Inbound
|
2023-07-01 12:26:43 +00:00
|
|
|
|
|
2023-06-15 21:38:35 +00:00
|
|
|
|
err := db.Model(model.Inbound{}).Find(&inbounds).Error
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, inbound := range inbounds {
|
|
|
|
|
if inbound.Settings == "" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
settings := map[string][]model.Client{}
|
|
|
|
|
json.Unmarshal([]byte(inbound.Settings), &settings)
|
|
|
|
|
clients := settings["clients"]
|
|
|
|
|
|
|
|
|
|
for _, client := range clients {
|
|
|
|
|
limitIp := client.LimitIP
|
2025-05-28 11:48:00 +00:00
|
|
|
|
maxDevices := client.MaxDevices // 新增:获取MaxDevices
|
|
|
|
|
if limitIp > 0 || maxDevices > 0 { // 修改:检查LimitIP或MaxDevices
|
2023-06-15 21:38:35 +00:00
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-01 12:26:43 +00:00
|
|
|
|
|
2023-06-15 21:38:35 +00:00
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-05 13:39:20 +00:00
|
|
|
|
func (j *CheckClientIpJob) processLogFile() bool {
|
2024-02-03 14:24:04 +00:00
|
|
|
|
|
2025-01-05 17:58:51 +00:00
|
|
|
|
ipRegex := regexp.MustCompile(`from (?:tcp:|udp:)?\[?([0-9a-fA-F\.:]+)\]?:\d+ accepted`)
|
2024-10-28 19:13:42 +00:00
|
|
|
|
emailRegex := regexp.MustCompile(`email: (.+)$`)
|
|
|
|
|
|
|
|
|
|
accessLogPath, _ := xray.GetAccessLogPath()
|
|
|
|
|
file, _ := os.Open(accessLogPath)
|
|
|
|
|
defer file.Close()
|
2024-02-03 10:41:57 +00:00
|
|
|
|
|
2024-10-28 19:13:42 +00:00
|
|
|
|
inboundClientIps := make(map[string]map[string]struct{}, 100)
|
2024-02-03 10:41:57 +00:00
|
|
|
|
|
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
|
|
|
for scanner.Scan() {
|
|
|
|
|
line := scanner.Text()
|
2023-02-28 19:54:29 +00:00
|
|
|
|
|
2024-10-28 19:13:42 +00:00
|
|
|
|
ipMatches := ipRegex.FindStringSubmatch(line)
|
|
|
|
|
if len(ipMatches) < 2 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2023-02-28 19:54:29 +00:00
|
|
|
|
|
2024-10-28 19:13:42 +00:00
|
|
|
|
ip := ipMatches[1]
|
2023-02-28 19:54:29 +00:00
|
|
|
|
|
2024-10-28 19:13:42 +00:00
|
|
|
|
if ip == "127.0.0.1" || ip == "::1" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2023-04-13 19:37:13 +00:00
|
|
|
|
|
2024-10-28 19:13:42 +00:00
|
|
|
|
emailMatches := emailRegex.FindStringSubmatch(line)
|
|
|
|
|
if len(emailMatches) < 2 {
|
|
|
|
|
continue
|
2023-02-28 19:54:29 +00:00
|
|
|
|
}
|
2024-10-28 19:13:42 +00:00
|
|
|
|
email := emailMatches[1]
|
2023-07-01 12:26:43 +00:00
|
|
|
|
|
2024-10-28 19:13:42 +00:00
|
|
|
|
if _, exists := inboundClientIps[email]; !exists {
|
|
|
|
|
inboundClientIps[email] = make(map[string]struct{})
|
|
|
|
|
}
|
|
|
|
|
inboundClientIps[email][ip] = struct{}{}
|
|
|
|
|
}
|
2024-02-03 10:41:57 +00:00
|
|
|
|
|
2023-06-15 19:15:34 +00:00
|
|
|
|
shouldCleanLog := false
|
2025-05-28 11:48:00 +00:00
|
|
|
|
db := database.GetDB()
|
|
|
|
|
|
2024-10-28 19:13:42 +00:00
|
|
|
|
for email, uniqueIps := range inboundClientIps {
|
2025-05-28 11:48:00 +00:00
|
|
|
|
var clientData model.Client
|
|
|
|
|
// Find the client by email. This requires iterating through inbounds and their clients.
|
|
|
|
|
// This is a simplified representation. In a real scenario, you'd need a more efficient way to get client by email.
|
|
|
|
|
foundClient := false
|
|
|
|
|
var allInbounds []*model.Inbound
|
|
|
|
|
db.Find(&allInbounds)
|
|
|
|
|
for _, inbound := range allInbounds {
|
|
|
|
|
if inbound.Settings == "" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
settings := map[string][]model.Client{}
|
|
|
|
|
json.Unmarshal([]byte(inbound.Settings), &settings)
|
|
|
|
|
clients := settings["clients"]
|
|
|
|
|
for _, c := range clients {
|
|
|
|
|
// Match client by email, or ID, or password based on what's available and matches 'email' (which is clientIdentifier in this context)
|
|
|
|
|
clientIdentifierInLog := email // email from log is the clientIdentifier
|
|
|
|
|
matched := false
|
|
|
|
|
if c.Email != "" && c.Email == clientIdentifierInLog {
|
|
|
|
|
matched = true
|
|
|
|
|
} else if c.ID != "" && c.ID == clientIdentifierInLog { // For vmess/vless if email is used as ID in logs
|
|
|
|
|
matched = true
|
|
|
|
|
} else if c.Password != "" && c.Password == clientIdentifierInLog { // For trojan if email is used as password in logs
|
|
|
|
|
matched = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if matched {
|
|
|
|
|
clientData = c
|
|
|
|
|
clientInboundID = inbound.Id // Store the inbound ID
|
|
|
|
|
foundClient = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if foundClient {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !foundClient {
|
|
|
|
|
logger.Warningf("Client with identifier %s not found for IP processing", email)
|
|
|
|
|
continue
|
|
|
|
|
}
|
2023-02-28 19:54:29 +00:00
|
|
|
|
|
2025-05-28 11:48:00 +00:00
|
|
|
|
currentLoggedIps := make([]string, 0, len(uniqueIps))
|
2024-10-28 19:13:42 +00:00
|
|
|
|
for ip := range uniqueIps {
|
2025-05-28 11:48:00 +00:00
|
|
|
|
currentLoggedIps = append(currentLoggedIps, ip)
|
|
|
|
|
}
|
|
|
|
|
sort.Strings(currentLoggedIps)
|
|
|
|
|
|
|
|
|
|
clientIpsRecord, err := j.getInboundClientIps(email) // This function likely needs to be adapted or clientData used directly
|
|
|
|
|
|
|
|
|
|
activeIPs := []string{}
|
|
|
|
|
if clientData.ActiveIPs != "" {
|
|
|
|
|
errUnmarshal := json.Unmarshal([]byte(clientData.ActiveIPs), &activeIPs)
|
|
|
|
|
if errUnmarshal != nil {
|
|
|
|
|
logger.Warningf("Error unmarshalling ActiveIPs for client %s: %v", email, errUnmarshal)
|
|
|
|
|
activeIPs = []string{} // Reset if unmarshalling fails
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newActiveIPs := make([]string, len(activeIPs))
|
|
|
|
|
copy(newActiveIPs, activeIPs)
|
|
|
|
|
changedActiveIPs := false
|
|
|
|
|
|
|
|
|
|
for _, loggedIp := range currentLoggedIps {
|
|
|
|
|
isExistingActiveIP := j.contains(newActiveIPs, loggedIp)
|
|
|
|
|
|
|
|
|
|
if clientData.MaxDevices > 0 {
|
|
|
|
|
if !isExistingActiveIP {
|
|
|
|
|
if len(newActiveIPs) < clientData.MaxDevices {
|
|
|
|
|
newActiveIPs = append(newActiveIPs, loggedIp)
|
|
|
|
|
changedActiveIPs = true
|
|
|
|
|
} else {
|
|
|
|
|
if !j.contains(j.disAllowedIps, loggedIp) {
|
|
|
|
|
j.disAllowedIps = append(j.disAllowedIps, loggedIp)
|
|
|
|
|
logger.Infof("[MaxDevices] IP %s for client %s banned due to exceeding max device limit (%d)", loggedIp, email, clientData.MaxDevices)
|
|
|
|
|
shouldCleanLog = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} // End MaxDevices check
|
|
|
|
|
} // End loop currentLoggedIps
|
|
|
|
|
|
|
|
|
|
if changedActiveIPs {
|
|
|
|
|
activeIPsBytes, marshalErr := json.Marshal(newActiveIPs)
|
|
|
|
|
if marshalErr != nil {
|
|
|
|
|
logger.Warningf("Error marshalling new ActiveIPs for client %s: %v", email, marshalErr)
|
|
|
|
|
} else {
|
|
|
|
|
// Update clientData.ActiveIPs in the database
|
|
|
|
|
// This part is complex because clientData is part of a JSON string in Inbound.Settings
|
|
|
|
|
// A proper solution would involve updating the specific client within the Inbound's settings JSON
|
|
|
|
|
// and then saving the Inbound object.
|
|
|
|
|
// For simplicity, we'll log it. A full implementation needs to update the DB.
|
|
|
|
|
logger.Infof("Client %s ActiveIPs updated to: %s", email, string(activeIPsBytes))
|
|
|
|
|
// Placeholder for actual DB update logic for clientData.ActiveIPs
|
|
|
|
|
// Example: err := s.updateClientActiveIPsInDB(inbound.Id, clientData.ID_or_Email, string(activeIPsBytes)); if err != nil { ... }
|
|
|
|
|
inboundService := service.InboundService{} // Create an instance of InboundService
|
|
|
|
|
dbUpdateErr := inboundService.UpdateClientActiveIPsInDB(clientInboundID, email, string(activeIPsBytes))
|
|
|
|
|
if dbUpdateErr != nil {
|
|
|
|
|
logger.Warningf("Failed to update ActiveIPs in DB for client %s: %v", email, dbUpdateErr)
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-10-28 19:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2025-05-28 11:48:00 +00:00
|
|
|
|
if err != nil { // This 'err' is from j.getInboundClientIps(email)
|
|
|
|
|
j.addInboundClientIps(email, currentLoggedIps) // This function likely needs to be adapted
|
2024-10-28 19:13:42 +00:00
|
|
|
|
continue
|
2023-02-28 19:54:29 +00:00
|
|
|
|
}
|
2024-10-28 19:13:42 +00:00
|
|
|
|
|
2025-05-28 11:48:00 +00:00
|
|
|
|
// Original LimitIP logic (needs to be integrated with new ActiveIPs logic if LimitIP is also active)
|
|
|
|
|
shouldCleanLog = j.updateInboundClientIps(clientIpsRecord, email, currentLoggedIps) || shouldCleanLog
|
2023-04-13 19:37:13 +00:00
|
|
|
|
}
|
2023-06-15 21:38:35 +00:00
|
|
|
|
|
2024-03-05 13:39:20 +00:00
|
|
|
|
return shouldCleanLog
|
2023-02-28 19:54:29 +00:00
|
|
|
|
}
|
2023-07-01 12:26:43 +00:00
|
|
|
|
|
2024-10-28 19:13:42 +00:00
|
|
|
|
func (j *CheckClientIpJob) checkFail2BanInstalled() bool {
|
2024-03-13 07:54:41 +00:00
|
|
|
|
cmd := "fail2ban-client"
|
|
|
|
|
args := []string{"-h"}
|
|
|
|
|
err := exec.Command(cmd, args...).Run()
|
2024-10-28 19:13:42 +00:00
|
|
|
|
return err == nil
|
2024-03-13 07:54:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-09-12 07:44:17 +00:00
|
|
|
|
func (j *CheckClientIpJob) checkAccessLogAvailable(iplimitActive bool) bool {
|
2024-03-13 07:54:41 +00:00
|
|
|
|
accessLogPath, err := xray.GetAccessLogPath()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-12 07:44:17 +00:00
|
|
|
|
if accessLogPath == "none" || accessLogPath == "" {
|
|
|
|
|
if iplimitActive {
|
2025-05-28 11:48:00 +00:00
|
|
|
|
logger.Warning("[LimitIP/MaxDevices] Access log path is not set, Please configure the access log path in Xray configs.") // Updated log message
|
2024-09-12 07:44:17 +00:00
|
|
|
|
}
|
|
|
|
|
return false
|
2024-03-10 21:31:24 +00:00
|
|
|
|
}
|
2024-03-13 07:54:41 +00:00
|
|
|
|
|
2024-09-12 07:44:17 +00:00
|
|
|
|
return true
|
2024-03-10 21:31:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-07-01 12:26:43 +00:00
|
|
|
|
func (j *CheckClientIpJob) checkError(e error) {
|
2023-04-13 19:37:13 +00:00
|
|
|
|
if e != nil {
|
2023-02-28 19:54:29 +00:00
|
|
|
|
logger.Warning("client ip job err:", e)
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-01 12:26:43 +00:00
|
|
|
|
|
|
|
|
|
func (j *CheckClientIpJob) contains(s []string, str string) bool {
|
2025-03-12 19:13:51 +00:00
|
|
|
|
return slices.Contains(s, str)
|
2023-02-28 19:54:29 +00:00
|
|
|
|
}
|
2023-07-01 12:26:43 +00:00
|
|
|
|
|
|
|
|
|
func (j *CheckClientIpJob) getInboundClientIps(clientEmail string) (*model.InboundClientIps, error) {
|
2023-02-28 19:54:29 +00:00
|
|
|
|
db := database.GetDB()
|
|
|
|
|
InboundClientIps := &model.InboundClientIps{}
|
|
|
|
|
err := db.Model(model.InboundClientIps{}).Where("client_email = ?", clientEmail).First(InboundClientIps).Error
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return InboundClientIps, nil
|
|
|
|
|
}
|
2023-07-01 12:26:43 +00:00
|
|
|
|
|
|
|
|
|
func (j *CheckClientIpJob) addInboundClientIps(clientEmail string, ips []string) error {
|
2023-02-28 19:54:29 +00:00
|
|
|
|
inboundClientIps := &model.InboundClientIps{}
|
2023-03-25 16:35:46 +00:00
|
|
|
|
jsonIps, err := json.Marshal(ips)
|
2023-07-01 12:26:43 +00:00
|
|
|
|
j.checkError(err)
|
2023-02-28 19:54:29 +00:00
|
|
|
|
|
|
|
|
|
inboundClientIps.ClientEmail = clientEmail
|
|
|
|
|
inboundClientIps.Ips = string(jsonIps)
|
|
|
|
|
|
|
|
|
|
db := database.GetDB()
|
|
|
|
|
tx := db.Begin()
|
|
|
|
|
|
|
|
|
|
defer func() {
|
2023-06-03 15:29:32 +00:00
|
|
|
|
if err == nil {
|
2023-05-24 23:51:31 +00:00
|
|
|
|
tx.Commit()
|
2023-06-03 15:29:32 +00:00
|
|
|
|
} else {
|
|
|
|
|
tx.Rollback()
|
2023-02-28 19:54:29 +00:00
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
err = tx.Save(inboundClientIps).Error
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2023-06-03 15:29:32 +00:00
|
|
|
|
|
2023-07-01 12:26:43 +00:00
|
|
|
|
func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.InboundClientIps, clientEmail string, ips []string) bool {
|
2023-06-03 15:29:32 +00:00
|
|
|
|
jsonIps, err := json.Marshal(ips)
|
2024-07-08 21:08:00 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error("failed to marshal IPs to JSON:", err)
|
|
|
|
|
return false
|
|
|
|
|
}
|
2023-06-03 15:29:32 +00:00
|
|
|
|
|
|
|
|
|
inboundClientIps.ClientEmail = clientEmail
|
|
|
|
|
inboundClientIps.Ips = string(jsonIps)
|
2023-04-13 19:37:13 +00:00
|
|
|
|
|
2023-07-01 12:26:43 +00:00
|
|
|
|
inbound, err := j.getInboundByEmail(clientEmail)
|
2024-07-08 21:08:00 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Errorf("failed to fetch inbound settings for email %s: %s", clientEmail, err)
|
|
|
|
|
return false
|
|
|
|
|
}
|
2023-02-28 19:54:29 +00:00
|
|
|
|
|
|
|
|
|
if inbound.Settings == "" {
|
2024-07-08 21:08:00 +00:00
|
|
|
|
logger.Debug("wrong data:", inbound)
|
2023-06-08 10:20:35 +00:00
|
|
|
|
return false
|
2023-02-28 19:54:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
settings := map[string][]model.Client{}
|
|
|
|
|
json.Unmarshal([]byte(inbound.Settings), &settings)
|
|
|
|
|
clients := settings["clients"]
|
2023-06-15 19:15:34 +00:00
|
|
|
|
shouldCleanLog := false
|
2024-01-21 11:09:15 +00:00
|
|
|
|
j.disAllowedIps = []string{}
|
2023-02-28 19:54:29 +00:00
|
|
|
|
|
2024-07-08 21:08:00 +00:00
|
|
|
|
logIpFile, err := os.OpenFile(xray.GetIPLimitLogPath(), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
2023-07-01 12:26:43 +00:00
|
|
|
|
if err != nil {
|
2024-07-08 21:08:00 +00:00
|
|
|
|
logger.Errorf("failed to open IP limit log file: %s", err)
|
|
|
|
|
return false
|
2023-07-01 12:26:43 +00:00
|
|
|
|
}
|
|
|
|
|
defer logIpFile.Close()
|
|
|
|
|
log.SetOutput(logIpFile)
|
|
|
|
|
log.SetFlags(log.LstdFlags)
|
|
|
|
|
|
2023-02-28 19:54:29 +00:00
|
|
|
|
for _, client := range clients {
|
|
|
|
|
if client.Email == clientEmail {
|
|
|
|
|
limitIp := client.LimitIP
|
2023-06-03 15:29:32 +00:00
|
|
|
|
|
2024-07-08 21:08:00 +00:00
|
|
|
|
if limitIp > 0 && inbound.Enable {
|
2023-06-15 19:15:34 +00:00
|
|
|
|
shouldCleanLog = true
|
|
|
|
|
|
2024-07-08 21:08:00 +00:00
|
|
|
|
if limitIp < len(ips) {
|
2024-01-21 11:09:15 +00:00
|
|
|
|
j.disAllowedIps = append(j.disAllowedIps, ips[limitIp:]...)
|
2023-06-15 21:38:35 +00:00
|
|
|
|
for i := limitIp; i < len(ips); i++ {
|
2024-07-18 21:03:48 +00:00
|
|
|
|
log.Printf("[LIMIT_IP] Email = %s || SRC = %s", clientEmail, ips[i])
|
2023-06-15 19:15:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-15 21:38:35 +00:00
|
|
|
|
}
|
2023-02-28 19:54:29 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-01-21 11:09:15 +00:00
|
|
|
|
|
|
|
|
|
sort.Strings(j.disAllowedIps)
|
|
|
|
|
|
|
|
|
|
if len(j.disAllowedIps) > 0 {
|
2024-07-08 21:08:00 +00:00
|
|
|
|
logger.Debug("disAllowedIps:", j.disAllowedIps)
|
2024-01-21 11:09:15 +00:00
|
|
|
|
}
|
2023-02-28 19:54:29 +00:00
|
|
|
|
|
|
|
|
|
db := database.GetDB()
|
|
|
|
|
err = db.Save(inboundClientIps).Error
|
2024-07-08 21:08:00 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error("failed to save inboundClientIps:", err)
|
|
|
|
|
return false
|
|
|
|
|
}
|
2024-03-05 13:39:20 +00:00
|
|
|
|
|
2023-06-15 19:15:34 +00:00
|
|
|
|
return shouldCleanLog
|
2023-02-28 19:54:29 +00:00
|
|
|
|
}
|
2023-06-08 10:20:35 +00:00
|
|
|
|
|
2023-07-01 12:26:43 +00:00
|
|
|
|
func (j *CheckClientIpJob) getInboundByEmail(clientEmail string) (*model.Inbound, error) {
|
2023-02-28 19:54:29 +00:00
|
|
|
|
db := database.GetDB()
|
2024-12-16 13:26:47 +00:00
|
|
|
|
inbound := &model.Inbound{}
|
2023-07-01 12:26:43 +00:00
|
|
|
|
|
2024-12-16 13:26:47 +00:00
|
|
|
|
err := db.Model(&model.Inbound{}).Where("settings LIKE ?", "%"+clientEmail+"%").First(inbound).Error
|
2023-02-28 19:54:29 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2023-07-01 12:26:43 +00:00
|
|
|
|
|
2024-12-16 13:26:47 +00:00
|
|
|
|
return inbound, nil
|
2023-06-15 21:38:35 +00:00
|
|
|
|
}
|