|
@@ -10,12 +10,9 @@ import (
|
|
|
"x-ui/web/service"
|
|
|
"x-ui/xray"
|
|
|
|
|
|
- "net"
|
|
|
"sort"
|
|
|
"strings"
|
|
|
"time"
|
|
|
-
|
|
|
- "github.com/go-cmd/cmd"
|
|
|
)
|
|
|
|
|
|
type CheckClientIpJob struct {
|
|
@@ -88,6 +85,7 @@ func processLogFile() {
|
|
|
|
|
|
}
|
|
|
disAllowedIps = []string{}
|
|
|
+ shouldCleanLog := false
|
|
|
|
|
|
for clientEmail, ips := range InboundClientIps {
|
|
|
inboundClientIps, err := GetInboundClientIps(clientEmail)
|
|
@@ -96,23 +94,19 @@ func processLogFile() {
|
|
|
addInboundClientIps(clientEmail, ips)
|
|
|
|
|
|
} else {
|
|
|
- shouldCleanLog := updateInboundClientIps(inboundClientIps, clientEmail, ips)
|
|
|
- if shouldCleanLog {
|
|
|
- // clean log
|
|
|
- if err := os.Truncate(GetAccessLogPath(), 0); err != nil {
|
|
|
- checkError(err)
|
|
|
- }
|
|
|
- }
|
|
|
+ shouldCleanLog = 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)
|
|
|
- time.Sleep(10 * time.Second)
|
|
|
- stop <- true
|
|
|
+
|
|
|
+ time.Sleep(time.Second * 5)
|
|
|
+ //added 5 seconds delay before cleaning logs to reduce chance of logging IP that already has been banned
|
|
|
+ if shouldCleanLog {
|
|
|
+ // clean log
|
|
|
+ if err := os.Truncate(GetAccessLogPath(), 0); err != nil {
|
|
|
+ checkError(err)
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
func GetAccessLogPath() string {
|
|
@@ -203,17 +197,25 @@ func updateInboundClientIps(inboundClientIps *model.InboundClientIps, clientEmai
|
|
|
settings := map[string][]model.Client{}
|
|
|
json.Unmarshal([]byte(inbound.Settings), &settings)
|
|
|
clients := settings["clients"]
|
|
|
+ shouldCleanLog := false
|
|
|
|
|
|
for _, client := range clients {
|
|
|
if client.Email == clientEmail {
|
|
|
|
|
|
limitIp := client.LimitIP
|
|
|
|
|
|
- if limitIp < len(ips) && limitIp != 0 && inbound.Enable {
|
|
|
+ if limitIp != 0 {
|
|
|
|
|
|
- disAllowedIps = append(disAllowedIps, ips[limitIp:]...)
|
|
|
- return true
|
|
|
- }
|
|
|
+ shouldCleanLog = true
|
|
|
+
|
|
|
+ if limitIp < len(ips) && inbound.Enable {
|
|
|
+
|
|
|
+ disAllowedIps = append(disAllowedIps, ips[limitIp:]...)
|
|
|
+ for i:=limitIp; i < len(ips); i++ {
|
|
|
+ logger.Info("[LIMIT_IP] Email=", clientEmail, " SRC=", ips[i])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
logger.Debug("disAllowedIps ", disAllowedIps)
|
|
@@ -222,9 +224,9 @@ func updateInboundClientIps(inboundClientIps *model.InboundClientIps, clientEmai
|
|
|
db := database.GetDB()
|
|
|
err = db.Save(inboundClientIps).Error
|
|
|
if err != nil {
|
|
|
- return false
|
|
|
+ return shouldCleanLog
|
|
|
}
|
|
|
- return false
|
|
|
+ return shouldCleanLog
|
|
|
}
|
|
|
|
|
|
func DisableInbound(id int) error {
|
|
@@ -250,104 +252,4 @@ func GetInboundByEmail(clientEmail string) (*model.Inbound, error) {
|
|
|
return nil, err
|
|
|
}
|
|
|
return inbounds, nil
|
|
|
-}
|
|
|
-
|
|
|
-func LimitDevice() {
|
|
|
-
|
|
|
- localIp, err := LocalIP()
|
|
|
- checkError(err)
|
|
|
-
|
|
|
- c := cmd.NewCmd("bash", "-c", "ss --tcp | grep -E '"+IPsToRegex(localIp)+"'| awk '{if($1==\"ESTAB\") print $4,$5;}'", "| sort | uniq -c | sort -nr | head")
|
|
|
-
|
|
|
- <-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]+)`)
|
|
|
-
|
|
|
- for _, row := range c.Status().Stdout {
|
|
|
-
|
|
|
- data := strings.Split(row, " ")
|
|
|
-
|
|
|
- destIp, destPort, srcIp, srcPort := "", "", "", ""
|
|
|
-
|
|
|
- destIp = string(ipRegx.FindString(data[0]))
|
|
|
-
|
|
|
- destPort = portRegx.FindString(data[0])
|
|
|
- destPort = strings.Replace(destPort, ":", "", -1)
|
|
|
-
|
|
|
- srcIp = string(ipRegx.FindString(data[1]))
|
|
|
-
|
|
|
- srcPort = portRegx.FindString(data[1])
|
|
|
- srcPort = strings.Replace(srcPort, ":", "", -1)
|
|
|
-
|
|
|
- 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
|
|
|
-
|
|
|
- ifaces, err := net.Interfaces()
|
|
|
- ips := []string{}
|
|
|
- if err != nil {
|
|
|
- return ips, err
|
|
|
- }
|
|
|
- for _, i := range ifaces {
|
|
|
- addrs, err := i.Addrs()
|
|
|
- if err != nil {
|
|
|
- return ips, err
|
|
|
- }
|
|
|
-
|
|
|
- for _, addr := range addrs {
|
|
|
- var ip net.IP
|
|
|
- switch v := addr.(type) {
|
|
|
- case *net.IPNet:
|
|
|
- ip = v.IP
|
|
|
- case *net.IPAddr:
|
|
|
- ip = v.IP
|
|
|
- }
|
|
|
-
|
|
|
- ips = append(ips, ip.String())
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
- logger.Debug("System IPs : ", ips)
|
|
|
-
|
|
|
- return ips, nil
|
|
|
-}
|
|
|
-
|
|
|
-func IPsToRegex(ips []string) string {
|
|
|
-
|
|
|
- regx := ""
|
|
|
- for _, ip := range ips {
|
|
|
- regx += "(" + strings.Replace(ip, ".", "\\.", -1) + ")"
|
|
|
-
|
|
|
- }
|
|
|
- regx = "(" + strings.Replace(regx, ")(", ")|(.", -1) + ")"
|
|
|
-
|
|
|
- return regx
|
|
|
-}
|
|
|
-
|
|
|
-func schedule(LimitDevice func(), delay time.Duration) chan bool {
|
|
|
- stop := make(chan bool)
|
|
|
-
|
|
|
- go func() {
|
|
|
- for {
|
|
|
- LimitDevice()
|
|
|
- select {
|
|
|
- case <-time.After(delay):
|
|
|
- case <-stop:
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
- }()
|
|
|
-
|
|
|
- return stop
|
|
|
-}
|
|
|
+}
|