From e528693c4050b17a6a8d7ed0d9363e788551a0b5 Mon Sep 17 00:00:00 2001 From: bitwiresys Date: Sat, 30 May 2026 08:44:29 +0300 Subject: [PATCH] feat(wireguard): WireGuard peers via Xray inbound UserManager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a WireGuard backend path that provisions/removes peers on Xray's WireGuard inbound through the UserManager gRPC API (AddUser/RemoveUser), so WG users can be managed at runtime without restarting the core — mirroring how the other Xray inbounds are handled. - backend/xray/api/wireguard_account.go: WireGuard account -> PeerConfig - backend/xray/api/wireguard_key.go: base64<->hex key helpers - backend/xray/wireguard_sync.go: push/sync WG peers via UserManager - backend/xray/{config,user,xray}.go, api/account.go: wire WG into the inbound/user flow - common/service.proto (+ regenerated service.pb.go): add Wireguard pre_shared_key field so PSK can be delivered to the node - bump xtls/xray-core to a revision that ships the WG inbound UserManager --- backend/xray/api/account.go | 1 + backend/xray/api/wireguard_account.go | 61 +++++++++++++++++++++++++++ backend/xray/api/wireguard_key.go | 31 ++++++++++++++ backend/xray/config.go | 32 +++++++++++++- backend/xray/user.go | 31 +++++++++++++- backend/xray/wireguard_sync.go | 58 +++++++++++++++++++++++++ backend/xray/xray.go | 6 +++ common/service.pb.go | 15 +++++-- common/service.proto | 1 + go.mod | 29 ++++++++----- go.sum | 58 +++++++++++++++---------- 11 files changed, 285 insertions(+), 38 deletions(-) create mode 100644 backend/xray/api/wireguard_account.go create mode 100644 backend/xray/api/wireguard_key.go create mode 100644 backend/xray/wireguard_sync.go diff --git a/backend/xray/api/account.go b/backend/xray/api/account.go index efaee4a..8af03be 100644 --- a/backend/xray/api/account.go +++ b/backend/xray/api/account.go @@ -205,4 +205,5 @@ type ProxySettings struct { Shadowsocks *ShadowsocksTcpAccount Shadowsocks2022 *ShadowsocksAccount Hysteria *HysteriaAccount + Wireguard *WireguardAccount } diff --git a/backend/xray/api/wireguard_account.go b/backend/xray/api/wireguard_account.go new file mode 100644 index 0000000..bd8e8e8 --- /dev/null +++ b/backend/xray/api/wireguard_account.go @@ -0,0 +1,61 @@ +package api + +import ( + "fmt" + + "github.com/xtls/xray-core/common/serial" + "github.com/xtls/xray-core/proxy/wireguard" + + "github.com/pasarguard/node/common" +) + +// WireguardAccount is a WireGuard peer for Xray inbound UserManager (email = hex public key). +type WireguardAccount struct { + BaseAccount + PublicKey string + PreSharedKey string + AllowedIPs []string +} + +func (wa *WireguardAccount) Message() (*serial.TypedMessage, error) { + return ToTypedMessage(&wireguard.PeerConfig{ + PublicKey: wa.PublicKey, + PreSharedKey: wa.PreSharedKey, + AllowedIps: wa.AllowedIPs, + }) +} + +func NewWireguardAccount(user *common.User) (*WireguardAccount, error) { + wg := user.GetProxies().GetWireguard() + if wg == nil || wg.GetPublicKey() == "" { + return nil, fmt.Errorf("wireguard public_key is required") + } + + pubHex, err := WireguardKeyToHex(wg.GetPublicKey()) + if err != nil { + return nil, fmt.Errorf("wireguard public_key: %w", err) + } + + pskHex := "" + if psk := wg.GetPreSharedKey(); psk != "" { + pskHex, err = WireguardKeyToHex(psk) + if err != nil { + return nil, fmt.Errorf("wireguard pre_shared_key: %w", err) + } + } + + allowed := wg.GetPeerIps() + if len(allowed) == 0 { + return nil, fmt.Errorf("wireguard peer_ips is required") + } + + return &WireguardAccount{ + BaseAccount: BaseAccount{ + Email: pubHex, + Level: 0, + }, + PublicKey: pubHex, + PreSharedKey: pskHex, + AllowedIPs: allowed, + }, nil +} diff --git a/backend/xray/api/wireguard_key.go b/backend/xray/api/wireguard_key.go new file mode 100644 index 0000000..473ec96 --- /dev/null +++ b/backend/xray/api/wireguard_key.go @@ -0,0 +1,31 @@ +package api + +import ( + "encoding/base64" + "encoding/hex" + "fmt" + "strings" +) + +// WireguardKeyToHex normalizes a WireGuard key from base64 (panel) or hex (Xray API) to hex. +func WireguardKeyToHex(key string) (string, error) { + key = strings.TrimSpace(key) + if key == "" { + return "", fmt.Errorf("empty wireguard key") + } + + if len(key) == 64 { + if _, err := hex.DecodeString(key); err == nil { + return key, nil + } + } + + raw, err := base64.StdEncoding.DecodeString(key) + if err != nil { + return "", fmt.Errorf("invalid wireguard key encoding: %w", err) + } + if len(raw) != 32 { + return "", fmt.Errorf("invalid wireguard key length: %d", len(raw)) + } + return hex.EncodeToString(raw), nil +} diff --git a/backend/xray/config.go b/backend/xray/config.go index 9ffa05e..8ff1395 100644 --- a/backend/xray/config.go +++ b/backend/xray/config.go @@ -25,6 +25,7 @@ const ( Trojan = "trojan" Shadowsocks = "shadowsocks" Hysteria = "hysteria" + Wireguard = "wireguard" ) type Config struct { @@ -98,7 +99,11 @@ func (c *Config) buildInboundUpdates(users []*common.User) (map[string]*Inbound, if isActive { update.accounts = append(update.accounts, account) } else { - update.removeEmailSet[userEmail] = struct{}{} + removeKey := userEmail + if inbound.Protocol == Wireguard && settings.Wireguard != nil { + removeKey = settings.Wireguard.GetEmail() + } + update.removeEmailSet[removeKey] = struct{}{} } } } @@ -199,6 +204,21 @@ func (i *Inbound) syncUsers(users []*common.User) { i.clients[user.GetEmail()] = api.NewHysteriaAccount(user) } } + + case Wireguard: + for _, user := range users { + if user.GetProxies().GetWireguard() == nil { + continue + } + if slices.Contains(user.Inbounds, i.Tag) { + account, err := api.NewWireguardAccount(user) + if err != nil { + log.Println("error for user", user.GetEmail(), ":", err) + continue + } + i.clients[account.GetEmail()] = account + } + } } } @@ -235,6 +255,9 @@ func (i *Inbound) updateUser(account api.Account) { case *api.HysteriaAccount: i.clients[email] = a + + case *api.WireguardAccount: + i.clients[email] = a } } @@ -291,6 +314,13 @@ func (i *Inbound) updateUsers(accounts []api.Account, removeEmails []string) { i.clients[account.GetEmail()] = a } } + + case Wireguard: + for _, account := range accounts { + if a, ok := account.(*api.WireguardAccount); ok { + i.clients[account.GetEmail()] = a + } + } } for _, email := range removeEmails { diff --git a/backend/xray/user.go b/backend/xray/user.go index 8ae7453..c44c8f7 100644 --- a/backend/xray/user.go +++ b/backend/xray/user.go @@ -40,6 +40,12 @@ func setupUserAccount(user *common.User) (api.ProxySettings, error) { settings.Hysteria = api.NewHysteriaAccount(user) } + if user.GetProxies().GetWireguard() != nil { + if wgAccount, err := api.NewWireguardAccount(user); err == nil { + settings.Wireguard = wgAccount + } + } + return settings, nil } @@ -114,11 +120,24 @@ func isActiveInbound(inbound *Inbound, inbounds []string, settings api.ProxySett return nil, false } return settings.Hysteria, true + + case Wireguard: + if settings.Wireguard == nil { + return nil, false + } + return settings.Wireguard, true } } return nil, false } +func wireguardRemoveEmail(inbound *Inbound, user *common.User, settings api.ProxySettings) string { + if inbound.Protocol != Wireguard || settings.Wireguard == nil { + return user.GetEmail() + } + return settings.Wireguard.GetEmail() +} + func (x *Xray) SyncUser(ctx context.Context, user *common.User) error { x.syncMu.Lock() defer x.syncMu.Unlock() @@ -140,7 +159,8 @@ func (x *Xray) SyncUser(ctx context.Context, user *common.User) error { continue } - _ = handler.RemoveInboundUser(ctx, inbound.Tag, user.Email) + removeEmail := wireguardRemoveEmail(inbound, user, proxySetting) + _ = handler.RemoveInboundUser(ctx, inbound.Tag, removeEmail) account, isActive := isActiveInbound(inbound, userInbounds, proxySetting) if isActive { inbound.updateUser(account) @@ -232,6 +252,15 @@ func (x *Xray) UpdateUsers(ctx context.Context, users []*common.User) error { inbound.updateUsers(update.accounts, removeEmails) for _, email := range removeEmails { + if inbound.Protocol == Wireguard { + for _, user := range users { + settings, _ := setupUserAccount(user) + if settings.Wireguard != nil && user.GetEmail() == email { + email = settings.Wireguard.GetEmail() + break + } + } + } handler.RemoveInboundUser(ctx, tag, email) } diff --git a/backend/xray/wireguard_sync.go b/backend/xray/wireguard_sync.go new file mode 100644 index 0000000..a8f680d --- /dev/null +++ b/backend/xray/wireguard_sync.go @@ -0,0 +1,58 @@ +package xray + +import ( + "context" + "errors" + "log" + "slices" + + "github.com/pasarguard/node/common" +) + +// pushWireguardPeers applies WG peers via Xray HandlerService (no process restart). +// Initial JSON should keep settings.peers empty; panel passes users on Start. +func (x *Xray) pushWireguardPeers(ctx context.Context, users []*common.User) error { + handler := x.handler + if handler == nil { + return errors.New("xray handler not ready") + } + + var errMessage string + applied := 0 + + for _, user := range users { + proxySetting, err := setupUserAccount(user) + if err != nil || proxySetting.Wireguard == nil { + continue + } + + userInbounds := user.GetInbounds() + for _, inbound := range x.config.InboundConfigs { + if inbound.exclude || inbound.Protocol != Wireguard { + continue + } + if !slices.Contains(userInbounds, inbound.Tag) { + continue + } + + account := proxySetting.Wireguard + _ = handler.RemoveInboundUser(ctx, inbound.Tag, account.GetEmail()) + inbound.updateUser(account) + if err := handler.AddInboundUser(ctx, inbound.Tag, accountForAPI(inbound, account)); err != nil { + log.Printf("wireguard add peer %s on %s: %v", account.GetEmail(), inbound.Tag, err) + errMessage += "\n" + err.Error() + continue + } + applied++ + } + } + + if applied > 0 { + log.Printf("wireguard: applied %d peer(s) via API", applied) + } + + if errMessage != "" { + return errors.New("failed to push wireguard peers:" + errMessage) + } + return nil +} diff --git a/backend/xray/xray.go b/backend/xray/xray.go index 205a611..dfbf7ae 100644 --- a/backend/xray/xray.go +++ b/backend/xray/xray.go @@ -95,6 +95,12 @@ func New(ctx context.Context, xrayConfig *Config, users []*common.User, apiPort, return nil, err } + if len(users) > 0 { + if err = xray.pushWireguardPeers(ctx, users); err != nil { + log.Printf("wireguard peer sync after start: %v", err) + } + } + // Wait a bit for Xray to fully initialize before starting health checks // This prevents false positives during startup go xray.checkXrayHealth(xCtx) diff --git a/common/service.pb.go b/common/service.pb.go index 0ce968b..77406ae 100644 --- a/common/service.pb.go +++ b/common/service.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v7.34.1 +// protoc v6.31.1 // source: common/service.proto package common @@ -1205,6 +1205,7 @@ type Wireguard struct { state protoimpl.MessageState `protogen:"open.v1"` PublicKey string `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` PeerIps []string `protobuf:"bytes,2,rep,name=peer_ips,json=peerIps,proto3" json:"peer_ips,omitempty"` + PreSharedKey string `protobuf:"bytes,3,opt,name=pre_shared_key,json=preSharedKey,proto3" json:"pre_shared_key,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1253,6 +1254,13 @@ func (x *Wireguard) GetPeerIps() []string { return nil } +func (x *Wireguard) GetPreSharedKey() string { + if x != nil { + return x.PreSharedKey + } + return "" +} + type Hysteria struct { state protoimpl.MessageState `protogen:"open.v1"` Auth string `protobuf:"bytes,1,opt,name=auth,proto3" json:"auth,omitempty"` @@ -1626,11 +1634,12 @@ const file_common_service_proto_rawDesc = "" + "\bpassword\x18\x01 \x01(\tR\bpassword\"A\n" + "\vShadowsocks\x12\x1a\n" + "\bpassword\x18\x01 \x01(\tR\bpassword\x12\x16\n" + - "\x06method\x18\x02 \x01(\tR\x06method\"E\n" + + "\x06method\x18\x02 \x01(\tR\x06method\"k\n" + "\tWireguard\x12\x1d\n" + "\n" + "public_key\x18\x01 \x01(\tR\tpublicKey\x12\x19\n" + - "\bpeer_ips\x18\x02 \x03(\tR\apeerIps\"\x1e\n" + + "\bpeer_ips\x18\x02 \x03(\tR\apeerIps\x12$\n" + + "\x0epre_shared_key\x18\x03 \x01(\tR\fpreSharedKey\"\x1e\n" + "\bHysteria\x12\x12\n" + "\x04auth\x18\x01 \x01(\tR\x04auth\"\x95\x02\n" + "\x05Proxy\x12$\n" + diff --git a/common/service.proto b/common/service.proto index 7ecfa6d..8642fd6 100644 --- a/common/service.proto +++ b/common/service.proto @@ -131,6 +131,7 @@ message Shadowsocks { message Wireguard { string public_key = 1; repeated string peer_ips = 2; + string pre_shared_key = 3; } message Hysteria { diff --git a/go.mod b/go.mod index ab4187f..7889c17 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/joho/godotenv v1.5.1 github.com/shirou/gopsutil/v4 v4.26.6 github.com/vishvananda/netlink v1.3.1 - github.com/xtls/xray-core v1.260327.0 + github.com/xtls/xray-core v1.260327.1-0.20260627131803-45cf2898ab12 golang.org/x/sys v0.46.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 google.golang.org/grpc v1.82.0 @@ -18,8 +18,8 @@ require ( require ( github.com/andybalholm/brotli v1.1.0 // indirect - github.com/apernet/quic-go v0.59.1-0.20260217092621-db4786c77a22 // indirect - github.com/cloudflare/circl v1.6.3 // indirect + github.com/apernet/quic-go v0.59.1-0.20260425001925-6c6cc9bcb716 // indirect + github.com/cloudflare/circl v1.6.4 // indirect github.com/ebitengine/purego v0.10.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/google/btree v1.1.2 // indirect @@ -34,29 +34,36 @@ require ( github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/socket v0.5.1 // indirect github.com/miekg/dns v1.1.72 // indirect - github.com/pires/go-proxyproto v0.11.0 // indirect + github.com/pion/dtls/v3 v3.1.4 // indirect + github.com/pion/logging v0.2.4 // indirect + github.com/pion/stun/v3 v3.1.6 // indirect + github.com/pion/transport/v4 v4.0.2 // indirect + github.com/pires/go-proxyproto v0.12.0 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/quic-go/qpack v0.6.0 // indirect github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/sagernet/sing v0.5.1 // indirect github.com/sagernet/sing-shadowsocks v0.2.7 // indirect github.com/tklauser/go-sysconf v0.3.16 // indirect github.com/tklauser/numcpus v0.11.0 // indirect github.com/vishvananda/netns v0.0.5 // indirect + github.com/wlynxg/anet v0.0.5 // indirect github.com/xtls/reality v0.0.0-20260322125925-9234c772ba8f // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/crypto v0.50.0 // indirect + golang.org/x/crypto v0.53.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/mod v0.34.0 // indirect - golang.org/x/net v0.53.0 // indirect - golang.org/x/sync v0.20.0 // indirect - golang.org/x/text v0.36.0 // indirect - golang.org/x/time v0.12.0 // indirect - golang.org/x/tools v0.43.0 // indirect + golang.org/x/mod v0.36.0 // indirect + golang.org/x/net v0.56.0 // indirect + golang.org/x/sync v0.21.0 // indirect + golang.org/x/text v0.38.0 // indirect + golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.45.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb // indirect + golang.zx2c4.com/wireguard/windows v1.0.1 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0 // indirect lukechampine.com/blake3 v1.4.1 // indirect diff --git a/go.sum b/go.sum index bb1b93e..f3ae4cb 100644 --- a/go.sum +++ b/go.sum @@ -2,15 +2,15 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/apernet/quic-go v0.59.1-0.20260217092621-db4786c77a22 h1:00ziBGnLWQEcR9LThDwvxOznJJquJ9bYUdmBFnawLMU= -github.com/apernet/quic-go v0.59.1-0.20260217092621-db4786c77a22/go.mod h1:Npbg8qBtAZlsAB3FWmqwlVh5jtVG6a4DlYsOylUpvzA= +github.com/apernet/quic-go v0.59.1-0.20260425001925-6c6cc9bcb716 h1:J1O+xpLuJWkdYbw5JPGwBqIHs2J8tiEP7Py9lPqkN2I= +github.com/apernet/quic-go v0.59.1-0.20260425001925-6c6cc9bcb716/go.mod h1:Npbg8qBtAZlsAB3FWmqwlVh5jtVG6a4DlYsOylUpvzA= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8= -github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= +github.com/cloudflare/circl v1.6.4 h1:pOXuDTCEYyzydgUpQ0CQz3LsinKjiSk6nNP5Lt5K64U= +github.com/cloudflare/circl v1.6.4/go.mod h1:YxarevkLlbaHuWsxG6vmYNWBEsSp4pnp7j+4VljMavY= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -92,8 +92,16 @@ github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCL github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pires/go-proxyproto v0.11.0 h1:gUQpS85X/VJMdUsYyEgyn59uLJvGqPhJV5YvG68wXH4= -github.com/pires/go-proxyproto v0.11.0/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU= +github.com/pion/dtls/v3 v3.1.4 h1:QhvtMflMfu9Kf0RcDC5BJBle4caPskByrKQR6uuYqpY= +github.com/pion/dtls/v3 v3.1.4/go.mod h1:cr/qotLISUw/9C1m83ZPNZtj9WnXkYLpfCptPqbkInc= +github.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8= +github.com/pion/logging v0.2.4/go.mod h1:DffhXTKYdNZU+KtJ5pyQDjvOAh/GsNSyv1lbkFbe3so= +github.com/pion/stun/v3 v3.1.6 h1:WnhsD0eHCiwCfKNkVx0VJJwr2Y3eV4Ueih3KJ+dfZy8= +github.com/pion/stun/v3 v3.1.6/go.mod h1:zRUghXSQU32Lx5orJsz3uYMkIihweXb3mu5gIns02fs= +github.com/pion/transport/v4 v4.0.2 h1:ifYlPqNwsy6aKQ9y8yzxXlHae5431ZrH2avkD/Rn6Tk= +github.com/pion/transport/v4 v4.0.2/go.mod h1:06hFI+jCFcok2X2MekVufNZ/uzNZXivGBPfviSVcjgM= +github.com/pires/go-proxyproto v0.12.0 h1:TTCxD66dU898tahivkqc3hoceZp7P44FnorWyo9d5vM= +github.com/pires/go-proxyproto v0.12.0/go.mod h1:qUvfqUMEoX7T8g0q7TQLDnhMjdTrxnG0hvpMn+7ePNI= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -104,6 +112,8 @@ github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af h1:er2acxbi3N1nvEq6HXHUAR1nTWEJmQfqiGR8EVT9rfs= github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y= @@ -129,10 +139,12 @@ github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4= github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= +github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= github.com/xtls/reality v0.0.0-20260322125925-9234c772ba8f h1:iy2JRioxmUpoJ3SzbFPyTxHZMbR/rSHP7dOOgYaq1O8= github.com/xtls/reality v0.0.0-20260322125925-9234c772ba8f/go.mod h1:DsJblcWDGt76+FVqBVwbwRhxyyNJsGV48gJLch0OOWI= -github.com/xtls/xray-core v1.260327.0 h1:g4TzxMwyPrxslZh6uD+FiG3lXKTrnNO+b4ky2OhogHE= -github.com/xtls/xray-core v1.260327.0/go.mod h1:OXMlhBloFry8mw0KwWLWLd3RQyXJzEYsCGlgsX36h60= +github.com/xtls/xray-core v1.260327.1-0.20260627131803-45cf2898ab12 h1:0RZBYuLmkxxlMrSsCNRrdNWHhW5zHTfkC2vAknzZ5P4= +github.com/xtls/xray-core v1.260327.1-0.20260627131803-45cf2898ab12/go.mod h1:5J11wfaLGhI6HNOi90zVI6E87c1ykA8grPfUeHZYbhA= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= @@ -160,8 +172,8 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/W golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= -golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= +golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= @@ -171,8 +183,8 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= -golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= +golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= +golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -181,16 +193,16 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= -golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= -golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -206,10 +218,10 @@ golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= -golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= -golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= -golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= +golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -219,8 +231,8 @@ golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= -golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= +golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= +golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -231,6 +243,8 @@ golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb h1:whnFRlWMcXI9d+Z golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb/go.mod h1:rpwXGsirqLqN2L0JDJQlwOboGHmptD5ZD6T2VmcqhTw= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 h1:3GDAcqdIg1ozBNLgPy4SLT84nfcBjr6rhGtXYtrkWLU= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10/go.mod h1:T97yPqesLiNrOYxkwmhMI0ZIlJDm+p0PMR8eRVeR5tQ= +golang.zx2c4.com/wireguard/windows v1.0.1 h1:eOxiDVbywPC+ZQqvdCK7x+ZwWXKbYv50TtH8ysFIbw8= +golang.zx2c4.com/wireguard/windows v1.0.1/go.mod h1:+fbT3FFdX4zzYDLwJh5+HPEcNN/3HyNdzhNSVsQM+zs= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=