diff --git a/config/config.go b/config/config.go index e1c7f911..e3fe1709 100644 --- a/config/config.go +++ b/config/config.go @@ -45,6 +45,22 @@ func IsDebug() bool { return os.Getenv("XUI_DEBUG") == "true" } -func GetDBPath() string { - return fmt.Sprintf("/etc/%s/%s.db", GetName(), GetName()) +func GetBinFolderPath() string { + binFolderPath := os.Getenv("XUI_BIN_FOLDER") + if binFolderPath == "" { + binFolderPath = "bin" + } + return binFolderPath +} + +func GetDBFolderPath() string { + dbFolderPath := os.Getenv("XUI_DB_FOLDER") + if dbFolderPath == "" { + dbFolderPath = "/etc/x-ui" + } + return dbFolderPath +} + +func GetDBPath() string { + return fmt.Sprintf("%s/%s.db", GetDBFolderPath(), GetName()) } diff --git a/main.go b/main.go index d857ab46..0d6e0f90 100644 --- a/main.go +++ b/main.go @@ -217,7 +217,7 @@ func main() { v2uiCmd := flag.NewFlagSet("v2-ui", flag.ExitOnError) var dbPath string - v2uiCmd.StringVar(&dbPath, "db", "/etc/v2-ui/v2-ui.db", "set v2-ui db file path") + v2uiCmd.StringVar(&dbPath, "db", fmt.Sprintf("%s/v2-ui.db", config.GetDBFolderPath()), "set v2-ui db file path") settingCmd := flag.NewFlagSet("setting", flag.ExitOnError) var port int diff --git a/web/job/check_clinet_ip_job.go b/web/job/check_client_ip_job.go similarity index 60% rename from web/job/check_clinet_ip_job.go rename to web/job/check_client_ip_job.go index ed86b42d..95a652cd 100644 --- a/web/job/check_clinet_ip_job.go +++ b/web/job/check_client_ip_job.go @@ -1,28 +1,30 @@ package job import ( - "x-ui/logger" - "x-ui/web/service" + "encoding/json" + "os" + "regexp" + ss "strings" "x-ui/database" "x-ui/database/model" - "os" - ss "strings" - "regexp" - "encoding/json" - // "strconv" + "x-ui/logger" + "x-ui/web/service" + "x-ui/xray" + // "strconv" + "github.com/go-cmd/cmd" + "net" + "sort" "strings" "time" - "net" - "github.com/go-cmd/cmd" - "sort" ) type CheckClientIpJob struct { xrayService service.XrayService inboundService service.InboundService } + var job *CheckClientIpJob -var disAllowedIps []string +var disAllowedIps []string func NewCheckClientIpJob() *CheckClientIpJob { job = new(CheckClientIpJob) @@ -34,94 +36,91 @@ func (j *CheckClientIpJob) Run() { processLogFile() // disAllowedIps = []string{"192.168.1.183","192.168.1.197"} - blockedIps := []byte(ss.Join(disAllowedIps,",")) - err := os.WriteFile("./bin/blockedIPs", blockedIps, 0755) + blockedIps := []byte(ss.Join(disAllowedIps, ",")) + err := os.WriteFile(xray.GetBlockedIPsPath(), blockedIps, 0755) checkError(err) } func processLogFile() { accessLogPath := GetAccessLogPath() - if(accessLogPath == "") { + if accessLogPath == "" { logger.Warning("xray log not init in config.json") return } - data, err := os.ReadFile(accessLogPath) + data, err := os.ReadFile(accessLogPath) InboundClientIps := make(map[string][]string) - checkError(err) + checkError(err) // clean log if err := os.Truncate(GetAccessLogPath(), 0); err != nil { checkError(err) } - + lines := ss.Split(string(data), "\n") for _, line := range lines { ipRegx, _ := regexp.Compile(`[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+`) emailRegx, _ := regexp.Compile(`email:.+`) matchesIp := ipRegx.FindString(line) - if(len(matchesIp) > 0) { + if len(matchesIp) > 0 { ip := string(matchesIp) - if( ip == "127.0.0.1" || ip == "1.1.1.1") { + if ip == "127.0.0.1" || ip == "1.1.1.1" { continue } matchesEmail := emailRegx.FindString(line) - if(matchesEmail == "") { + if matchesEmail == "" { continue } matchesEmail = ss.Split(matchesEmail, "email: ")[1] - - if(InboundClientIps[matchesEmail] != nil) { - if(contains(InboundClientIps[matchesEmail],ip)){ + + if InboundClientIps[matchesEmail] != nil { + if contains(InboundClientIps[matchesEmail], ip) { continue } - InboundClientIps[matchesEmail] = append(InboundClientIps[matchesEmail],ip) + InboundClientIps[matchesEmail] = append(InboundClientIps[matchesEmail], ip) - - - }else{ - InboundClientIps[matchesEmail] = append(InboundClientIps[matchesEmail],ip) - } + } else { + InboundClientIps[matchesEmail] = append(InboundClientIps[matchesEmail], ip) + } } } disAllowedIps = []string{} for clientEmail, ips := range InboundClientIps { - inboundClientIps,err := GetInboundClientIps(clientEmail) + inboundClientIps, err := GetInboundClientIps(clientEmail) sort.Sort(sort.StringSlice(ips)) - if(err != nil){ - addInboundClientIps(clientEmail,ips) + if err != nil { + addInboundClientIps(clientEmail, ips) - }else{ - updateInboundClientIps(inboundClientIps,clientEmail,ips) + } else { + updateInboundClientIps(inboundClientIps, clientEmail, ips) } - - } + } // check if inbound connection is more than limited ip and drop connection LimitDevice := func() { LimitDevice() } - stop := schedule(LimitDevice, 1000 *time.Millisecond) + stop := schedule(LimitDevice, 1000*time.Millisecond) time.Sleep(10 * time.Second) stop <- true - + } func GetAccessLogPath() string { - - config, err := os.ReadFile("bin/config.json") - checkError(err) + + config, err := os.ReadFile(xray.GetConfigPath()) + checkError(err) jsonConfig := map[string]interface{}{} - err = json.Unmarshal([]byte(config), &jsonConfig) + err = json.Unmarshal([]byte(config), &jsonConfig) checkError(err) - if(jsonConfig["log"] != nil) { + if jsonConfig["log"] != nil { jsonLog := jsonConfig["log"].(map[string]interface{}) - if(jsonLog["access"] != nil) { + if jsonLog["access"] != nil { accessLogPath := jsonLog["access"].(string) @@ -132,7 +131,7 @@ func GetAccessLogPath() string { } func checkError(e error) { - if e != nil { + if e != nil { logger.Warning("client ip job err:", e) } } @@ -182,20 +181,20 @@ func addInboundClientIps(clientEmail string, ips []string) error { } return nil } -func updateInboundClientIps(inboundClientIps *model.InboundClientIps,clientEmail string,ips []string) error { +func updateInboundClientIps(inboundClientIps *model.InboundClientIps, clientEmail string, ips []string) error { - jsonIps, err := json.Marshal(ips) + jsonIps, err := json.Marshal(ips) checkError(err) inboundClientIps.ClientEmail = clientEmail inboundClientIps.Ips = string(jsonIps) - + // check inbound limitation inbound, err := GetInboundByEmail(clientEmail) checkError(err) if inbound.Settings == "" { - logger.Debug("wrong data ",inbound) + logger.Debug("wrong data ", inbound) return nil } @@ -205,17 +204,17 @@ func updateInboundClientIps(inboundClientIps *model.InboundClientIps,clientEmail for _, client := range clients { if client.Email == clientEmail { - + limitIp := client.LimitIP - - if(limitIp < len(ips) && limitIp != 0 && inbound.Enable) { - - disAllowedIps = append(disAllowedIps,ips[limitIp:]...) + + if limitIp < len(ips) && limitIp != 0 && inbound.Enable { + + disAllowedIps = append(disAllowedIps, ips[limitIp:]...) } } } - logger.Debug("disAllowedIps ",disAllowedIps) - sort.Sort(sort.StringSlice(disAllowedIps)) + logger.Debug("disAllowedIps ", disAllowedIps) + sort.Sort(sort.StringSlice(disAllowedIps)) db := database.GetDB() err = db.Save(inboundClientIps).Error @@ -224,13 +223,13 @@ func updateInboundClientIps(inboundClientIps *model.InboundClientIps,clientEmail } return nil } -func DisableInbound(id int) error{ +func DisableInbound(id int) error { db := database.GetDB() result := db.Model(model.Inbound{}). Where("id = ? and enable = ?", id, true). Update("enable", false) err := result.Error - logger.Warning("disable inbound with id:",id) + logger.Warning("disable inbound with id:", id) if err == nil { job.xrayService.SetToNeedRestart() @@ -242,7 +241,7 @@ func DisableInbound(id int) error{ func GetInboundByEmail(clientEmail string) (*model.Inbound, error) { db := database.GetDB() var inbounds *model.Inbound - err := db.Model(model.Inbound{}).Where("settings LIKE ?", "%" + clientEmail + "%").Find(&inbounds).Error + err := db.Model(model.Inbound{}).Where("settings LIKE ?", "%"+clientEmail+"%").Find(&inbounds).Error if err != nil { return nil, err } @@ -250,45 +249,44 @@ func GetInboundByEmail(clientEmail string) (*model.Inbound, error) { } func LimitDevice() { - var destIp, destPort, srcIp, srcPort string - - localIp,err := LocalIP() - checkError(err) + var destIp, destPort, srcIp, srcPort string - c := cmd.NewCmd("bash","-c","ss --tcp | grep -E '" + IPsToRegex(localIp) + "'| awk '{if($1==\"ESTAB\") print $4,$5;}'","| sort | uniq -c | sort -nr | head") + localIp, err := LocalIP() + checkError(err) - <-c.Start() - if len(c.Status().Stdout) > 0 { - ipRegx, _ := regexp.Compile(`[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+`) - portRegx, _ := regexp.Compile(`(?:(:))([0-9]..[^.][0-9]+)`) + c := cmd.NewCmd("bash", "-c", "ss --tcp | grep -E '"+IPsToRegex(localIp)+"'| awk '{if($1==\"ESTAB\") print $4,$5;}'", "| sort | uniq -c | sort -nr | head") - for _, row := range c.Status().Stdout { + <-c.Start() + if len(c.Status().Stdout) > 0 { + ipRegx, _ := regexp.Compile(`[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+`) + portRegx, _ := regexp.Compile(`(?:(:))([0-9]..[^.][0-9]+)`) - data := strings.Split(row," ") + for _, row := range c.Status().Stdout { - if len(data) < 2 { - continue // Skip this row if it doesn't have at least two elements - } + data := strings.Split(row, " ") - destIp = string(ipRegx.FindString(data[0])) - destPort = portRegx.FindString(data[0]) - destPort = strings.Replace(destPort,":","",-1) + if len(data) < 2 { + continue // Skip this row if it doesn't have at least two elements + } - srcIp = string(ipRegx.FindString(data[1])) - srcPort = portRegx.FindString(data[1]) - srcPort = strings.Replace(srcPort,":","",-1) + destIp = string(ipRegx.FindString(data[0])) + destPort = portRegx.FindString(data[0]) + destPort = strings.Replace(destPort, ":", "", -1) - if contains(disAllowedIps,srcIp){ - dropCmd := cmd.NewCmd("bash","-c","ss -K dport = " + srcPort) - dropCmd.Start() + srcIp = string(ipRegx.FindString(data[1])) + srcPort = portRegx.FindString(data[1]) + srcPort = strings.Replace(srcPort, ":", "", -1) - logger.Debug("request droped : ",srcIp,srcPort,"to",destIp,destPort) - } - } - } + if contains(disAllowedIps, srcIp) { + dropCmd := cmd.NewCmd("bash", "-c", "ss -K dport = "+srcPort) + dropCmd.Start() + + logger.Debug("request droped : ", srcIp, srcPort, "to", destIp, destPort) + } + } + } } - func LocalIP() ([]string, error) { // get machine ips @@ -312,24 +310,23 @@ func LocalIP() ([]string, error) { ip = v.IP } - ips = append(ips,ip.String()) - + ips = append(ips, ip.String()) + } } - logger.Debug("System IPs : ",ips) + logger.Debug("System IPs : ", ips) return ips, nil } - -func IPsToRegex(ips []string) (string){ +func IPsToRegex(ips []string) string { regx := "" for _, ip := range ips { regx += "(" + strings.Replace(ip, ".", "\\.", -1) + ")" } - regx = "(" + strings.Replace(regx, ")(", ")|(.", -1) + ")" + regx = "(" + strings.Replace(regx, ")(", ")|(.", -1) + ")" return regx } diff --git a/web/translation/translate.en_US.toml b/web/translation/translate.en_US.toml index 6b6e296f..3e23ecfd 100644 --- a/web/translation/translate.en_US.toml +++ b/web/translation/translate.en_US.toml @@ -106,8 +106,8 @@ "expireDate" = "Expire date" "resetTraffic" = "Reset traffic" "addInbound" = "Add Inbound" -"addTo" = "Add To" -"revise" = "Revise" +"addTo" = "Create" +"revise" = "Update" "modifyInbound" = "Modify InBound" "deleteInbound" = "Delete Inbound" "deleteInboundContent" = "Are you sure you want to delete inbound?" diff --git a/xray/process.go b/xray/process.go index a73ff95f..35907391 100644 --- a/xray/process.go +++ b/xray/process.go @@ -14,6 +14,7 @@ import ( "runtime" "strings" "time" + "x-ui/config" "x-ui/util/common" "github.com/Workiva/go-datastructures/queue" @@ -29,19 +30,23 @@ func GetBinaryName() string { } func GetBinaryPath() string { - return "bin/" + GetBinaryName() + return config.GetBinFolderPath() + "/" + GetBinaryName() } func GetConfigPath() string { - return "bin/config.json" + return config.GetBinFolderPath() + "/config.json" } func GetGeositePath() string { - return "bin/geosite.dat" + return config.GetBinFolderPath() + "/geosite.dat" } func GetGeoipPath() string { - return "bin/geoip.dat" + return config.GetBinFolderPath() + "/geoip.dat" +} + +func GetBlockedIPsPath() string { + return config.GetBinFolderPath() + "/blockedIPs" } func stopProcess(p *Process) { @@ -162,7 +167,7 @@ func (p *process) Start() (err error) { return common.NewErrorf("Failed to write configuration file: %v", err) } - cmd := exec.Command(GetBinaryPath(), "-c", configPath, "-restrictedIPsPath", "./bin/blockedIPs") + cmd := exec.Command(GetBinaryPath(), "-c", configPath, "-restrictedIPsPath", GetBlockedIPsPath()) p.cmd = cmd stdReader, err := cmd.StdoutPipe()