mirror of
https://github.com/wyx2685/V2bX.git
synced 2026-02-04 12:40:11 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
248ff3764f | ||
|
|
3dfeba7e68 | ||
|
|
8eb623b3f0 | ||
|
|
cdcbddd464 | ||
|
|
e81d47321b | ||
|
|
4d82eff518 | ||
|
|
b96545649b | ||
|
|
8757b955a6 |
@@ -2,7 +2,6 @@ package panel
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"reflect"
|
||||
@@ -10,7 +9,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/InazumaV/V2bX/common/crypt"
|
||||
"github.com/goccy/go-json"
|
||||
)
|
||||
|
||||
@@ -186,18 +184,6 @@ func (c *Client) GetNodeInfo() (node *NodeInfo, err error) {
|
||||
cm = &rsp.CommonNode
|
||||
node.VAllss = rsp
|
||||
node.Security = node.VAllss.Tls
|
||||
if len(rsp.NetworkSettings) > 0 {
|
||||
err = json.Unmarshal(rsp.NetworkSettings, &rsp.RealityConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode reality config error: %s", err)
|
||||
}
|
||||
}
|
||||
if node.Security == Reality {
|
||||
if rsp.TlsSettings.PrivateKey == "" {
|
||||
key := crypt.GenX25519Private([]byte("vless" + c.Token))
|
||||
rsp.TlsSettings.PrivateKey = base64.RawURLEncoding.EncodeToString(key)
|
||||
}
|
||||
}
|
||||
case "shadowsocks":
|
||||
rsp := &ShadowsocksNode{}
|
||||
err = json.Unmarshal(r.Body(), rsp)
|
||||
|
||||
@@ -284,15 +284,23 @@ func (n *Hysteria2node) getMasqHandler(tlsconfig *server.TLSConfig, conn net.Pac
|
||||
}
|
||||
u, err := url.Parse(c.Masquerade.Proxy.URL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(fmt.Sprintf("masquerade.proxy.url %s", err))
|
||||
return nil, fmt.Errorf("masquerade.proxy.url %s", err)
|
||||
}
|
||||
handler = &httputil.ReverseProxy{
|
||||
Rewrite: func(r *httputil.ProxyRequest) {
|
||||
r.SetURL(u)
|
||||
// SetURL rewrites the Host header,
|
||||
// but we don't want that if rewriteHost is false
|
||||
Director: func(req *http.Request) {
|
||||
req.URL.Scheme = u.Scheme
|
||||
req.URL.Host = u.Host
|
||||
|
||||
if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
|
||||
xff := req.Header.Get("X-Forwarded-For")
|
||||
if xff != "" {
|
||||
clientIP = xff + ", " + clientIP
|
||||
}
|
||||
req.Header.Set("X-Forwarded-For", clientIP)
|
||||
}
|
||||
|
||||
if !c.Masquerade.Proxy.RewriteHost {
|
||||
r.Out.Host = r.In.Host
|
||||
req.Host = req.URL.Host
|
||||
}
|
||||
},
|
||||
ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
|
||||
@@ -4,10 +4,14 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/InazumaV/V2bX/common/counter"
|
||||
"github.com/InazumaV/V2bX/common/format"
|
||||
"github.com/InazumaV/V2bX/limiter"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type HookServer struct {
|
||||
Tag string
|
||||
logger *zap.Logger
|
||||
Counter sync.Map
|
||||
}
|
||||
|
||||
@@ -15,6 +19,21 @@ func (h *HookServer) LogTraffic(id string, tx, rx uint64) (ok bool) {
|
||||
var c interface{}
|
||||
var exists bool
|
||||
|
||||
limiterinfo, err := limiter.GetLimiter(h.Tag)
|
||||
if err != nil {
|
||||
h.logger.Error("Get limiter error", zap.String("tag", h.Tag), zap.Error(err))
|
||||
return false
|
||||
}
|
||||
|
||||
userLimit, ok := limiterinfo.UserLimitInfo.Load(format.UserTag(h.Tag, id))
|
||||
if ok {
|
||||
userlimitInfo := userLimit.(*limiter.UserLimitInfo)
|
||||
if userlimitInfo.OverLimit {
|
||||
userlimitInfo.OverLimit = false
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if c, exists = h.Counter.Load(h.Tag); !exists {
|
||||
c = counter.NewTrafficCounter()
|
||||
h.Counter.Store(h.Tag, c)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/InazumaV/V2bX/common/format"
|
||||
"github.com/InazumaV/V2bX/limiter"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
@@ -46,12 +47,18 @@ var logFormatMap = map[string]zapcore.EncoderConfig{
|
||||
}
|
||||
|
||||
func (l *serverLogger) Connect(addr net.Addr, uuid string, tx uint64) {
|
||||
limiter, err := limiter.GetLimiter(l.Tag)
|
||||
limiterinfo, err := limiter.GetLimiter(l.Tag)
|
||||
if err != nil {
|
||||
l.logger.Panic("Get limiter error", zap.String("tag", l.Tag), zap.Error(err))
|
||||
}
|
||||
if _, r := limiter.CheckLimit(uuid, extractIPFromAddr(addr), addr.Network() == "tcp"); r {
|
||||
l.logger.Warn("Need Reject", zap.String("addr", addr.String()), zap.String("uuid", uuid))
|
||||
if _, r := limiterinfo.CheckLimit(format.UserTag(l.Tag, uuid), extractIPFromAddr(addr), addr.Network() == "tcp", true); r {
|
||||
if userLimit, ok := limiterinfo.UserLimitInfo.Load(format.UserTag(l.Tag, uuid)); ok {
|
||||
userLimit.(*limiter.UserLimitInfo).OverLimit = true
|
||||
}
|
||||
} else {
|
||||
if userLimit, ok := limiterinfo.UserLimitInfo.Load(format.UserTag(l.Tag, uuid)); ok {
|
||||
userLimit.(*limiter.UserLimitInfo).OverLimit = false
|
||||
}
|
||||
}
|
||||
l.logger.Info("client connected", zap.String("addr", addr.String()), zap.String("uuid", uuid), zap.Uint64("tx", tx))
|
||||
}
|
||||
@@ -61,12 +68,18 @@ func (l *serverLogger) Disconnect(addr net.Addr, uuid string, err error) {
|
||||
}
|
||||
|
||||
func (l *serverLogger) TCPRequest(addr net.Addr, uuid, reqAddr string) {
|
||||
limiter, err := limiter.GetLimiter(l.Tag)
|
||||
limiterinfo, err := limiter.GetLimiter(l.Tag)
|
||||
if err != nil {
|
||||
l.logger.Panic("Get limiter error", zap.String("tag", l.Tag), zap.Error(err))
|
||||
}
|
||||
if _, r := limiter.CheckLimit(uuid, extractIPFromAddr(addr), addr.Network() == "tcp"); r {
|
||||
l.logger.Warn("Need Reject", zap.String("addr", addr.String()), zap.String("uuid", uuid))
|
||||
if _, r := limiterinfo.CheckLimit(format.UserTag(l.Tag, uuid), extractIPFromAddr(addr), addr.Network() == "tcp", true); r {
|
||||
if userLimit, ok := limiterinfo.UserLimitInfo.Load(format.UserTag(l.Tag, uuid)); ok {
|
||||
userLimit.(*limiter.UserLimitInfo).OverLimit = true
|
||||
}
|
||||
} else {
|
||||
if userLimit, ok := limiterinfo.UserLimitInfo.Load(format.UserTag(l.Tag, uuid)); ok {
|
||||
userLimit.(*limiter.UserLimitInfo).OverLimit = false
|
||||
}
|
||||
}
|
||||
l.logger.Debug("TCP request", zap.String("addr", addr.String()), zap.String("uuid", uuid), zap.String("reqAddr", reqAddr))
|
||||
}
|
||||
@@ -80,12 +93,18 @@ func (l *serverLogger) TCPError(addr net.Addr, uuid, reqAddr string, err error)
|
||||
}
|
||||
|
||||
func (l *serverLogger) UDPRequest(addr net.Addr, uuid string, sessionId uint32, reqAddr string) {
|
||||
limiter, err := limiter.GetLimiter(l.Tag)
|
||||
limiterinfo, err := limiter.GetLimiter(l.Tag)
|
||||
if err != nil {
|
||||
l.logger.Panic("Get limiter error", zap.String("tag", l.Tag), zap.Error(err))
|
||||
}
|
||||
if _, r := limiter.CheckLimit(uuid, extractIPFromAddr(addr), addr.Network() == "tcp"); r {
|
||||
l.logger.Warn("Need Reject", zap.String("addr", addr.String()), zap.String("uuid", uuid))
|
||||
if _, r := limiterinfo.CheckLimit(format.UserTag(l.Tag, uuid), extractIPFromAddr(addr), addr.Network() == "tcp", true); r {
|
||||
if userLimit, ok := limiterinfo.UserLimitInfo.Load(format.UserTag(l.Tag, uuid)); ok {
|
||||
userLimit.(*limiter.UserLimitInfo).OverLimit = true
|
||||
}
|
||||
} else {
|
||||
if userLimit, ok := limiterinfo.UserLimitInfo.Load(format.UserTag(l.Tag, uuid)); ok {
|
||||
userLimit.(*limiter.UserLimitInfo).OverLimit = false
|
||||
}
|
||||
}
|
||||
l.logger.Debug("UDP request", zap.String("addr", addr.String()), zap.String("uuid", uuid), zap.Uint32("sessionId", sessionId), zap.String("reqAddr", reqAddr))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package hy2
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/InazumaV/V2bX/api/panel"
|
||||
"github.com/InazumaV/V2bX/conf"
|
||||
"github.com/apernet/hysteria/core/v2/server"
|
||||
@@ -38,7 +40,8 @@ func (h *Hysteria2) AddNode(tag string, info *panel.NodeInfo, config *conf.Optio
|
||||
logger: h.Logger,
|
||||
},
|
||||
TrafficLogger: &HookServer{
|
||||
Tag: tag,
|
||||
Tag: tag,
|
||||
logger: h.Logger,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -55,7 +58,9 @@ func (h *Hysteria2) AddNode(tag string, info *panel.NodeInfo, config *conf.Optio
|
||||
h.Hy2nodes[tag] = n
|
||||
go func() {
|
||||
if err := s.Serve(); err != nil {
|
||||
h.Logger.Error("Server Error", zap.Error(err))
|
||||
if !strings.Contains(err.Error(), "quic: server closed") {
|
||||
h.Logger.Error("Server Error", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
|
||||
@@ -17,9 +17,14 @@ import (
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/service"
|
||||
)
|
||||
|
||||
var _ adapter.ClashServer = (*HookServer)(nil)
|
||||
|
||||
type HookServer struct {
|
||||
ctx context.Context
|
||||
urlTestHistory *urltest.HistoryStorage
|
||||
EnableConnClear bool
|
||||
counter sync.Map
|
||||
connClears sync.Map
|
||||
@@ -56,12 +61,18 @@ func (h *HookServer) ModeList() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewHookServer(enableClear bool) *HookServer {
|
||||
return &HookServer{
|
||||
func NewHookServer(ctx context.Context, enableClear bool) *HookServer {
|
||||
server := &HookServer{
|
||||
ctx: ctx,
|
||||
EnableConnClear: enableClear,
|
||||
counter: sync.Map{},
|
||||
connClears: sync.Map{},
|
||||
}
|
||||
server.urlTestHistory = service.PtrFromContext[urltest.HistoryStorage](ctx)
|
||||
if server.urlTestHistory == nil {
|
||||
server.urlTestHistory = urltest.NewHistoryStorage()
|
||||
}
|
||||
return server
|
||||
}
|
||||
|
||||
func (h *HookServer) Start() error {
|
||||
@@ -69,6 +80,7 @@ func (h *HookServer) Start() error {
|
||||
}
|
||||
|
||||
func (h *HookServer) Close() error {
|
||||
h.urlTestHistory.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -96,7 +108,7 @@ func (h *HookServer) RoutedConnection(_ context.Context, conn net.Conn, m adapte
|
||||
return conn, t
|
||||
}
|
||||
ip := m.Source.Addr.String()
|
||||
if b, r := l.CheckLimit(format.UserTag(m.Inbound, m.User), ip, true); r {
|
||||
if b, r := l.CheckLimit(format.UserTag(m.Inbound, m.User), ip, true, true); r {
|
||||
conn.Close()
|
||||
log.Error("[", m.Inbound, "] ", "Limited ", m.User, " by ip or conn")
|
||||
return conn, t
|
||||
@@ -150,7 +162,7 @@ func (h *HookServer) RoutedPacketConnection(_ context.Context, conn N.PacketConn
|
||||
return conn, t
|
||||
}
|
||||
ip := m.Source.Addr.String()
|
||||
if b, r := l.CheckLimit(format.UserTag(m.Inbound, m.User), ip, true); r {
|
||||
if b, r := l.CheckLimit(format.UserTag(m.Inbound, m.User), ip, true, false); r {
|
||||
conn.Close()
|
||||
log.Error("[", m.Inbound, "] ", "Limited ", m.User, " by ip or conn")
|
||||
return conn, t
|
||||
@@ -193,7 +205,7 @@ func (h *HookServer) CacheFile() adapter.CacheFile {
|
||||
return nil
|
||||
}
|
||||
func (h *HookServer) HistoryStorage() *urltest.HistoryStorage {
|
||||
return nil
|
||||
return h.urlTestHistory
|
||||
}
|
||||
|
||||
func (h *HookServer) StoreFakeIP() bool {
|
||||
|
||||
@@ -40,6 +40,15 @@ type WsNetworkConfig struct {
|
||||
Headers map[string]string `json:"headers"`
|
||||
}
|
||||
|
||||
type GrpcNetworkConfig struct {
|
||||
ServiceName string `json:"serviceName"`
|
||||
}
|
||||
|
||||
type HttpupgradeNetworkConfig struct {
|
||||
Path string `json:"path"`
|
||||
Host string `json:"host"`
|
||||
}
|
||||
|
||||
func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (option.Inbound, error) {
|
||||
addr, err := netip.ParseAddr(c.ListenIP)
|
||||
if err != nil {
|
||||
@@ -170,12 +179,28 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
|
||||
Headers: headers,
|
||||
}
|
||||
case "grpc":
|
||||
network := GrpcNetworkConfig{}
|
||||
if len(n.NetworkSettings) != 0 {
|
||||
err := json.Unmarshal(n.NetworkSettings, &t.GRPCOptions)
|
||||
err := json.Unmarshal(n.NetworkSettings, &network)
|
||||
if err != nil {
|
||||
return option.Inbound{}, fmt.Errorf("decode NetworkSettings error: %s", err)
|
||||
}
|
||||
}
|
||||
t.GRPCOptions = option.V2RayGRPCOptions{
|
||||
ServiceName: network.ServiceName,
|
||||
}
|
||||
case "httpupgrade":
|
||||
network := HttpupgradeNetworkConfig{}
|
||||
if len(n.NetworkSettings) != 0 {
|
||||
err := json.Unmarshal(n.NetworkSettings, &network)
|
||||
if err != nil {
|
||||
return option.Inbound{}, fmt.Errorf("decode NetworkSettings error: %s", err)
|
||||
}
|
||||
}
|
||||
t.HTTPUpgradeOptions = option.V2RayHTTPUpgradeOptions{
|
||||
Path: network.Path,
|
||||
Host: network.Host,
|
||||
}
|
||||
}
|
||||
if info.Type == "vless" {
|
||||
in.Type = "vless"
|
||||
@@ -203,7 +228,7 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
|
||||
switch n.Cipher {
|
||||
case "2022-blake3-aes-128-gcm":
|
||||
keyLength = 16
|
||||
case "2022-blake3-aes-256-gcm":
|
||||
case "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305":
|
||||
keyLength = 32
|
||||
default:
|
||||
keyLength = 16
|
||||
@@ -263,12 +288,16 @@ func getInboundOptions(tag string, info *panel.NodeInfo, c *conf.Options) (optio
|
||||
Headers: headers,
|
||||
}
|
||||
case "grpc":
|
||||
network := GrpcNetworkConfig{}
|
||||
if len(n.NetworkSettings) != 0 {
|
||||
err := json.Unmarshal(n.NetworkSettings, &t.GRPCOptions)
|
||||
err := json.Unmarshal(n.NetworkSettings, &network)
|
||||
if err != nil {
|
||||
return option.Inbound{}, fmt.Errorf("decode NetworkSettings error: %s", err)
|
||||
}
|
||||
}
|
||||
t.GRPCOptions = option.V2RayGRPCOptions{
|
||||
ServiceName: network.ServiceName,
|
||||
}
|
||||
default:
|
||||
t.Type = ""
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ func New(c *conf.CoreConfig) (vCore.Core, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hs := NewHookServer(c.SingConfig.EnableConnClear)
|
||||
hs := NewHookServer(b.Router().GetCtx(), c.SingConfig.EnableConnClear)
|
||||
b.Router().SetClashServer(hs)
|
||||
return &Sing{
|
||||
ctx: b.Router().GetCtx(),
|
||||
|
||||
@@ -177,7 +177,8 @@ func (d *DefaultDispatcher) getLink(ctx context.Context, network net.Network) (*
|
||||
// Speed Limit and Device Limit
|
||||
w, reject := limit.CheckLimit(user.Email,
|
||||
sessionInbound.Source.Address.IP().String(),
|
||||
network == net.Network_TCP)
|
||||
network == net.Network_TCP,
|
||||
sessionInbound.Source.Network == net.Network_TCP)
|
||||
if reject {
|
||||
errors.LogInfo(ctx, "Limited ", user.Email, " by conn or ip")
|
||||
common.Close(outboundLink.Writer)
|
||||
@@ -241,7 +242,7 @@ func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResu
|
||||
protocolString = resComp.ProtocolForDomainResult()
|
||||
}
|
||||
for _, p := range request.OverrideDestinationForProtocol {
|
||||
if strings.HasPrefix(protocolString, p) || strings.HasPrefix(protocolString, p) {
|
||||
if strings.HasPrefix(protocolString, p) || strings.HasPrefix(p, protocolString) {
|
||||
return true
|
||||
}
|
||||
if fkr0, ok := d.fdns.(dns.FakeDNSEngineRev0); ok && protocolString != "bittorrent" && p == "fakedns" &&
|
||||
|
||||
@@ -190,7 +190,7 @@ func buildV2ray(config *conf.Options, nodeInfo *panel.NodeInfo, inbound *coreCon
|
||||
return nil
|
||||
}
|
||||
|
||||
t := coreConf.TransportProtocol(nodeInfo.VAllss.Network)
|
||||
t := coreConf.TransportProtocol(v.Network)
|
||||
inbound.StreamSetting = &coreConf.StreamConfig{Network: &t}
|
||||
switch v.Network {
|
||||
case "tcp":
|
||||
@@ -208,6 +208,26 @@ func buildV2ray(config *conf.Options, nodeInfo *panel.NodeInfo, inbound *coreCon
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshal grpc settings error: %s", err)
|
||||
}
|
||||
case "http":
|
||||
err := json.Unmarshal(v.NetworkSettings, &inbound.StreamSetting.HTTPSettings)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshal grpc settings error: %s", err)
|
||||
}
|
||||
case "quic":
|
||||
err := json.Unmarshal(v.NetworkSettings, &inbound.StreamSetting.QUICSettings)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshal grpc settings error: %s", err)
|
||||
}
|
||||
case "httpupgrade":
|
||||
err := json.Unmarshal(v.NetworkSettings, &inbound.StreamSetting.HTTPUPGRADESettings)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshal httpupgrade settings error: %s", err)
|
||||
}
|
||||
case "splithttp":
|
||||
err := json.Unmarshal(v.NetworkSettings, &inbound.StreamSetting.SplitHTTPSettings)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshal splithttp settings error: %s", err)
|
||||
}
|
||||
default:
|
||||
return errors.New("the network type is not vail")
|
||||
}
|
||||
|
||||
18
go.mod
18
go.mod
@@ -5,8 +5,8 @@ go 1.22
|
||||
toolchain go1.22.5
|
||||
|
||||
require (
|
||||
github.com/apernet/hysteria/core/v2 v2.5.1-0.20240702222552-458ee1386cc4
|
||||
github.com/apernet/hysteria/extras/v2 v2.5.1-0.20240702222552-458ee1386cc4
|
||||
github.com/apernet/hysteria/core/v2 v2.5.1-0.20240710201643-b563f3981fc6
|
||||
github.com/apernet/hysteria/extras/v2 v2.5.1-0.20240710201643-b563f3981fc6
|
||||
github.com/beevik/ntp v1.2.0
|
||||
github.com/fsnotify/fsnotify v1.7.0
|
||||
github.com/go-acme/lego/v4 v4.17.4
|
||||
@@ -14,12 +14,12 @@ require (
|
||||
github.com/goccy/go-json v0.10.3
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/juju/ratelimit v1.0.2
|
||||
github.com/sagernet/sing v0.5.0-alpha.12
|
||||
github.com/sagernet/sing-box v1.10.0
|
||||
github.com/sagernet/sing v0.5.0-alpha.13
|
||||
github.com/sagernet/sing-box v1.10.0-alpha.23
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/viper v1.15.0
|
||||
github.com/xtls/xray-core v1.8.17-0.20240708033233-ce637c0c232c
|
||||
github.com/xtls/xray-core v1.8.21
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/crypto v0.25.0
|
||||
golang.org/x/sys v0.22.0
|
||||
@@ -211,7 +211,7 @@ require (
|
||||
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 // indirect
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.27 // indirect
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 // indirect
|
||||
github.com/selectel/domains-go v1.1.0 // indirect
|
||||
github.com/selectel/go-selvpcclient/v3 v3.1.1 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
@@ -237,7 +237,7 @@ require (
|
||||
github.com/vishvananda/netlink v1.2.1-beta.2.0.20230316163032-ced5aaba43e3 // indirect
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
github.com/vultr/govultr/v2 v2.17.2 // indirect
|
||||
github.com/xtls/reality v0.0.0-20240429224917-ecc4401070cc // indirect
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d // indirect
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20240318083951-4fe6125f286e // indirect
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20240318084659-dfa50323a0b4 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
@@ -273,5 +273,5 @@ require (
|
||||
lukechampine.com/blake3 v1.3.0 // indirect
|
||||
)
|
||||
|
||||
//github.com/apernet/hysteria/core v1.3.5-0.20240201034858-bb99579bb92c => /root/hysteria/core
|
||||
replace github.com/sagernet/sing-box v1.10.0 => github.com/wyx2685/sing-box_mod v0.0.9
|
||||
// replace github.com/sagernet/sing-box v1.10.0-alpha.22 => /root/sing-box_mod
|
||||
replace github.com/sagernet/sing-box v1.10.0-alpha.23 => github.com/wyx2685/sing-box_mod v1.10.0-alpha.23
|
||||
|
||||
28
go.sum
28
go.sum
@@ -112,10 +112,10 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/apernet/hysteria/core/v2 v2.5.1-0.20240702222552-458ee1386cc4 h1:Dmxsp/nPY3ssoqkUO3OeEHE1zyE6hSix0lHtPirhAsg=
|
||||
github.com/apernet/hysteria/core/v2 v2.5.1-0.20240702222552-458ee1386cc4/go.mod h1:swZ3kYbiPIYNW5amiJdrUCfn+JTzGlICDpQHJZtG/qc=
|
||||
github.com/apernet/hysteria/extras/v2 v2.5.1-0.20240702222552-458ee1386cc4 h1:OLvBwyUl9auGo6lXAO83rfIzNVrEZafid2q3XkYylwY=
|
||||
github.com/apernet/hysteria/extras/v2 v2.5.1-0.20240702222552-458ee1386cc4/go.mod h1:vUBc13ojigSWAaiwUGbGqbNGXv8PtmiRk5JmsLC0dbA=
|
||||
github.com/apernet/hysteria/core/v2 v2.5.1-0.20240710201643-b563f3981fc6 h1:8JJ2Q9n3U49rHhMPfu4sAGMH4ppMh1ER4XErtF+1rH0=
|
||||
github.com/apernet/hysteria/core/v2 v2.5.1-0.20240710201643-b563f3981fc6/go.mod h1:swZ3kYbiPIYNW5amiJdrUCfn+JTzGlICDpQHJZtG/qc=
|
||||
github.com/apernet/hysteria/extras/v2 v2.5.1-0.20240710201643-b563f3981fc6 h1:IDAE/lE/cc0ituffxHPmrlN02ibiRpi/TbQ1nLDnLD0=
|
||||
github.com/apernet/hysteria/extras/v2 v2.5.1-0.20240710201643-b563f3981fc6/go.mod h1:vUBc13ojigSWAaiwUGbGqbNGXv8PtmiRk5JmsLC0dbA=
|
||||
github.com/apernet/quic-go v0.45.2-0.20240702221538-ed74cfbe8b6e h1:KBs8aBfKl5AKPKGpfn3bl0joDJXDq5fnH+AjFODiU+A=
|
||||
github.com/apernet/quic-go v0.45.2-0.20240702221538-ed74cfbe8b6e/go.mod h1:MjGWpXA31DZZWESdX3/PjIpSWIT1fOm8FNCqyXXFZFU=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
@@ -777,8 +777,8 @@ github.com/sagernet/quic-go v0.45.1-beta.2/go.mod h1:+N3FqM9DAzOWfe64uxXuBejVJwX
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||
github.com/sagernet/sing v0.5.0-alpha.12 h1:pjffG3SUpuF9PLDCqPO2fOAUozXItIBmnMVTKQ/QMhM=
|
||||
github.com/sagernet/sing v0.5.0-alpha.12/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.5.0-alpha.13 h1:fpR4TFZfu/9V3LbHSAnnnwcaXGMF8ijmAAPoY2WHSKw=
|
||||
github.com/sagernet/sing v0.5.0-alpha.13/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-dns v0.3.0-beta.10 h1:Js61EjQXVpcu2VDegWEQTH1isCcVwJju8WEHYgG4tQ0=
|
||||
github.com/sagernet/sing-dns v0.3.0-beta.10/go.mod h1:nXE6EYMXahB5DV3AcXYbFfuorqF7tbQ86kxweSxRKM4=
|
||||
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo=
|
||||
@@ -808,8 +808,8 @@ github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.27 h1:yGAraK1uUjlhSXgNMIy8o/J4LFNcy7yeipBqt9N9mVg=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.27/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U=
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 h1:emzAzMZ1L9iaKCTxdy3Em8Wv4ChIAGnfiz18Cda70g4=
|
||||
github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg=
|
||||
github.com/selectel/domains-go v1.1.0 h1:futG50J43ALLKQAnZk9H9yOtLGnSUh7c5hSvuC5gSHo=
|
||||
github.com/selectel/domains-go v1.1.0/go.mod h1:SugRKfq4sTpnOHquslCpzda72wV8u0cMBHx0C0l+bzA=
|
||||
github.com/selectel/go-selvpcclient/v3 v3.1.1 h1:C1q2LqqosiapoLpnGITGmysg0YCSQYDo2Gh69CioevM=
|
||||
@@ -941,16 +941,16 @@ github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1Y
|
||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs=
|
||||
github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI=
|
||||
github.com/wyx2685/sing-box_mod v0.0.9 h1:xxxPk107vFiAFiD8jOCCAHbNLPJ5Jgq5IJIi1Lil4NI=
|
||||
github.com/wyx2685/sing-box_mod v0.0.9/go.mod h1:0IErt79whUyLappgPDCSORcDQCP1kubkf9KW6FVqPOk=
|
||||
github.com/wyx2685/sing-box_mod v1.10.0-alpha.23 h1:DqByg8ldMTMXoUBLJO1fGhmOE7DavSR7Zlr1uYGl1ZY=
|
||||
github.com/wyx2685/sing-box_mod v1.10.0-alpha.23/go.mod h1:a9BYzpu6AtQHdiIkf2B059xPFd95jh9QKXS2EaX8p7E=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
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-20240429224917-ecc4401070cc h1:0Nj8T1n7F7+v4vRVroaJIvY6R0vNABLfPH+lzPHRJvI=
|
||||
github.com/xtls/reality v0.0.0-20240429224917-ecc4401070cc/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE=
|
||||
github.com/xtls/xray-core v1.8.17-0.20240708033233-ce637c0c232c h1:HqAL1uLn/MdQGzgc7DQBYGJ0w8SelFRYnaCjoXMCsKE=
|
||||
github.com/xtls/xray-core v1.8.17-0.20240708033233-ce637c0c232c/go.mod h1:OJ7TLCJp8If5yZVDIaOapGDe0ljBTYzwNpB9MA0ZIDY=
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d h1:+B97uD9uHLgAAulhigmys4BVwZZypzK7gPN3WtpgRJg=
|
||||
github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE=
|
||||
github.com/xtls/xray-core v1.8.21 h1:cNdepud+R9PENKzXlSZsq0je4BWI6liXAuep6CD6xvk=
|
||||
github.com/xtls/xray-core v1.8.21/go.mod h1:0CwyMPNA5Cs+ukPXHbYQGgne/ug0PuXOSVqBu7zyXOc=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20240318083951-4fe6125f286e h1:jLIqA7M9qY31g/Nw/5htVD0DFbxmLnlFZcHKJiG3osI=
|
||||
github.com/yandex-cloud/go-genproto v0.0.0-20240318083951-4fe6125f286e/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
|
||||
github.com/yandex-cloud/go-sdk v0.0.0-20240318084659-dfa50323a0b4 h1:wtzLQJmghkSUb1YkeFphIh7ST7NNVDaVOJZSAJcjMdw=
|
||||
|
||||
@@ -3,6 +3,7 @@ package limiter
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -48,6 +49,7 @@ type UserLimitInfo struct {
|
||||
DeviceLimit int
|
||||
DynamicSpeedLimit int
|
||||
ExpireTime int64
|
||||
OverLimit bool
|
||||
}
|
||||
|
||||
func AddLimiter(tag string, l *conf.LimitConfig, users []panel.UserInfo) *Limiter {
|
||||
@@ -69,6 +71,7 @@ func AddLimiter(tag string, l *conf.LimitConfig, users []panel.UserInfo) *Limite
|
||||
if users[i].DeviceLimit != 0 {
|
||||
userLimit.DeviceLimit = users[i].DeviceLimit
|
||||
}
|
||||
userLimit.OverLimit = false
|
||||
info.UserLimitInfo.Store(format.UserTag(tag, users[i].Uuid), userLimit)
|
||||
}
|
||||
info.UUIDtoUID = uuidmap
|
||||
@@ -110,6 +113,7 @@ func (l *Limiter) UpdateUser(tag string, added []panel.UserInfo, deleted []panel
|
||||
if added[i].DeviceLimit != 0 {
|
||||
userLimit.DeviceLimit = added[i].DeviceLimit
|
||||
}
|
||||
userLimit.OverLimit = false
|
||||
l.UserLimitInfo.Store(format.UserTag(tag, added[i].Uuid), userLimit)
|
||||
l.UUIDtoUID[added[i].Uuid] = added[i].Id
|
||||
}
|
||||
@@ -126,7 +130,10 @@ func (l *Limiter) UpdateDynamicSpeedLimit(tag, uuid string, limit int, expire ti
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Limiter) CheckLimit(taguuid string, ip string, isTcp bool) (Bucket *ratelimit.Bucket, Reject bool) {
|
||||
func (l *Limiter) CheckLimit(taguuid string, ip string, isTcp bool, noSSUDP bool) (Bucket *ratelimit.Bucket, Reject 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
|
||||
@@ -152,23 +159,24 @@ func (l *Limiter) CheckLimit(taguuid string, ip string, isTcp bool) (Bucket *rat
|
||||
userLimit = determineSpeedLimit(u.SpeedLimit, u.DynamicSpeedLimit)
|
||||
}
|
||||
}
|
||||
|
||||
// Store online user for device limit
|
||||
ipMap := new(sync.Map)
|
||||
ipMap.Store(ip, uid)
|
||||
// If any device is online
|
||||
if v, ok := l.UserOnlineIP.LoadOrStore(taguuid, ipMap); ok {
|
||||
ipMap := v.(*sync.Map)
|
||||
// If this is a new ip
|
||||
if _, ok := ipMap.LoadOrStore(ip, uid); !ok {
|
||||
counter := 0
|
||||
ipMap.Range(func(key, value interface{}) bool {
|
||||
counter++
|
||||
return true
|
||||
})
|
||||
if counter > deviceLimit && deviceLimit > 0 {
|
||||
ipMap.Delete(ip)
|
||||
return nil, true
|
||||
if noSSUDP {
|
||||
// Store online user for device limit
|
||||
ipMap := new(sync.Map)
|
||||
ipMap.Store(ip, uid)
|
||||
// If any device is online
|
||||
if v, ok := l.UserOnlineIP.LoadOrStore(taguuid, ipMap); ok {
|
||||
ipMap := v.(*sync.Map)
|
||||
// If this is a new ip
|
||||
if _, ok := ipMap.LoadOrStore(ip, uid); !ok {
|
||||
counter := 0
|
||||
ipMap.Range(func(key, value interface{}) bool {
|
||||
counter++
|
||||
return true
|
||||
})
|
||||
if counter > deviceLimit && deviceLimit > 0 {
|
||||
ipMap.Delete(ip)
|
||||
return nil, true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/InazumaV/V2bX/api/panel"
|
||||
@@ -60,7 +59,7 @@ func (c *Controller) reportUserTrafficTask() (err error) {
|
||||
data := make(map[int][]string)
|
||||
for _, onlineuser := range result {
|
||||
// json structure: { UID1:["ip1","ip2"],UID2:["ip3","ip4"] }
|
||||
data[onlineuser.UID] = append(data[onlineuser.UID], fmt.Sprintf("%s_%d", onlineuser.IP, c.info.Id))
|
||||
data[onlineuser.UID] = append(data[onlineuser.UID], onlineuser.IP)
|
||||
if _, ok := reportOnline[onlineuser.UID]; ok {
|
||||
reportOnline[onlineuser.UID]++
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user