Merge pull request #6 from hossinasaadi/limit-connection

Limit connection for inbound (IP Restricts )
This commit is contained in:
Hossin Asaadi
2022-11-04 18:04:05 +03:30
committed by GitHub
4 changed files with 143 additions and 15 deletions

1
go.mod
View File

@@ -8,6 +8,7 @@ require (
github.com/Workiva/go-datastructures v1.0.53
github.com/gin-contrib/sessions v0.0.3
github.com/gin-gonic/gin v1.7.1
github.com/go-cmd/cmd v1.4.1 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
github.com/nicksnyder/go-i18n/v2 v2.1.2

3
go.sum
View File

@@ -57,6 +57,8 @@ github.com/gin-gonic/gin v1.7.1 h1:qC89GU3p8TvKWMAVhEpmpB2CIb1hnqt2UdKZaP93mS8=
github.com/gin-gonic/gin v1.7.1/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-cmd/cmd v1.4.1 h1:JUcEIE84v8DSy02XTZpUDeGKExk2oW3DA10hTjbQwmc=
github.com/go-cmd/cmd v1.4.1/go.mod h1:tbBenttXtZU4c5djS1o7PWL5pd2xAr5sIqH1kGdNiRc=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
@@ -72,6 +74,7 @@ github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7a
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc=
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8=
github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=

View File

@@ -11,7 +11,11 @@ import (
"encoding/json"
"gorm.io/gorm"
"strconv"
"strings"
"time"
"net"
"github.com/go-cmd/cmd"
"sort"
)
type CheckClientIpJob struct {
@@ -19,7 +23,8 @@ type CheckClientIpJob struct {
inboundService service.InboundService
}
var job *CheckClientIpJob
var disAllowedIps []string
func NewCheckClientIpJob() *CheckClientIpJob {
job = new(CheckClientIpJob)
return job
@@ -84,6 +89,8 @@ func processLogFile() {
}
var inboundsClientIps []*model.InboundClientIps
disAllowedIps = []string{}
for clientEmail, ips := range InboundClientIps {
inboundClientIps := GetInboundClientIps(clientEmail, ips)
if inboundClientIps != nil {
@@ -93,6 +100,14 @@ func processLogFile() {
err = AddInboundsClientIps(inboundsClientIps)
checkError(err)
// check if inbound connection is more than limited ip and drop connection
LimitDevice := func() { LimitDevice() }
stop := schedule(LimitDevice, 700 *time.Millisecond)
time.Sleep(60 * time.Second)
stop <- true
}
func GetAccessLogPath() string {
@@ -157,9 +172,17 @@ func GetInboundClientIps(clientEmail string, ips []string) *model.InboundClientI
if err != nil {
return nil
}
if(limitIp < len(ips) && limitIp != 0 && inbound.Enable) {
DisableInbound(inbound.Id)
if(limitIp == 1){
limitIp = 2
}
disAllowedIps = append(disAllowedIps,ips[limitIp - 1:]...)
}
logger.Debug("disAllowedIps ",disAllowedIps)
sort.Sort(sort.StringSlice(disAllowedIps))
return inboundClientIps
}
@@ -190,17 +213,118 @@ func GetInboundByEmail(clientEmail string) (*model.Inbound, error) {
return inbounds, nil
}
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)
func LimitDevice(){
localIp,err := LocalIP()
checkError(err)
if err == nil {
job.xrayService.SetToNeedRestart()
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 {
for _, row := range c.Status().Stdout {
data := strings.Split(row," ")
dest,src := strings.Split(data[0],":"),strings.Split(data[1],":")
destIp,destPort := dest[0],dest[1]
srcIp,srcPort := src[0],src[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)
}
}
}
return err
}
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
}
if isPrivateIP(ip) {
ips = append(ips,ip.String())
}
}
}
logger.Debug("System IPs : ",ips)
return ips, nil
}
func isPrivateIP(ip net.IP) bool {
var privateIPBlocks []*net.IPNet
for _, cidr := range []string{
// don't check loopback ips
//"127.0.0.0/8", // IPv4 loopback
//"::1/128", // IPv6 loopback
//"fe80::/10", // IPv6 link-local
"10.0.0.0/8", // RFC1918
"172.16.0.0/12", // RFC1918
"192.168.0.0/16", // RFC1918
} {
_, block, _ := net.ParseCIDR(cidr)
privateIPBlocks = append(privateIPBlocks, block)
}
for _, block := range privateIPBlocks {
if block.Contains(ip) {
return true
}
}
return false
}
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

@@ -296,8 +296,8 @@ func (s *Server) startTask() {
// 每 30 秒检查一次 inbound 流量超出和到期的情况
s.cron.AddJob("@every 30s", job.NewCheckInboundJob())
// check client ips from log file every 1 min
s.cron.AddJob("@every 1m", job.NewCheckClientIpJob())
// check client ips from log file every 30 sec
s.cron.AddJob("@every 30s", job.NewCheckClientIpJob())
// 每一天提示一次流量情况,上海时间8点30
var entry cron.EntryID