Removed ipLimit from the panel, changed the code to work with fail2ban (#580)

* Logging for fail2ban service
Removed limitDevice and other unnecessary functions

* Logging for fail2ban service
Removed limitDevice and other unnecessary functions

* fixed shouldCleanLog

* last fix

* reduced ip limit detection frequency to 30 sec (less logging, more precise)
    changed maxretry in fail2ban jail config to 2 to fit above

* fixed check delay

* added 5 seconds delay before cleaning logs
This commit is contained in:
somebodywashere 2023-06-15 22:15:34 +03:00 committed by GitHub
parent d40e61fc45
commit 4e89c71095
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 126 deletions

View file

@ -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,16 +197,24 @@ 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])
}
}
}
}
}
@ -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 {
@ -251,103 +253,3 @@ func GetInboundByEmail(clientEmail string) (*model.Inbound, error) {
}
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
}

View file

@ -250,8 +250,8 @@ func (s *Server) startTask() {
// Check the inbound traffic every 30 seconds that the traffic exceeds and expires
s.cron.AddJob("@every 30s", job.NewCheckInboundJob())
// check client ips from log file every 10 sec
s.cron.AddJob("@every 10s", job.NewCheckClientIpJob())
// check client ips from log file every 30 sec
s.cron.AddJob("@every 30s", job.NewCheckClientIpJob())
// Make a traffic condition every day, 8:30
var entry cron.EntryID