mirror of
https://github.com/wyx2685/V2bX.git
synced 2026-02-04 20:50:09 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc284b3b9f |
@@ -39,23 +39,21 @@ type cachedReader struct {
|
||||
cache buf.MultiBuffer
|
||||
}
|
||||
|
||||
func (r *cachedReader) Cache(b *buf.Buffer) {
|
||||
mb, _ := r.reader.ReadMultiBufferTimeout(time.Millisecond * 100)
|
||||
func (r *cachedReader) Cache(b *buf.Buffer, deadline time.Duration) error {
|
||||
mb, err := r.reader.ReadMultiBufferTimeout(deadline)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Lock()
|
||||
if !mb.IsEmpty() {
|
||||
r.cache, _ = buf.MergeMulti(r.cache, mb)
|
||||
}
|
||||
cacheLen := r.cache.Len()
|
||||
if cacheLen <= b.Cap() {
|
||||
b.Clear()
|
||||
} else {
|
||||
b.Release()
|
||||
*b = *buf.NewWithSize(cacheLen)
|
||||
}
|
||||
rawBytes := b.Extend(cacheLen)
|
||||
b.Clear()
|
||||
rawBytes := b.Extend(min(r.cache.Len(), b.Cap()))
|
||||
n := r.cache.Copy(rawBytes)
|
||||
b.Resize(0, int32(n))
|
||||
r.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *cachedReader) readInternal() buf.MultiBuffer {
|
||||
@@ -115,7 +113,7 @@ func init() {
|
||||
core.OptionalFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
||||
d.fdns = fdns
|
||||
})
|
||||
return d.Init(config.(*Config), om, router, pm, sm, dc)
|
||||
return d.Init(config.(*Config), om, router, pm, sm)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -124,12 +122,11 @@ func init() {
|
||||
}
|
||||
|
||||
// Init initializes DefaultDispatcher.
|
||||
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager, dns dns.Client) error {
|
||||
func (d *DefaultDispatcher) Init(config *Config, om outbound.Manager, router routing.Router, pm policy.Manager, sm stats.Manager) error {
|
||||
d.ohm = om
|
||||
d.router = router
|
||||
d.policy = pm
|
||||
d.stats = sm
|
||||
d.dns = dns
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -364,7 +361,7 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
|
||||
protocol = resComp.ProtocolForDomainResult()
|
||||
}
|
||||
isFakeIP := false
|
||||
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && ob.Target.Address.Family().IsIP() && fkr0.IsIPInIPPool(ob.Target.Address) {
|
||||
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && fkr0.IsIPInIPPool(ob.Target.Address) {
|
||||
isFakeIP = true
|
||||
}
|
||||
if sniffingRequest.RouteOnly && protocol != "fakedns" && protocol != "fakedns+others" && !isFakeIP {
|
||||
@@ -372,7 +369,6 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
|
||||
} else {
|
||||
ob.Target = destination
|
||||
}
|
||||
destination.Address.Family()
|
||||
}
|
||||
d.routedDispatch(ctx, outbound, destination, nil, content.Protocol)
|
||||
}
|
||||
@@ -381,7 +377,7 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
|
||||
}
|
||||
|
||||
func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, network net.Network) (SniffResult, error) {
|
||||
payload := buf.New()
|
||||
payload := buf.NewWithSize(32767)
|
||||
defer payload.Release()
|
||||
|
||||
sniffer := NewSniffer(ctx)
|
||||
@@ -393,26 +389,36 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
|
||||
}
|
||||
|
||||
contentResult, contentErr := func() (SniffResult, error) {
|
||||
cacheDeadline := 200 * time.Millisecond
|
||||
totalAttempt := 0
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
totalAttempt++
|
||||
if totalAttempt > 2 {
|
||||
return nil, errSniffingTimeout
|
||||
cachingStartingTimeStamp := time.Now()
|
||||
err := cReader.Cache(payload, cacheDeadline)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cachingTimeElapsed := time.Since(cachingStartingTimeStamp)
|
||||
cacheDeadline -= cachingTimeElapsed
|
||||
|
||||
cReader.Cache(payload)
|
||||
if !payload.IsEmpty() {
|
||||
result, err := sniffer.Sniff(ctx, payload.Bytes(), network)
|
||||
if err != common.ErrNoClue {
|
||||
switch err {
|
||||
case common.ErrNoClue: // No Clue: protocol not matches, and sniffer cannot determine whether there will be a match or not
|
||||
totalAttempt++
|
||||
case protocol.ErrProtoNeedMoreData: // Protocol Need More Data: protocol matches, but need more data to complete sniffing
|
||||
// in this case, do not add totalAttempt(allow to read until timeout)
|
||||
default:
|
||||
return result, err
|
||||
}
|
||||
} else {
|
||||
totalAttempt++
|
||||
}
|
||||
if payload.IsFull() {
|
||||
return nil, errUnknownContent
|
||||
if totalAttempt >= 2 || cacheDeadline <= 0 {
|
||||
return nil, errSniffingTimeout
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -429,29 +435,10 @@ func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool, netw
|
||||
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination, l *limiter.Limiter, protocol string) {
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
if hosts, ok := d.dns.(dns.HostsLookup); ok && destination.Address.Family().IsDomain() {
|
||||
proxied := hosts.LookupHosts(ob.Target.String())
|
||||
if proxied != nil {
|
||||
ro := ob.RouteTarget == destination
|
||||
destination.Address = *proxied
|
||||
if ro {
|
||||
ob.RouteTarget = destination
|
||||
} else {
|
||||
ob.Target = destination
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sessionInbound := session.InboundFromContext(ctx)
|
||||
if sessionInbound.User != nil {
|
||||
if l != nil {
|
||||
// del connect count
|
||||
if destination.Network == net.Network_TCP {
|
||||
defer func() {
|
||||
l.ConnLimiter.DelConnCount(sessionInbound.User.Email, sessionInbound.Source.Address.IP().String())
|
||||
}()
|
||||
}
|
||||
} else {
|
||||
if l == nil {
|
||||
var err error
|
||||
l, err = limiter.GetLimiter(sessionInbound.Tag)
|
||||
if err != nil {
|
||||
@@ -510,7 +497,11 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
|
||||
outTag := route.GetOutboundTag()
|
||||
if h := d.ohm.GetHandler(outTag); h != nil {
|
||||
isPickRoute = 2
|
||||
errors.LogInfo(ctx, "taking detour [", outTag, "] for [", destination, "]")
|
||||
if route.GetRuleTag() == "" {
|
||||
errors.LogInfo(ctx, "taking detour [", outTag, "] for [", destination, "]")
|
||||
} else {
|
||||
errors.LogInfo(ctx, "Hit route rule: [", route.GetRuleTag(), "] so taking detour [", outTag, "] for [", destination, "]")
|
||||
}
|
||||
handler = h
|
||||
} else {
|
||||
errors.LogWarning(ctx, "non existing outTag: ", outTag)
|
||||
@@ -520,10 +511,6 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
|
||||
}
|
||||
}
|
||||
|
||||
if handler == nil {
|
||||
handler = d.ohm.GetHandler(inTag)
|
||||
}
|
||||
|
||||
if handler == nil {
|
||||
handler = d.ohm.GetDefaultHandler()
|
||||
}
|
||||
@@ -535,6 +522,7 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
|
||||
return
|
||||
}
|
||||
|
||||
ob.Tag = handler.Tag()
|
||||
if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil {
|
||||
if tag := handler.Tag(); tag != "" {
|
||||
if inTag == "" {
|
||||
|
||||
16
go.mod
16
go.mod
@@ -20,7 +20,7 @@ require (
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/xtls/xray-core v1.250306.1-0.20250430044058-87ab8e512882
|
||||
github.com/xtls/xray-core v1.250516.1-0.20250527015530-84c8e24a6c6b
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/crypto v0.38.0
|
||||
golang.org/x/sys v0.33.0
|
||||
@@ -214,8 +214,8 @@ require (
|
||||
github.com/pquerna/otp v1.4.0 // indirect
|
||||
github.com/prometheus-community/pro-bing v0.4.0 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/quic-go v0.51.0 // indirect
|
||||
github.com/refraction-networking/utls v1.7.1 // indirect
|
||||
github.com/quic-go/quic-go v0.52.0 // indirect
|
||||
github.com/refraction-networking/utls v1.7.3 // indirect
|
||||
github.com/regfish/regfish-dnsapi-go v0.1.1 // indirect
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||
github.com/sacloud/api-client-go v0.2.10 // indirect
|
||||
@@ -278,13 +278,13 @@ require (
|
||||
github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec // indirect
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect
|
||||
github.com/vinyldns/go-vinyldns v0.9.16 // indirect
|
||||
github.com/vishvananda/netlink v1.3.0 // indirect
|
||||
github.com/vishvananda/netlink v1.3.1 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
github.com/volcengine/volc-sdk-golang v1.0.189 // indirect
|
||||
github.com/vultr/govultr/v3 v3.9.1 // indirect
|
||||
github.com/wyx2685/sing-vmess v0.0.0-20250524094403-696835735021 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 // indirect
|
||||
github.com/xtls/reality v0.0.0-20250527000105-e679ef7bb130 // indirect
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20241220122821-aeb3b05efd1c // indirect
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20241220131134-2393e243c134 // indirect
|
||||
github.com/zeebo/blake3 v0.2.4 // indirect
|
||||
@@ -317,15 +317,15 @@ require (
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
|
||||
google.golang.org/grpc v1.72.0 // indirect
|
||||
google.golang.org/grpc v1.72.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/ns1/ns1-go.v2 v2.13.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20250428193742-2d800c3129d5 // indirect
|
||||
lukechampine.com/blake3 v1.4.0 // indirect
|
||||
lukechampine.com/blake3 v1.4.1 // indirect
|
||||
)
|
||||
|
||||
//replace github.com/sagernet/sing-box v1.12.0 => ./sing-box_mod
|
||||
|
||||
replace github.com/sagernet/sing-box v1.12.0 => github.com/wyx2685/sing-box_mod v1.12.0-beta.17.1
|
||||
replace github.com/sagernet/sing-box v1.12.0 => github.com/wyx2685/sing-box_mod v1.12.0-beta.17.2
|
||||
|
||||
33
go.sum
33
go.sum
@@ -878,14 +878,14 @@ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc=
|
||||
github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
|
||||
github.com/quic-go/quic-go v0.52.0 h1:/SlHrCRElyaU6MaEPKqKr9z83sBg2v4FLLvWM+Z47pA=
|
||||
github.com/quic-go/quic-go v0.52.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4=
|
||||
github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA=
|
||||
github.com/refraction-networking/utls v1.7.1 h1:dxg+jla3uocgN8HtX+ccwDr68uCBBO3qLrkZUbqkcw0=
|
||||
github.com/refraction-networking/utls v1.7.1/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
|
||||
github.com/refraction-networking/utls v1.7.3 h1:L0WRhHY7Oq1T0zkdzVZMR6zWZv+sXbHB9zcuvsAEqCo=
|
||||
github.com/refraction-networking/utls v1.7.3/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ=
|
||||
github.com/regfish/regfish-dnsapi-go v0.1.1 h1:TJFtbePHkd47q5GZwYl1h3DIYXmoxdLjW/SBsPtB5IE=
|
||||
github.com/regfish/regfish-dnsapi-go v0.1.1/go.mod h1:ubIgXSfqarSnl3XHSn8hIFwFF3h0yrq0ZiWD93Y2VjY=
|
||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||
@@ -1081,18 +1081,17 @@ github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF
|
||||
github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU=
|
||||
github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4ulRMcQ=
|
||||
github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
|
||||
github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk=
|
||||
github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
|
||||
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
|
||||
github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4=
|
||||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.189 h1:VMDTHWYXakXJtZqPYn0As/h4eB0c4imvyru6mIp+o60=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.189/go.mod h1:u0VtPvlXWpXDTmc9IHkaW1q+5Jjwus4oAqRhNMDRInE=
|
||||
github.com/vultr/govultr/v3 v3.9.1 h1:uxSIb8Miel7tqTs3ee+z3t+JelZikwqBBsZzCOPBy/8=
|
||||
github.com/vultr/govultr/v3 v3.9.1/go.mod h1:Rd8ebpXm7jxH3MDmhnEs+zrlYW212ouhx+HeUMfHm2o=
|
||||
github.com/wyx2685/sing-box_mod v1.12.0-beta.17.1 h1:cP+MU7/XO6H5pSaoYhkEYMlPe6Ano02NFl/pELAzJC4=
|
||||
github.com/wyx2685/sing-box_mod v1.12.0-beta.17.1/go.mod h1:ZybQCajA3r+okcxY9jNzcTIh35Kj35wbYANSoHU/kM8=
|
||||
github.com/wyx2685/sing-box_mod v1.12.0-beta.17.2 h1:jBxJBXGc4z+8iV1Q8Y3b05i0iE9S/xdGx/ASmgf7kYw=
|
||||
github.com/wyx2685/sing-box_mod v1.12.0-beta.17.2/go.mod h1:ZybQCajA3r+okcxY9jNzcTIh35Kj35wbYANSoHU/kM8=
|
||||
github.com/wyx2685/sing-vmess v0.0.0-20250524094403-696835735021 h1:B/OF9zLyAl930HyOXnsVg1rN1uTZHFHOf6otkLHu1a4=
|
||||
github.com/wyx2685/sing-vmess v0.0.0-20250524094403-696835735021/go.mod h1:9GsbMmRg+GD02PRq9zv/K4MCollzq281D9qN5bpCBhM=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
@@ -1106,10 +1105,10 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463 h1:g1Cj7d+my6k/HHxLAyxPwyX8i7FGRr6ulBDMkBzg2BM=
|
||||
github.com/xtls/reality v0.0.0-20240909153216-e26ae2305463/go.mod h1:BjIOLmkEEtAgloAiVUcYj0Mt+YU00JARZw8AEU0IwAg=
|
||||
github.com/xtls/xray-core v1.250306.1-0.20250430044058-87ab8e512882 h1:O/aN4TCrJ+fmaDOBoQhtTRev2hVHIENy2EJ70jQcyEY=
|
||||
github.com/xtls/xray-core v1.250306.1-0.20250430044058-87ab8e512882/go.mod h1:v7SYLVSg2wkuP8jo9/0qaJ5zrCQhmUig7bSnUOdMqu0=
|
||||
github.com/xtls/reality v0.0.0-20250527000105-e679ef7bb130 h1:v/TVypWnLferyoaNHh6a8oyggj9APBUzfl1OOgXNbpw=
|
||||
github.com/xtls/reality v0.0.0-20250527000105-e679ef7bb130/go.mod h1:bJdU3ExzfUlY40Xxfibq3THW9IHiE8mHu/tEzud5JWM=
|
||||
github.com/xtls/xray-core v1.250516.1-0.20250527015530-84c8e24a6c6b h1:vliQlr474cVfZU404dkdTRMhpShSrIcrxKMkhtLXFTM=
|
||||
github.com/xtls/xray-core v1.250516.1-0.20250527015530-84c8e24a6c6b/go.mod h1:gEwI49AiHj+J0lTqwhy0SZnpnG9GXZxo/SwJB7ulGXI=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20241220122821-aeb3b05efd1c h1:Rnr+lDYXVkP+3eT8/d68iq4G/UeIhyCQk+HKa8toTvg=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20241220122821-aeb3b05efd1c/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo=
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20241220131134-2393e243c134 h1:qmpz0Kvr9GAng8LAhRcKIpY71CEAcL3EBkftVlsP5Cw=
|
||||
@@ -1604,8 +1603,8 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
|
||||
google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
|
||||
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -1673,8 +1672,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
lukechampine.com/blake3 v1.4.0 h1:xDbKOZCVbnZsfzM6mHSYcGRHZ3YrLDzqz8XnV4uaD5w=
|
||||
lukechampine.com/blake3 v1.4.0/go.mod h1:MQJNQCTnR+kwOP/JEZSxj3MaQjp80FOFSNMMHXcSeX0=
|
||||
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
|
||||
lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package limiter
|
||||
|
||||
import log "github.com/sirupsen/logrus"
|
||||
|
||||
func ClearOnlineIP() error {
|
||||
log.WithField("Type", "Limiter").
|
||||
Debug("Clear online ip...")
|
||||
limitLock.RLock()
|
||||
for _, l := range limiter {
|
||||
l.ConnLimiter.ClearOnlineIP()
|
||||
}
|
||||
limitLock.RUnlock()
|
||||
log.WithField("Type", "Limiter").
|
||||
Debug("Clear online ip done")
|
||||
return nil
|
||||
}
|
||||
165
limiter/conn.go
165
limiter/conn.go
@@ -1,165 +0,0 @@
|
||||
package limiter
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ConnLimiter struct {
|
||||
realtime bool
|
||||
ipLimit int
|
||||
connLimit int
|
||||
count sync.Map // map[string]int
|
||||
ip sync.Map // map[string]map[string]int
|
||||
}
|
||||
|
||||
func NewConnLimiter(conn int, ip int, realtime bool) *ConnLimiter {
|
||||
return &ConnLimiter{
|
||||
realtime: realtime,
|
||||
connLimit: conn,
|
||||
ipLimit: ip,
|
||||
count: sync.Map{},
|
||||
ip: sync.Map{},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConnLimiter) AddConnCount(user string, ip string, isTcp bool) (limit bool) {
|
||||
if c.connLimit != 0 {
|
||||
if v, ok := c.count.Load(user); ok {
|
||||
if v.(int) >= c.connLimit {
|
||||
// over connection limit
|
||||
return true
|
||||
} else if isTcp {
|
||||
// tcp protocol
|
||||
// connection count add
|
||||
c.count.Store(user, v.(int)+1)
|
||||
}
|
||||
} else if isTcp {
|
||||
// tcp protocol
|
||||
// store connection count
|
||||
c.count.Store(user, 1)
|
||||
}
|
||||
}
|
||||
if c.ipLimit == 0 {
|
||||
return false
|
||||
}
|
||||
// first user map
|
||||
ipMap := new(sync.Map)
|
||||
if c.realtime {
|
||||
if isTcp {
|
||||
ipMap.Store(ip, 2)
|
||||
} else {
|
||||
ipMap.Store(ip, 1)
|
||||
}
|
||||
} else {
|
||||
ipMap.Store(ip, time.Now())
|
||||
}
|
||||
// check user online ip
|
||||
if v, ok := c.ip.LoadOrStore(user, ipMap); ok {
|
||||
// have user
|
||||
ips := v.(*sync.Map)
|
||||
cn := 0
|
||||
if online, ok := ips.Load(ip); ok {
|
||||
// online ip
|
||||
if c.realtime {
|
||||
if isTcp {
|
||||
// tcp count add
|
||||
ips.Store(ip, online.(int)+2)
|
||||
}
|
||||
} else {
|
||||
// update connect time for not realtime
|
||||
ips.Store(ip, time.Now())
|
||||
}
|
||||
} else {
|
||||
// not online ip
|
||||
ips.Range(func(_, _ interface{}) bool {
|
||||
cn++
|
||||
if cn >= c.ipLimit {
|
||||
limit = true
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
if limit {
|
||||
// over ip limit
|
||||
return
|
||||
}
|
||||
if c.realtime {
|
||||
if isTcp {
|
||||
ips.Store(ip, 2)
|
||||
} else {
|
||||
ips.Store(ip, 1)
|
||||
}
|
||||
} else {
|
||||
ips.Store(ip, time.Now())
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DelConnCount Delete tcp connection count, no tcp do not use
|
||||
func (c *ConnLimiter) DelConnCount(user string, ip string) {
|
||||
if !c.realtime {
|
||||
return
|
||||
}
|
||||
if c.connLimit != 0 {
|
||||
if v, ok := c.count.Load(user); ok {
|
||||
if v.(int) == 1 {
|
||||
c.count.Delete(user)
|
||||
} else {
|
||||
c.count.Store(user, v.(int)-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
if c.ipLimit == 0 {
|
||||
return
|
||||
}
|
||||
if i, ok := c.ip.Load(user); ok {
|
||||
is := i.(*sync.Map)
|
||||
if i, ok := is.Load(ip); ok {
|
||||
if i.(int) == 2 {
|
||||
is.Delete(ip)
|
||||
} else {
|
||||
is.Store(user, i.(int)-2)
|
||||
}
|
||||
notDel := false
|
||||
c.ip.Range(func(_, _ any) bool {
|
||||
notDel = true
|
||||
return false
|
||||
})
|
||||
if !notDel {
|
||||
c.ip.Delete(user)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ClearOnlineIP Clear udp,icmp and other packet protocol online ip
|
||||
func (c *ConnLimiter) ClearOnlineIP() {
|
||||
c.ip.Range(func(u, v any) bool {
|
||||
userIp := v.(*sync.Map)
|
||||
notDel := false
|
||||
userIp.Range(func(ip, v any) bool {
|
||||
notDel = true
|
||||
if _, ok := v.(int); ok {
|
||||
if v.(int) == 1 {
|
||||
// clear packet ip for realtime
|
||||
userIp.Delete(ip)
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
// clear ip for not realtime
|
||||
if v.(time.Time).Before(time.Now().Add(time.Minute)) {
|
||||
// 1 minute no active
|
||||
userIp.Delete(ip)
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
if !notDel {
|
||||
c.ip.Delete(u)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package limiter
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var c *ConnLimiter
|
||||
|
||||
func init() {
|
||||
c = NewConnLimiter(1, 1, true)
|
||||
}
|
||||
|
||||
func TestConnLimiter_AddConnCount(t *testing.T) {
|
||||
t.Log(c.AddConnCount("1", "1", true))
|
||||
t.Log(c.AddConnCount("1", "2", true))
|
||||
}
|
||||
|
||||
func TestConnLimiter_DelConnCount(t *testing.T) {
|
||||
t.Log(c.AddConnCount("1", "1", true))
|
||||
t.Log(c.AddConnCount("1", "2", true))
|
||||
c.DelConnCount("1", "1")
|
||||
t.Log(c.AddConnCount("1", "2", true))
|
||||
}
|
||||
|
||||
func TestConnLimiter_ClearOnlineIP(t *testing.T) {
|
||||
t.Log(c.AddConnCount("1", "1", false))
|
||||
t.Log(c.AddConnCount("1", "2", false))
|
||||
c.ClearOnlineIP()
|
||||
t.Log(c.AddConnCount("1", "2", true))
|
||||
c.DelConnCount("1", "2")
|
||||
t.Log(c.AddConnCount("1", "1", false))
|
||||
// not realtime
|
||||
c.realtime = false
|
||||
t.Log(c.AddConnCount("3", "2", true))
|
||||
c.ClearOnlineIP()
|
||||
t.Log(c.ip.Load("3"))
|
||||
time.Sleep(time.Minute)
|
||||
c.ClearOnlineIP()
|
||||
t.Log(c.ip.Load("3"))
|
||||
}
|
||||
|
||||
func BenchmarkConnLimiter(b *testing.B) {
|
||||
wg := sync.WaitGroup{}
|
||||
for i := 0; i < b.N; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
c.AddConnCount("1", "2", true)
|
||||
c.DelConnCount("1", "2")
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
}
|
||||
@@ -11,8 +11,6 @@ import (
|
||||
"github.com/InazumaV/V2bX/common/format"
|
||||
"github.com/InazumaV/V2bX/conf"
|
||||
"github.com/juju/ratelimit"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/xtls/xray-core/common/task"
|
||||
)
|
||||
|
||||
var limitLock sync.RWMutex
|
||||
@@ -20,16 +18,6 @@ var limiter map[string]*Limiter
|
||||
|
||||
func Init() {
|
||||
limiter = map[string]*Limiter{}
|
||||
c := task.Periodic{
|
||||
Interval: time.Minute * 3,
|
||||
Execute: ClearOnlineIP,
|
||||
}
|
||||
go func() {
|
||||
log.WithField("Type", "Limiter").
|
||||
Debug("ClearOnlineIP started")
|
||||
time.Sleep(time.Minute * 3)
|
||||
_ = c.Start()
|
||||
}()
|
||||
}
|
||||
|
||||
type Limiter struct {
|
||||
@@ -40,7 +28,6 @@ type Limiter struct {
|
||||
OldUserOnline *sync.Map // Key: Ip, value: Uid
|
||||
UUIDtoUID map[string]int // Key: UUID, value: Uid
|
||||
UserLimitInfo *sync.Map // Key: Uid value: UserLimitInfo
|
||||
ConnLimiter *ConnLimiter // Key: Uid value: ConnLimiter
|
||||
SpeedLimiter *sync.Map // key: Uid, value: *ratelimit.Bucket
|
||||
AliveList map[int]int // Key: Uid, value: alive_ip
|
||||
}
|
||||
@@ -59,7 +46,6 @@ func AddLimiter(tag string, l *conf.LimitConfig, users []panel.UserInfo, aliveLi
|
||||
SpeedLimit: l.SpeedLimit,
|
||||
UserOnlineIP: new(sync.Map),
|
||||
UserLimitInfo: new(sync.Map),
|
||||
ConnLimiter: NewConnLimiter(l.ConnLimit, l.IPLimit, l.EnableRealtime),
|
||||
SpeedLimiter: new(sync.Map),
|
||||
AliveList: aliveList,
|
||||
OldUserOnline: new(sync.Map),
|
||||
@@ -140,10 +126,6 @@ func (l *Limiter) CheckLimit(taguuid string, ip string, isTcp bool, noSSUDP bool
|
||||
// check if ipv4 mapped ipv6
|
||||
ip = strings.TrimPrefix(ip, "::ffff:")
|
||||
|
||||
// ip and conn limiter
|
||||
if l.ConnLimiter.AddConnCount(taguuid, ip, isTcp) {
|
||||
return nil, true
|
||||
}
|
||||
// check and gen speed limit Bucket
|
||||
nodeLimit := l.SpeedLimit
|
||||
userLimit := 0
|
||||
@@ -169,17 +151,21 @@ func (l *Limiter) CheckLimit(taguuid string, ip string, isTcp bool, noSSUDP bool
|
||||
}
|
||||
if noSSUDP {
|
||||
// Store online user for device limit
|
||||
ipMap := new(sync.Map)
|
||||
ipMap.Store(ip, uid)
|
||||
newipMap := new(sync.Map)
|
||||
newipMap.Store(ip, uid)
|
||||
aliveIp := l.AliveList[uid]
|
||||
// If any device is online
|
||||
if v, ok := l.UserOnlineIP.LoadOrStore(taguuid, ipMap); ok {
|
||||
ipMap := v.(*sync.Map)
|
||||
if v, loaded := l.UserOnlineIP.LoadOrStore(taguuid, newipMap); loaded {
|
||||
oldipMap := v.(*sync.Map)
|
||||
// If this is a new ip
|
||||
if _, ok := ipMap.LoadOrStore(ip, uid); !ok {
|
||||
if deviceLimit > 0 {
|
||||
if _, loaded := oldipMap.LoadOrStore(ip, uid); !loaded {
|
||||
if v, loaded := l.OldUserOnline.Load(ip); loaded {
|
||||
if v.(int) == uid {
|
||||
l.OldUserOnline.Delete(ip)
|
||||
}
|
||||
} else if deviceLimit > 0 {
|
||||
if deviceLimit <= aliveIp {
|
||||
ipMap.Delete(ip)
|
||||
oldipMap.Delete(ip)
|
||||
return nil, true
|
||||
}
|
||||
}
|
||||
@@ -214,6 +200,7 @@ func (l *Limiter) CheckLimit(taguuid string, ip string, isTcp bool, noSSUDP bool
|
||||
|
||||
func (l *Limiter) GetOnlineDevice() (*[]panel.OnlineUser, error) {
|
||||
var onlineUser []panel.OnlineUser
|
||||
l.OldUserOnline = new(sync.Map)
|
||||
l.UserOnlineIP.Range(func(key, value interface{}) bool {
|
||||
taguuid := key.(string)
|
||||
ipMap := value.(*sync.Map)
|
||||
|
||||
Reference in New Issue
Block a user