Compare commits

..

10 Commits

Author SHA1 Message Date
Shtorm
df39546485 Merge commit 'b19e232df23e115ab99b9a797f8d5c28dfce6809' into extended 2026-07-16 11:17:27 +03:00
Shtorm
4624fd51b1 Fixes and improvements 2026-07-16 11:16:10 +03:00
Shtorm
b19e232df2 Merge pull request #105 from Arsolitt/feat/provider-custom-headers
feat(provider): add custom HTTP headers support for remote providers
2026-07-03 09:52:06 +03:00
Arsolitt
1e826a201d feat(provider): add custom HTTP headers support for remote providers
Some subscription panels (e.g. Remnawave with incy/happ integration)
require device-identification headers to return the real server list
instead of a dummy config. Add a 'headers' field to the remote provider
options so users can attach arbitrary HTTP headers to subscription
fetch requests.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
2026-07-01 21:58:01 +03:00
Shtorm
a27453e4f7 Merge pull request #97 from v14d4n/feat/masque-configurable-sni
Make masque TLS SNI configurable via server_name
2026-06-26 14:39:20 +03:00
Shtorm
2a77348470 Update README.md 2026-06-26 04:04:01 +03:00
Shtorm
1ae82a483a Merge branch 'extended' of https://github.com/shtorm-7/sing-box-extended into extended 2026-06-26 03:51:16 +03:00
Shtorm
31acf60eca Fix examples
Signed-off-by: Shtorm <108103062+shtorm-7@users.noreply.github.com>
2026-06-25 15:54:57 +03:00
v14d4n
7bfad732e2 feat(masque): make TLS SNI configurable via server_name
MASQUE outbound previously hardcoded the TLS SNI to consumer-masque.cloudflareclient.com. Add a server_name field to the MASQUE outbound TLS options. When empty it falls back to the existing default (cloudflare.ConnectSNI), so existing configs are unaffected.
2026-06-22 14:12:40 +04:00
Shtorm
2cbc7691f0 Update Telegram badge from channel to chat
Signed-off-by: Shtorm <108103062+shtorm-7@users.noreply.github.com>
2026-06-15 10:43:03 +03:00
36 changed files with 1218 additions and 1477 deletions

View File

@@ -131,7 +131,7 @@ upload_android:
./codeberg-release.sh --replace --draft --prerelease -p 5 "v${VERSION}" dist/release_android
rm -rf dist/release_android
release_android: build_android upload_android
release_android: lib_android update_android_version build_android upload_android
publish_android:
cd ../sing-box-for-android && ./gradlew :app:publishPlayReleaseBundle && ./gradlew --stop

View File

@@ -3,7 +3,7 @@
[![license](https://img.shields.io/badge/license-GPLv3-blue.svg)](LICENSE)
[![go](https://img.shields.io/badge/go-1.26-00ADD8.svg)](go.mod)
[![codeberg](https://img.shields.io/badge/mirror-codeberg-2185D0.svg)](https://codeberg.org/shtorm-7/sing-box-extended)
[![telegram](https://img.shields.io/badge/telegram-channel-26A5E4.svg)](https://t.me/sing_box_extended)
[![telegram](https://img.shields.io/badge/telegram-chat-26A5E4.svg)](https://t.me/sing_box_extended)
Sing-box with extended features.
@@ -17,6 +17,7 @@ Sing-box with extended features.
- **OpenVPN** — OpenVPN client with tls-auth, tls-crypt and tls-crypt-v2 support
- **TrustTunnel** — AdGuard's obfuscated VPN protocol, indistinguishable from HTTPS traffic
- **Sudoku** — Traffic obfuscation protocol based on 4×4 Sudoku puzzles with low-entropy fingerprints
- **Snell** — Lightweight encrypted proxy (v1v5) with TLS / HTTP obfuscation
- **SSH** — SSH client and server with certificate authentication and upstream fallback
- **VPN** — Routed tunnel over any TCP sing-box protocol
- **Bond** — Link aggregation for increasing throughput

View File

@@ -1,4 +1,4 @@
package sqlite
package sql
import (
"encoding/json"

29
common/sql/json.go Normal file
View File

@@ -0,0 +1,29 @@
package sql
import (
"encoding/json"
"fmt"
)
type SliceJSON[T any] []T
func (s *SliceJSON[T]) Scan(src interface{}) error {
if src == nil {
*s = nil
return nil
}
var data []byte
switch v := src.(type) {
case []byte:
data = v
case string:
data = []byte(v)
default:
return fmt.Errorf("sliceJSON.Scan: unsupported type %T", src)
}
if len(data) == 0 {
*s = nil
return nil
}
return json.Unmarshal(data, (*[]T)(s))
}

53
common/sql/timestamp.go Normal file
View File

@@ -0,0 +1,53 @@
package sql
import (
"time"
"github.com/huandu/go-sqlbuilder"
E "github.com/sagernet/sing/common/exceptions"
)
const timestampFormat = "2006-01-02 15:04:05.000"
func FormatTimestamp(t time.Time) string {
return t.UTC().Format(timestampFormat)
}
func ParseTimestamp(value string) (time.Time, error) {
return time.ParseInLocation(timestampFormat, value, time.UTC)
}
func ParseFilterTimestamp(value string) (time.Time, error) {
if t, err := time.Parse(time.RFC3339Nano, value); err == nil {
return t, nil
}
if t, err := time.Parse(time.RFC3339, value); err == nil {
return t, nil
}
if t, err := ParseTimestamp(value); err == nil {
return t, nil
}
return time.Time{}, E.New("invalid timestamp: ", value)
}
func TimestampGreaterEqualThanFilter(field string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
t, err := ParseFilterTimestamp(value[0])
if err != nil {
return err
}
sb.Where(sb.GreaterEqualThan(field, FormatTimestamp(t)))
return nil
}
}
func TimestampLessEqualThanFilter(field string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
t, err := ParseFilterTimestamp(value[0])
if err != nil {
return err
}
sb.Where(sb.LessEqualThan(field, FormatTimestamp(t)))
return nil
}
}

View File

@@ -107,6 +107,10 @@ func extractNegativeTTL(response *dns.Msg) (uint32, bool) {
}
func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, message *dns.Msg, options adapter.DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) (*dns.Msg, error) {
transportStack := transportStackFromContext(ctx)
if containsTransport(transportStack, transport.Tag()) {
return nil, E.New("DNS resolution loop detected: ", formatTransportLoop(transportStack, transport.Tag()))
}
if len(message.Question) == 0 {
if c.logger != nil {
c.logger.WarnContext(ctx, "bad question size: ", len(message.Question))
@@ -137,6 +141,7 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
len(message.Extra[0].(*dns.OPT).Option) == 0) &&
!options.ClientSubnet.IsValid()
disableCache := !isSimpleRequest || c.disableCache || options.DisableCache
ctx = contextWithTransportStack(ctx, append(transportStack, transport.Tag()))
if !disableCache {
cacheKey := transportCacheKey{Question: question, transportTag: transport.Tag()}
if c.cache != nil {
@@ -177,11 +182,6 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
}
messageId := message.Id
contextTransport, clientSubnetLoaded := transportTagFromContext(ctx)
if clientSubnetLoaded && transport.Tag() == contextTransport {
return nil, E.New("DNS query loopback in transport[", contextTransport, "]")
}
ctx = contextWithTransportTag(ctx, transport.Tag())
if !disableCache && responseChecker != nil && c.rdrc != nil {
rejected := c.rdrc.LoadRDRC(transport.Tag(), question.Name, question.Qtype)
if rejected {
@@ -547,15 +547,36 @@ func MessageToAddresses(response *dns.Msg) []netip.Addr {
return addresses
}
type transportKey struct{}
type transportStackKey struct{}
func contextWithTransportTag(ctx context.Context, transportTag string) context.Context {
return context.WithValue(ctx, transportKey{}, transportTag)
func contextWithTransportStack(ctx context.Context, stack []string) context.Context {
return context.WithValue(ctx, transportStackKey{}, stack)
}
func transportTagFromContext(ctx context.Context) (string, bool) {
value, loaded := ctx.Value(transportKey{}).(string)
return value, loaded
func transportStackFromContext(ctx context.Context) []string {
value, _ := ctx.Value(transportStackKey{}).([]string)
return value
}
func containsTransport(stack []string, tag string) bool {
for _, t := range stack {
if t == tag {
return true
}
}
return false
}
func formatTransportLoop(stack []string, loopTag string) string {
result := ""
for i, t := range stack {
if i > 0 {
result += " -> "
}
result += t
}
result += " -> " + loopTag
return result
}
func FixedResponseStatus(message *dns.Msg, rcode int) *dns.Msg {

View File

@@ -66,7 +66,7 @@
"action": "hijack-dns"
}
],
"final": "connection-limiter"
"final": "traffic-limiter"
},
"services": [
{

View File

@@ -42,6 +42,7 @@
"congestion_controller": "bbr",
"cwnd": 0,
"tls": { // TLS fields for HTTP2
"server_name": "", // SNI; empty = default "consumer-masque.cloudflareclient.com"
"insecure": false,
"cipher_suites": [],
"curve_preferences": [],

View File

@@ -47,6 +47,30 @@
// shareable links, or plain link list.
"url": "https://example.com/subscription.txt",
"user_agent": "sing-box",
// Custom HTTP headers sent with each subscription request.
// Some subscription panels (e.g. Remnawave with incy/happ
// integration) require device-identification headers to
// return the real server list instead of a dummy config.
//
// !!! DO NOT COPY THE VALUE BELOW !!!
// x-hwid must be generated per-device. A random UUID will
// be rejected by the panel. Generate yours on Linux:
//
// python3 -c "import hashlib,socket,getpass;m=open('/etc/machine-id').read().strip();d=hashlib.sha256(f'{m}|{socket.gethostname()}|Linux|amd64|{getpass.getuser()}'.encode()).hexdigest();h=hashlib.sha256(('incy_hwid_'+d).encode()).hexdigest();print(f'{h[:8]}-{h[8:12]}-{h[12:16]}-{h[16:20]}-{h[20:32]}'.upper())"
//
// Algorithm: SHA256("incy_hwid_" + SHA256(deviceId))
// Linux deviceId: "machineId|hostname|Linux|amd64|user"
// Android deviceId: "androidId|manufacturer|model|brand|device|product|board|hardware"
// Ref: https://github.com/INCY-DEV/incy-docs/blob/main/ru/dev-docs/hwid.md
"headers": {
"x-hwid": ["REPLACE_WITH_GENERATED_HWID"],
// Platform: linux, android, ios, windows, macos
"x-device-os": ["linux"],
// OS version — on Linux: uname -r
"x-ver-os": ["6.12.0-arch1-1"],
// Device model — on Linux: uname -m
"x-device-model": ["x86_64"]
},
// Fetch the subscription through this outbound instead of the
// default route (useful when the subscription host is blocked).
"download_detour": "direct",

View File

@@ -14,23 +14,43 @@
{
"type": "warp",
"tag": "warp-out",
"system": false,
"name": "warp0",
"listen_port": 10000,
"udp_timeout": "5m0s",
"persistent_keepalive_interval": 25,
"workers": 8,
"preallocated_buffers_per_pool": 256,
"disable_pauses": true,
"amnezia": {
"jc": 120,
"jmin": 23,
"jmax": 911,
"s1": 1,
"s2": 2,
"s3": 3,
"s4": 4,
"h1": 1,
"h2": 2,
"h3": 3,
"h4": 4
"h4": 4,
"i1": "<b 0xc70000000108...",
"i2": "<b 0xc70000000108...",
"i3": "<b 0xc70000000108...",
"i4": "<b 0xc70000000108...",
"i5": "<b 0xc70000000108...",
"j1": "<b 0xc70000000108...",
"j2": "<b 0xc70000000108...",
"j3": "<b 0xc70000000108...",
"itime": 50
},
"profile": {
"detour": "direct",
// For getting existing WARP device profile, else sing-box will create new profile
"id": "",
"private_key": "",
"auth_token": ""
"auth_token": "",
"recreate": false
}
// Dial Fields
}

35
go.mod
View File

@@ -60,14 +60,14 @@ require (
github.com/stretchr/testify v1.11.1
github.com/vishvananda/netns v0.0.5
github.com/yosida95/uritemplate/v3 v3.0.2
go.uber.org/zap v1.27.1
go.uber.org/zap v1.28.0
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
golang.org/x/crypto v0.49.0
golang.org/x/crypto v0.53.0
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90
golang.org/x/mod v0.34.0
golang.org/x/net v0.52.0
golang.org/x/sync v0.20.0
golang.org/x/sys v0.42.0
golang.org/x/mod v0.36.0
golang.org/x/net v0.56.0
golang.org/x/sync v0.21.0
golang.org/x/sys v0.46.0
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10
google.golang.org/grpc v1.79.1
google.golang.org/protobuf v1.36.11
@@ -81,10 +81,12 @@ require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/docker/docker v28.5.2+incompatible // indirect
github.com/docker/go-connections v0.6.0 // indirect
github.com/docker/go-connections v0.7.0 // indirect
github.com/dunglas/httpsfv v1.1.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/panjf2000/ants/v2 v2.12.0 // indirect
@@ -93,7 +95,9 @@ require (
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/tylertreat/BoomFilters v0.0.0-20251117164519-53813c36cc1b // indirect
github.com/zeebo/assert v1.3.0 // indirect
go.opentelemetry.io/otel v1.41.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect
go.opentelemetry.io/otel v1.44.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.44.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
gvisor.dev/gvisor v0.0.0-20260408064518-65a410b0d584 // indirect
modernc.org/libc v1.72.0 // indirect
@@ -109,7 +113,7 @@ require (
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
github.com/ameshkov/dnscrypt/v2 v2.4.0
github.com/ameshkov/dnsstamps v1.0.3 // indirect
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/andybalholm/brotli v1.2.1 // indirect
github.com/caddyserver/zerossl v0.1.5 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect
@@ -118,7 +122,7 @@ require (
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 // indirect
github.com/dolonet/mtg-multi v1.8.0
github.com/ebitengine/purego v0.10.0 // indirect
github.com/ebitengine/purego v0.10.1 // indirect
github.com/florianl/go-nfqueue/v2 v2.0.2 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
@@ -135,7 +139,6 @@ require (
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
github.com/huandu/go-clone v1.7.3 // indirect
@@ -145,7 +148,7 @@ require (
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jsimonetti/rtnetlink v1.4.0 // indirect
github.com/klauspost/compress v1.18.3 // indirect
github.com/klauspost/compress v1.18.6 // indirect
github.com/klauspost/cpuid/v2 v2.3.0
github.com/leodido/go-urn v1.4.0 // indirect
github.com/libdns/libdns v1.1.1 // indirect
@@ -153,7 +156,7 @@ require (
github.com/mdlayher/netlink v1.9.0 // indirect
github.com/mdlayher/socket v0.5.1 // indirect
github.com/mitchellh/go-ps v1.0.0 // indirect
github.com/pierrec/lz4/v4 v4.1.25 // indirect
github.com/pierrec/lz4/v4 v4.1.27 // indirect
github.com/pires/go-proxyproto v0.11.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus-community/pro-bing v0.4.0 // indirect
@@ -209,10 +212,10 @@ require (
go.uber.org/zap/exp v0.3.0 // indirect
go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect
golang.org/x/oauth2 v0.34.0 // indirect
golang.org/x/term v0.41.0 // indirect
golang.org/x/text v0.35.0 // indirect
golang.org/x/term v0.44.0 // indirect
golang.org/x/text v0.38.0 // indirect
golang.org/x/time v0.12.0
golang.org/x/tools v0.43.0 // indirect
golang.org/x/tools v0.45.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect

89
go.sum
View File

@@ -6,8 +6,8 @@ github.com/AdguardTeam/golibs v0.32.7 h1:3dmGlAVgmvquCCwHsvEl58KKcRAK3z1UnjMnwSI
github.com/AdguardTeam/golibs v0.32.7/go.mod h1:bE8KV1zqTzgZjmjFyBJ9f9O5DEKO717r7e57j1HclJA=
github.com/AliRizaAynaci/gorl/v2 v2.2.0 h1:E8oAwkordOwm9ItNNVJ5VKvGroDcHvWNvG11HaCVLZI=
github.com/AliRizaAynaci/gorl/v2 v2.2.0/go.mod h1:13wcj/W736v44b6uygUuwypMY9N3RXJuhAYXukIIdCo=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
@@ -20,8 +20,8 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7V
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eTWro=
github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/anthropics/anthropic-sdk-go v1.26.0 h1:oUTzFaUpAevfuELAP1sjL6CQJ9HHAfT7CoSYSac11PY=
github.com/anthropics/anthropic-sdk-go v1.26.0/go.mod h1:qUKmaW+uuPB64iy1l+4kOSvaLqPXnHTTBKH6RVZ7q5Q=
github.com/anytls/sing-anytls v0.0.11 h1:w8e9Uj1oP3m4zxkyZDewPk0EcQbvVxb7Nn+rapEx4fc=
@@ -79,16 +79,16 @@ github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c=
github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dunglas/httpsfv v1.1.0 h1:Jw76nAyKWKZKFrpMMcL76y35tOpYHqQPzHQiwDvpe54=
github.com/dunglas/httpsfv v1.1.0/go.mod h1:zID2mqw9mFsnt7YC3vYQ9/cjq30q41W+1AnDwH8TiMg=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU=
github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/ebitengine/purego v0.10.1 h1:dewVBCBT2GaMu1SrNTYxQhgQBethzfhiwvZiLGP/qyY=
github.com/ebitengine/purego v0.10.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/enfein/mieru/v3 v3.33.0 h1:hv2jK8nqYHwpSG86U2rpZR2I8Aff1/J3ifRmd9NBbFc=
github.com/enfein/mieru/v3 v3.33.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
@@ -189,8 +189,8 @@ github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUF
github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E=
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw=
github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -233,8 +233,8 @@ github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
@@ -253,8 +253,8 @@ github.com/panjf2000/ants/v2 v2.12.0 h1:u9JhESo83i/GkZnhfTNuFMMWcNt7mnV1bGJ6FT4w
github.com/panjf2000/ants/v2 v2.12.0/go.mod h1:tSQuaNQ6r6NRhPt+IZVUevvDyFMTs+eS4ztZc52uJTY=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pierrec/lz4/v4 v4.1.25 h1:kocOqRffaIbU5djlIBr7Wh+cx82C0vtFb0fOurZHqD0=
github.com/pierrec/lz4/v4 v4.1.25/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
github.com/pierrec/lz4/v4 v4.1.27 h1:+PhzhWDrjRj89TH2sw43nE3+4+W8lSxIuQadEHZyjUk=
github.com/pierrec/lz4/v4 v4.1.27/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -461,71 +461,72 @@ github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo=
go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q=
go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U=
go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
go4.org/mem v0.0.0-20240501181205-ae6ca9944745 h1:Tl++JLUCe4sxGu8cTpDzRLd3tN7US4hOxG5YpKCzkek=
go4.org/mem v0.0.0-20240501181205-ae6ca9944745/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
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-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
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.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
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/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
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.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=

View File

@@ -24,6 +24,7 @@ type MASQUEOutboundOptions struct {
}
type MASQUEOutboundTLSOptions struct {
ServerName string `json:"server_name,omitempty"`
Insecure bool `json:"insecure,omitempty"`
CipherSuites badoption.Listable[string] `json:"cipher_suites,omitempty"`
CurvePreferences badoption.Listable[CurvePreference] `json:"curve_preferences,omitempty"`

View File

@@ -55,6 +55,7 @@ type ProviderLocalOptions struct {
type ProviderRemoteOptions struct {
URL string `json:"url"`
UserAgent string `json:"user_agent,omitempty"`
Headers badoption.HTTPHeader `json:"headers,omitempty"`
DownloadDetour string `json:"download_detour,omitempty"`
UpdateInterval badoption.Duration `json:"update_interval,omitempty"`

View File

@@ -8,7 +8,6 @@ type WARPEndpointOptions struct {
ListenPort uint16 `json:"listen_port,omitempty"`
UDPTimeout badoption.Duration `json:"udp_timeout,omitempty"`
PersistentKeepaliveInterval uint16 `json:"persistent_keepalive_interval,omitempty"`
Reserved []uint8 `json:"reserved,omitempty"`
Workers int `json:"workers,omitempty"`
PreallocatedBuffersPerPool uint32 `json:"preallocated_buffers_per_pool,omitempty"`
DisablePauses bool `json:"disable_pauses,omitempty"`

View File

@@ -76,6 +76,15 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
return outbound, nil
}
func (h *Outbound) Start(stage adapter.StartStage) error {
for _, outbound := range h.outbounds {
if err := adapter.LegacyStart(outbound, stage); err != nil {
return err
}
}
return nil
}
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
if N.NetworkName(network) == N.NetworkUDP {
return h.uotClient.DialContext(ctx, network, destination)

View File

@@ -99,9 +99,9 @@ func (h *Inbound) connHandler(ctx context.Context, conn net.Conn, metadata adapt
failoverConn := NewFailoverConn(ctx, conn, nil, func() {
h.sessionMtx.Lock(sessionUUID)
h.mtx.Lock()
defer h.sessionMtx.Unlock(sessionUUID)
defer h.mtx.Unlock()
delete(h.conns, sessionUUID)
h.sessionMtx.Unlock(sessionUUID)
h.mtx.Unlock()
})
h.mtx.Lock()
h.conns[sessionUUID] = failoverConn
@@ -118,6 +118,7 @@ func (h *Inbound) connHandler(ctx context.Context, conn net.Conn, metadata adapt
serverConn, ok := h.conns[sessionUUID]
h.mtx.RUnlock()
if !ok {
h.sessionMtx.Unlock(sessionUUID)
_, err := conn.Write([]byte{StatusSessionNotFound})
if err != nil {
return err

View File

@@ -70,7 +70,7 @@ func (c *Config) SelectEndpointFromConfig(useHTTP2 bool, useIPv6 bool, port int)
v4 := c.EndpointH2V4
ip := net.ParseIP(v4)
if ip == nil {
return nil, fmt.Errorf("invalid endpoint_h2_v4 value %q")
return nil, fmt.Errorf("invalid endpoint_h2_v4 value %q", v4)
}
return &net.TCPAddr{IP: ip, Port: port}, nil
}

View File

@@ -102,7 +102,11 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
logger.ErrorContext(ctx, E.New("failed to generate cert: ", err))
return
}
tlsConfig, err := tls.NewMASQUEClient(ctx, logger, "consumer-masque.cloudflareclient.com", cert, privKey, peerPubKey, common.PtrValueOrDefault(options.TLS))
serverName := cloudflare.ConnectSNI
if options.TLS != nil && options.TLS.ServerName != "" {
serverName = options.TLS.ServerName
}
tlsConfig, err := tls.NewMASQUEClient(ctx, logger, serverName, cert, privKey, peerPubKey, common.PtrValueOrDefault(options.TLS))
if err != nil {
logger.ErrorContext(ctx, E.New("failed to prepare TLS config: ", err))
return

View File

@@ -59,6 +59,7 @@ type ProviderRemote struct {
updateInterval time.Duration
exclude *regexp.Regexp
include *regexp.Regexp
headers http.Header
}
func NewProviderRemote(ctx context.Context, router adapter.Router, logFactory log.Factory, tag string, options option.ProviderRemoteOptions) (adapter.Provider, error) {
@@ -94,6 +95,7 @@ func NewProviderRemote(ctx context.Context, router adapter.Router, logFactory lo
url: options.URL,
userAgent: userAgent,
downloadDetour: options.DownloadDetour,
headers: options.Headers.Build(),
updateInterval: updateInterval,
exclude: (*regexp.Regexp)(options.Exclude),
include: (*regexp.Regexp)(options.Include),
@@ -191,6 +193,9 @@ func (s *ProviderRemote) fetch(ctx context.Context) error {
req.Header.Set("If-None-Match", s.lastEtag)
}
req.Header.Set("User-Agent", s.userAgent)
for name, values := range s.headers {
req.Header[name] = values
}
resp, err := client.Do(req.WithContext(ctx))
if err != nil {
return err

View File

@@ -0,0 +1 @@
with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_manager,with_admin_panel,with_masque,with_mtproxy,with_ccm,with_ocm,with_openvpn,with_trusttunnel,with_sudoku,with_snell,with_naive_outbound,with_musl,badlinkname,tfogo_checklinkname0

View File

@@ -2,7 +2,7 @@ package postgresql
import (
"context"
"database/sql"
dbsql "database/sql"
"encoding/json"
"errors"
"time"
@@ -11,11 +11,12 @@ import (
"github.com/huandu/go-sqlbuilder"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/sagernet/sing-box/common/sql"
"github.com/sagernet/sing-box/service/manager/constant"
"github.com/sagernet/sing/common/byteformats"
)
var squadFilters, nodeFilters, userFilters, bandwidthLimiterFilters, connectionLimiterFilters, trafficLimiterFilters, rateLimiterFilters map[string]Filter
var squadFilters, nodeFilters, userFilters, bandwidthLimiterFilters, connectionLimiterFilters, trafficLimiterFilters, rateLimiterFilters map[string]sql.Filter
type PostgreSQLRepository struct {
db *pgxpool.Pool
@@ -23,7 +24,7 @@ type PostgreSQLRepository struct {
}
func NewPostgreSQLRepository(ctx context.Context, dsn string) (*PostgreSQLRepository, error) {
db, err := sql.Open("postgres", dsn)
db, err := dbsql.Open("postgres", dsn)
if err != nil {
return nil, err
}
@@ -91,8 +92,8 @@ func (r *PostgreSQLRepository) GetSquads(filters map[string][]string) ([]constan
}
}
}
sql, args := sb.Build()
rows, err := r.db.Query(r.ctx, sql, args...)
query, args := sb.Build()
rows, err := r.db.Query(r.ctx, query, args...)
if err != nil {
return nil, err
}
@@ -124,9 +125,9 @@ func (r *PostgreSQLRepository) GetSquadsCount(filters map[string][]string) (int,
}
}
}
sql, args := sb.Build()
query, args := sb.Build()
var count int
err := r.db.QueryRow(r.ctx, sql, args...).Scan(&count)
err := r.db.QueryRow(r.ctx, query, args...).Scan(&count)
return count, err
}
@@ -396,8 +397,8 @@ func (r *PostgreSQLRepository) GetNodes(filters map[string][]string) ([]constant
}
}
}
sql, args := sb.Build()
rows, err := r.db.Query(r.ctx, sql, args...)
query, args := sb.Build()
rows, err := r.db.Query(r.ctx, query, args...)
if err != nil {
return nil, err
}
@@ -430,9 +431,9 @@ func (r *PostgreSQLRepository) GetNodesCount(filters map[string][]string) (int,
}
}
}
sql, args := sb.Build()
query, args := sb.Build()
var count int
err := r.db.QueryRow(r.ctx, sql, args...).Scan(&count)
err := r.db.QueryRow(r.ctx, query, args...).Scan(&count)
return count, err
}
@@ -519,7 +520,7 @@ func (r *PostgreSQLRepository) CreateUser(user constant.UserCreate) (constant.Us
if err != nil {
return u, err
}
var authorizedKeys stringSliceJSON
var authorizedKeys sql.SliceJSON[string]
err = tx.QueryRow(
r.ctx, `
INSERT INTO users (
@@ -629,8 +630,8 @@ func (r *PostgreSQLRepository) GetUsers(filters map[string][]string) ([]constant
}
}
}
sql, args := sb.Build()
rows, err := r.db.Query(r.ctx, sql, args...)
query, args := sb.Build()
rows, err := r.db.Query(r.ctx, query, args...)
if err != nil {
return nil, err
}
@@ -671,9 +672,9 @@ func (r *PostgreSQLRepository) GetUsersCount(filters map[string][]string) (int,
}
}
}
sql, args := sb.Build()
query, args := sb.Build()
var count int
err := r.db.QueryRow(r.ctx, sql, args...).Scan(&count)
err := r.db.QueryRow(r.ctx, query, args...).Scan(&count)
return count, err
}
@@ -783,16 +784,33 @@ func (r *PostgreSQLRepository) UpdateUser(id int, user constant.UserUpdate) (con
func (r *PostgreSQLRepository) DeleteUser(id int) (constant.User, error) {
var u constant.User
err := r.db.QueryRow(r.ctx, `
tx, err := r.db.Begin(r.ctx)
if err != nil {
return u, err
}
defer tx.Rollback(r.ctx)
var squadIDs []int
squadRows, err := tx.Query(r.ctx, `SELECT squad_id FROM user_to_squad WHERE user_id = $1`, id)
if err != nil {
return u, err
}
for squadRows.Next() {
var squadID int
if err = squadRows.Scan(&squadID); err != nil {
squadRows.Close()
return u, err
}
squadIDs = append(squadIDs, squadID)
}
squadRows.Close()
if err = squadRows.Err(); err != nil {
return u, err
}
err = tx.QueryRow(r.ctx, `
DELETE FROM users
WHERE id = $1
RETURNING
id,
ARRAY(
SELECT squad_id
FROM user_to_squad
WHERE user_to_squad.user_id = users.id
) as squad_ids,
username,
inbound,
type,
@@ -806,7 +824,6 @@ func (r *PostgreSQLRepository) DeleteUser(id int) (constant.User, error) {
updated_at
`, id).Scan(
&u.ID,
&u.SquadIDs,
&u.Username,
&u.Inbound,
&u.Type,
@@ -819,7 +836,11 @@ func (r *PostgreSQLRepository) DeleteUser(id int) (constant.User, error) {
&u.CreatedAt,
&u.UpdatedAt,
)
return u, err
if err != nil {
return u, err
}
u.SquadIDs = squadIDs
return u, tx.Commit(r.ctx)
}
func (r *PostgreSQLRepository) CreateConnectionLimiter(limiter constant.ConnectionLimiterCreate) (constant.ConnectionLimiter, error) {
@@ -924,8 +945,8 @@ func (r *PostgreSQLRepository) GetConnectionLimiters(filters map[string][]string
}
}
}
sql, args := sb.Build()
rows, err := r.db.Query(r.ctx, sql, args...)
query, args := sb.Build()
rows, err := r.db.Query(r.ctx, query, args...)
if err != nil {
return nil, err
}
@@ -965,9 +986,9 @@ func (r *PostgreSQLRepository) GetConnectionLimitersCount(filters map[string][]s
}
}
}
sql, args := sb.Build()
query, args := sb.Build()
var count int
err := r.db.QueryRow(r.ctx, sql, args...).Scan(&count)
err := r.db.QueryRow(r.ctx, query, args...).Scan(&count)
return count, err
}
@@ -1057,16 +1078,33 @@ func (r *PostgreSQLRepository) UpdateConnectionLimiter(id int, limiter constant.
func (r *PostgreSQLRepository) DeleteConnectionLimiter(id int) (constant.ConnectionLimiter, error) {
var cl constant.ConnectionLimiter
err := r.db.QueryRow(r.ctx, `
tx, err := r.db.Begin(r.ctx)
if err != nil {
return cl, err
}
defer tx.Rollback(r.ctx)
var squadIDs []int
squadRows, err := tx.Query(r.ctx, `SELECT squad_id FROM connection_limiter_to_squad WHERE connection_limiter_id = $1`, id)
if err != nil {
return cl, err
}
for squadRows.Next() {
var squadID int
if err = squadRows.Scan(&squadID); err != nil {
squadRows.Close()
return cl, err
}
squadIDs = append(squadIDs, squadID)
}
squadRows.Close()
if err = squadRows.Err(); err != nil {
return cl, err
}
err = tx.QueryRow(r.ctx, `
DELETE FROM connection_limiters
WHERE id=$1
RETURNING
id,
ARRAY(
SELECT squad_id
FROM connection_limiter_to_squad
WHERE connection_limiter_to_squad.connection_limiter_id = connection_limiters.id
) as squad_ids,
username,
outbound,
strategy,
@@ -1077,7 +1115,6 @@ func (r *PostgreSQLRepository) DeleteConnectionLimiter(id int) (constant.Connect
updated_at
`, id).Scan(
&cl.ID,
&cl.SquadIDs,
&cl.Username,
&cl.Outbound,
&cl.Strategy,
@@ -1087,7 +1124,11 @@ func (r *PostgreSQLRepository) DeleteConnectionLimiter(id int) (constant.Connect
&cl.CreatedAt,
&cl.UpdatedAt,
)
return cl, err
if err != nil {
return cl, err
}
cl.SquadIDs = squadIDs
return cl, tx.Commit(r.ctx)
}
func (r *PostgreSQLRepository) CreateBandwidthLimiter(limiter constant.BandwidthLimiterCreate) (constant.BandwidthLimiter, error) {
@@ -1109,7 +1150,7 @@ func (r *PostgreSQLRepository) CreateBandwidthLimiter(limiter constant.Bandwidth
if err != nil {
return bl, err
}
var flowKeys stringSliceJSON
var flowKeys sql.SliceJSON[string]
now := time.Now()
err = tx.QueryRow(
r.ctx, `
@@ -1217,8 +1258,8 @@ func (r *PostgreSQLRepository) GetBandwidthLimiters(filters map[string][]string)
}
}
}
sql, args := sb.Build()
rows, err := r.db.Query(r.ctx, sql, args...)
query, args := sb.Build()
rows, err := r.db.Query(r.ctx, query, args...)
if err != nil {
return nil, err
}
@@ -1226,7 +1267,7 @@ func (r *PostgreSQLRepository) GetBandwidthLimiters(filters map[string][]string)
var result []constant.BandwidthLimiter
for rows.Next() {
var bl constant.BandwidthLimiter
var flowKeys stringSliceJSON
var flowKeys sql.SliceJSON[string]
if err := rows.Scan(
&bl.ID,
&bl.SquadIDs,
@@ -1260,15 +1301,15 @@ func (r *PostgreSQLRepository) GetBandwidthLimitersCount(filters map[string][]st
}
}
}
sql, args := sb.Build()
query, args := sb.Build()
var count int
err := r.db.QueryRow(r.ctx, sql, args...).Scan(&count)
err := r.db.QueryRow(r.ctx, query, args...).Scan(&count)
return count, err
}
func (r *PostgreSQLRepository) GetBandwidthLimiter(id int) (constant.BandwidthLimiter, error) {
var bl constant.BandwidthLimiter
var flowKeys stringSliceJSON
var flowKeys sql.SliceJSON[string]
err := r.db.QueryRow(r.ctx, `
SELECT
id,
@@ -1309,7 +1350,7 @@ func (r *PostgreSQLRepository) GetBandwidthLimiter(id int) (constant.BandwidthLi
func (r *PostgreSQLRepository) UpdateBandwidthLimiter(id int, limiter constant.BandwidthLimiterUpdate) (constant.BandwidthLimiter, error) {
var bl constant.BandwidthLimiter
var flowKeys stringSliceJSON
var flowKeys sql.SliceJSON[string]
bytesSpeed, err := json.Marshal(limiter.Speed)
if err != nil {
return bl, err
@@ -1384,17 +1425,34 @@ func (r *PostgreSQLRepository) UpdateBandwidthLimiter(id int, limiter constant.B
func (r *PostgreSQLRepository) DeleteBandwidthLimiter(id int) (constant.BandwidthLimiter, error) {
var bl constant.BandwidthLimiter
var flowKeys stringSliceJSON
err := r.db.QueryRow(r.ctx, `
var flowKeys sql.SliceJSON[string]
tx, err := r.db.Begin(r.ctx)
if err != nil {
return bl, err
}
defer tx.Rollback(r.ctx)
var squadIDs []int
squadRows, err := tx.Query(r.ctx, `SELECT squad_id FROM bandwidth_limiter_to_squad WHERE bandwidth_limiter_id = $1`, id)
if err != nil {
return bl, err
}
for squadRows.Next() {
var squadID int
if err = squadRows.Scan(&squadID); err != nil {
squadRows.Close()
return bl, err
}
squadIDs = append(squadIDs, squadID)
}
squadRows.Close()
if err = squadRows.Err(); err != nil {
return bl, err
}
err = tx.QueryRow(r.ctx, `
DELETE FROM bandwidth_limiters
WHERE id=$1
RETURNING
id,
ARRAY(
SELECT squad_id
FROM bandwidth_limiter_to_squad
WHERE bandwidth_limiter_to_squad.bandwidth_limiter_id = bandwidth_limiters.id
) as squad_ids,
username,
outbound,
strategy,
@@ -1407,7 +1465,6 @@ func (r *PostgreSQLRepository) DeleteBandwidthLimiter(id int) (constant.Bandwidt
updated_at
`, id).Scan(
&bl.ID,
&bl.SquadIDs,
&bl.Username,
&bl.Outbound,
&bl.Strategy,
@@ -1419,8 +1476,12 @@ func (r *PostgreSQLRepository) DeleteBandwidthLimiter(id int) (constant.Bandwidt
&bl.CreatedAt,
&bl.UpdatedAt,
)
if err != nil {
return bl, err
}
bl.SquadIDs = squadIDs
bl.FlowKeys = []string(flowKeys)
return bl, err
return bl, tx.Commit(r.ctx)
}
func (r *PostgreSQLRepository) CreateTrafficLimiter(limiter constant.TrafficLimiterCreate) (constant.TrafficLimiter, error) {
@@ -1540,8 +1601,8 @@ func (r *PostgreSQLRepository) GetTrafficLimiters(filters map[string][]string) (
}
}
}
sql, args := sb.Build()
rows, err := r.db.Query(r.ctx, sql, args...)
query, args := sb.Build()
rows, err := r.db.Query(r.ctx, query, args...)
if err != nil {
return nil, err
}
@@ -1581,9 +1642,9 @@ func (r *PostgreSQLRepository) GetTrafficLimitersCount(filters map[string][]stri
}
}
}
sql, args := sb.Build()
query, args := sb.Build()
var count int
err := r.db.QueryRow(r.ctx, sql, args...).Scan(&count)
err := r.db.QueryRow(r.ctx, query, args...).Scan(&count)
return count, err
}
@@ -1740,16 +1801,33 @@ func (r *PostgreSQLRepository) UpdateTrafficLimiterUsed(id int, current uint64)
func (r *PostgreSQLRepository) DeleteTrafficLimiter(id int) (constant.TrafficLimiter, error) {
var tl constant.TrafficLimiter
err := r.db.QueryRow(r.ctx, `
tx, err := r.db.Begin(r.ctx)
if err != nil {
return tl, err
}
defer tx.Rollback(r.ctx)
var squadIDs []int
squadRows, err := tx.Query(r.ctx, `SELECT squad_id FROM traffic_limiter_to_squad WHERE traffic_limiter_id = $1`, id)
if err != nil {
return tl, err
}
for squadRows.Next() {
var squadID int
if err = squadRows.Scan(&squadID); err != nil {
squadRows.Close()
return tl, err
}
squadIDs = append(squadIDs, squadID)
}
squadRows.Close()
if err = squadRows.Err(); err != nil {
return tl, err
}
err = tx.QueryRow(r.ctx, `
DELETE FROM traffic_limiters
WHERE id=$1
RETURNING
id,
ARRAY(
SELECT squad_id
FROM traffic_limiter_to_squad
WHERE traffic_limiter_to_squad.traffic_limiter_id = traffic_limiters.id
) as squad_ids,
username,
outbound,
strategy,
@@ -1762,7 +1840,6 @@ func (r *PostgreSQLRepository) DeleteTrafficLimiter(id int) (constant.TrafficLim
updated_at
`, id).Scan(
&tl.ID,
&tl.SquadIDs,
&tl.Username,
&tl.Outbound,
&tl.Strategy,
@@ -1774,7 +1851,11 @@ func (r *PostgreSQLRepository) DeleteTrafficLimiter(id int) (constant.TrafficLim
&tl.CreatedAt,
&tl.UpdatedAt,
)
return tl, err
if err != nil {
return tl, err
}
tl.SquadIDs = squadIDs
return tl, tx.Commit(r.ctx)
}
func (r *PostgreSQLRepository) CreateRateLimiter(limiter constant.RateLimiterCreate) (constant.RateLimiter, error) {
@@ -1880,8 +1961,8 @@ func (r *PostgreSQLRepository) GetRateLimiters(filters map[string][]string) ([]c
}
}
}
sql, args := sb.Build()
rows, err := r.db.Query(r.ctx, sql, args...)
query, args := sb.Build()
rows, err := r.db.Query(r.ctx, query, args...)
if err != nil {
return nil, err
}
@@ -1919,9 +2000,9 @@ func (r *PostgreSQLRepository) GetRateLimitersCount(filters map[string][]string)
}
}
}
sql, args := sb.Build()
query, args := sb.Build()
var count int
err := r.db.QueryRow(r.ctx, sql, args...).Scan(&count)
err := r.db.QueryRow(r.ctx, query, args...).Scan(&count)
return count, err
}
@@ -2015,16 +2096,33 @@ func (r *PostgreSQLRepository) UpdateRateLimiter(id int, limiter constant.RateLi
func (r *PostgreSQLRepository) DeleteRateLimiter(id int) (constant.RateLimiter, error) {
var rl constant.RateLimiter
err := r.db.QueryRow(r.ctx, `
tx, err := r.db.Begin(r.ctx)
if err != nil {
return rl, err
}
defer tx.Rollback(r.ctx)
var squadIDs []int
squadRows, err := tx.Query(r.ctx, `SELECT squad_id FROM rate_limiter_to_squad WHERE rate_limiter_id = $1`, id)
if err != nil {
return rl, err
}
for squadRows.Next() {
var squadID int
if err = squadRows.Scan(&squadID); err != nil {
squadRows.Close()
return rl, err
}
squadIDs = append(squadIDs, squadID)
}
squadRows.Close()
if err = squadRows.Err(); err != nil {
return rl, err
}
err = tx.QueryRow(r.ctx, `
DELETE FROM rate_limiters
WHERE id=$1
RETURNING
id,
ARRAY(
SELECT squad_id
FROM rate_limiter_to_squad
WHERE rate_limiter_to_squad.rate_limiter_id = rate_limiters.id
) as squad_ids,
username,
outbound,
strategy,
@@ -2035,7 +2133,6 @@ func (r *PostgreSQLRepository) DeleteRateLimiter(id int) (constant.RateLimiter,
updated_at
`, id).Scan(
&rl.ID,
&rl.SquadIDs,
&rl.Username,
&rl.Outbound,
&rl.Strategy,
@@ -2045,29 +2142,30 @@ func (r *PostgreSQLRepository) DeleteRateLimiter(id int) (constant.RateLimiter,
&rl.CreatedAt,
&rl.UpdatedAt,
)
return rl, err
if err != nil {
return rl, err
}
rl.SquadIDs = squadIDs
return rl, tx.Commit(r.ctx)
}
func init() {
squadFilters = map[string]Filter{
"id": EqualFilter("id"),
"id_in": InFilter("id"),
"pk": EqualFilter("id"),
"name": EqualFilter("name"),
"created_at_start": GreaterThanFilter("created_at"),
"created_at_end": LessThanFilter("created_at"),
"updated_at_start": GreaterThanFilter("updated_at"),
"updated_at_end": LessThanFilter("updated_at"),
"sort_asc": SortAscFilter([]string{"id", "name", "created_at", "updated_at"}),
"sort_desc": SortDescFilter([]string{"id", "name", "created_at", "updated_at"}),
"offset": OffsetFilter(),
"limit": LimitFilter(),
}
nodeFilters = map[string]Filter{
"uuid": EqualFilter("uuid"),
"pk": EqualFilter("uuid"),
"name": EqualFilter("name"),
"squad_id_in": ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
squadFilters = map[string]sql.Filter{"id": sql.EqualFilter("id"),
"id_in": sql.InFilter("id"),
"pk": sql.EqualFilter("id"),
"name": sql.EqualFilter("name"),
"created_at_start": sql.GreaterThanFilter("created_at"),
"created_at_end": sql.LessThanFilter("created_at"),
"updated_at_start": sql.GreaterThanFilter("updated_at"),
"updated_at_end": sql.LessThanFilter("updated_at"),
"sort_asc": sql.SortAscFilter([]string{"id", "name", "created_at", "updated_at"}),
"sort_desc": sql.SortDescFilter([]string{"id", "name", "created_at", "updated_at"}),
"offset": sql.OffsetFilter(),
"limit": sql.LimitFilter()}
nodeFilters = map[string]sql.Filter{"uuid": sql.EqualFilter("uuid"),
"pk": sql.EqualFilter("uuid"),
"name": sql.EqualFilter("name"),
"squad_id_in": sql.ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
return sqlbuilder.PostgreSQL.NewSelectBuilder().
Select(
"squad_id",
@@ -2079,19 +2177,17 @@ func init() {
"node_to_squad",
)
}, "node_to_squad.squad_id"),
"created_at_start": GreaterThanFilter("created_at"),
"created_at_end": LessThanFilter("created_at"),
"updated_at_start": GreaterThanFilter("updated_at"),
"updated_at_end": LessThanFilter("updated_at"),
"sort_asc": SortAscFilter([]string{"uuid", "name", "created_at", "updated_at"}),
"sort_desc": SortDescFilter([]string{"uuid", "name", "created_at", "updated_at"}),
"offset": OffsetFilter(),
"limit": LimitFilter(),
}
userFilters = map[string]Filter{
"id": EqualFilter("id"),
"pk": EqualFilter("id"),
"squad_id_in": ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
"created_at_start": sql.GreaterThanFilter("created_at"),
"created_at_end": sql.LessThanFilter("created_at"),
"updated_at_start": sql.GreaterThanFilter("updated_at"),
"updated_at_end": sql.LessThanFilter("updated_at"),
"sort_asc": sql.SortAscFilter([]string{"uuid", "name", "created_at", "updated_at"}),
"sort_desc": sql.SortDescFilter([]string{"uuid", "name", "created_at", "updated_at"}),
"offset": sql.OffsetFilter(),
"limit": sql.LimitFilter()}
userFilters = map[string]sql.Filter{"id": sql.EqualFilter("id"),
"pk": sql.EqualFilter("id"),
"squad_id_in": sql.ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
return sqlbuilder.PostgreSQL.NewSelectBuilder().
Select(
"squad_id",
@@ -2103,21 +2199,19 @@ func init() {
"user_to_squad",
)
}, "user_to_squad.squad_id"),
"username": EqualFilter("username"),
"inbound": EqualFilter("inbound"),
"created_at_start": GreaterThanFilter("created_at"),
"created_at_end": LessThanFilter("created_at"),
"updated_at_start": GreaterThanFilter("updated_at"),
"updated_at_end": LessThanFilter("updated_at"),
"sort_asc": SortAscFilter([]string{"id", "username", "inbound", "type", "created_at", "updated_at"}),
"sort_desc": SortDescFilter([]string{"id", "username", "inbound", "type", "created_at", "updated_at"}),
"offset": OffsetFilter(),
"limit": LimitFilter(),
}
connectionLimiterFilters = map[string]Filter{
"id": EqualFilter("id"),
"pk": EqualFilter("id"),
"squad_id_in": ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
"username": sql.EqualFilter("username"),
"inbound": sql.EqualFilter("inbound"),
"created_at_start": sql.GreaterThanFilter("created_at"),
"created_at_end": sql.LessThanFilter("created_at"),
"updated_at_start": sql.GreaterThanFilter("updated_at"),
"updated_at_end": sql.LessThanFilter("updated_at"),
"sort_asc": sql.SortAscFilter([]string{"id", "username", "inbound", "type", "created_at", "updated_at"}),
"sort_desc": sql.SortDescFilter([]string{"id", "username", "inbound", "type", "created_at", "updated_at"}),
"offset": sql.OffsetFilter(),
"limit": sql.LimitFilter()}
connectionLimiterFilters = map[string]sql.Filter{"id": sql.EqualFilter("id"),
"pk": sql.EqualFilter("id"),
"squad_id_in": sql.ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
return sqlbuilder.PostgreSQL.NewSelectBuilder().
Select(
"squad_id",
@@ -2129,24 +2223,22 @@ func init() {
"connection_limiter_to_squad",
)
}, "connection_limiter_to_squad.squad_id"),
"strategy": EqualFilter("strategy"),
"username": EqualFilter("username"),
"outbound": EqualFilter("outbound"),
"connection_type": EqualFilter("connection_type"),
"lock_type": EqualFilter("lock_type"),
"created_at_start": GreaterThanFilter("created_at"),
"created_at_end": LessThanFilter("created_at"),
"updated_at_start": GreaterThanFilter("updated_at"),
"updated_at_end": LessThanFilter("updated_at"),
"sort_asc": SortAscFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "lock_type", "count", "created_at", "updated_at"}),
"sort_desc": SortDescFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "lock_type", "count", "created_at", "updated_at"}),
"offset": OffsetFilter(),
"limit": LimitFilter(),
}
bandwidthLimiterFilters = map[string]Filter{
"id": EqualFilter("id"),
"pk": EqualFilter("id"),
"squad_id_in": ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
"strategy": sql.EqualFilter("strategy"),
"username": sql.EqualFilter("username"),
"outbound": sql.EqualFilter("outbound"),
"connection_type": sql.EqualFilter("connection_type"),
"lock_type": sql.EqualFilter("lock_type"),
"created_at_start": sql.GreaterThanFilter("created_at"),
"created_at_end": sql.LessThanFilter("created_at"),
"updated_at_start": sql.GreaterThanFilter("updated_at"),
"updated_at_end": sql.LessThanFilter("updated_at"),
"sort_asc": sql.SortAscFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "lock_type", "count", "created_at", "updated_at"}),
"sort_desc": sql.SortDescFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "lock_type", "count", "created_at", "updated_at"}),
"offset": sql.OffsetFilter(),
"limit": sql.LimitFilter()}
bandwidthLimiterFilters = map[string]sql.Filter{"id": sql.EqualFilter("id"),
"pk": sql.EqualFilter("id"),
"squad_id_in": sql.ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
return sqlbuilder.PostgreSQL.NewSelectBuilder().
Select(
"squad_id",
@@ -2158,28 +2250,22 @@ func init() {
"bandwidth_limiter_to_squad",
)
}, "bandwidth_limiter_to_squad.squad_id"),
"strategy": EqualFilter("strategy"),
"mode": EqualFilter("mode"),
"username": EqualFilter("username"),
"created_at_start": GreaterThanFilter("created_at"),
"created_at_end": LessThanFilter("created_at"),
"updated_at_start": GreaterThanFilter("updated_at"),
"updated_at_end": LessThanFilter("updated_at"),
"sort_asc": ReplacedSortAscFilter(
map[string]string{"speed": "raw_speed"},
[]string{"id", "username", "outbound", "strategy", "connection_type", "mode", "raw_speed", "created_at", "updated_at"},
),
"sort_desc": ReplacedSortDescFilter(
map[string]string{"speed": "raw_speed"},
[]string{"id", "username", "outbound", "strategy", "connection_type", "mode", "raw_speed", "created_at", "updated_at"},
),
"offset": OffsetFilter(),
"limit": LimitFilter(),
}
trafficLimiterFilters = map[string]Filter{
"id": EqualFilter("id"),
"pk": EqualFilter("id"),
"squad_id_in": ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
"strategy": sql.EqualFilter("strategy"),
"mode": sql.EqualFilter("mode"),
"username": sql.EqualFilter("username"),
"created_at_start": sql.GreaterThanFilter("created_at"),
"created_at_end": sql.LessThanFilter("created_at"),
"updated_at_start": sql.GreaterThanFilter("updated_at"),
"updated_at_end": sql.LessThanFilter("updated_at"),
"sort_asc": sql.ReplacedSortAscFilter(map[string]string{"speed": "raw_speed"},
[]string{"id", "username", "outbound", "strategy", "connection_type", "mode", "raw_speed", "created_at", "updated_at"}),
"sort_desc": sql.ReplacedSortDescFilter(map[string]string{"speed": "raw_speed"},
[]string{"id", "username", "outbound", "strategy", "connection_type", "mode", "raw_speed", "created_at", "updated_at"}),
"offset": sql.OffsetFilter(),
"limit": sql.LimitFilter()}
trafficLimiterFilters = map[string]sql.Filter{"id": sql.EqualFilter("id"),
"pk": sql.EqualFilter("id"),
"squad_id_in": sql.ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
return sqlbuilder.PostgreSQL.NewSelectBuilder().
Select(
"squad_id",
@@ -2191,33 +2277,27 @@ func init() {
"traffic_limiter_to_squad",
)
}, "traffic_limiter_to_squad.squad_id"),
"username": EqualFilter("username"),
"outbound": EqualFilter("outbound"),
"strategy": EqualFilter("strategy"),
"mode": EqualFilter("mode"),
"used_start": SpeedGreaterEqualThanFilter("raw_used"),
"used_end": SpeedLessEqualThanFilter("raw_used"),
"quota_start": SpeedGreaterEqualThanFilter("raw_quota"),
"quota_end": SpeedLessEqualThanFilter("raw_quota"),
"created_at_start": GreaterThanFilter("created_at"),
"created_at_end": LessThanFilter("created_at"),
"updated_at_start": GreaterThanFilter("updated_at"),
"updated_at_end": LessThanFilter("updated_at"),
"sort_asc": ReplacedSortAscFilter(
map[string]string{"used": "raw_used", "quota": "raw_quota"},
[]string{"id", "username", "outbound", "strategy", "mode", "raw_used", "raw_quota", "created_at", "updated_at"},
),
"sort_desc": ReplacedSortDescFilter(
map[string]string{"used": "raw_used", "quota": "raw_quota"},
[]string{"id", "username", "outbound", "strategy", "mode", "raw_used", "raw_quota", "created_at", "updated_at"},
),
"offset": OffsetFilter(),
"limit": LimitFilter(),
}
rateLimiterFilters = map[string]Filter{
"id": EqualFilter("id"),
"pk": EqualFilter("id"),
"squad_id_in": ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
"username": sql.EqualFilter("username"),
"outbound": sql.EqualFilter("outbound"),
"strategy": sql.EqualFilter("strategy"),
"mode": sql.EqualFilter("mode"),
"used_start": sql.SpeedGreaterEqualThanFilter("raw_used"),
"used_end": sql.SpeedLessEqualThanFilter("raw_used"),
"quota_start": sql.SpeedGreaterEqualThanFilter("raw_quota"),
"quota_end": sql.SpeedLessEqualThanFilter("raw_quota"),
"created_at_start": sql.GreaterThanFilter("created_at"),
"created_at_end": sql.LessThanFilter("created_at"),
"updated_at_start": sql.GreaterThanFilter("updated_at"),
"updated_at_end": sql.LessThanFilter("updated_at"),
"sort_asc": sql.ReplacedSortAscFilter(map[string]string{"used": "raw_used", "quota": "raw_quota"},
[]string{"id", "username", "outbound", "strategy", "mode", "raw_used", "raw_quota", "created_at", "updated_at"}),
"sort_desc": sql.ReplacedSortDescFilter(map[string]string{"used": "raw_used", "quota": "raw_quota"},
[]string{"id", "username", "outbound", "strategy", "mode", "raw_used", "raw_quota", "created_at", "updated_at"}),
"offset": sql.OffsetFilter(),
"limit": sql.LimitFilter()}
rateLimiterFilters = map[string]sql.Filter{"id": sql.EqualFilter("id"),
"pk": sql.EqualFilter("id"),
"squad_id_in": sql.ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
return sqlbuilder.PostgreSQL.NewSelectBuilder().
Select(
"squad_id",
@@ -2229,20 +2309,19 @@ func init() {
"rate_limiter_to_squad",
)
}, "rate_limiter_to_squad.squad_id"),
"strategy": EqualFilter("strategy"),
"username": EqualFilter("username"),
"outbound": EqualFilter("outbound"),
"connection_type": EqualFilter("connection_type"),
"interval": EqualFilter("interval"),
"count_start": GreaterEqualThanFilter("count"),
"count_end": LessEqualThanFilter("count"),
"created_at_start": GreaterThanFilter("created_at"),
"created_at_end": LessThanFilter("created_at"),
"updated_at_start": GreaterThanFilter("updated_at"),
"updated_at_end": LessThanFilter("updated_at"),
"sort_asc": SortAscFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "count", "interval", "created_at", "updated_at"}),
"sort_desc": SortDescFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "count", "interval", "created_at", "updated_at"}),
"offset": OffsetFilter(),
"limit": LimitFilter(),
}
"strategy": sql.EqualFilter("strategy"),
"username": sql.EqualFilter("username"),
"outbound": sql.EqualFilter("outbound"),
"connection_type": sql.EqualFilter("connection_type"),
"interval": sql.EqualFilter("interval"),
"count_start": sql.GreaterEqualThanFilter("count"),
"count_end": sql.LessEqualThanFilter("count"),
"created_at_start": sql.GreaterThanFilter("created_at"),
"created_at_end": sql.LessThanFilter("created_at"),
"updated_at_start": sql.GreaterThanFilter("updated_at"),
"updated_at_end": sql.LessThanFilter("updated_at"),
"sort_asc": sql.SortAscFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "count", "interval", "created_at", "updated_at"}),
"sort_desc": sql.SortDescFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "count", "interval", "created_at", "updated_at"}),
"offset": sql.OffsetFilter(),
"limit": sql.LimitFilter()}
}

View File

@@ -0,0 +1,12 @@
package postgresql
import (
"encoding/json"
)
func marshalStringSlice(values []string) ([]byte, error) {
if values == nil {
values = []string{}
}
return json.Marshal(values)
}

View File

@@ -2,27 +2,28 @@ package sqlite
import (
"context"
"database/sql"
dbsql "database/sql"
"encoding/json"
"errors"
"time"
"github.com/golang-migrate/migrate/v4"
"github.com/huandu/go-sqlbuilder"
"github.com/sagernet/sing-box/common/sql"
"github.com/sagernet/sing-box/service/manager/constant"
"github.com/sagernet/sing/common/byteformats"
_ "modernc.org/sqlite"
)
var squadFilters, nodeFilters, userFilters, bandwidthLimiterFilters, connectionLimiterFilters, trafficLimiterFilters, rateLimiterFilters map[string]Filter
var squadFilters, nodeFilters, userFilters, bandwidthLimiterFilters, connectionLimiterFilters, trafficLimiterFilters, rateLimiterFilters map[string]sql.Filter
type SQLiteRepository struct {
db *sql.DB
db *dbsql.DB
ctx context.Context
}
func NewSQLiteRepository(ctx context.Context, dsn string) (*SQLiteRepository, error) {
db, err := sql.Open("sqlite", dsn)
db, err := dbsql.Open("sqlite", dsn)
if err != nil {
return nil, err
}
@@ -34,7 +35,7 @@ func NewSQLiteRepository(ctx context.Context, dsn string) (*SQLiteRepository, er
}
func notFoundErr(err error) error {
if errors.Is(err, sql.ErrNoRows) {
if errors.Is(err, dbsql.ErrNoRows) {
return constant.ErrNotFound
}
return err
@@ -397,7 +398,7 @@ func (r *SQLiteRepository) GetNodes(filters map[string][]string) ([]constant.Nod
var result []constant.Node
for rows.Next() {
var n constant.Node
var squadIDs intSliceJSON
var squadIDs sql.SliceJSON[int]
if err := rows.Scan(
&n.UUID,
&n.Name,
@@ -432,7 +433,7 @@ func (r *SQLiteRepository) GetNodesCount(filters map[string][]string) (int, erro
func (r *SQLiteRepository) GetNode(uuid string) (constant.Node, error) {
var n constant.Node
var squadIDs intSliceJSON
var squadIDs sql.SliceJSON[int]
err := r.db.QueryRowContext(r.ctx, `
SELECT
uuid,
@@ -514,7 +515,7 @@ func (r *SQLiteRepository) CreateUser(user constant.UserCreate) (constant.User,
if err != nil {
return u, err
}
var authorizedKeys stringSliceJSON
var authorizedKeys sql.SliceJSON[string]
err = tx.QueryRowContext(
r.ctx, `
INSERT INTO users (
@@ -629,8 +630,8 @@ func (r *SQLiteRepository) GetUsers(filters map[string][]string) ([]constant.Use
var result []constant.User
for rows.Next() {
var u constant.User
var squadIDs intSliceJSON
var authorizedKeys stringSliceJSON
var squadIDs sql.SliceJSON[int]
var authorizedKeys sql.SliceJSON[string]
if err := rows.Scan(
&u.ID,
&squadIDs,
@@ -674,8 +675,8 @@ func (r *SQLiteRepository) GetUsersCount(filters map[string][]string) (int, erro
func (r *SQLiteRepository) GetUser(id int) (constant.User, error) {
var u constant.User
var squadIDs intSliceJSON
var authorizedKeys stringSliceJSON
var squadIDs sql.SliceJSON[int]
var authorizedKeys sql.SliceJSON[string]
err := r.db.QueryRowContext(r.ctx, `
SELECT
id,
@@ -719,8 +720,8 @@ func (r *SQLiteRepository) GetUser(id int) (constant.User, error) {
func (r *SQLiteRepository) UpdateUser(id int, user constant.UserUpdate) (constant.User, error) {
var u constant.User
var squadIDs intSliceJSON
var authorizedKeys stringSliceJSON
var squadIDs sql.SliceJSON[int]
var authorizedKeys sql.SliceJSON[string]
authorizedKeysJSON, err := marshalStringSlice(user.AuthorizedKeys)
if err != nil {
return u, err
@@ -786,18 +787,34 @@ func (r *SQLiteRepository) UpdateUser(id int, user constant.UserUpdate) (constan
func (r *SQLiteRepository) DeleteUser(id int) (constant.User, error) {
var u constant.User
var squadIDs intSliceJSON
var authorizedKeys stringSliceJSON
err := r.db.QueryRowContext(r.ctx, `
var authorizedKeys sql.SliceJSON[string]
tx, err := r.db.BeginTx(r.ctx, nil)
if err != nil {
return u, err
}
defer tx.Rollback()
var squadIDs []int
squadRows, err := tx.QueryContext(r.ctx, `SELECT squad_id FROM user_to_squad WHERE user_id = ?`, id)
if err != nil {
return u, err
}
for squadRows.Next() {
var squadID int
if err = squadRows.Scan(&squadID); err != nil {
squadRows.Close()
return u, err
}
squadIDs = append(squadIDs, squadID)
}
squadRows.Close()
if err = squadRows.Err(); err != nil {
return u, err
}
err = tx.QueryRowContext(r.ctx, `
DELETE FROM users
WHERE id = ?
RETURNING
id,
(
SELECT json_group_array(squad_id)
FROM user_to_squad
WHERE user_to_squad.user_id = users.id
) as squad_ids,
username,
inbound,
type,
@@ -811,7 +828,6 @@ func (r *SQLiteRepository) DeleteUser(id int) (constant.User, error) {
updated_at
`, id).Scan(
&u.ID,
&squadIDs,
&u.Username,
&u.Inbound,
&u.Type,
@@ -824,9 +840,12 @@ func (r *SQLiteRepository) DeleteUser(id int) (constant.User, error) {
&u.CreatedAt,
&u.UpdatedAt,
)
u.SquadIDs = []int(squadIDs)
if err != nil {
return u, err
}
u.SquadIDs = squadIDs
u.AuthorizedKeys = []string(authorizedKeys)
return u, err
return u, tx.Commit()
}
func (r *SQLiteRepository) CreateConnectionLimiter(limiter constant.ConnectionLimiterCreate) (constant.ConnectionLimiter, error) {
@@ -936,7 +955,7 @@ func (r *SQLiteRepository) GetConnectionLimiters(filters map[string][]string) ([
var result []constant.ConnectionLimiter
for rows.Next() {
var cl constant.ConnectionLimiter
var squadIDs intSliceJSON
var squadIDs sql.SliceJSON[int]
if err := rows.Scan(
&cl.ID,
&squadIDs,
@@ -978,7 +997,7 @@ func (r *SQLiteRepository) GetConnectionLimitersCount(filters map[string][]strin
func (r *SQLiteRepository) GetConnectionLimiter(id int) (constant.ConnectionLimiter, error) {
var cl constant.ConnectionLimiter
var squadIDs intSliceJSON
var squadIDs sql.SliceJSON[int]
err := r.db.QueryRowContext(r.ctx, `
SELECT
id,
@@ -1015,7 +1034,7 @@ func (r *SQLiteRepository) GetConnectionLimiter(id int) (constant.ConnectionLimi
func (r *SQLiteRepository) UpdateConnectionLimiter(id int, limiter constant.ConnectionLimiterUpdate) (constant.ConnectionLimiter, error) {
var cl constant.ConnectionLimiter
var squadIDs intSliceJSON
var squadIDs sql.SliceJSON[int]
err := r.db.QueryRowContext(
r.ctx, `
UPDATE connection_limiters
@@ -1066,17 +1085,33 @@ func (r *SQLiteRepository) UpdateConnectionLimiter(id int, limiter constant.Conn
func (r *SQLiteRepository) DeleteConnectionLimiter(id int) (constant.ConnectionLimiter, error) {
var cl constant.ConnectionLimiter
var squadIDs intSliceJSON
err := r.db.QueryRowContext(r.ctx, `
tx, err := r.db.BeginTx(r.ctx, nil)
if err != nil {
return cl, err
}
defer tx.Rollback()
var squadIDs []int
squadRows, err := tx.QueryContext(r.ctx, `SELECT squad_id FROM connection_limiter_to_squad WHERE connection_limiter_id = ?`, id)
if err != nil {
return cl, err
}
for squadRows.Next() {
var squadID int
if err = squadRows.Scan(&squadID); err != nil {
squadRows.Close()
return cl, err
}
squadIDs = append(squadIDs, squadID)
}
squadRows.Close()
if err = squadRows.Err(); err != nil {
return cl, err
}
err = tx.QueryRowContext(r.ctx, `
DELETE FROM connection_limiters
WHERE id=?
RETURNING
id,
(
SELECT json_group_array(squad_id)
FROM connection_limiter_to_squad
WHERE connection_limiter_to_squad.connection_limiter_id = connection_limiters.id
) as squad_ids,
username,
outbound,
strategy,
@@ -1087,7 +1122,6 @@ func (r *SQLiteRepository) DeleteConnectionLimiter(id int) (constant.ConnectionL
updated_at
`, id).Scan(
&cl.ID,
&squadIDs,
&cl.Username,
&cl.Outbound,
&cl.Strategy,
@@ -1097,8 +1131,11 @@ func (r *SQLiteRepository) DeleteConnectionLimiter(id int) (constant.ConnectionL
&cl.CreatedAt,
&cl.UpdatedAt,
)
cl.SquadIDs = []int(squadIDs)
return cl, err
if err != nil {
return cl, err
}
cl.SquadIDs = squadIDs
return cl, tx.Commit()
}
func (r *SQLiteRepository) CreateBandwidthLimiter(limiter constant.BandwidthLimiterCreate) (constant.BandwidthLimiter, error) {
@@ -1120,7 +1157,7 @@ func (r *SQLiteRepository) CreateBandwidthLimiter(limiter constant.BandwidthLimi
if err != nil {
return bl, err
}
var flowKeys stringSliceJSON
var flowKeys sql.SliceJSON[string]
now := time.Now()
err = tx.QueryRowContext(
r.ctx, `
@@ -1233,8 +1270,8 @@ func (r *SQLiteRepository) GetBandwidthLimiters(filters map[string][]string) ([]
var result []constant.BandwidthLimiter
for rows.Next() {
var bl constant.BandwidthLimiter
var squadIDs intSliceJSON
var flowKeys stringSliceJSON
var squadIDs sql.SliceJSON[int]
var flowKeys sql.SliceJSON[string]
if err := rows.Scan(
&bl.ID,
&squadIDs,
@@ -1277,8 +1314,8 @@ func (r *SQLiteRepository) GetBandwidthLimitersCount(filters map[string][]string
func (r *SQLiteRepository) GetBandwidthLimiter(id int) (constant.BandwidthLimiter, error) {
var bl constant.BandwidthLimiter
var squadIDs intSliceJSON
var flowKeys stringSliceJSON
var squadIDs sql.SliceJSON[int]
var flowKeys sql.SliceJSON[string]
err := r.db.QueryRowContext(r.ctx, `
SELECT
id,
@@ -1320,8 +1357,8 @@ func (r *SQLiteRepository) GetBandwidthLimiter(id int) (constant.BandwidthLimite
func (r *SQLiteRepository) UpdateBandwidthLimiter(id int, limiter constant.BandwidthLimiterUpdate) (constant.BandwidthLimiter, error) {
var bl constant.BandwidthLimiter
var squadIDs intSliceJSON
var flowKeys stringSliceJSON
var squadIDs sql.SliceJSON[int]
var flowKeys sql.SliceJSON[string]
bytesSpeed, err := json.Marshal(limiter.Speed)
if err != nil {
return bl, err
@@ -1397,18 +1434,34 @@ func (r *SQLiteRepository) UpdateBandwidthLimiter(id int, limiter constant.Bandw
func (r *SQLiteRepository) DeleteBandwidthLimiter(id int) (constant.BandwidthLimiter, error) {
var bl constant.BandwidthLimiter
var squadIDs intSliceJSON
var flowKeys stringSliceJSON
err := r.db.QueryRowContext(r.ctx, `
var flowKeys sql.SliceJSON[string]
tx, err := r.db.BeginTx(r.ctx, nil)
if err != nil {
return bl, err
}
defer tx.Rollback()
var squadIDs []int
squadRows, err := tx.QueryContext(r.ctx, `SELECT squad_id FROM bandwidth_limiter_to_squad WHERE bandwidth_limiter_id = ?`, id)
if err != nil {
return bl, err
}
for squadRows.Next() {
var squadID int
if err = squadRows.Scan(&squadID); err != nil {
squadRows.Close()
return bl, err
}
squadIDs = append(squadIDs, squadID)
}
squadRows.Close()
if err = squadRows.Err(); err != nil {
return bl, err
}
err = tx.QueryRowContext(r.ctx, `
DELETE FROM bandwidth_limiters
WHERE id=?
RETURNING
id,
(
SELECT json_group_array(squad_id)
FROM bandwidth_limiter_to_squad
WHERE bandwidth_limiter_to_squad.bandwidth_limiter_id = bandwidth_limiters.id
) as squad_ids,
username,
outbound,
strategy,
@@ -1421,7 +1474,6 @@ func (r *SQLiteRepository) DeleteBandwidthLimiter(id int) (constant.BandwidthLim
updated_at
`, id).Scan(
&bl.ID,
&squadIDs,
&bl.Username,
&bl.Outbound,
&bl.Strategy,
@@ -1433,9 +1485,12 @@ func (r *SQLiteRepository) DeleteBandwidthLimiter(id int) (constant.BandwidthLim
&bl.CreatedAt,
&bl.UpdatedAt,
)
bl.SquadIDs = []int(squadIDs)
if err != nil {
return bl, err
}
bl.SquadIDs = squadIDs
bl.FlowKeys = []string(flowKeys)
return bl, err
return bl, tx.Commit()
}
func (r *SQLiteRepository) CreateTrafficLimiter(limiter constant.TrafficLimiterCreate) (constant.TrafficLimiter, error) {
@@ -1560,7 +1615,7 @@ func (r *SQLiteRepository) GetTrafficLimiters(filters map[string][]string) ([]co
var result []constant.TrafficLimiter
for rows.Next() {
var tl constant.TrafficLimiter
var squadIDs intSliceJSON
var squadIDs sql.SliceJSON[int]
if err := rows.Scan(
&tl.ID,
&squadIDs,
@@ -1602,7 +1657,7 @@ func (r *SQLiteRepository) GetTrafficLimitersCount(filters map[string][]string)
func (r *SQLiteRepository) GetTrafficLimiter(id int) (constant.TrafficLimiter, error) {
var tl constant.TrafficLimiter
var squadIDs intSliceJSON
var squadIDs sql.SliceJSON[int]
err := r.db.QueryRowContext(r.ctx, `
SELECT
id,
@@ -1643,7 +1698,7 @@ func (r *SQLiteRepository) GetTrafficLimiter(id int) (constant.TrafficLimiter, e
func (r *SQLiteRepository) UpdateTrafficLimiter(id int, limiter constant.TrafficLimiterUpdate) (constant.TrafficLimiter, error) {
var tl constant.TrafficLimiter
var squadIDs intSliceJSON
var squadIDs sql.SliceJSON[int]
bytesQuota, err := json.Marshal(limiter.Quota)
if err != nil {
return tl, err
@@ -1710,7 +1765,7 @@ func (r *SQLiteRepository) UpdateTrafficLimiter(id int, limiter constant.Traffic
func (r *SQLiteRepository) UpdateTrafficLimiterUsed(id int, current uint64) (constant.TrafficLimiter, error) {
var tl constant.TrafficLimiter
var squadIDs intSliceJSON
var squadIDs sql.SliceJSON[int]
err := r.db.QueryRowContext(
r.ctx, `
UPDATE traffic_limiters
@@ -1759,17 +1814,33 @@ func (r *SQLiteRepository) UpdateTrafficLimiterUsed(id int, current uint64) (con
func (r *SQLiteRepository) DeleteTrafficLimiter(id int) (constant.TrafficLimiter, error) {
var tl constant.TrafficLimiter
var squadIDs intSliceJSON
err := r.db.QueryRowContext(r.ctx, `
tx, err := r.db.BeginTx(r.ctx, nil)
if err != nil {
return tl, err
}
defer tx.Rollback()
var squadIDs []int
squadRows, err := tx.QueryContext(r.ctx, `SELECT squad_id FROM traffic_limiter_to_squad WHERE traffic_limiter_id = ?`, id)
if err != nil {
return tl, err
}
for squadRows.Next() {
var squadID int
if err = squadRows.Scan(&squadID); err != nil {
squadRows.Close()
return tl, err
}
squadIDs = append(squadIDs, squadID)
}
squadRows.Close()
if err = squadRows.Err(); err != nil {
return tl, err
}
err = tx.QueryRowContext(r.ctx, `
DELETE FROM traffic_limiters
WHERE id=?
RETURNING
id,
(
SELECT json_group_array(squad_id)
FROM traffic_limiter_to_squad
WHERE traffic_limiter_to_squad.traffic_limiter_id = traffic_limiters.id
) as squad_ids,
username,
outbound,
strategy,
@@ -1782,7 +1853,6 @@ func (r *SQLiteRepository) DeleteTrafficLimiter(id int) (constant.TrafficLimiter
updated_at
`, id).Scan(
&tl.ID,
&squadIDs,
&tl.Username,
&tl.Outbound,
&tl.Strategy,
@@ -1794,8 +1864,11 @@ func (r *SQLiteRepository) DeleteTrafficLimiter(id int) (constant.TrafficLimiter
&tl.CreatedAt,
&tl.UpdatedAt,
)
tl.SquadIDs = []int(squadIDs)
return tl, err
if err != nil {
return tl, err
}
tl.SquadIDs = squadIDs
return tl, tx.Commit()
}
func (r *SQLiteRepository) CreateRateLimiter(limiter constant.RateLimiterCreate) (constant.RateLimiter, error) {
@@ -1906,7 +1979,7 @@ func (r *SQLiteRepository) GetRateLimiters(filters map[string][]string) ([]const
var result []constant.RateLimiter
for rows.Next() {
var rl constant.RateLimiter
var squadIDs intSliceJSON
var squadIDs sql.SliceJSON[int]
if err := rows.Scan(
&rl.ID,
&squadIDs,
@@ -1946,7 +2019,7 @@ func (r *SQLiteRepository) GetRateLimitersCount(filters map[string][]string) (in
func (r *SQLiteRepository) GetRateLimiter(id int) (constant.RateLimiter, error) {
var rl constant.RateLimiter
var squadIDs intSliceJSON
var squadIDs sql.SliceJSON[int]
err := r.db.QueryRowContext(r.ctx, `
SELECT
id,
@@ -1983,7 +2056,7 @@ func (r *SQLiteRepository) GetRateLimiter(id int) (constant.RateLimiter, error)
func (r *SQLiteRepository) UpdateRateLimiter(id int, limiter constant.RateLimiterUpdate) (constant.RateLimiter, error) {
var rl constant.RateLimiter
var squadIDs intSliceJSON
var squadIDs sql.SliceJSON[int]
err := r.db.QueryRowContext(
r.ctx, `
UPDATE rate_limiters
@@ -2038,17 +2111,33 @@ func (r *SQLiteRepository) UpdateRateLimiter(id int, limiter constant.RateLimite
func (r *SQLiteRepository) DeleteRateLimiter(id int) (constant.RateLimiter, error) {
var rl constant.RateLimiter
var squadIDs intSliceJSON
err := r.db.QueryRowContext(r.ctx, `
tx, err := r.db.BeginTx(r.ctx, nil)
if err != nil {
return rl, err
}
defer tx.Rollback()
var squadIDs []int
squadRows, err := tx.QueryContext(r.ctx, `SELECT squad_id FROM rate_limiter_to_squad WHERE rate_limiter_id = ?`, id)
if err != nil {
return rl, err
}
for squadRows.Next() {
var squadID int
if err = squadRows.Scan(&squadID); err != nil {
squadRows.Close()
return rl, err
}
squadIDs = append(squadIDs, squadID)
}
squadRows.Close()
if err = squadRows.Err(); err != nil {
return rl, err
}
err = tx.QueryRowContext(r.ctx, `
DELETE FROM rate_limiters
WHERE id=?
RETURNING
id,
(
SELECT json_group_array(squad_id)
FROM rate_limiter_to_squad
WHERE rate_limiter_to_squad.rate_limiter_id = rate_limiters.id
) as squad_ids,
username,
outbound,
strategy,
@@ -2059,7 +2148,6 @@ func (r *SQLiteRepository) DeleteRateLimiter(id int) (constant.RateLimiter, erro
updated_at
`, id).Scan(
&rl.ID,
&squadIDs,
&rl.Username,
&rl.Outbound,
&rl.Strategy,
@@ -2069,30 +2157,30 @@ func (r *SQLiteRepository) DeleteRateLimiter(id int) (constant.RateLimiter, erro
&rl.CreatedAt,
&rl.UpdatedAt,
)
rl.SquadIDs = []int(squadIDs)
return rl, err
if err != nil {
return rl, err
}
rl.SquadIDs = squadIDs
return rl, tx.Commit()
}
func init() {
squadFilters = map[string]Filter{
"id": EqualFilter("id"),
"id_in": InFilter("id"),
"pk": EqualFilter("id"),
"name": EqualFilter("name"),
"created_at_start": GreaterThanFilter("created_at"),
"created_at_end": LessThanFilter("created_at"),
"updated_at_start": GreaterThanFilter("updated_at"),
"updated_at_end": LessThanFilter("updated_at"),
"sort_asc": SortAscFilter([]string{"id", "name", "created_at", "updated_at"}),
"sort_desc": SortDescFilter([]string{"id", "name", "created_at", "updated_at"}),
"offset": OffsetFilter(),
"limit": LimitFilter(),
}
nodeFilters = map[string]Filter{
"uuid": EqualFilter("uuid"),
"pk": EqualFilter("uuid"),
"name": EqualFilter("name"),
"squad_id_in": ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
squadFilters = map[string]sql.Filter{"id": sql.EqualFilter("id"),
"id_in": sql.InFilter("id"),
"pk": sql.EqualFilter("id"),
"name": sql.EqualFilter("name"),
"created_at_start": sql.GreaterThanFilter("created_at"),
"created_at_end": sql.LessThanFilter("created_at"),
"updated_at_start": sql.GreaterThanFilter("updated_at"),
"updated_at_end": sql.LessThanFilter("updated_at"),
"sort_asc": sql.SortAscFilter([]string{"id", "name", "created_at", "updated_at"}),
"sort_desc": sql.SortDescFilter([]string{"id", "name", "created_at", "updated_at"}),
"offset": sql.OffsetFilter(),
"limit": sql.LimitFilter()}
nodeFilters = map[string]sql.Filter{"uuid": sql.EqualFilter("uuid"),
"pk": sql.EqualFilter("uuid"),
"name": sql.EqualFilter("name"),
"squad_id_in": sql.ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
return sqlbuilder.SQLite.NewSelectBuilder().
Select(
"squad_id",
@@ -2104,19 +2192,17 @@ func init() {
"node_to_squad",
)
}, "node_to_squad.squad_id"),
"created_at_start": GreaterThanFilter("created_at"),
"created_at_end": LessThanFilter("created_at"),
"updated_at_start": GreaterThanFilter("updated_at"),
"updated_at_end": LessThanFilter("updated_at"),
"sort_asc": SortAscFilter([]string{"uuid", "name", "created_at", "updated_at"}),
"sort_desc": SortDescFilter([]string{"uuid", "name", "created_at", "updated_at"}),
"offset": OffsetFilter(),
"limit": LimitFilter(),
}
userFilters = map[string]Filter{
"id": EqualFilter("id"),
"pk": EqualFilter("id"),
"squad_id_in": ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
"created_at_start": sql.GreaterThanFilter("created_at"),
"created_at_end": sql.LessThanFilter("created_at"),
"updated_at_start": sql.GreaterThanFilter("updated_at"),
"updated_at_end": sql.LessThanFilter("updated_at"),
"sort_asc": sql.SortAscFilter([]string{"uuid", "name", "created_at", "updated_at"}),
"sort_desc": sql.SortDescFilter([]string{"uuid", "name", "created_at", "updated_at"}),
"offset": sql.OffsetFilter(),
"limit": sql.LimitFilter()}
userFilters = map[string]sql.Filter{"id": sql.EqualFilter("id"),
"pk": sql.EqualFilter("id"),
"squad_id_in": sql.ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
return sqlbuilder.SQLite.NewSelectBuilder().
Select(
"squad_id",
@@ -2128,21 +2214,19 @@ func init() {
"user_to_squad",
)
}, "user_to_squad.squad_id"),
"username": EqualFilter("username"),
"inbound": EqualFilter("inbound"),
"created_at_start": GreaterThanFilter("created_at"),
"created_at_end": LessThanFilter("created_at"),
"updated_at_start": GreaterThanFilter("updated_at"),
"updated_at_end": LessThanFilter("updated_at"),
"sort_asc": SortAscFilter([]string{"id", "username", "inbound", "type", "created_at", "updated_at"}),
"sort_desc": SortDescFilter([]string{"id", "username", "inbound", "type", "created_at", "updated_at"}),
"offset": OffsetFilter(),
"limit": LimitFilter(),
}
connectionLimiterFilters = map[string]Filter{
"id": EqualFilter("id"),
"pk": EqualFilter("id"),
"squad_id_in": ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
"username": sql.EqualFilter("username"),
"inbound": sql.EqualFilter("inbound"),
"created_at_start": sql.GreaterThanFilter("created_at"),
"created_at_end": sql.LessThanFilter("created_at"),
"updated_at_start": sql.GreaterThanFilter("updated_at"),
"updated_at_end": sql.LessThanFilter("updated_at"),
"sort_asc": sql.SortAscFilter([]string{"id", "username", "inbound", "type", "created_at", "updated_at"}),
"sort_desc": sql.SortDescFilter([]string{"id", "username", "inbound", "type", "created_at", "updated_at"}),
"offset": sql.OffsetFilter(),
"limit": sql.LimitFilter()}
connectionLimiterFilters = map[string]sql.Filter{"id": sql.EqualFilter("id"),
"pk": sql.EqualFilter("id"),
"squad_id_in": sql.ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
return sqlbuilder.SQLite.NewSelectBuilder().
Select(
"squad_id",
@@ -2154,24 +2238,22 @@ func init() {
"connection_limiter_to_squad",
)
}, "connection_limiter_to_squad.squad_id"),
"strategy": EqualFilter("strategy"),
"username": EqualFilter("username"),
"outbound": EqualFilter("outbound"),
"connection_type": EqualFilter("connection_type"),
"lock_type": EqualFilter("lock_type"),
"created_at_start": GreaterThanFilter("created_at"),
"created_at_end": LessThanFilter("created_at"),
"updated_at_start": GreaterThanFilter("updated_at"),
"updated_at_end": LessThanFilter("updated_at"),
"sort_asc": SortAscFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "lock_type", "count", "created_at", "updated_at"}),
"sort_desc": SortDescFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "lock_type", "count", "created_at", "updated_at"}),
"offset": OffsetFilter(),
"limit": LimitFilter(),
}
bandwidthLimiterFilters = map[string]Filter{
"id": EqualFilter("id"),
"pk": EqualFilter("id"),
"squad_id_in": ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
"strategy": sql.EqualFilter("strategy"),
"username": sql.EqualFilter("username"),
"outbound": sql.EqualFilter("outbound"),
"connection_type": sql.EqualFilter("connection_type"),
"lock_type": sql.EqualFilter("lock_type"),
"created_at_start": sql.GreaterThanFilter("created_at"),
"created_at_end": sql.LessThanFilter("created_at"),
"updated_at_start": sql.GreaterThanFilter("updated_at"),
"updated_at_end": sql.LessThanFilter("updated_at"),
"sort_asc": sql.SortAscFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "lock_type", "count", "created_at", "updated_at"}),
"sort_desc": sql.SortDescFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "lock_type", "count", "created_at", "updated_at"}),
"offset": sql.OffsetFilter(),
"limit": sql.LimitFilter()}
bandwidthLimiterFilters = map[string]sql.Filter{"id": sql.EqualFilter("id"),
"pk": sql.EqualFilter("id"),
"squad_id_in": sql.ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
return sqlbuilder.SQLite.NewSelectBuilder().
Select(
"squad_id",
@@ -2183,28 +2265,22 @@ func init() {
"bandwidth_limiter_to_squad",
)
}, "bandwidth_limiter_to_squad.squad_id"),
"strategy": EqualFilter("strategy"),
"mode": EqualFilter("mode"),
"username": EqualFilter("username"),
"created_at_start": GreaterThanFilter("created_at"),
"created_at_end": LessThanFilter("created_at"),
"updated_at_start": GreaterThanFilter("updated_at"),
"updated_at_end": LessThanFilter("updated_at"),
"sort_asc": ReplacedSortAscFilter(
map[string]string{"speed": "raw_speed"},
[]string{"id", "username", "outbound", "strategy", "connection_type", "mode", "raw_speed", "created_at", "updated_at"},
),
"sort_desc": ReplacedSortDescFilter(
map[string]string{"speed": "raw_speed"},
[]string{"id", "username", "outbound", "strategy", "connection_type", "mode", "raw_speed", "created_at", "updated_at"},
),
"offset": OffsetFilter(),
"limit": LimitFilter(),
}
trafficLimiterFilters = map[string]Filter{
"id": EqualFilter("id"),
"pk": EqualFilter("id"),
"squad_id_in": ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
"strategy": sql.EqualFilter("strategy"),
"mode": sql.EqualFilter("mode"),
"username": sql.EqualFilter("username"),
"created_at_start": sql.GreaterThanFilter("created_at"),
"created_at_end": sql.LessThanFilter("created_at"),
"updated_at_start": sql.GreaterThanFilter("updated_at"),
"updated_at_end": sql.LessThanFilter("updated_at"),
"sort_asc": sql.ReplacedSortAscFilter(map[string]string{"speed": "raw_speed"},
[]string{"id", "username", "outbound", "strategy", "connection_type", "mode", "raw_speed", "created_at", "updated_at"}),
"sort_desc": sql.ReplacedSortDescFilter(map[string]string{"speed": "raw_speed"},
[]string{"id", "username", "outbound", "strategy", "connection_type", "mode", "raw_speed", "created_at", "updated_at"}),
"offset": sql.OffsetFilter(),
"limit": sql.LimitFilter()}
trafficLimiterFilters = map[string]sql.Filter{"id": sql.EqualFilter("id"),
"pk": sql.EqualFilter("id"),
"squad_id_in": sql.ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
return sqlbuilder.SQLite.NewSelectBuilder().
Select(
"squad_id",
@@ -2216,33 +2292,27 @@ func init() {
"traffic_limiter_to_squad",
)
}, "traffic_limiter_to_squad.squad_id"),
"username": EqualFilter("username"),
"outbound": EqualFilter("outbound"),
"strategy": EqualFilter("strategy"),
"mode": EqualFilter("mode"),
"used_start": SpeedGreaterEqualThanFilter("raw_used"),
"used_end": SpeedLessEqualThanFilter("raw_used"),
"quota_start": SpeedGreaterEqualThanFilter("raw_quota"),
"quota_end": SpeedLessEqualThanFilter("raw_quota"),
"created_at_start": GreaterThanFilter("created_at"),
"created_at_end": LessThanFilter("created_at"),
"updated_at_start": GreaterThanFilter("updated_at"),
"updated_at_end": LessThanFilter("updated_at"),
"sort_asc": ReplacedSortAscFilter(
map[string]string{"used": "raw_used", "quota": "raw_quota"},
[]string{"id", "username", "outbound", "strategy", "mode", "raw_used", "raw_quota", "created_at", "updated_at"},
),
"sort_desc": ReplacedSortDescFilter(
map[string]string{"used": "raw_used", "quota": "raw_quota"},
[]string{"id", "username", "outbound", "strategy", "mode", "raw_used", "raw_quota", "created_at", "updated_at"},
),
"offset": OffsetFilter(),
"limit": LimitFilter(),
}
rateLimiterFilters = map[string]Filter{
"id": EqualFilter("id"),
"pk": EqualFilter("id"),
"squad_id_in": ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
"username": sql.EqualFilter("username"),
"outbound": sql.EqualFilter("outbound"),
"strategy": sql.EqualFilter("strategy"),
"mode": sql.EqualFilter("mode"),
"used_start": sql.SpeedGreaterEqualThanFilter("raw_used"),
"used_end": sql.SpeedLessEqualThanFilter("raw_used"),
"quota_start": sql.SpeedGreaterEqualThanFilter("raw_quota"),
"quota_end": sql.SpeedLessEqualThanFilter("raw_quota"),
"created_at_start": sql.GreaterThanFilter("created_at"),
"created_at_end": sql.LessThanFilter("created_at"),
"updated_at_start": sql.GreaterThanFilter("updated_at"),
"updated_at_end": sql.LessThanFilter("updated_at"),
"sort_asc": sql.ReplacedSortAscFilter(map[string]string{"used": "raw_used", "quota": "raw_quota"},
[]string{"id", "username", "outbound", "strategy", "mode", "raw_used", "raw_quota", "created_at", "updated_at"}),
"sort_desc": sql.ReplacedSortDescFilter(map[string]string{"used": "raw_used", "quota": "raw_quota"},
[]string{"id", "username", "outbound", "strategy", "mode", "raw_used", "raw_quota", "created_at", "updated_at"}),
"offset": sql.OffsetFilter(),
"limit": sql.LimitFilter()}
rateLimiterFilters = map[string]sql.Filter{"id": sql.EqualFilter("id"),
"pk": sql.EqualFilter("id"),
"squad_id_in": sql.ExistsAndWhereInFilter(func() *sqlbuilder.SelectBuilder {
return sqlbuilder.SQLite.NewSelectBuilder().
Select(
"squad_id",
@@ -2254,20 +2324,19 @@ func init() {
"rate_limiter_to_squad",
)
}, "rate_limiter_to_squad.squad_id"),
"strategy": EqualFilter("strategy"),
"username": EqualFilter("username"),
"outbound": EqualFilter("outbound"),
"connection_type": EqualFilter("connection_type"),
"interval": EqualFilter("interval"),
"count_start": GreaterEqualThanFilter("count"),
"count_end": LessEqualThanFilter("count"),
"created_at_start": GreaterThanFilter("created_at"),
"created_at_end": LessThanFilter("created_at"),
"updated_at_start": GreaterThanFilter("updated_at"),
"updated_at_end": LessThanFilter("updated_at"),
"sort_asc": SortAscFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "count", "interval", "created_at", "updated_at"}),
"sort_desc": SortDescFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "count", "interval", "created_at", "updated_at"}),
"offset": OffsetFilter(),
"limit": LimitFilter(),
}
"strategy": sql.EqualFilter("strategy"),
"username": sql.EqualFilter("username"),
"outbound": sql.EqualFilter("outbound"),
"connection_type": sql.EqualFilter("connection_type"),
"interval": sql.EqualFilter("interval"),
"count_start": sql.GreaterEqualThanFilter("count"),
"count_end": sql.LessEqualThanFilter("count"),
"created_at_start": sql.GreaterThanFilter("created_at"),
"created_at_end": sql.LessThanFilter("created_at"),
"updated_at_start": sql.GreaterThanFilter("updated_at"),
"updated_at_end": sql.LessThanFilter("updated_at"),
"sort_asc": sql.SortAscFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "count", "interval", "created_at", "updated_at"}),
"sort_desc": sql.SortDescFilter([]string{"id", "username", "outbound", "strategy", "connection_type", "count", "interval", "created_at", "updated_at"}),
"offset": sql.OffsetFilter(),
"limit": sql.LimitFilter()}
}

View File

@@ -0,0 +1,16 @@
package sqlite
import (
"encoding/json"
)
func marshalStringSlice(values []string) (string, error) {
if values == nil {
values = []string{}
}
data, err := json.Marshal(values)
if err != nil {
return "", err
}
return string(data), nil
}

View File

@@ -1,195 +0,0 @@
package postgresql
import (
"encoding/json"
"slices"
"strconv"
"github.com/huandu/go-sqlbuilder"
"github.com/sagernet/sing/common/byteformats"
E "github.com/sagernet/sing/common/exceptions"
)
type Filter func(sb *sqlbuilder.SelectBuilder, value []string) error
func EqualFilter(field string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
sb.Where(sb.Equal(field, value[0]))
return nil
}
}
func EqualOrNullFilter(field string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
sb.Where(sb.Or(sb.Equal(field, value[0]), sb.IsNull(field)))
return nil
}
}
func GreaterThanFilter(field string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
sb.Where(sb.GreaterThan(field, value[0]))
return nil
}
}
func LessThanFilter(field string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
sb.Where(sb.LessThan(field, value[0]))
return nil
}
}
func GreaterEqualThanFilter(field string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
sb.Where(sb.GreaterEqualThan(field, value[0]))
return nil
}
}
func LessEqualThanFilter(field string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
sb.Where(sb.LessEqualThan(field, value[0]))
return nil
}
}
func SpeedGreaterEqualThanFilter(field string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
bytesSpeed, err := json.Marshal(value[0])
if err != nil {
return err
}
speed := &byteformats.NetworkBytesCompat{}
err = speed.UnmarshalJSON(bytesSpeed)
if err != nil {
return err
}
sb.Where(sb.GreaterEqualThan(field, speed.Value()))
return nil
}
}
func SpeedLessEqualThanFilter(field string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
bytesSpeed, err := json.Marshal(value[0])
if err != nil {
return err
}
speed := &byteformats.NetworkBytesCompat{}
err = speed.UnmarshalJSON(bytesSpeed)
if err != nil {
return err
}
sb.Where(sb.LessEqualThan(field, speed.Value()))
return nil
}
}
func ExistsAndWhereInFilter(subqueryFactory func() *sqlbuilder.SelectBuilder, field string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
values := make([]interface{}, len(value))
for i, v := range value {
values[i] = v
}
subquery := subqueryFactory()
subquery.Where(subquery.In(field, values...))
sb.Where(sb.Exists(subquery))
return nil
}
}
func InFilter(field string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
if len(value) == 0 {
return nil
}
values := make([]interface{}, len(value))
for i, v := range value {
values[i] = v
}
sb.Where(sb.In(field, values...))
return nil
}
}
func SortAscFilter(columns []string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
column, err := isValidSortColumn(value[0], columns)
if err != nil {
return err
}
sb.OrderByAsc(column)
return nil
}
}
func SortDescFilter(columns []string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
column, err := isValidSortColumn(value[0], columns)
if err != nil {
return err
}
sb.OrderByDesc(column)
return nil
}
}
func ReplacedSortAscFilter(replace map[string]string, columns []string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
column, ok := replace[value[0]]
if !ok {
column = value[0]
}
column, err := isValidSortColumn(column, columns)
if err != nil {
return err
}
sb.OrderByAsc(column)
return nil
}
}
func ReplacedSortDescFilter(replace map[string]string, columns []string) Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
column, ok := replace[value[0]]
if !ok {
column = value[0]
}
column, err := isValidSortColumn(column, columns)
if err != nil {
return err
}
sb.OrderByDesc(column)
return nil
}
}
func LimitFilter() Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
limit, err := strconv.Atoi(value[0])
if err != nil {
return err
}
sb.Limit(limit)
return nil
}
}
func OffsetFilter() Filter {
return func(sb *sqlbuilder.SelectBuilder, value []string) error {
offset, err := strconv.Atoi(value[0])
if err != nil {
return err
}
sb.Offset(offset)
return nil
}
}
func isValidSortColumn(column string, columns []string) (string, error) {
if slices.Contains(columns, column) {
return column, nil
}
return "", E.New("invalid sort column \"", column, "\"")
}

View File

@@ -1,36 +0,0 @@
package postgresql
import (
"encoding/json"
"fmt"
)
type stringSliceJSON []string
func (s *stringSliceJSON) Scan(src interface{}) error {
if src == nil {
*s = nil
return nil
}
var data []byte
switch v := src.(type) {
case []byte:
data = v
case string:
data = []byte(v)
default:
return fmt.Errorf("stringSliceJSON.Scan: unsupported type %T", src)
}
if len(data) == 0 {
*s = nil
return nil
}
return json.Unmarshal(data, (*[]string)(s))
}
func marshalStringSlice(values []string) ([]byte, error) {
if values == nil {
values = []string{}
}
return json.Marshal(values)
}

View File

@@ -1,63 +0,0 @@
package sqlite
import (
"encoding/json"
"fmt"
)
type intSliceJSON []int
func (s *intSliceJSON) Scan(src interface{}) error {
if src == nil {
*s = nil
return nil
}
var data []byte
switch v := src.(type) {
case []byte:
data = v
case string:
data = []byte(v)
default:
return fmt.Errorf("intSliceJSON.Scan: unsupported type %T", src)
}
if len(data) == 0 {
*s = nil
return nil
}
return json.Unmarshal(data, (*[]int)(s))
}
type stringSliceJSON []string
func (s *stringSliceJSON) Scan(src interface{}) error {
if src == nil {
*s = nil
return nil
}
var data []byte
switch v := src.(type) {
case []byte:
data = v
case string:
data = []byte(v)
default:
return fmt.Errorf("stringSliceJSON.Scan: unsupported type %T", src)
}
if len(data) == 0 {
*s = nil
return nil
}
return json.Unmarshal(data, (*[]string)(s))
}
func marshalStringSlice(values []string) (string, error) {
if values == nil {
values = []string{}
}
data, err := json.Marshal(values)
if err != nil {
return "", err
}
return string(data), nil
}

View File

@@ -16,8 +16,8 @@ import (
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/service/manager/constant"
"github.com/sagernet/sing-box/service/manager/repository/postgresql"
"github.com/sagernet/sing-box/service/manager/repository/sqlite"
"github.com/sagernet/sing-box/service/manager/repository/main/postgresql"
"github.com/sagernet/sing-box/service/manager/repository/main/sqlite"
E "github.com/sagernet/sing/common/exceptions"
"github.com/shtorm-7/go-cache/v2"
wpconstant "github.com/shtorm-7/workerpool/constant"

View File

@@ -2,199 +2,223 @@ module test
go 1.26.4
require github.com/sagernet/sing-box v0.0.0
replace github.com/sagernet/sing-box => ../
replace github.com/sagernet/wireguard-go => github.com/shtorm-7/wireguard-go v0.0.2-beta.1-extended-1.4.3
replace github.com/sagernet/tailscale => github.com/shtorm-7/tailscale v1.92.4-sing-box-1.13-mod.7-extended-1.0.2
replace github.com/sagernet/sing-mux => github.com/shtorm-7/sing-mux v0.3.4-extended-1.0.0
replace github.com/ameshkov/dnscrypt/v2 => github.com/shtorm-7/dnscrypt/v2 v2.4.0-extended-1.0.0
replace github.com/sagernet/sing-vmess => github.com/shtorm-7/sing-vmess v0.2.7-extended-1.0.0
replace github.com/sagernet/sing => /home/shtorm/Projects/shtorm-7/sing
replace github.com/dolonet/mtg-multi => github.com/shtorm-7/mtg-multi v1.11.0-extended-1.0.0
replace github.com/Diniboy1123/connect-ip-go => github.com/shtorm-7/connect-ip-go v1.0.0-extended-1.0.0
replace github.com/shtorm-7/go-cache/v2 => /home/shtorm/Projects/shtorm-7/go-cache
replace github.com/sagernet/smux => /home/shtorm/Projects/shtorm-7/smux
require (
github.com/docker/docker v28.5.2+incompatible
github.com/docker/go-connections v0.6.0
github.com/AliRizaAynaci/gorl/v2 v2.2.0
github.com/Diniboy1123/connect-ip-go v0.0.0-20260409225322-8d7bb0a858a2
github.com/anthropics/anthropic-sdk-go v1.26.0
github.com/anytls/sing-anytls v0.0.11
github.com/caddyserver/certmagic v0.25.2
github.com/coder/websocket v1.8.14
github.com/cretz/bine v0.2.0
github.com/database64128/tfo-go/v2 v2.3.2
github.com/enfein/mieru/v3 v3.33.0
github.com/go-chi/chi/v5 v5.2.5
github.com/go-chi/render v1.0.3
github.com/go-playground/validator/v10 v10.30.1
github.com/gobwas/ws v1.4.0
github.com/godbus/dbus/v5 v5.2.2
github.com/gofrs/uuid/v5 v5.4.0
github.com/golang-migrate/migrate/v4 v4.19.1
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.3
github.com/huandu/go-sqlbuilder v1.39.1
github.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91
github.com/jackc/pgx/v5 v5.8.0
github.com/keybase/go-keychain v0.0.1
github.com/libdns/acmedns v0.5.0
github.com/libdns/alidns v1.0.6
github.com/libdns/cloudflare v0.2.2
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/metacubex/utls v1.8.4
github.com/mholt/acmez/v3 v3.1.6
github.com/miekg/dns v1.1.72
github.com/openai/openai-go/v3 v3.26.0
github.com/oschwald/maxminddb-golang v1.13.1
github.com/pion/datachannel v1.6.0
github.com/pion/interceptor v0.1.44
github.com/pion/rtp v1.10.1
github.com/pion/webrtc/v4 v4.2.9
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e
github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
github.com/sagernet/cors v1.2.1
github.com/sagernet/cronet-go v0.0.0-20260620140045-05ab0dc17597
github.com/sagernet/cronet-go/all v0.0.0-20260620140045-05ab0dc17597
github.com/sagernet/fswatch v0.1.2
github.com/sagernet/gomobile v0.1.12
github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1
github.com/sagernet/quic-go v0.59.0-sing-box-mod.4
github.com/sagernet/sing v0.8.10
github.com/sagernet/sing v0.8.11
github.com/sagernet/sing-box v0.0.0-00010101000000-000000000000
github.com/sagernet/sing-mux v0.3.5
github.com/sagernet/sing-quic v0.6.1
github.com/sagernet/sing-shadowsocks v0.2.8
github.com/sagernet/sing-shadowsocks2 v0.2.1
github.com/spyzhov/ajson v0.9.4
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
github.com/sagernet/sing-tun v0.8.11
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1
github.com/sagernet/smux v1.5.50-sing-box-mod.1
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.7
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20260224074747-506b7631853c
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
github.com/shtorm-7/go-cache/v2 v2.1.0-extended-1.0.2
github.com/shtorm-7/workerpool v0.5.0
github.com/spf13/cobra v1.10.2
github.com/stretchr/testify v1.11.1
go.uber.org/goleak v1.3.0
golang.org/x/net v0.52.0
github.com/vishvananda/netns v0.0.5
github.com/yosida95/uritemplate/v3 v3.0.2
go.uber.org/zap v1.28.0
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
golang.org/x/crypto v0.53.0
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90
golang.org/x/mod v0.36.0
golang.org/x/net v0.56.0
golang.org/x/sync v0.21.0
golang.org/x/sys v0.46.0
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10
google.golang.org/grpc v1.79.1
google.golang.org/protobuf v1.36.11
howett.net/plist v1.0.1
modernc.org/sqlite v1.50.0
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/AdguardTeam/golibs v0.32.7 // indirect
github.com/AliRizaAynaci/gorl/v2 v2.2.0 // indirect
github.com/Diniboy1123/connect-ip-go v0.0.0-20260409225322-8d7bb0a858a2 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ClickHouse/ch-go v0.73.0 // indirect
github.com/ClickHouse/clickhouse-go/v2 v2.47.0 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/docker/docker v28.5.2+incompatible // indirect
github.com/docker/go-connections v0.7.0 // indirect
github.com/dunglas/httpsfv v1.1.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/go-faster/city v1.0.1 // indirect
github.com/go-faster/errors v0.7.1 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/panjf2000/ants/v2 v2.12.0 // indirect
github.com/paulmach/orb v0.13.0 // indirect
github.com/pion/dtls/v3 v3.1.2 // indirect
github.com/pion/ice/v4 v4.2.1 // indirect
github.com/pion/logging v0.2.4 // indirect
github.com/pion/mdns/v2 v2.1.0 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.16 // indirect
github.com/pion/sctp v1.9.2 // indirect
github.com/pion/sdp/v3 v3.0.18 // indirect
github.com/pion/srtp/v3 v3.0.10 // indirect
github.com/pion/stun/v3 v3.1.1 // indirect
github.com/pion/transport/v4 v4.0.1 // indirect
github.com/pion/turn/v4 v4.1.4 // indirect
github.com/quic-go/quic-go v0.59.0 // indirect
github.com/redis/go-redis/v9 v9.8.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/segmentio/asm v1.2.1 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/tylertreat/BoomFilters v0.0.0-20251117164519-53813c36cc1b // indirect
github.com/wlynxg/anet v0.0.5 // indirect
github.com/zeebo/assert v1.3.0 // indirect
go.opentelemetry.io/otel v1.44.0 // indirect
go.opentelemetry.io/otel/trace v1.44.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
gvisor.dev/gvisor v0.0.0-20260408064518-65a410b0d584 // indirect
modernc.org/libc v1.72.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
)
require (
filippo.io/edwards25519 v1.1.0
github.com/AdguardTeam/golibs v0.32.7 // indirect
github.com/ajg/form v1.5.1 // indirect
github.com/akutz/memconn v0.1.0 // indirect
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
github.com/ameshkov/dnscrypt/v2 v2.4.0 // indirect
github.com/ameshkov/dnscrypt/v2 v2.4.0
github.com/ameshkov/dnsstamps v1.0.3 // indirect
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/anthropics/anthropic-sdk-go v1.26.0 // indirect
github.com/anytls/sing-anytls v0.0.11 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/caddyserver/certmagic v0.25.2 // indirect
github.com/andybalholm/brotli v1.2.1 // indirect
github.com/caddyserver/zerossl v0.1.5 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/coder/websocket v1.8.14 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect
github.com/cretz/bine v0.2.0 // indirect
github.com/database64128/netx-go v0.1.1 // indirect
github.com/database64128/tfo-go/v2 v2.3.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dolonet/mtg-multi v1.8.0 // indirect
github.com/dunglas/httpsfv v1.1.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/ebitengine/purego v0.10.0 // indirect
github.com/enfein/mieru/v3 v3.33.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 // indirect
github.com/dolonet/mtg-multi v1.8.0
github.com/ebitengine/purego v0.10.1 // indirect
github.com/florianl/go-nfqueue/v2 v2.0.2 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
github.com/gaissmai/bart v0.18.0 // indirect
github.com/go-chi/chi/v5 v5.2.5 // indirect
github.com/go-chi/render v1.0.3 // indirect
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.30.1 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.4.0 // indirect
github.com/godbus/dbus/v5 v5.2.2 // indirect
github.com/golang-migrate/migrate/v4 v4.19.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
github.com/huandu/go-clone v1.7.3 // indirect
github.com/huandu/go-sqlbuilder v1.39.1 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.8.0 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jsimonetti/rtnetlink v1.4.0 // indirect
github.com/keybase/go-keychain v0.0.1 // indirect
github.com/klauspost/compress v1.18.3 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/klauspost/compress v1.18.6 // indirect
github.com/klauspost/cpuid/v2 v2.3.0
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/libdns/acmedns v0.5.0 // indirect
github.com/libdns/alidns v1.0.6 // indirect
github.com/libdns/cloudflare v0.2.2 // indirect
github.com/libdns/libdns v1.1.1 // indirect
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mdlayher/netlink v1.9.0 // indirect
github.com/mdlayher/socket v0.5.1 // indirect
github.com/metacubex/utls v1.8.4 // indirect
github.com/mholt/acmez/v3 v3.1.6 // indirect
github.com/miekg/dns v1.1.72 // indirect
github.com/mitchellh/go-ps v1.0.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/sys/atomicwriter v0.1.0 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/openai/openai-go/v3 v3.26.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/panjf2000/ants/v2 v2.12.0 // indirect
github.com/pierrec/lz4/v4 v4.1.25 // indirect
github.com/pierrec/lz4/v4 v4.1.27 // indirect
github.com/pires/go-proxyproto v0.11.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus-community/pro-bing v0.4.0 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.59.0 // indirect
github.com/redis/go-redis/v9 v9.8.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/safchain/ethtool v0.3.0 // indirect
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect
github.com/sagernet/cors v1.2.1 // indirect
github.com/sagernet/cronet-go v0.0.0-20260513071958-2faf34666c2c // indirect
github.com/sagernet/cronet-go/all v0.0.0-20260513071958-2faf34666c2c // indirect
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260513071149-ade33496efb8 // indirect
github.com/sagernet/fswatch v0.1.2 // indirect
github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237 // indirect
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260620135226-def9ff0fb992 // indirect
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
github.com/sagernet/nftables v0.3.0-mod.2 // indirect
github.com/sagernet/sing-mux v0.3.4 // indirect
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 // indirect
github.com/sagernet/sing-tun v0.8.9 // indirect
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 // indirect
github.com/sagernet/smux v1.5.50-sing-box-mod.1 // indirect
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.7 // indirect
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20260224074747-506b7631853c // indirect
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect
github.com/shtorm-7/go-cache/v2 v2.1.0-extended-1.0.2 // indirect
github.com/shtorm-7/workerpool v0.5.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect
github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect
@@ -206,43 +230,40 @@ require (
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/tylertreat/BoomFilters v0.0.0-20251117164519-53813c36cc1b // indirect
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
github.com/vishvananda/netns v0.0.5 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
github.com/zeebo/blake3 v0.2.4 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.41.0 // indirect
go.opentelemetry.io/otel/metric v1.41.0 // indirect
go.opentelemetry.io/otel/trace v1.41.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.1 // indirect
go.uber.org/zap/exp v0.3.0 // indirect
go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
golang.org/x/crypto v0.49.0 // indirect
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect
golang.org/x/mod v0.34.0 // indirect
golang.org/x/oauth2 v0.34.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/sys v0.42.0 // indirect
golang.org/x/term v0.41.0 // indirect
golang.org/x/text v0.35.0 // indirect
golang.org/x/time v0.12.0 // indirect
golang.org/x/tools v0.43.0 // indirect
golang.org/x/term v0.44.0 // indirect
golang.org/x/text v0.38.0 // indirect
golang.org/x/time v0.12.0
golang.org/x/tools v0.45.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 // indirect
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
google.golang.org/grpc v1.79.1 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.1 // indirect
lukechampine.com/blake3 v1.4.1 // indirect
modernc.org/libc v1.72.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
modernc.org/sqlite v1.50.0 // indirect
gopkg.in/yaml.v3 v3.0.1
lukechampine.com/blake3 v1.4.1
)
replace github.com/sagernet/wireguard-go => github.com/shtorm-7/wireguard-go v0.0.2-beta.1-extended-1.4.3
replace github.com/sagernet/tailscale => github.com/shtorm-7/tailscale v1.92.4-sing-box-1.13-mod.7-extended-1.0.2
replace github.com/sagernet/sing-mux => github.com/shtorm-7/sing-mux v0.3.4-extended-1.0.0
replace github.com/ameshkov/dnscrypt/v2 => github.com/shtorm-7/dnscrypt/v2 v2.4.0-extended-1.0.0
replace github.com/sagernet/sing-vmess => github.com/shtorm-7/sing-vmess v0.2.7-extended-1.0.0
replace github.com/dolonet/mtg-multi => github.com/shtorm-7/mtg-multi v1.11.0-extended-1.0.0
replace github.com/Diniboy1123/connect-ip-go => github.com/shtorm-7/connect-ip-go v1.0.0-extended-1.1.0
replace github.com/shtorm-7/go-cache/v2 => github.com/shtorm-7/go-cache/v2 v2.1.0-extended-1.2.0
replace github.com/sagernet/sing => github.com/shtorm-7/sing v0.8.10-extended-1.2.0
replace github.com/sagernet/sing-box => ../

View File

@@ -8,6 +8,11 @@ github.com/AliRizaAynaci/gorl/v2 v2.2.0 h1:E8oAwkordOwm9ItNNVJ5VKvGroDcHvWNvG11H
github.com/AliRizaAynaci/gorl/v2 v2.2.0/go.mod h1:13wcj/W736v44b6uygUuwypMY9N3RXJuhAYXukIIdCo=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/ClickHouse/ch-go v0.73.0 h1:jsHiGRbQ3sz+gekvDFJF29LWDo5dzbJm5s1h8TWVP2M=
github.com/ClickHouse/ch-go v0.73.0/go.mod h1:wkFIxrqlXeRJ9cn3r5Fz5Qen9jl5aTMPuGZeuJpANNY=
github.com/ClickHouse/clickhouse-go v1.4.3 h1:iAFMa2UrQdR5bHJ2/yaSLffZkxpcOYQMCUuKeNXGdqc=
github.com/ClickHouse/clickhouse-go/v2 v2.47.0 h1:ZDAzrnKSOPTIsm4tdUNfrii2yc8dk4SVRLC77BR7Z5Q=
github.com/ClickHouse/clickhouse-go/v2 v2.47.0/go.mod h1:sPj7C7UYQ2MWHcfX+4eGN6nwnCqwUKfgO6PcwKpd6K8=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
@@ -22,6 +27,8 @@ github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1O
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eTWro=
github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/anthropics/anthropic-sdk-go v1.26.0 h1:oUTzFaUpAevfuELAP1sjL6CQJ9HHAfT7CoSYSac11PY=
github.com/anthropics/anthropic-sdk-go v1.26.0/go.mod h1:qUKmaW+uuPB64iy1l+4kOSvaLqPXnHTTBKH6RVZ7q5Q=
github.com/anytls/sing-anytls v0.0.11 h1:w8e9Uj1oP3m4zxkyZDewPk0EcQbvVxb7Nn+rapEx4fc=
@@ -54,6 +61,7 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0=
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U=
@@ -68,6 +76,7 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa h1:h8TfIT1xc8FWbwwpmHn1J5i43Y0uZP97GqasGCzSRJk=
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa/go.mod h1:Nx87SkVqTKd8UtT+xu7sM/l+LgXs6c0aHrlKusR+2EQ=
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dhui/dktest v0.4.6 h1:+DPKyScKSEp3VLtbMDHcUq6V5Lm5zfZZVb0Sk7Ahom4=
@@ -80,6 +89,7 @@ github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaft
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dunglas/httpsfv v1.1.0 h1:Jw76nAyKWKZKFrpMMcL76y35tOpYHqQPzHQiwDvpe54=
@@ -88,6 +98,7 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU=
github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/ebitengine/purego v0.10.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/enfein/mieru/v3 v3.33.0 h1:hv2jK8nqYHwpSG86U2rpZR2I8Aff1/J3ifRmd9NBbFc=
github.com/enfein/mieru/v3 v3.33.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
@@ -108,6 +119,10 @@ github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw=
github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg=
github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo=
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced h1:Q311OHjMh/u5E2TITc++WlTP5We0xNseRMkHDyvhW7I=
@@ -145,14 +160,18 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdFk6Vl1yPGtSRtwGpVkWyZww1OCil2MI=
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
@@ -171,6 +190,7 @@ github.com/huandu/go-sqlbuilder v1.39.1 h1:uUaj41yLNTQBe7ojNF6Im1RPbHCN4zCjMRyST
github.com/huandu/go-sqlbuilder v1.39.1/go.mod h1:zdONH67liL+/TvoUMwnZP/sUYGSSvHh9psLe/HpXn8E=
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91 h1:u9i04mGE3iliBh0EFuWaKsmcwrLacqGmq1G3XoaM7gY=
github.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91/go.mod h1:qfvBmyDNp+/liLEYWRvqny/PEz9hGe2Dz833eXILSmo=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
@@ -181,12 +201,15 @@ github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo=
github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUFKrq2I=
github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E=
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw=
github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -247,12 +270,49 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
github.com/panjf2000/ants/v2 v2.12.0 h1:u9JhESo83i/GkZnhfTNuFMMWcNt7mnV1bGJ6FT4wXH8=
github.com/panjf2000/ants/v2 v2.12.0/go.mod h1:tSQuaNQ6r6NRhPt+IZVUevvDyFMTs+eS4ztZc52uJTY=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/paulmach/orb v0.13.0 h1:r7n7mQGGF+cj/CbcivEj9J3HGK+XR+yXnvzRdq9saIw=
github.com/paulmach/orb v0.13.0/go.mod h1:6scRWINywA2Jf05dcjOfLfxrUIMECvTSG2MVbRLxu/k=
github.com/pierrec/lz4/v4 v4.1.25 h1:kocOqRffaIbU5djlIBr7Wh+cx82C0vtFb0fOurZHqD0=
github.com/pierrec/lz4/v4 v4.1.25/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
github.com/pierrec/lz4/v4 v4.1.27 h1:+PhzhWDrjRj89TH2sw43nE3+4+W8lSxIuQadEHZyjUk=
github.com/pierrec/lz4/v4 v4.1.27/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
github.com/pion/datachannel v1.6.0 h1:XecBlj+cvsxhAMZWFfFcPyUaDZtd7IJvrXqlXD/53i0=
github.com/pion/datachannel v1.6.0/go.mod h1:ur+wzYF8mWdC+Mkis5Thosk+u/VOL287apDNEbFpsIk=
github.com/pion/dtls/v3 v3.1.2 h1:gqEdOUXLtCGW+afsBLO0LtDD8GnuBBjEy6HRtyofZTc=
github.com/pion/dtls/v3 v3.1.2/go.mod h1:Hw/igcX4pdY69z1Hgv5x7wJFrUkdgHwAn/Q/uo7YHRo=
github.com/pion/ice/v4 v4.2.1 h1:XPRYXaLiFq3LFDG7a7bMrmr3mFr27G/gtXN3v/TVfxY=
github.com/pion/ice/v4 v4.2.1/go.mod h1:2quLV1S5v1tAx3VvAJaH//KGitRXvo4RKlX6D3tnN+c=
github.com/pion/interceptor v0.1.44 h1:sNlZwM8dWXU9JQAkJh8xrarC0Etn8Oolcniukmuy0/I=
github.com/pion/interceptor v0.1.44/go.mod h1:4atVlBkcgXuUP+ykQF0qOCGU2j7pQzX2ofvPRFsY5RY=
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/mdns/v2 v2.1.0 h1:3IJ9+Xio6tWYjhN6WwuY142P/1jA0D5ERaIqawg/fOY=
github.com/pion/mdns/v2 v2.1.0/go.mod h1:pcez23GdynwcfRU1977qKU0mDxSeucttSHbCSfFOd9A=
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
github.com/pion/rtcp v1.2.16 h1:fk1B1dNW4hsI78XUCljZJlC4kZOPk67mNRuQ0fcEkSo=
github.com/pion/rtcp v1.2.16/go.mod h1:/as7VKfYbs5NIb4h6muQ35kQF/J0ZVNz2Z3xKoCBYOo=
github.com/pion/rtp v1.10.1 h1:xP1prZcCTUuhO2c83XtxyOHJteISg6o8iPsE2acaMtA=
github.com/pion/rtp v1.10.1/go.mod h1:rF5nS1GqbR7H/TCpKwylzeq6yDM+MM6k+On5EgeThEM=
github.com/pion/sctp v1.9.2 h1:HxsOzEV9pWoeggv7T5kewVkstFNcGvhMPx0GvUOUQXo=
github.com/pion/sctp v1.9.2/go.mod h1:OTOlsQ5EDQ6mQ0z4MUGXt2CgQmKyafBEXhUVqLRB6G8=
github.com/pion/sdp/v3 v3.0.18 h1:l0bAXazKHpepazVdp+tPYnrsy9dfh7ZbT8DxesH5ZnI=
github.com/pion/sdp/v3 v3.0.18/go.mod h1:ZREGo6A9ZygQ9XkqAj5xYCQtQpif0i6Pa81HOiAdqQ8=
github.com/pion/srtp/v3 v3.0.10 h1:tFirkpBb3XccP5VEXLi50GqXhv5SKPxqrdlhDCJlZrQ=
github.com/pion/srtp/v3 v3.0.10/go.mod h1:3mOTIB0cq9qlbn59V4ozvv9ClW/BSEbRp4cY0VtaR7M=
github.com/pion/stun/v3 v3.1.1 h1:CkQxveJ4xGQjulGSROXbXq94TAWu8gIX2dT+ePhUkqw=
github.com/pion/stun/v3 v3.1.1/go.mod h1:qC1DfmcCTQjl9PBaMa5wSn3x9IPmKxSdcCsxBcDBndM=
github.com/pion/transport/v4 v4.0.1 h1:sdROELU6BZ63Ab7FrOLn13M6YdJLY20wldXW2Cu2k8o=
github.com/pion/transport/v4 v4.0.1/go.mod h1:nEuEA4AD5lPdcIegQDpVLgNoDGreqM/YqmEx3ovP4jM=
github.com/pion/turn/v4 v4.1.4 h1:EU11yMXKIsK43FhcUnjLlrhE4nboHZq+TXBIi3QpcxQ=
github.com/pion/turn/v4 v4.1.4/go.mod h1:ES1DXVFKnOhuDkqn9hn5VJlSWmZPaRJLyBXoOeO/BmQ=
github.com/pion/webrtc/v4 v4.2.9 h1:DZIh1HAhPIL3RvwEDFsmL5hfPSLEpxsQk9/Jir2vkJE=
github.com/pion/webrtc/v4 v4.2.9/go.mod h1:9EmLZve0H76eTzf8v2FmchZ6tcBXtDgpfTEu+drW6SY=
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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -266,6 +326,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/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e h1:dCWirM5F3wMY+cmRda/B1BiPsFtmzXqV9b0hLWtVBMs=
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e/go.mod h1:9leZcVcItj6m9/CfHY5Em/iBrCz7js8LcRQGTKEEv2M=
github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI=
github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
@@ -274,76 +336,81 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/rs/zerolog v1.35.0 h1:VD0ykx7HMiMJytqINBsKcbLS+BJ4WYjz+05us+LRTdI=
github.com/rs/zerolog v1.35.0/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0=
github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs=
github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1/go.mod h1:JULDuzTMn2gyZFcjpTVZP4/UuwAdbHJ0bum2RdjXojU=
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0=
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
github.com/sagernet/cronet-go v0.0.0-20260513071958-2faf34666c2c h1:JatMWK/reVa5Y+x3D3l49SVtHB/EQUEtQnAFTxPBNxY=
github.com/sagernet/cronet-go v0.0.0-20260513071958-2faf34666c2c/go.mod h1:T/mwtrpC4JlWfScw73CmSBvHzIvc7BatQ1MhRr+cYNw=
github.com/sagernet/cronet-go/all v0.0.0-20260513071958-2faf34666c2c h1:F/tL+VzLZ2F4SNZZze6SRSRL/jcX7LwIsuL1+hECiz0=
github.com/sagernet/cronet-go/all v0.0.0-20260513071958-2faf34666c2c/go.mod h1:GGE1tBbFgHq8kV99AKX1JXFY+9FvgNSK/W6Z5j24Ihc=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260513071149-ade33496efb8 h1:NCKxyAnEkwsEueAEbuuUUjs2FEZAIflr+WN3Mwbvsdg=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260513071149-ade33496efb8/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260513071149-ade33496efb8 h1:o3AGm7/L/zAdBvPu0u1dFgDR/tH086qyuXZkjLNJ7/E=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260513071149-ade33496efb8/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260513071149-ade33496efb8 h1:AeO8yHQj7aNj16fiJNU797alyuM3T+3VASnETHeV220=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260513071149-ade33496efb8/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260513071149-ade33496efb8 h1:ZgW2/Qq/5Q6eTlW80QXLokU56kfjvbLJSEGYTkcG3hU=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260513071149-ade33496efb8/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260513071149-ade33496efb8 h1:orYgvX5X9aUa+sRrAuuqA6PXiiBUI2D367ZJqan4lIU=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260513071149-ade33496efb8/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260513071149-ade33496efb8 h1:2w1s3wEk7qW2w4IGwlJflxwXBM97UChNiqAErKpvHr0=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260513071149-ade33496efb8/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260513071149-ade33496efb8 h1:22k6CB3d4gHT+SARUh2bgNyGU4QwYupcCdP8cGuwygY=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260513071149-ade33496efb8/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260513071149-ade33496efb8 h1:PkJ5EaqLrv6bNR+MHx1/joJXoRcoYcV7JA4NtXbFQsc=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260513071149-ade33496efb8/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260513071149-ade33496efb8 h1:V629H+OQ9yOR2d0Jkq5y42j5btpvoSWJbUaBH7FCGPI=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260513071149-ade33496efb8/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260513071149-ade33496efb8 h1:gfObF5uoqJslCdMRRm2Yo+gmPJQPVlrci5Myrki0Kzk=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260513071149-ade33496efb8/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260513071149-ade33496efb8 h1:JRPN0RBKvoOBEHezJh/54KD9ftWL7YadtcCgOf/vRnw=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260513071149-ade33496efb8/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260513071149-ade33496efb8 h1:mM8gNdFlXSpjZFs9kgaMgW94oTRF8YdEEQgdOp/OEUA=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260513071149-ade33496efb8/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260513071149-ade33496efb8 h1:ZtCH0fH07giTK6wqkenA9fdFYt7krjWiyOvC8z9nPwk=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260513071149-ade33496efb8/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260513071149-ade33496efb8 h1:Uviqmw+Q4No9kCxJWJ5CYcq6PNHB9f0jQhd15j39+no=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260513071149-ade33496efb8/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260513071149-ade33496efb8 h1:la4zRTE9zpZCmsixwzKT2LnHuo0e439EmGwOlB1An9Q=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260513071149-ade33496efb8/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260513071149-ade33496efb8 h1:KodFGMqn+X2dqET0O3xww3iemAGmpoC8U4JW8gwt0x4=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260513071149-ade33496efb8/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260513071149-ade33496efb8 h1:QTk1RXNLOIcorZYcF0rBrwLpCIZCKEA2Jr69eFrt8xg=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260513071149-ade33496efb8/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260513071149-ade33496efb8 h1:SXqSlM/GjZFvNdUV3IvHq5gqHfW4iWlQHMGzEsgXGXE=
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260513071149-ade33496efb8/go.mod h1:Wt5uFdU3tnmm8YzobYewwdF7Mt6SucRQg6xeTNWC3Tk=
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260513071149-ade33496efb8 h1:aAgLWpfESvy7rfDVH7ioOZQ7u2kmRsbUqJVrwJtkFWs=
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260513071149-ade33496efb8/go.mod h1:lyIF6wKBLwWa5ZXaAKbAoewewl+yCHo2iYev39Mbj4E=
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260513071149-ade33496efb8 h1:oTLUyhLckc8TZQ8SRCapgTYyRbz1pBpIvzjMCLMPFu8=
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260513071149-ade33496efb8/go.mod h1:H46PnSTTZNcZokLLiDeMDaHiS1l14PH3tzWi0eykjD8=
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260513071149-ade33496efb8 h1:LHm/85Y3zN0kNgG+li5qHvP3dzvavEytCYzdLtrfrrg=
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260513071149-ade33496efb8/go.mod h1:RBhSUDAKWq7fswtV4nQUQhuaTLcX3ettR7teA7/yf2w=
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260513071149-ade33496efb8 h1:Pom5TSHV8Cln73uOgQlJ+JtmEu9xh+OuLHWq57dBaVg=
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260513071149-ade33496efb8/go.mod h1:wRzoIOGG4xbpp3Gh3triLKwMwYriScXzFtunLYhY4w0=
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260513071149-ade33496efb8 h1:1pPcb15BonaFl4153tRo7zOJ7U2zD1vjH+5JipSfJ3g=
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260513071149-ade33496efb8/go.mod h1:LNiZXmWil1OPwKCheqQjtakZlJuKGFz+iv2eGF76Hhs=
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260513071149-ade33496efb8 h1:3Dy4exYQ/IVJGcnTtvW3LmjfjDaxFgJT1hn/ALBpd2M=
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260513071149-ade33496efb8/go.mod h1:YFDGKTkpkJGc5+hnX/RYosZyTWg9h+68VB55fYRRLYc=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260513071149-ade33496efb8 h1:mo9YMCYTGCRUiWNKtPVQb+qEetufxnch372xUOh9q3M=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260513071149-ade33496efb8/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260513071149-ade33496efb8 h1:mhh3JEDDx68oKT4kfqKlWp5QTyzVR84OS/qgqHYIbq0=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260513071149-ade33496efb8/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260513071149-ade33496efb8 h1:04KOo38hZojV3bJ5Vqwbpj48ZQy6o7aliYXLN/TNX6g=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260513071149-ade33496efb8/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260513071149-ade33496efb8 h1:p535QakpDZEeBz/BfFZGZo0D+Pdn74TE8UTr6c6MSog=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260513071149-ade33496efb8/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260513071149-ade33496efb8 h1:dovTyKHh3toBIUOS70P4Yx+3Baw6Gppsfy1sJbXoAy0=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260513071149-ade33496efb8/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
github.com/sagernet/cronet-go v0.0.0-20260620140045-05ab0dc17597 h1:QkwE/ZFnShDuPF+ExmAyZlQaMwFNgkYZMekrabiStfg=
github.com/sagernet/cronet-go v0.0.0-20260620140045-05ab0dc17597/go.mod h1:T/mwtrpC4JlWfScw73CmSBvHzIvc7BatQ1MhRr+cYNw=
github.com/sagernet/cronet-go/all v0.0.0-20260620140045-05ab0dc17597 h1:cLALmGKP9eOS8622gWQIiVbZlOfH29PGNsoxbEloIdk=
github.com/sagernet/cronet-go/all v0.0.0-20260620140045-05ab0dc17597/go.mod h1:zVHZ5tgDTwbNvUGffAgLmouYs4in0grEzhSdaggoZOw=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260620135226-def9ff0fb992 h1:J9l8PP4vb79Wm5zKaMO6LNZ/AiP1FvyAWJBlkKHrRBU=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260620135226-def9ff0fb992 h1:wXDjUNeKuihv85Kg51FomkiEH7xGsDgRcfRLiyZxacQ=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260620135226-def9ff0fb992 h1:IF04nGyY3Q6Nbk9XJwTX1mckwhf12iIx4RhZ4TLOZIU=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260620135226-def9ff0fb992/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260620135226-def9ff0fb992 h1:dlnG1E42xx8ms2fyZigYwsYJ1Gqoj2QT8WeGlpOAWK8=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260620135226-def9ff0fb992 h1:aYAQQN3jZP89MmT1ZzpJz52jAsXx1WApmv5Qidc+ez4=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260620135226-def9ff0fb992 h1:n81+aLphvjLpL2M6lI+BC8Ldw4S/FPA3CFDXTWL4g3I=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260620135226-def9ff0fb992 h1:mOseesF+CxgPG2U1a2Yh2fUUMdOaPxSuk4eIL6g7EU8=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260620135226-def9ff0fb992/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260620135226-def9ff0fb992 h1:JK9kP72IxAoyVQTnh9gGkh8S9RjP4FBkj95WjrLPyKs=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260620135226-def9ff0fb992 h1:3EtgLRsUpmeRaOBynTARxVC8tDegykigutmpAow2ayc=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260620135226-def9ff0fb992/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260620135226-def9ff0fb992 h1:Vr3I2sC9E/1FurpZwJXAL29C7jJROyN3JfulQWjhKuA=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260620135226-def9ff0fb992 h1:flxwC8loz0C4LQ/tLK7LvNMKx4iqaXayPggzzCxCevI=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260620135226-def9ff0fb992/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260620135226-def9ff0fb992 h1:G4vwPmOVR/jXDngIUC9owbEtMKXLZl/BgUHhEWWl8ec=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260620135226-def9ff0fb992 h1:zHIxR2FlJOW5GRmgwyA2Gjgx7potOCtlOmdl8k4mwJI=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260620135226-def9ff0fb992/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260620135226-def9ff0fb992 h1:U1OrR5zP+lkOPqrDpZsn8sPK1XBWZ84isXaFBZLsOfs=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260620135226-def9ff0fb992/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260620135226-def9ff0fb992 h1:F59ptY4AdtKEg73OWaL+lTb5yoxp5b/gTuDbvA6xMyg=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260620135226-def9ff0fb992 h1:Y5axK4sCWXH+2OCpKYPI8nX3OSBuRb/6yC+5xBi9/uo=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260620135226-def9ff0fb992/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260620135226-def9ff0fb992 h1:QCBwCdv9y+RJj7p0b9Db2p9fFt1wtnawD0sn9oV3vRs=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260620135226-def9ff0fb992/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260620135226-def9ff0fb992 h1:6gXFFaAMiGCPZdfUs64qzj9cl7EleVs9HsNfRi8jWWw=
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:Wt5uFdU3tnmm8YzobYewwdF7Mt6SucRQg6xeTNWC3Tk=
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260620135226-def9ff0fb992 h1:VGoIX2u4CWVg9kiyjQdIpFMaFUNCW3yz0pyrEKI5X0o=
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260620135226-def9ff0fb992/go.mod h1:lyIF6wKBLwWa5ZXaAKbAoewewl+yCHo2iYev39Mbj4E=
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260620135226-def9ff0fb992 h1:SjPuqtUNCzIDaEm7iY86JZ7L+ixTmai4i2DIC++eUvw=
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260620135226-def9ff0fb992/go.mod h1:H46PnSTTZNcZokLLiDeMDaHiS1l14PH3tzWi0eykjD8=
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260620135226-def9ff0fb992 h1:ao2FrDzTYhu2MYsMri9nzqIdnAL7ooUWQN6/FFr+Lbk=
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260620135226-def9ff0fb992/go.mod h1:RBhSUDAKWq7fswtV4nQUQhuaTLcX3ettR7teA7/yf2w=
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260620135226-def9ff0fb992 h1:5gPMu6EUlX6gqCRTOJrJk1FMILO6ugtnopQF1c2R/lY=
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260620135226-def9ff0fb992/go.mod h1:wRzoIOGG4xbpp3Gh3triLKwMwYriScXzFtunLYhY4w0=
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260620135226-def9ff0fb992 h1:UaLOQKbjnLrO943Sm+ff/jm+NmemRuJXiImmtqShd8s=
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:LNiZXmWil1OPwKCheqQjtakZlJuKGFz+iv2eGF76Hhs=
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260620135226-def9ff0fb992 h1:wxlsDfxDowVk99Ay2hzfuIXPpXH1lGQxSL/2sX/D7jw=
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260620135226-def9ff0fb992/go.mod h1:YFDGKTkpkJGc5+hnX/RYosZyTWg9h+68VB55fYRRLYc=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260620135226-def9ff0fb992 h1:pgRpWh2JPE73mtedovPPu3gmmAqHz3Rfz79QVxciu2o=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260620135226-def9ff0fb992/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260620135226-def9ff0fb992 h1:9jtXyxukTS2ZdhMy3u1hg4StkZpgP48BOfgYhXf835w=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260620135226-def9ff0fb992 h1:gKgD1LJZbZzacaaqBQX/YKy4dyomhn8xtfmDKayVLW4=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260620135226-def9ff0fb992/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260620135226-def9ff0fb992 h1:Lv8gtKP4QRn6Yjv3h5L215aGQBgwCyAE5YqejmN9Bqc=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260620135226-def9ff0fb992 h1:2wsRAcqJHOTlj6zGc3oQyxAZHDnGwyB/pTdAOUtLgHY=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260620135226-def9ff0fb992/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
github.com/sagernet/fswatch v0.1.2 h1:/TT7k4mkce1qFPxamLO842WjqBgbTBiXP2mlUjp9PFk=
github.com/sagernet/fswatch v0.1.2/go.mod h1:5BpGmpUQVd3Mc5r313HRpvADHRg3/rKn5QbwFteB880=
github.com/sagernet/gomobile v0.1.12/go.mod h1:A8l3FlHi2D/+mfcd4HHvk5DGFPW/ShFb9jHP5VmSiDY=
github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1 h1:AzCE2RhBjLJ4WIWc/GejpNh+z30d5H1hwaB0nD9eY3o=
github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1/go.mod h1:NJKBtm9nVEK3iyOYWsUlrDQuoGh4zJ4KOPhSYVidvQ4=
github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237 h1:SUPFNB+vSP4RBPrSEgNII+HkfqC8hKMpYLodom4o4EU=
github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237/go.mod h1:QkkPEJLw59/tfxgapHta14UL5qMUah5NXhO0Kw2Kan4=
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
@@ -360,20 +427,27 @@ github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnq
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w=
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
github.com/sagernet/sing-tun v0.8.9 h1:ixFKKUGdVcJl4wb0xbL36hobiw9l6DIH497EQf5ILpM=
github.com/sagernet/sing-tun v0.8.9/go.mod h1:QvarqUtHfj1ULaRR+6kZOS/OoCE+pYGq67A5tyIy+dQ=
github.com/sagernet/sing-tun v0.8.11 h1:BFu4+8LNl2JiTQtto5f+5AbkH90qgdoZEAqUbGiEXCg=
github.com/sagernet/sing-tun v0.8.11/go.mod h1:QvarqUtHfj1ULaRR+6kZOS/OoCE+pYGq67A5tyIy+dQ=
github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478=
github.com/sagernet/smux v1.5.50-sing-box-mod.1/go.mod h1:NjhsCEWedJm7eFLyhuBgIEzwfhRmytrUoiLluxs5Sk8=
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA=
github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/shtorm-7/connect-ip-go v1.0.0-extended-1.0.0 h1:ws7BIsYLd31Wjifq88BYCHRVlgO+07iwil39s6ERba8=
github.com/shtorm-7/connect-ip-go v1.0.0-extended-1.0.0/go.mod h1:mRwx4w32qQxsWB2kThuHpbo7iNjJiq1jYWubgqEPjHA=
github.com/shtorm-7/connect-ip-go v1.0.0-extended-1.1.0/go.mod h1:mRwx4w32qQxsWB2kThuHpbo7iNjJiq1jYWubgqEPjHA=
github.com/shtorm-7/dnscrypt/v2 v2.4.0-extended-1.0.0 h1:e5s7RKBd2rIPR0StbvZ2vTVtJ5jDTsTk5wtIIapZTRg=
github.com/shtorm-7/dnscrypt/v2 v2.4.0-extended-1.0.0/go.mod h1:WpEFV2uhebXb8Jhes/5/fSdpmhGV8TL22RDaeWwV6hI=
github.com/shtorm-7/go-cache/v2 v2.1.0-extended-1.1.0 h1:PLZ/YHqnApPx13wt6MX3ItqESp4ueBr1tGSi0bEGqYw=
github.com/shtorm-7/go-cache/v2 v2.1.0-extended-1.1.0/go.mod h1:Ek4yz5OK6stwhLKgLsRRYDI+FA+ZWvRJiWLjsi/vMM4=
github.com/shtorm-7/go-cache/v2 v2.1.0-extended-1.2.0 h1:aOd9Vy2LGSwgMM+4805AgLBE/MQf8UymbXHxUZjSmoU=
github.com/shtorm-7/go-cache/v2 v2.1.0-extended-1.2.0/go.mod h1:Ek4yz5OK6stwhLKgLsRRYDI+FA+ZWvRJiWLjsi/vMM4=
github.com/shtorm-7/mtg-multi v1.11.0-extended-1.0.0 h1:iBLll4ZZG8ULQcHWs6gGslZWtBN72Zo1zjySzMVHF7g=
github.com/shtorm-7/mtg-multi v1.11.0-extended-1.0.0/go.mod h1:3rvdhwdPABkwKBdvgMt3VwMn9uSq8hpoHRezZ5jRJU0=
github.com/shtorm-7/sing v0.8.10-extended-1.1.0 h1:P4JL2cugjvEvnYu8tMmpR30SE1qsS45RcnNEwzDz5as=
github.com/shtorm-7/sing v0.8.10-extended-1.1.0/go.mod h1:olXxWQNqRW/l2Q6JI3b2Qmz8iQnIFlOeeH8bx6JhgUA=
github.com/shtorm-7/sing v0.8.10-extended-1.2.0 h1:5yw9j0+P2QkRWvxBvb71wvNdpAlHmmpBv4hj2gqvass=
github.com/shtorm-7/sing v0.8.10-extended-1.2.0/go.mod h1:olXxWQNqRW/l2Q6JI3b2Qmz8iQnIFlOeeH8bx6JhgUA=
github.com/shtorm-7/sing-mux v0.3.4-extended-1.0.0 h1:a5OoXr3e2ACbM6vDIaaGL44IdHQ6wPjcSoU13vfC0Sw=
github.com/shtorm-7/sing-mux v0.3.4-extended-1.0.0/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk=
github.com/shtorm-7/sing-vmess v0.2.7-extended-1.0.0 h1:WVheKmQH5hSQbJU1ZTKthKSutkTLWSb2hp4JuQhJBow=
@@ -386,6 +460,9 @@ github.com/shtorm-7/workerpool v0.5.0 h1:NPZuNgyH0EUm4aQsTL09xR1iV+7GCFw6jX9Z4aA
github.com/shtorm-7/workerpool v0.5.0/go.mod h1:NI0pUZgmGu0BdKO9j3mct1DNZmgXbyTS9foorljdH6E=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spyzhov/ajson v0.9.4 h1:MVibcTCgO7DY4IlskdqIlCmDOsUOZ9P7oKj8ifdcf84=
github.com/spyzhov/ajson v0.9.4/go.mod h1:a6oSw0MMb7Z5aD2tPoPO+jq11ETKgXUr2XktHdT8Wt8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -433,6 +510,8 @@ github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
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/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
@@ -451,20 +530,26 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -475,8 +560,11 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q=
go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U=
go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
go4.org/mem v0.0.0-20240501181205-ae6ca9944745 h1:Tl++JLUCe4sxGu8cTpDzRLd3tN7US4hOxG5YpKCzkek=
go4.org/mem v0.0.0-20240501181205-ae6ca9944745/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g=
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
@@ -484,21 +572,29 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/W
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
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-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
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.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -507,18 +603,26 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
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/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
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.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 h1:3GDAcqdIg1ozBNLgPy4SLT84nfcBjr6rhGtXYtrkWLU=
@@ -539,6 +643,7 @@ google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -549,6 +654,7 @@ gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
gvisor.dev/gvisor v0.0.0-20260408064518-65a410b0d584 h1:QyFROp5Ew7XZWKPtp8ap78z4gpY6xHpJIEdHgVA4bzA=
gvisor.dev/gvisor v0.0.0-20260408064518-65a410b0d584/go.mod h1:xQ2PWgHmWJA/Ph4i1q1jBm39BKhc3W0DXqWoDSyuBOY=
howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo=
modernc.org/cc/v4 v4.27.3 h1:uNCgn37E5U09mTv1XgskEVUJ8ADKpmFMPxzGJ0TSo+U=

View File

@@ -1,444 +0,0 @@
//go:build with_openvpn && with_gvisor
// OpenVPN E2E tests. Require a local OpenVPN server setup.
//
// Setup (run once before testing):
//
// # Generate PKI
// mkdir -p /tmp/ovpn-e2e/pki/{issued,private}
// cd /tmp/ovpn-e2e/pki
// openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -days 1 -nodes -keyout ca.key -out ca.crt -subj "/CN=E2ETestCA"
// openssl req -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes -keyout private/server.key -out server.csr -subj "/CN=server"
// openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out issued/server.crt -days 1
// openssl req -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes -keyout private/client.key -out client.csr -subj "/CN=client"
// openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out issued/client.crt -days 1
// openvpn --genkey secret ta.key
// openvpn --genkey secret ta-auth.key
//
// # Start servers (4 instances: TCP/UDP × tls-crypt/tls-auth)
// # TCP + tls-crypt on :11940, subnet 10.99.0.0/24
// # UDP + tls-crypt on :11941, subnet 10.99.1.0/24
// # TCP + tls-auth on :11942, subnet 10.99.2.0/24
// # UDP + tls-auth on :11943, subnet 10.99.3.0/24
// #
// # Each server config needs: topology subnet, duplicate-cn, persist-tun,
// # data-ciphers AES-256-GCM:AES-128-GCM:AES-192-GCM:CHACHA20-POLY1305:AES-256-CBC:AES-128-CBC:AES-192-CBC
// # auth SHA256, keepalive 10 60, ca/cert/key from above PKI.
// # tls-auth servers use: tls-auth ta-auth.key 0
// # tls-crypt servers use: tls-crypt ta.key
// sudo openvpn --config /tmp/ovpn-e2e/server-tcp-crypt.conf --daemon
// sudo openvpn --config /tmp/ovpn-e2e/server-udp-crypt.conf --daemon
// sudo openvpn --config /tmp/ovpn-e2e/server-tcp-auth.conf --daemon
// sudo openvpn --config /tmp/ovpn-e2e/server-udp-auth.conf --daemon
//
// # Start HTTP servers on each VPN subnet
// for ip in 10.99.0.1 10.99.1.1 10.99.2.1 10.99.3.1; do
// mkdir -p /tmp/ovpn-e2e/$ip && echo "hello" > /tmp/ovpn-e2e/$ip/index.html
// cd /tmp/ovpn-e2e/$ip && python3 -m http.server 8080 --bind $ip &
// done
//
// Run tests:
//
// go test -tags "with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_masque,with_mtproxy,with_manager,with_admin_panel,with_v2ray_api,with_ccm,with_ocm,with_profiler,with_openvpn,with_sudoku,with_trusttunnel" \
// -run TestE2E -v -count=1 ./transport/openvpn/ -timeout 300s
//
// Tests all 28 combinations: 2 protos (tcp/udp) × 2 TLS modes (tls-crypt/tls-auth) × 7 ciphers.
package openvpn_test
import (
"context"
"fmt"
"io"
"net"
"os"
"strings"
"sync/atomic"
"testing"
"time"
"github.com/sagernet/sing-box"
"github.com/sagernet/sing-box/include"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/json/badoption"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/protocol/socks"
)
// Servers (started externally):
// TCP+tls-crypt :11940 subnet 10.99.0.0/24
// UDP+tls-crypt :11941 subnet 10.99.1.0/24
// TCP+tls-auth :11942 subnet 10.99.2.0/24
// UDP+tls-auth :11943 subnet 10.99.3.0/24
// TCP+plain :11944 subnet 10.99.4.0/24
// UDP+plain :11945 subnet 10.99.5.0/24
// TCP+tls-crypt+SHA1 :11946 subnet 10.99.6.0/24 (CBC only)
// TCP+tls-crypt+SHA512 :11947 subnet 10.99.7.0/24 (CBC only)
// Each has HTTP on .1:8080 serving "hello"
const pkiDir = "/tmp/ovpn-e2e/pki"
type serverConfig struct {
proto string
port uint16
tlsMode string // "tls-crypt" or "tls-auth"
httpAddr string
}
var servers = []serverConfig{
{"tcp", 11940, "tls-crypt", "10.99.0.1:8080"},
{"udp", 11941, "tls-crypt", "10.99.1.1:8080"},
{"tcp", 11942, "tls-auth", "10.99.2.1:8080"},
{"udp", 11943, "tls-auth", "10.99.3.1:8080"},
}
var ciphers = []string{
"AES-128-GCM",
"AES-192-GCM",
"AES-256-GCM",
"CHACHA20-POLY1305",
"AES-128-CBC",
"AES-192-CBC",
"AES-256-CBC",
}
var portCounter atomic.Uint32
func init() { portCounter.Store(18100) }
func nextPort() uint16 { return uint16(portCounter.Add(1)) }
func readFile(t *testing.T, path string) string {
t.Helper()
data, err := os.ReadFile(path)
if err != nil {
t.Skipf("PKI not found: %v", err)
}
return string(data)
}
func testCombo(t *testing.T, srv serverConfig, cipher string) {
t.Helper()
ca := readFile(t, pkiDir+"/ca.crt")
cert := readFile(t, pkiDir+"/issued/client.crt")
key := readFile(t, pkiDir+"/private/client.key")
ovpnOpts := &option.OpenVPNOutboundOptions{
Servers: []option.ServerOptions{{Server: "127.0.0.1", ServerPort: srv.port}},
Proto: srv.proto,
Cipher: cipher,
Auth: "SHA256",
OpenVPNOutboundTLSOptionsContainer: option.OpenVPNOutboundTLSOptionsContainer{
TLS: &option.OpenVPNTLSOptions{CA: ca, Certificate: cert, Key: key},
},
}
switch srv.tlsMode {
case "tls-crypt":
ovpnOpts.TLSCrypt = readFile(t, pkiDir+"/ta.key")
case "tls-auth":
ovpnOpts.TLSAuth = readFile(t, pkiDir+"/ta-auth.key")
ovpnOpts.KeyDirection = 1
}
port := nextPort()
opts := option.Options{
Log: &option.LogOptions{Level: "error"},
Inbounds: []option.Inbound{{
Type: "socks",
Options: &option.SocksInboundOptions{
ListenOptions: option.ListenOptions{
Listen: (*badoption.Addr)(&badoption.Addr{}),
ListenPort: port,
},
},
}},
Outbounds: []option.Outbound{{Type: "openvpn", Tag: "vpn", Options: ovpnOpts}},
Route: &option.RouteOptions{Final: "vpn"},
}
ctx := include.Context(context.Background())
instance, err := box.New(box.Options{Context: ctx, Options: opts})
if err != nil {
t.Fatal(err)
}
if err := instance.Start(); err != nil {
t.Fatal(err)
}
defer instance.Close()
time.Sleep(2 * time.Second)
dialer := socks.NewClient(N.SystemDialer, M.ParseSocksaddrHostPort("127.0.0.1", port), socks.Version5, "", "")
conn, err := dialer.DialContext(context.Background(), "tcp", M.ParseSocksaddr(srv.httpAddr))
if err != nil {
t.Fatal("dial:", err)
}
defer conn.Close()
conn.SetDeadline(time.Now().Add(5 * time.Second))
_, err = conn.Write([]byte("GET /index.html HTTP/1.0\r\nHost: test\r\n\r\n"))
if err != nil {
t.Fatal("write:", err)
}
body, err := io.ReadAll(conn)
if err != nil {
t.Fatal("read:", err)
}
if !strings.Contains(string(body), "hello") {
t.Fatalf("no 'hello' in response: %s", string(body)[:min(len(body), 200)])
}
}
// 4 servers × 7 ciphers = 28 combinations
func TestE2E(t *testing.T) {
for _, srv := range servers {
for _, cipher := range ciphers {
name := fmt.Sprintf("%s/%s/%s", srv.proto, srv.tlsMode, cipher)
srv, cipher := srv, cipher
t.Run(name, func(t *testing.T) {
testCombo(t, srv, cipher)
})
}
}
}
// Test CBC ciphers with different auth algorithms (SHA1, SHA512)
func TestE2E_Auth(t *testing.T) {
type authServer struct {
port uint16
auth string
httpAddr string
}
authServers := []authServer{
{11946, "SHA1", "10.99.6.1:8080"},
{11947, "SHA512", "10.99.7.1:8080"},
}
cbcCiphers := []string{"AES-128-CBC", "AES-256-CBC"}
for _, as := range authServers {
for _, cipher := range cbcCiphers {
name := fmt.Sprintf("auth-%s/%s", as.auth, cipher)
as, cipher := as, cipher
t.Run(name, func(t *testing.T) {
ca := readFile(t, pkiDir+"/ca.crt")
cert := readFile(t, pkiDir+"/issued/client.crt")
key := readFile(t, pkiDir+"/private/client.key")
tlsCrypt := readFile(t, pkiDir+"/ta.key")
port := nextPort()
opts := option.Options{
Log: &option.LogOptions{Level: "error"},
Inbounds: []option.Inbound{{
Type: "socks",
Options: &option.SocksInboundOptions{
ListenOptions: option.ListenOptions{
Listen: (*badoption.Addr)(&badoption.Addr{}),
ListenPort: port,
},
},
}},
Outbounds: []option.Outbound{{
Type: "openvpn", Tag: "vpn",
Options: &option.OpenVPNOutboundOptions{
Servers: []option.ServerOptions{{Server: "127.0.0.1", ServerPort: as.port}},
Proto: "tcp",
Cipher: cipher,
Auth: as.auth,
TLSCrypt: tlsCrypt,
OpenVPNOutboundTLSOptionsContainer: option.OpenVPNOutboundTLSOptionsContainer{
TLS: &option.OpenVPNTLSOptions{CA: ca, Certificate: cert, Key: key},
},
},
}},
Route: &option.RouteOptions{Final: "vpn"},
}
ctx := include.Context(context.Background())
instance, err := box.New(box.Options{Context: ctx, Options: opts})
if err != nil {
t.Fatal(err)
}
if err := instance.Start(); err != nil {
t.Fatal(err)
}
defer instance.Close()
time.Sleep(2 * time.Second)
doHTTPCheck(t, port, as.httpAddr)
})
}
}
}
// Test tunnel stability with multiple sequential requests
func TestE2E_BulkData(t *testing.T) {
ca := readFile(t, pkiDir+"/ca.crt")
cert := readFile(t, pkiDir+"/issued/client.crt")
key := readFile(t, pkiDir+"/private/client.key")
tlsCrypt := readFile(t, pkiDir+"/ta.key")
port := nextPort()
opts := option.Options{
Log: &option.LogOptions{Level: "error"},
Inbounds: []option.Inbound{{
Type: "socks",
Options: &option.SocksInboundOptions{
ListenOptions: option.ListenOptions{
Listen: (*badoption.Addr)(&badoption.Addr{}),
ListenPort: port,
},
},
}},
Outbounds: []option.Outbound{{
Type: "openvpn", Tag: "vpn",
Options: &option.OpenVPNOutboundOptions{
Servers: []option.ServerOptions{{Server: "127.0.0.1", ServerPort: 11940}},
Proto: "tcp",
Cipher: "AES-256-GCM",
Auth: "SHA256",
TLSCrypt: tlsCrypt,
OpenVPNOutboundTLSOptionsContainer: option.OpenVPNOutboundTLSOptionsContainer{
TLS: &option.OpenVPNTLSOptions{CA: ca, Certificate: cert, Key: key},
},
},
}},
Route: &option.RouteOptions{Final: "vpn"},
}
ctx := include.Context(context.Background())
instance, err := box.New(box.Options{Context: ctx, Options: opts})
if err != nil {
t.Fatal(err)
}
if err := instance.Start(); err != nil {
t.Fatal(err)
}
defer instance.Close()
time.Sleep(2 * time.Second)
dialer := socks.NewClient(N.SystemDialer, M.ParseSocksaddrHostPort("127.0.0.1", port), socks.Version5, "", "")
for i := 0; i < 10; i++ {
conn, err := dialer.DialContext(context.Background(), "tcp", M.ParseSocksaddr("10.99.0.1:8080"))
if err != nil {
t.Fatalf("request %d dial: %v", i, err)
}
conn.SetDeadline(time.Now().Add(5 * time.Second))
fmt.Fprintf(conn, "GET /index.html HTTP/1.0\r\nHost: test\r\n\r\n")
body, err := io.ReadAll(conn)
conn.Close()
if err != nil {
t.Fatalf("request %d read: %v", i, err)
}
if !strings.Contains(string(body), "hello") {
t.Fatalf("request %d: no 'hello'", i)
}
}
}
func doHTTPCheck(t *testing.T, socksPort uint16, httpAddr string) {
t.Helper()
dialer := socks.NewClient(N.SystemDialer, M.ParseSocksaddrHostPort("127.0.0.1", socksPort), socks.Version5, "", "")
conn, err := dialer.DialContext(context.Background(), "tcp", M.ParseSocksaddr(httpAddr))
if err != nil {
t.Fatal("dial:", err)
}
defer conn.Close()
conn.SetDeadline(time.Now().Add(5 * time.Second))
_, err = conn.Write([]byte("GET /index.html HTTP/1.0\r\nHost: test\r\n\r\n"))
if err != nil {
t.Fatal("write:", err)
}
body, err := io.ReadAll(conn)
if err != nil {
t.Fatal("read:", err)
}
if !strings.Contains(string(body), "hello") {
t.Fatalf("no 'hello' in response: %s", string(body)[:min(len(body), 200)])
}
}
func startInstance(t *testing.T, ovpnOpts *option.OpenVPNOutboundOptions) uint16 {
t.Helper()
port := nextPort()
opts := option.Options{
Log: &option.LogOptions{Level: "error"},
Inbounds: []option.Inbound{{
Type: "socks",
Options: &option.SocksInboundOptions{
ListenOptions: option.ListenOptions{
Listen: (*badoption.Addr)(&badoption.Addr{}),
ListenPort: port,
},
},
}},
Outbounds: []option.Outbound{{Type: "openvpn", Tag: "vpn", Options: ovpnOpts}},
Route: &option.RouteOptions{Final: "vpn"},
}
ctx := include.Context(context.Background())
instance, err := box.New(box.Options{Context: ctx, Options: opts})
if err != nil {
t.Fatal(err)
}
if err := instance.Start(); err != nil {
t.Fatal(err)
}
t.Cleanup(func() { instance.Close() })
time.Sleep(2 * time.Second)
return port
}
func TestE2E_CompLZO(t *testing.T) {
ca := readFile(t, pkiDir+"/ca.crt")
cert := readFile(t, pkiDir+"/issued/client.crt")
key := readFile(t, pkiDir+"/private/client.key")
tlsCrypt := readFile(t, pkiDir+"/ta.key")
for _, cipher := range ciphers {
cipher := cipher
t.Run(cipher, func(t *testing.T) {
port := startInstance(t, &option.OpenVPNOutboundOptions{
Servers: []option.ServerOptions{{Server: "127.0.0.1", ServerPort: 11948}},
Proto: "udp",
Cipher: cipher,
Auth: "SHA256",
TLSCrypt: tlsCrypt,
OpenVPNOutboundTLSOptionsContainer: option.OpenVPNOutboundTLSOptionsContainer{
TLS: &option.OpenVPNTLSOptions{CA: ca, Certificate: cert, Key: key},
},
})
doHTTPCheck(t, port, "10.99.8.1:8080")
})
}
}
func TestE2E_AES192(t *testing.T) {
ca := readFile(t, pkiDir+"/ca.crt")
cert := readFile(t, pkiDir+"/issued/client.crt")
key := readFile(t, pkiDir+"/private/client.key")
tlsCrypt := readFile(t, pkiDir+"/ta.key")
type combo struct {
proto string
port uint16
httpAddr string
}
for _, c := range []combo{
{"tcp", 11940, "10.99.0.1:8080"},
{"udp", 11941, "10.99.1.1:8080"},
} {
for _, cipher := range []string{"AES-192-GCM", "AES-192-CBC"} {
c, cipher := c, cipher
t.Run(fmt.Sprintf("%s/%s", c.proto, cipher), func(t *testing.T) {
port := startInstance(t, &option.OpenVPNOutboundOptions{
Servers: []option.ServerOptions{{Server: "127.0.0.1", ServerPort: c.port}},
Proto: c.proto,
Cipher: cipher,
Auth: "SHA256",
TLSCrypt: tlsCrypt,
OpenVPNOutboundTLSOptionsContainer: option.OpenVPNOutboundTLSOptionsContainer{
TLS: &option.OpenVPNTLSOptions{CA: ca, Certificate: cert, Key: key},
},
})
doHTTPCheck(t, port, c.httpAddr)
})
}
}
}
var _ net.Conn

View File

@@ -1215,6 +1215,7 @@ func (c *pollConn) pullLoop() {
payload, err := base64.StdEncoding.DecodeString(line)
if err != nil {
_ = resp.Body.Close()
cancel()
_ = c.closeWithError(fmt.Errorf("poll pull decode failed: %w", err))
return
}
@@ -1222,6 +1223,7 @@ func (c *pollConn) pullLoop() {
case c.rxc <- payload:
case <-c.closed:
_ = resp.Body.Close()
cancel()
return
}
}

View File

@@ -312,7 +312,7 @@ func createHTTPClient(ctx context.Context, dest M.Socksaddr, dialer N.Dialer, op
if err != nil {
return nil, err
}
if httpVersion == "2" {
if tlsConfig != nil && httpVersion != "3" {
return tls.ClientHandshake(ctxInner, conn, tlsConfig)
}
return conn, nil