Compare commits

...

75 Commits

Author SHA1 Message Date
Shtorm
00d3ed46bf Resolve conflicts 2026-08-06 14:20:09 +03:00
Shtorm
d6b9f693c4 Add call protocol, Rmux. Update AmneziaWG. Fixes and improvements 2026-08-06 14:19:34 +03:00
Shtorm
051e928b01 Update sing-box core 2026-08-06 14:09:46 +03:00
Shtorm
b644e671c2 Fix typo in VPN description in README.md
Signed-off-by: Shtorm <108103062+shtorm-7@users.noreply.github.com>
2026-08-05 09:31:26 +03:00
世界
17ec3c71af Bump version 2026-08-03 19:19:51 +08:00
世界
6849e26ee7 tailscale: Fix system interface network category on Windows 2026-08-03 18:59:23 +08:00
世界
fd7cd31d21 Fix tailscale DNS transport missing DNS-only netmap updates 2026-08-03 18:59:23 +08:00
世界
d763884442 Fix tailscale panic with IP control URL 2026-08-03 18:59:23 +08:00
a29b4ea1e8 Fix AnyTLS URLTest results
Co-authored-by: makt28 <makt28@users.noreply.github.com>
2026-08-03 18:59:23 +08:00
Shtorm
4d0eedd474 Merge pull request #124 from anzix/extended-anytls-parser
feat(parser): Adding support parsing AnyTLS outbound
2026-08-03 07:47:44 +03:00
世界
256d42ad18 Update sing-quic 2026-08-03 12:33:48 +08:00
世界
cb88d94d6d Remove client metadata from AnyTLS requests by default 2026-08-03 12:33:41 +08:00
anzix
2979fe6e7f feat(parser): update README.md to mention AnyTLS 2026-08-01 12:42:14 +05:00
anzix
a22671d7c4 feat(parser): update the parsing documentation for provider 2026-08-01 12:14:50 +05:00
anzix
1dd63d4dcb feat(parser): update the parsing documentation 2026-08-01 11:47:12 +05:00
anzix
9d1745d29d feat(parser): adding support AnyTLS 2026-08-01 10:57:04 +05:00
世界
7da573f187 direct: Fix routing loop to exact TUN address on darwin 2026-07-31 11:04:35 +08:00
世界
9d103249e2 release: Fix rpm package format with rpm 6 2026-07-29 21:43:54 +08:00
世界
3708fa1876 Bump version 2026-07-29 19:17:31 +08:00
世界
dba80e614e Fix local DNS transport blocking on canceled queries 2026-07-29 19:17:00 +08:00
世界
c8f76760be Update sing-tun 2026-07-27 23:13:10 +08:00
世界
c9e81856e5 Update sing 2026-07-27 17:32:54 +08:00
世界
9791fa52fb release: Backport workflow refactor 2026-07-27 16:18:06 +08:00
世界
62cc3959b9 Update Go to 1.25.12 2026-07-27 16:18:06 +08:00
世界
1533244d34 Fix UDP message ownership 2026-07-27 15:51:12 +08:00
世界
890544e88b Fix rule-set file descriptor leak 2026-07-27 15:51:12 +08:00
世界
51531186d0 Strip EDNS padding from upstream DNS responses 2026-07-27 15:51:12 +08:00
世界
513910462e Fix DNS route suffix matching 2026-07-27 15:51:12 +08:00
世界
1f1d6d9a87 Fix string type 2026-07-27 15:51:12 +08:00
世界
cb0051d64d Fix inconsistent URLTest results 2026-07-27 15:51:12 +08:00
世界
397fb4d20a dns: Fix search domain expansion
DHCP option 119/15 and resolved link domains are not rooted, so appending
them to the query name produced a non-FQDN name, failing to pack with
"domain must be fully qualified".
2026-07-27 15:51:12 +08:00
世界
67a600dbfb Fix derp stun options 2026-07-27 15:51:12 +08:00
世界
9d7e9b9562 Fix Tailscale 4via6 subnet routing 2026-07-27 15:51:12 +08:00
H-TTTTT
3c4a5a6ed3 Fix naive HTTP/2 connections 2026-07-27 15:51:12 +08:00
世界
d72f0ec1c7 Fix tailscale version 2026-07-27 15:51:12 +08:00
世界
79bc79eeef Fix missing tun logger 2026-07-27 15:51:12 +08:00
世界
c8c41c2038 dialer: Fix auto_detect_interface for UDP connections 2026-07-27 15:51:12 +08:00
世界
4056231e5c Fix tailscale dns 2026-07-27 15:51:12 +08:00
世界
ee808c46be process: Fix panic when package manager is unavailable on Android 2026-07-27 15:51:12 +08:00
世界
7b9439f761 route: Refetch rule-set when cache restore fails 2026-07-27 15:51:12 +08:00
世界
dcfdd8a184 dns: Fix DHCP reset 2026-07-27 15:51:12 +08:00
世界
dc4ca85cbb Fix tailscale start dependencies 2026-07-27 15:51:12 +08:00
世界
61ede421b4 Fix stderr deprecated manager 2026-07-27 15:51:12 +08:00
世界
cb74ad78de Fix naive slow open 2026-07-27 15:51:12 +08:00
世界
b6e554e4c0 Fix ACME HTTP-01 challenge for IPv6 literal addresses 2026-07-27 15:51:12 +08:00
世界
95f2d6302f Update sing-shadowtls to v0.2.1 2026-07-27 15:50:40 +08:00
世界
0df408d807 Update sing-tun 2026-07-27 15:50:40 +08:00
世界
abdaa55e17 Update sing 2026-07-27 15:50:40 +08:00
Shtorm
c243a5b6e5 Merge branch 'extended' of https://github.com/shtorm-7/sing-box-extended into extended 2026-07-25 21:18:16 +03:00
Shtorm
b4ec688f1a Fix MASQUE endpoint parsing 2026-07-25 21:17:48 +03:00
Shtorm
2e083b2d8f Update sing-vmess 2026-07-25 21:16:01 +03:00
Shtorm
909f19640c Add Dial Fields comment to client.json
Signed-off-by: Shtorm <108103062+shtorm-7@users.noreply.github.com>
2026-07-24 15:59:49 +03:00
Shtorm
a79e16c03c Merge pull request #118 from embogomolov/fix/interrupt-group-deadlock-extended
common/interrupt: close connections outside group lock
2026-07-22 14:22:08 +03:00
embogomolov
d2805ffcc9 common/interrupt: close connections outside group lock 2026-07-22 14:09:56 +03:00
Shtorm
7c19b660b4 Merge pull request #116 from embogomolov/fix/xhttp-h3-udp-socket-leak
transport/v2rayxhttp: close UDP connection when HTTP/3 dial fails
2026-07-22 13:35:15 +03:00
embogomolov
33907d2e23 transport/v2rayxhttp: close UDP connection when HTTP/3 dial fails 2026-07-22 11:41:41 +03:00
Shtorm
ea48501b1d Merge branch 'extended' of https://github.com/shtorm-7/sing-box-extended into extended 2026-07-18 16:40:41 +03:00
Shtorm
ff11f007ec Enable naive proxy build in Docker image 2026-07-18 16:40:15 +03:00
Shtorm
dc4170ad6b Fix GroupCommonOption 2026-07-18 16:40:04 +03:00
Shtorm
03f2be2ee6 Fix MTProxy 2026-07-18 14:21:25 +03:00
Shtorm
6941854ce2 Fix XHTTP 2026-07-18 14:21:06 +03:00
Shtorm
09d2dca3c3 Fix TrustTunnel 2026-07-18 14:20:38 +03:00
Shtorm
425bfaf779 Update Telegram badge to include logo
Signed-off-by: Shtorm <108103062+shtorm-7@users.noreply.github.com>
2026-07-17 16:58:08 +03:00
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
世界
7067276170 Fix quic-go write leak 2026-07-09 11:07:27 +08: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
世界
0f1763877c Fix v2rayhttp upgrade leak 2026-07-03 12:28:39 +08: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
187 changed files with 18685 additions and 2055 deletions

View File

@@ -1 +1 @@
98d539ce67568fb911654e66a14cf4247ed833ec
617d38f41f935b46a68f550d9add2e38abb3f168

View File

@@ -2,7 +2,7 @@
set -euo pipefail
VERSION="1.25.10"
VERSION="1.25.12"
PATCH_COMMITS=(
"afe69d3cec1c6dcf0f1797b20546795730850070"
"1ed289b0cf87dc5aae9c6fe1aa5f200a83412938"

View File

@@ -2,14 +2,14 @@
set -euo pipefail
VERSION="1.25.10"
VERSION="1.25.12"
PATCH_COMMITS=(
"466f6c7a29bc098b0d4c987b803c779222894a11"
"1bdabae205052afe1dadb2ad6f1ba612cdbc532a"
"a90777dcf692dd2168577853ba743b4338721b06"
"f6bddda4e8ff58a957462a1a09562924d5f3d05c"
"bed309eff415bcb3c77dd4bc3277b682b89a388d"
"34b899c2fb39b092db4fa67c4417e41dc046be4b"
"da4094da73b3b419e3f347594d805e2831f65667"
"824aa60e77f06dbae86c20a164c78df722eb7047"
"a3b6ba31c8cc67b6d899b978bba7b53e95afc46b"
"edfa8de63435a409a59f60731b66ab5940d6d3a4"
"284f9b24d6284984966a8431e30fdc2583938f96"
"9864798dee8dd47b55d1d5100d2f1b909a2a6e6c"
)
CURL_ARGS=(
-fL

File diff suppressed because it is too large Load Diff

View File

@@ -55,7 +55,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ~1.25.10
go-version: 1.25.12
- name: Clone cronet-go
if: matrix.naive
run: |

View File

@@ -29,7 +29,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ~1.25.10
go-version: 1.25.12
- name: Check input version
if: github.event_name == 'workflow_dispatch'
run: |-
@@ -72,7 +72,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ~1.25.10
go-version: 1.25.12
- name: Clone cronet-go
if: matrix.naive
run: |
@@ -194,6 +194,7 @@ jobs:
run: |-
set -xeuo pipefail
sudo gem install fpm
echo '%_rpmformat 4' > "$HOME/.rpmmacros"
cp .fpm_systemd .fpm
fpm -t rpm \
--name "${NAME}" \

View File

@@ -25,6 +25,7 @@ builds:
- with_mtproxy
- with_openvpn
- with_trusttunnel
- with_call
- with_sudoku
- with_snell
- with_manager
@@ -64,6 +65,7 @@ builds:
- with_mtproxy
- with_openvpn
- with_trusttunnel
- with_call
- with_sudoku
- with_snell
- with_profiler
@@ -124,6 +126,7 @@ builds:
- with_mtproxy
- with_openvpn
- with_trusttunnel
- with_call
- with_sudoku
- with_snell
- with_manager
@@ -158,6 +161,7 @@ builds:
- with_mtproxy
- with_openvpn
- with_trusttunnel
- with_call
- with_sudoku
- with_snell
- with_manager
@@ -192,6 +196,7 @@ builds:
- with_mtproxy
- with_openvpn
- with_trusttunnel
- with_call
- with_sudoku
- with_snell
- with_manager
@@ -226,6 +231,7 @@ builds:
- with_mtproxy
- with_openvpn
- with_trusttunnel
- with_call
- with_sudoku
- with_snell
- with_manager
@@ -260,6 +266,7 @@ builds:
- with_mtproxy
- with_openvpn
- with_trusttunnel
- with_call
- with_sudoku
- with_snell
- with_manager
@@ -310,6 +317,7 @@ builds:
- with_mtproxy
- with_openvpn
- with_trusttunnel
- with_call
- with_sudoku
- with_snell
- with_manager
@@ -368,6 +376,7 @@ builds:
- with_mtproxy
- with_openvpn
- with_trusttunnel
- with_call
- with_sudoku
- with_snell
- with_profiler
@@ -441,6 +450,7 @@ builds:
- with_ocm
- with_openvpn
- with_trusttunnel
- with_call
- with_sudoku
- with_snell
- with_profiler

View File

@@ -1,18 +1,23 @@
FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS builder
FROM --platform=$BUILDPLATFORM golang:1.26 AS builder
LABEL maintainer="shtorm-7"
COPY . /go/src/github.com/sagernet/sing-box
WORKDIR /go/src/github.com/sagernet/sing-box
ARG TARGETOS TARGETARCH
ARG GOPROXY=""
ENV GOPROXY ${GOPROXY}
ENV CGO_ENABLED=0
ARG CRONET_GO_PATH=/go/src/github.com/sagernet/sing-box/cronet-go
ENV GOPROXY=${GOPROXY}
ENV CGO_ENABLED=1
ENV GOOS=$TARGETOS
ENV GOARCH=$TARGETARCH
ENV CRONET_GO_PATH=${CRONET_GO_PATH}
RUN set -ex \
&& apk add git build-base \
&& export COMMIT=$(git rev-parse --short HEAD) \
&& export VERSION=$(go run ./cmd/internal/read_tag) \
&& export TAGS=$(cat release/DEFAULT_BUILD_TAGS_OTHERS) \
&& git config --global --add safe.directory /go/src/github.com/sagernet/sing-box \
&& export GOTOOLCHAIN=local \
&& export CGO_ENABLED=1 GOOS=$TARGETOS GOARCH=$TARGETARCH \
&& eval "$(CGO_ENABLED=0 GOOS= GOARCH= go run -C "$CRONET_GO_PATH" ./cmd/build-naive --target=$GOOS/$GOARCH --libc=musl env --export)" \
&& export CGO_LDFLAGS="$CGO_LDFLAGS -Wl,-z,notext -Wl,-z,execstack" \
&& export VERSION=$(CGO_ENABLED=0 GOOS= GOARCH= go run ./cmd/internal/read_tag) \
&& export TAGS=$(cat release/DEFAULT_BUILD_TAGS_DOCKER) \
&& export LDFLAGS_SHARED=$(cat release/LDFLAGS) \
&& go build -v -trimpath -tags "$TAGS" \
-o /go/bin/sing-box \

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?logo=telegram)](https://t.me/sing_box_extended)
Sing-box with extended features.
@@ -17,8 +17,10 @@ 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
- **Call** — Traffic tunneling through video-call platforms (VK, Dion, Telemost, WBStream)
- **VPN** — Routed tunnel over any sing-box protocol
- **Bond** — Link aggregation for increasing throughput
- **Fallback** — Outbound group with priority-based switching
- **Failover** — Automatic outbound switching with session recovery for high availability
@@ -34,12 +36,13 @@ Sing-box with extended features.
- **Rate Limiter** — Request rate limiting
### Encryption & Obfuscation
- **Amnezia 2.0** — WireGuard traffic obfuscation
- **Amnezia 3.0** — WireGuard traffic obfuscation
- **VLESS encryption** — XRAY encryption for VLESS protocol
### Transports
- **mKCP** — Reliable UDP-based transport
- **XHTTP** — Modern XRAY transport
- **rmux** — Improved smux multiplex protocol
### Services
- **Admin Panel** — Web-based management interface
@@ -49,7 +52,7 @@ Sing-box with extended features.
### Miscellaneous
- **Providers** — Outbound subscriptions from local files, inline lists, or remote URLs (sing-box JSON, Clash YAML, SIP008, share links)
- **Link Parser** — Outbound configured from a share link (VLESS, VMess, Shadowsocks, Trojan, Hysteria, Hysteria2, TUIC)
- **Link Parser** — Outbound configured from a share link (VLESS, VMess, Shadowsocks, Trojan, Hysteria, Hysteria2, TUIC, AnyTLS)
- **Extended WireGuard options** — Advanced configuration capabilities
- **Unified Delay** — Unified latency measurement

View File

@@ -27,6 +27,11 @@ type OutboundWithPreferredRoutes interface {
PreferredAddress(address netip.Addr) bool
}
type OutboundWithMultiplex interface {
Outbound
MultiplexEnabled() bool
}
type DirectRouteOutbound interface {
Outbound
NewDirectRouteConnection(metadata InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error)

View File

@@ -289,7 +289,7 @@ func prepareAppStore(ctx context.Context) error {
return err
}
if len(builds.Data) == 0 {
log.Fatal(platform, " ", tag, " no build found")
log.Fatal(string(platform), " ", tag, " no build found")
}
buildID := common.Ptr(builds.Data[0].ID)
if version.ID == "" {

View File

@@ -63,7 +63,7 @@ func init() {
sharedFlags = append(sharedFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -X internal/godebug.defaultGODEBUG=multipathtcp=0 -s -w -buildid= -checklinkname=0")
debugFlags = append(debugFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -X internal/godebug.defaultGODEBUG=multipathtcp=0 -checklinkname=0")
sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_masque", "with_mtproxy", "with_trusttunnel", "with_openvpn", "with_sudoku", "with_snell", "with_utls", "with_naive_outbound", "with_clash_api", "badlinkname", "tfogo_checklinkname0")
sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_masque", "with_mtproxy", "with_trusttunnel", "with_call", "with_openvpn", "with_sudoku", "with_snell", "with_utls", "with_naive_outbound", "with_clash_api", "badlinkname", "tfogo_checklinkname0")
darwinTags = append(darwinTags, "with_dhcp", "grpcnotrace")
// memcTags = append(memcTags, "with_tailscale")
sharedTags = append(sharedTags, "with_tailscale", "ts_omit_logtail", "ts_omit_ssh", "ts_omit_drive", "ts_omit_taildrop", "ts_omit_webclient", "ts_omit_doctor", "ts_omit_capture", "ts_omit_kube", "ts_omit_aws", "ts_omit_synology", "ts_omit_bird")

View File

@@ -0,0 +1,165 @@
package main
import (
"archive/zip"
"crypto/sha256"
"flag"
"io"
"os"
"path/filepath"
"strings"
"github.com/sagernet/sing-box/log"
E "github.com/sagernet/sing/common/exceptions"
)
var outputPath string
func init() {
flag.StringVar(&outputPath, "output", "", "output AAR path")
}
func main() {
flag.Parse()
err := merge()
if err != nil {
log.Fatal(err)
}
}
func merge() error {
inputPaths := flag.Args()
if outputPath == "" {
return E.New("missing output path")
}
if len(inputPaths) == 0 {
return E.New("missing input AAR paths")
}
archiveReaders := make([]*zip.ReadCloser, 0, len(inputPaths))
for _, inputPath := range inputPaths {
archiveReader, err := zip.OpenReader(inputPath)
if err != nil {
return E.Cause(err, "open input AAR: ", inputPath)
}
archiveReaders = append(archiveReaders, archiveReader)
}
defer func() {
for _, archiveReader := range archiveReaders {
archiveReader.Close()
}
}()
referenceEntries := make(map[string][sha256.Size]byte)
selectedEntries := make([]*zip.File, 0)
selectedJNIEntries := make(map[string]bool)
for inputIndex, archiveReader := range archiveReaders {
seenEntries := make(map[string]bool)
for _, archiveFile := range archiveReader.File {
if strings.HasPrefix(archiveFile.Name, "jni/") {
if archiveFile.FileInfo().IsDir() {
continue
}
if selectedJNIEntries[archiveFile.Name] {
return E.New("duplicate AAR JNI entry: ", archiveFile.Name)
}
selectedJNIEntries[archiveFile.Name] = true
selectedEntries = append(selectedEntries, archiveFile)
continue
}
entryDigest, err := digestEntry(archiveFile)
if err != nil {
return E.Cause(err, "read AAR entry: ", archiveFile.Name)
}
if inputIndex == 0 {
referenceEntries[archiveFile.Name] = entryDigest
selectedEntries = append(selectedEntries, archiveFile)
} else {
referenceDigest, loaded := referenceEntries[archiveFile.Name]
if !loaded {
return E.New("unexpected AAR entry: ", archiveFile.Name)
}
if referenceDigest != entryDigest {
return E.New("AAR entry differs between architectures: ", archiveFile.Name)
}
}
seenEntries[archiveFile.Name] = true
}
if inputIndex > 0 {
for referenceName := range referenceEntries {
if !seenEntries[referenceName] {
return E.New("missing AAR entry: ", referenceName)
}
}
}
}
absoluteOutputPath, err := filepath.Abs(outputPath)
if err != nil {
return E.Cause(err, "resolve output AAR path")
}
err = os.MkdirAll(filepath.Dir(absoluteOutputPath), 0o755)
if err != nil {
return E.Cause(err, "create output AAR directory")
}
temporaryFile, err := os.CreateTemp(filepath.Dir(absoluteOutputPath), ".merge-aar-*.aar")
if err != nil {
return E.Cause(err, "create temporary output AAR")
}
temporaryPath := temporaryFile.Name()
defer os.Remove(temporaryPath)
archiveWriter := zip.NewWriter(temporaryFile)
for _, archiveFile := range selectedEntries {
rawReader, openErr := archiveFile.OpenRaw()
if openErr != nil {
archiveWriter.Close()
temporaryFile.Close()
return E.Cause(openErr, "open raw AAR entry: ", archiveFile.Name)
}
header := archiveFile.FileHeader
rawWriter, createErr := archiveWriter.CreateRaw(&header)
if createErr != nil {
archiveWriter.Close()
temporaryFile.Close()
return E.Cause(createErr, "create output AAR entry: ", archiveFile.Name)
}
_, copyErr := io.Copy(rawWriter, rawReader)
if copyErr != nil {
archiveWriter.Close()
temporaryFile.Close()
return E.Cause(copyErr, "copy output AAR entry: ", archiveFile.Name)
}
}
err = archiveWriter.Close()
if err != nil {
temporaryFile.Close()
return E.Cause(err, "finalize output AAR")
}
err = temporaryFile.Close()
if err != nil {
return E.Cause(err, "close output AAR")
}
err = os.Rename(temporaryPath, absoluteOutputPath)
if err != nil {
return E.Cause(err, "replace output AAR")
}
return nil
}
func digestEntry(archiveFile *zip.File) ([sha256.Size]byte, error) {
entryReader, err := archiveFile.Open()
if err != nil {
return [sha256.Size]byte{}, err
}
digest := sha256.New()
_, err = io.Copy(digest, entryReader)
closeErr := entryReader.Close()
if err != nil {
return [sha256.Size]byte{}, err
}
if closeErr != nil {
return [sha256.Size]byte{}, closeErr
}
var result [sha256.Size]byte
copy(result[:], digest.Sum(nil))
return result, nil
}

View File

@@ -0,0 +1,172 @@
package main
import (
"flag"
"os"
"os/exec"
"path/filepath"
"sort"
"strconv"
"strings"
"github.com/sagernet/sing-box/log"
E "github.com/sagernet/sing/common/exceptions"
"howett.net/plist"
)
type xcFrameworkInfo struct {
AvailableLibraries []xcFrameworkLibrary `plist:"AvailableLibraries"`
}
type xcFrameworkLibrary struct {
BinaryPath string `plist:"BinaryPath"`
LibraryIdentifier string `plist:"LibraryIdentifier"`
LibraryPath string `plist:"LibraryPath"`
SupportedArchitectures []string `plist:"SupportedArchitectures"`
SupportedPlatform string `plist:"SupportedPlatform"`
SupportedPlatformVariant string `plist:"SupportedPlatformVariant"`
}
type frameworkSlice struct {
rootPath string
library xcFrameworkLibrary
}
var outputPath string
func init() {
flag.StringVar(&outputPath, "output", "", "output XCFramework path")
}
func main() {
flag.Parse()
err := merge()
if err != nil {
log.Fatal(err)
}
}
func merge() error {
inputPaths := flag.Args()
if outputPath == "" {
return E.New("missing output path")
}
if len(inputPaths) == 0 {
return E.New("missing input XCFramework paths")
}
frameworkGroups := make(map[string][]frameworkSlice)
for _, inputPath := range inputPaths {
infoFile, err := os.Open(filepath.Join(inputPath, "Info.plist"))
if err != nil {
return E.Cause(err, "open XCFramework metadata: ", inputPath)
}
var info xcFrameworkInfo
decoder := plist.NewDecoder(infoFile)
err = decoder.Decode(&info)
closeErr := infoFile.Close()
if err != nil {
return E.Cause(err, "decode XCFramework metadata: ", inputPath)
}
if closeErr != nil {
return E.Cause(closeErr, "close XCFramework metadata: ", inputPath)
}
for _, library := range info.AvailableLibraries {
groupName := library.SupportedPlatform + "|" + library.SupportedPlatformVariant
frameworkGroups[groupName] = append(frameworkGroups[groupName], frameworkSlice{
rootPath: inputPath,
library: library,
})
}
}
groupNames := make([]string, 0, len(frameworkGroups))
for groupName := range frameworkGroups {
groupNames = append(groupNames, groupName)
}
sort.Strings(groupNames)
absoluteOutputPath, err := filepath.Abs(outputPath)
if err != nil {
return E.Cause(err, "resolve output XCFramework path")
}
err = os.MkdirAll(filepath.Dir(absoluteOutputPath), 0o755)
if err != nil {
return E.Cause(err, "create output XCFramework directory")
}
temporaryDirectory, err := os.MkdirTemp(filepath.Dir(absoluteOutputPath), ".merge-xcframework-*")
if err != nil {
return E.Cause(err, "create XCFramework merge directory")
}
defer os.RemoveAll(temporaryDirectory)
frameworkPaths := make([]string, 0, len(groupNames))
for groupIndex, groupName := range groupNames {
frameworkSlices := frameworkGroups[groupName]
firstSlice := frameworkSlices[0]
firstFrameworkPath := filepath.Join(firstSlice.rootPath, firstSlice.library.LibraryIdentifier, firstSlice.library.LibraryPath)
if len(frameworkSlices) == 1 {
frameworkPaths = append(frameworkPaths, firstFrameworkPath)
continue
}
architectures := make(map[string]bool)
binaryPaths := make([]string, 0, len(frameworkSlices))
for _, currentSlice := range frameworkSlices {
if currentSlice.library.LibraryPath != firstSlice.library.LibraryPath || currentSlice.library.BinaryPath != firstSlice.library.BinaryPath {
return E.New("incompatible XCFramework slices for platform: ", currentSlice.library.SupportedPlatform)
}
for _, architecture := range currentSlice.library.SupportedArchitectures {
if architectures[architecture] {
return E.New("duplicate XCFramework architecture: ", architecture)
}
architectures[architecture] = true
}
binaryPaths = append(binaryPaths, filepath.Join(currentSlice.rootPath, currentSlice.library.LibraryIdentifier, currentSlice.library.BinaryPath))
}
mergedFrameworkPath := filepath.Join(temporaryDirectory, "framework-"+strconv.Itoa(groupIndex), filepath.Base(firstSlice.library.LibraryPath))
copyCommand := exec.Command("ditto", firstFrameworkPath, mergedFrameworkPath)
copyCommand.Stdout = os.Stdout
copyCommand.Stderr = os.Stderr
err = copyCommand.Run()
if err != nil {
return E.Cause(err, "copy XCFramework slice")
}
binaryRelativePath, relativeErr := filepath.Rel(firstSlice.library.LibraryPath, firstSlice.library.BinaryPath)
if relativeErr != nil {
return E.Cause(relativeErr, "resolve XCFramework binary path")
}
if binaryRelativePath == "." || strings.HasPrefix(binaryRelativePath, ".."+string(filepath.Separator)) {
return E.New("invalid XCFramework binary path: ", firstSlice.library.BinaryPath)
}
mergedBinaryPath := filepath.Join(mergedFrameworkPath, binaryRelativePath)
temporaryBinaryPath := mergedBinaryPath + ".merged"
lipoArguments := append([]string{"lipo", "-create"}, binaryPaths...)
lipoArguments = append(lipoArguments, "-output", temporaryBinaryPath)
lipoCommand := exec.Command("xcrun", lipoArguments...)
lipoCommand.Stdout = os.Stdout
lipoCommand.Stderr = os.Stderr
err = lipoCommand.Run()
if err != nil {
return E.Cause(err, "merge XCFramework binaries")
}
err = os.Rename(temporaryBinaryPath, mergedBinaryPath)
if err != nil {
return E.Cause(err, "replace merged XCFramework binary")
}
frameworkPaths = append(frameworkPaths, mergedFrameworkPath)
}
err = os.RemoveAll(absoluteOutputPath)
if err != nil {
return E.Cause(err, "remove output XCFramework")
}
xcodebuildArguments := []string{"-create-xcframework"}
for _, frameworkPath := range frameworkPaths {
xcodebuildArguments = append(xcodebuildArguments, "-framework", frameworkPath)
}
xcodebuildArguments = append(xcodebuildArguments, "-output", absoluteOutputPath)
xcodebuildCommand := exec.Command("xcodebuild", xcodebuildArguments...)
xcodebuildCommand.Stdout = os.Stdout
xcodebuildCommand.Stderr = os.Stderr
err = xcodebuildCommand.Run()
if err != nil {
return E.Cause(err, "create XCFramework")
}
return nil
}

View File

@@ -106,6 +106,7 @@ func findAndReplaceProjectVersion(objectsMap map[string]any, projectContent stri
}
func findObjectKey(objectsMap map[string]any, bundleIDList []string) []string {
globalSettings := collectBuildSettings(objectsMap)
var objectKeyList []string
for objectKey, object := range objectsMap {
buildSettings := object.(map[string]any)["buildSettings"]
@@ -116,13 +117,51 @@ func findObjectKey(objectsMap map[string]any, bundleIDList []string) []string {
if bundleIDObject == nil {
continue
}
if common.Contains(bundleIDList, bundleIDObject.(string)) {
bundleID := expandBuildVariables(bundleIDObject.(string), globalSettings)
if common.Contains(bundleIDList, bundleID) {
objectKeyList = append(objectKeyList, objectKey)
}
}
return objectKeyList
}
func collectBuildSettings(objectsMap map[string]any) map[string]string {
settings := make(map[string]string)
for _, object := range objectsMap {
buildSettings, loaded := object.(map[string]any)["buildSettings"].(map[string]any)
if !loaded {
continue
}
for key, value := range buildSettings {
valueString, isString := value.(string)
if !isString {
continue
}
settings[key] = valueString
}
}
return settings
}
var buildVariableRegexp = regexp.MustCompile(`\$[({]([A-Za-z0-9_]+)[)}]`)
func expandBuildVariables(value string, settings map[string]string) string {
for {
expanded := buildVariableRegexp.ReplaceAllStringFunc(value, func(match string) string {
name := buildVariableRegexp.FindStringSubmatch(match)[1]
replacement, loaded := settings[name]
if !loaded {
return match
}
return replacement
})
if expanded == value {
return expanded
}
value = expanded
}
}
func findObjectKeyByDirectory(objectsMap map[string]any, directoryList []string) []string {
var objectKeyList []string
for objectKey, object := range objectsMap {

View File

@@ -36,6 +36,7 @@ type DefaultDialer struct {
udpAddr4 string
udpAddr6 string
netns string
autoDetectBindFunc control.Func
connectionManager adapter.ConnectionManager
networkManager adapter.NetworkManager
networkStrategy *C.NetworkStrategy
@@ -60,6 +61,7 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
networkType []C.InterfaceType
fallbackNetworkType []C.InterfaceType
networkFallbackDelay time.Duration
autoDetectBindFunc control.Func
)
if networkManager != nil {
interfaceFinder = networkManager.InterfaceFinder()
@@ -130,6 +132,7 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
bindFunc := networkManager.AutoDetectInterfaceFunc()
dialer.Control = control.Append(dialer.Control, bindFunc)
listener.Control = control.Append(listener.Control, bindFunc)
autoDetectBindFunc = bindFunc
}
}
if options.RoutingMark == 0 && defaultOptions.RoutingMark != 0 {
@@ -224,6 +227,7 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
udpAddr4: udpAddr4,
udpAddr6: udpAddr6,
netns: options.NetNs,
autoDetectBindFunc: autoDetectBindFunc,
connectionManager: connectionManager,
networkManager: networkManager,
networkStrategy: networkStrategy,
@@ -328,12 +332,18 @@ func (d *DefaultDialer) DialParallelInterface(ctx context.Context, network strin
func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
if d.networkStrategy == nil {
return d.trackPacketConn(listener.ListenNetworkNamespace[net.PacketConn](d.netns, func() (net.PacketConn, error) {
listenConfig := d.udpListener
if d.autoDetectBindFunc != nil && destination.Addr.IsValid() {
listenConfig.Control = control.Append(listenConfig.Control, func(network, address string, conn syscall.RawConn) error {
return d.autoDetectBindFunc(network, destination.String(), conn)
})
}
if destination.IsIPv6() {
return d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr6)
return listenConfig.ListenPacket(ctx, N.NetworkUDP, d.udpAddr6)
} else if destination.IsIPv4() && !destination.Addr.IsUnspecified() {
return d.udpListener.ListenPacket(ctx, N.NetworkUDP+"4", d.udpAddr4)
return listenConfig.ListenPacket(ctx, N.NetworkUDP+"4", d.udpAddr4)
} else {
return d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr4)
return listenConfig.ListenPacket(ctx, N.NetworkUDP, d.udpAddr4)
}
}))
} else {

View File

@@ -29,8 +29,8 @@ type Conn struct {
func (c *Conn) Close() error {
c.group.access.Lock()
defer c.group.access.Unlock()
c.group.connections.Remove(c.element)
c.group.access.Unlock()
return c.Conn.Close()
}
@@ -58,8 +58,8 @@ type PacketConn struct {
func (c *PacketConn) Close() error {
c.group.access.Lock()
defer c.group.access.Unlock()
c.group.connections.Remove(c.element)
c.group.access.Unlock()
return c.PacketConn.Close()
}
@@ -87,8 +87,8 @@ type SingPacketConn struct {
func (c *SingPacketConn) Close() error {
c.group.access.Lock()
defer c.group.access.Unlock()
c.group.connections.Remove(c.element)
c.group.access.Unlock()
return c.PacketConn.Close()
}

View File

@@ -47,15 +47,19 @@ func (g *Group) NewSingPacketConn(conn N.PacketConn, isExternal bool, isProvider
func (g *Group) Interrupt(interruptExternalConnections bool) {
g.access.Lock()
defer g.access.Unlock()
var toDelete []*list.Element[*groupConnItem]
var toClose []io.Closer
for element := g.connections.Front(); element != nil; element = element.Next() {
if !element.Value.isExternal || interruptExternalConnections {
element.Value.conn.Close()
toDelete = append(toDelete, element)
toClose = append(toClose, element.Value.conn)
}
}
for _, element := range toDelete {
g.connections.Remove(element)
}
g.access.Unlock()
for _, conn := range toClose {
_ = conn.Close()
}
}

View File

@@ -0,0 +1,66 @@
package interrupt
import (
"net"
"sync"
"testing"
"time"
)
type closeBarrierConn struct {
net.Conn
barrier *sync.WaitGroup
}
func (c *closeBarrierConn) Close() error {
c.barrier.Done()
c.barrier.Wait()
return c.Conn.Close()
}
func TestNestedGroupsInterruptWithoutDeadlock(t *testing.T) {
groupA := NewGroup()
groupB := NewGroup()
barrier := &sync.WaitGroup{}
barrier.Add(2)
barrierA, barrierAPeer := net.Pipe()
barrierB, barrierBPeer := net.Pipe()
t.Cleanup(func() {
barrierAPeer.Close()
barrierBPeer.Close()
})
groupA.NewConn(&closeBarrierConn{Conn: barrierA, barrier: barrier}, true, false)
groupB.NewConn(&closeBarrierConn{Conn: barrierB, barrier: barrier}, true, false)
connA, connAPeer := net.Pipe()
connB, connBPeer := net.Pipe()
t.Cleanup(func() {
connAPeer.Close()
connBPeer.Close()
})
wrapperA := groupA.NewConn(connA, true, false)
wrapperB := groupB.NewConn(connB, true, false)
groupA.NewConn(wrapperB, true, false)
groupB.NewConn(wrapperA, true, false)
done := make(chan struct{}, 2)
go func() {
groupA.Interrupt(true)
done <- struct{}{}
}()
go func() {
groupB.Interrupt(true)
done <- struct{}{}
}()
timeout := time.NewTimer(time.Second)
defer timeout.Stop()
for range 2 {
select {
case <-done:
case <-timeout.C:
t.Fatal("nested group interrupt deadlocked")
}
}
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
)
var _ Searcher = (*androidSearcher)(nil)
@@ -16,6 +17,9 @@ type androidSearcher struct {
}
func NewSearcher(config Config) (Searcher, error) {
if config.PackageManager == nil {
return nil, E.New("missing package manager")
}
return &androidSearcher{config.PackageManager}, nil
}

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

@@ -168,9 +168,9 @@ func (e *RealityClientConfig) ClientHandshake(ctx context.Context, conn net.Conn
}
binary.BigEndian.PutUint64(hello.SessionId, uint64(nowTime.Unix()))
hello.SessionId[0] = 1
hello.SessionId[1] = 8
hello.SessionId[2] = 1
hello.SessionId[0] = 26
hello.SessionId[1] = 7
hello.SessionId[2] = 11
binary.BigEndian.PutUint32(hello.SessionId[4:], uint32(time.Now().Unix()))
copy(hello.SessionId[8:], e.shortID[:])
if debug.Enabled {

View File

@@ -165,7 +165,7 @@ func NewSTDClient(ctx context.Context, logger logger.ContextLogger, serverAddres
if len(certificate) > 0 {
certPool := x509.NewCertPool()
if !certPool.AppendCertsFromPEM(certificate) {
return nil, E.New("failed to parse certificate:\n\n", certificate)
return nil, E.New("failed to parse certificate:\n\n", string(certificate))
}
tlsConfig.RootCAs = certPool
}

View File

@@ -171,7 +171,7 @@ func (c *STDServerConfig) certificateUpdated(path string) error {
for _, certPath := range c.clientCertificatePath {
content, err := os.ReadFile(certPath)
if err != nil {
c.logger.Error(E.Cause(err, "reload certificate from ", c.clientCertificatePath))
c.logger.Error(E.Cause(err, "reload certificate from ", certPath))
continue
}
if !clientCertificateCA.AppendCertsFromPEM(content) {

View File

@@ -218,7 +218,7 @@ func NewUTLSClient(ctx context.Context, logger logger.ContextLogger, serverAddre
if len(certificate) > 0 {
certPool := x509.NewCertPool()
if !certPool.AppendCertsFromPEM(certificate) {
return nil, E.New("failed to parse certificate:\n\n", certificate)
return nil, E.New("failed to parse certificate:\n\n", string(certificate))
}
tlsConfig.RootCAs = certPool
}

View File

@@ -11,6 +11,7 @@ import (
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing/common"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/ntp"
@@ -72,7 +73,18 @@ func (s *HistoryStorage) Close() error {
return nil
}
func URLTest(ctx context.Context, link string, detour N.Dialer) (t uint16, err error) {
func URLTest(ctx context.Context, link string, detour N.Dialer) (uint16, error) {
multiplexOutbound, isMultiplexOutbound := common.Cast[adapter.OutboundWithMultiplex](detour)
if isMultiplexOutbound && multiplexOutbound.MultiplexEnabled() {
_, err := urlTest(ctx, link, detour)
if err != nil {
return 0, err
}
}
return urlTest(ctx, link, detour)
}
func urlTest(ctx context.Context, link string, detour N.Dialer) (t uint16, err error) {
if link == "" {
link = "https://www.gstatic.com/generate_204"
}

View File

@@ -29,6 +29,7 @@ const (
TypeAnyTLS = "anytls"
TypeSudoku = "sudoku"
TypeSnell = "snell"
TypeCall = "call"
TypeShadowsocksR = "shadowsocksr"
TypeVLESS = "vless"
TypeTUIC = "tuic"
@@ -133,6 +134,8 @@ func ProxyDisplayName(proxyType string) string {
return "Sudoku"
case TypeSnell:
return "Snell"
case TypeCall:
return "Call"
case TypeFallback:
return "Fallback"
case TypeTailscale:

View File

@@ -106,7 +106,23 @@ func extractNegativeTTL(response *dns.Msg) (uint32, bool) {
return 0, false
}
func stripDNSPadding(response *dns.Msg) {
for _, record := range response.Extra {
opt, isOpt := record.(*dns.OPT)
if !isOpt {
continue
}
opt.Option = common.Filter(opt.Option, func(it dns.EDNS0) bool {
return it.Option() != dns.EDNS0PADDING
})
}
}
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 +153,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 +194,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 {
@@ -198,6 +210,8 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
} else {
return nil, err
}
} else {
stripDNSPadding(response)
}
/*if question.Qtype == dns.TypeA || question.Qtype == dns.TypeAAAA {
validResponse := response
@@ -547,15 +561,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

@@ -111,6 +111,7 @@ func (t *Transport) Close() error {
func (t *Transport) Reset() {
t.transportLock.Lock()
t.updatedAt = time.Time{}
t.lastError = nil
t.servers = nil
t.transportLock.Unlock()
}
@@ -295,9 +296,14 @@ func (t *Transport) fetchServersResponse(iface *control.Interface, packetConn ne
func (t *Transport) recreateServers(iface *control.Interface, dhcpPacket *dhcpv4.DHCPv4) error {
searchList := dhcpPacket.DomainSearch()
if searchList != nil && len(searchList.Labels) > 0 {
t.search = searchList.Labels
t.search = common.Filter(common.Map(searchList.Labels, mDNS.Fqdn), func(it string) bool {
return it != "."
})
} else if dhcpPacket.DomainName() != "" {
t.search = []string{dhcpPacket.DomainName()}
domainName := mDNS.Fqdn(dhcpPacket.DomainName())
if domainName != "." {
t.search = []string{domainName}
}
}
serverAddrs := common.Map(dhcpPacket.DNS(), func(it net.IP) M.Socksaddr {
return M.SocksaddrFrom(M.AddrFromIP(it), 53)

View File

@@ -120,13 +120,16 @@ func NewHTTPSRaw(
serverAddr M.Socksaddr,
tlsConfig tls.Config,
) *HTTPSTransport {
if tlsConfig != nil {
dialer = tls.NewDialer(dialer, tlsConfig)
}
return &HTTPSTransport{
TransportAdapter: adapter,
logger: logger,
dialer: dialer,
destination: destination,
headers: headers,
transport: NewHTTPSTransportWrapper(tls.NewDialer(dialer, tlsConfig), serverAddr),
transport: NewHTTPSTransportWrapper(dialer, serverAddr, destination),
}
}

View File

@@ -5,11 +5,13 @@ import (
"errors"
"net"
"net/http"
"net/url"
"sync/atomic"
"github.com/sagernet/sing-box/common/tls"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"golang.org/x/net/http2"
)
@@ -22,27 +24,36 @@ type HTTPSTransportWrapper struct {
fallback *atomic.Bool
}
func NewHTTPSTransportWrapper(dialer tls.Dialer, serverAddr M.Socksaddr) *HTTPSTransportWrapper {
func NewHTTPSTransportWrapper(dialer N.Dialer, serverAddr M.Socksaddr, destination *url.URL) *HTTPSTransportWrapper {
var fallback atomic.Bool
if destination.Scheme == "http" {
// plain HTTP DoH used by Tailscale
fallback.Store(true)
}
return &HTTPSTransportWrapper{
http2Transport: &http2.Transport{
DialTLSContext: func(ctx context.Context, _, _ string, _ *tls.STDConfig) (net.Conn, error) {
tlsConn, err := dialer.DialTLSContext(ctx, serverAddr)
resultConn, err := dialer.DialContext(ctx, N.NetworkTCP, serverAddr)
if err != nil {
return nil, err
}
state := tlsConn.ConnectionState()
if state.NegotiatedProtocol == http2.NextProtoTLS {
return tlsConn, nil
if tlsConn, isTLSConn := resultConn.(tls.Conn); isTLSConn {
state := tlsConn.ConnectionState()
if state.NegotiatedProtocol != http2.NextProtoTLS {
tlsConn.Close()
fallback.Store(true)
return nil, errFallback
}
}
tlsConn.Close()
fallback.Store(true)
return nil, errFallback
return resultConn, nil
},
},
httpTransport: &http.Transport{
DialContext: func(ctx context.Context, _, addr string) (net.Conn, error) {
return dialer.DialContext(ctx, N.NetworkTCP, serverAddr)
},
DialTLSContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
return dialer.DialTLSContext(ctx, serverAddr)
return dialer.DialContext(ctx, N.NetworkTCP, serverAddr)
},
},
fallback: &fallback,
@@ -52,16 +63,15 @@ func NewHTTPSTransportWrapper(dialer tls.Dialer, serverAddr M.Socksaddr) *HTTPST
func (h *HTTPSTransportWrapper) RoundTrip(request *http.Request) (*http.Response, error) {
if h.fallback.Load() {
return h.httpTransport.RoundTrip(request)
} else {
response, err := h.http2Transport.RoundTrip(request)
if err != nil {
if errors.Is(err, errFallback) {
return h.httpTransport.RoundTrip(request)
}
return nil, err
}
return response, nil
}
response, err := h.http2Transport.RoundTrip(request)
if err != nil {
if errors.Is(err, errFallback) {
return h.httpTransport.RoundTrip(request)
}
return nil, err
}
return response, nil
}
func (h *HTTPSTransportWrapper) CloseIdleConnections() {

View File

@@ -126,6 +126,12 @@ func (t *HTTP3Transport) newTransport() *http3.Transport {
conn.Close()
return nil, dialErr
}
// quic-go does not take ownership of the packet conn passed to
// DialEarly: when the connection ends it only stops reading.
go func() {
<-quicConn.Context().Done()
conn.Close()
}()
return quicConn, nil
},
TLSClientConfig: t.tlsConfig,

View File

@@ -4,6 +4,7 @@ import (
"context"
"errors"
"os"
"time"
"github.com/sagernet/quic-go"
"github.com/sagernet/sing-box/adapter"
@@ -117,6 +118,12 @@ func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg,
rawConn.Close()
return nil, E.Cause(err, "establish QUIC connection")
}
// quic-go does not take ownership of the packet conn passed to
// DialEarly: when the connection ends it only stops reading.
go func() {
<-earlyConnection.Context().Done()
rawConn.Close()
}()
return earlyConnection, nil
})
if err != nil {
@@ -144,6 +151,11 @@ func (t *Transport) exchange(ctx context.Context, message *mDNS.Msg, conn *quic.
return nil, E.Cause(err, "open stream")
}
defer stream.CancelRead(0)
stopWatch := context.AfterFunc(ctx, func() {
stream.CancelRead(0)
_ = stream.SetWriteDeadline(time.Now())
})
defer stopWatch()
err = transport.WriteMessage(stream, 0, message)
if err != nil {
stream.Close()

View File

@@ -2,6 +2,23 @@
icon: material/alert-decagram
---
#### 1.13.16
* Remove client metadata from AnyTLS requests by default **1**
* Fixes and improvements
**1**:
We found that the AnyTLS client implementation uploads metadata that is
**not used by the open-source server**, and there are reports of vendors using
it to profile and discriminate against users. We now leave it empty by default
and allow you to customize it, see
[AnyTLS client metadata](/manual/misc/anytls-client-metadata/).
#### 1.13.15
* Fixes and improvements
#### 1.13.14
* Fixes and improvements

View File

@@ -17,6 +17,7 @@ icon: material/new-box
"idle_session_check_interval": "30s",
"idle_session_timeout": "30s",
"min_idle_session": 5,
"client_metadata": "",
"tls": {},
... // Dial Fields
@@ -55,6 +56,12 @@ In the check, close sessions that have been idle for longer than this. Default:
In the check, at least the first `n` idle sessions are kept open. Default value: `n`=0
#### client_metadata
!!! question "Since sing-box 1.13.16"
Check [AnyTLS client metadata](/manual/misc/anytls-client-metadata/).
#### tls
==Required==

View File

@@ -17,6 +17,7 @@ icon: material/new-box
"idle_session_check_interval": "30s",
"idle_session_timeout": "30s",
"min_idle_session": 5,
"client_metadata": "",
"tls": {},
... // 拨号字段
@@ -55,6 +56,12 @@ AnyTLS 密码。
在检查中,至少前 `n` 个空闲会话保持打开状态。默认值:`n`=0
#### client_metadata
!!! question "自 sing-box 1.13.16 起"
参阅 [AnyTLS 客户端元数据](/zh/manual/misc/anytls-client-metadata/)。
#### tls
==必填==

View File

@@ -52,6 +52,7 @@ Multiplex protocol.
| smux | https://github.com/xtaci/smux |
| yamux | https://github.com/hashicorp/yamux |
| h2mux | https://golang.org/x/net/http2 |
| rmux | https://github.com/shtorm-7/rmux |
h2mux is used by default.

View File

@@ -51,6 +51,7 @@
| smux | https://github.com/xtaci/smux |
| yamux | https://github.com/hashicorp/yamux |
| h2mux | https://golang.org/x/net/http2 |
| rmux | https://github.com/shtorm-7/rmux |
默认使用 h2mux。

View File

@@ -0,0 +1,67 @@
---
icon: material/incognito
---
# AnyTLS client metadata
The AnyTLS protocol has a design flaw: its settings frame requires the client
to send its software name and version to the server, and the protocol
specification requires that clients not disguise this information.
This field serves no protocol purpose — AnyTLS already has a separate version
field for compatibility negotiation, and the open-source server implementation
does not use client metadata. However, the field allows vendors to collect and track client types, and for
platform-specific clients, potentially infer private information such as the operating system type and version range —
something that should not, and is not expected by users to, appear in an
anti-censorship protocol. We have received reports that
commercial proxy providers use this information to identify and block
connections from the official library provided by AnyTLS for sing-box
integration, reportedly because abusive users connect to their servers with
sing-box or with clients using the same official library. This indicates that
client metadata is being collected and used for discrimination in practice.
The protocol specification states that "disguising it has no value." We
disagree: the situation is analogous to browsers implementing TLS ECH GREASE —
without it, privacy-protecting clients can be fingerprinted and treated
differently.
## Status
### 2025-02-20
We merged the
[pull request adding this protocol](https://github.com/SagerNet/sing-box/pull/2615).
Since the metadata was fixed at `sing-anytls/<library version>` in the
implementation provided for our use, and we did not carefully review the
protocol specification and other implementations, we wrongly believed that it
was not private information.
### 2025-04-05
The protocol document
[added](https://github.com/anytls/anytls-go/commit/8812aae7ab29dd88bb89067b9ca676e2e7e29171)
the requirement that third-party implementations fill in the real software
name and version, claiming that "disguising it has no value".
### 2026-07-18
A [pull request submitted to sing-box](https://github.com/SagerNet/sing-box/pull/4311)
was found to additionally upload the `sing-box` name and the actual version;
the change was subsequently reverted and was never released.
### 2026-08-03
sing-box 1.13.16 and 1.14.0-beta.5 have been released; the client metadata in
AnyTLS requests is now empty by default. For compatibility, the
[client_metadata](/configuration/outbound/anytls/#client_metadata) outbound
option allows users to set a custom value.
Since the open-source server implementation does not use this information and
it has no legitimate use, this is not considered a breaking change.
## Recommendations
We recommend that the AnyTLS protocol remove the client metadata, or replace
it with an option that is not sent by default and can be customized by the
user; and that other client implementations also take action, to jointly stop
statistics collection and discrimination based on client metadata.

View File

@@ -0,0 +1,35 @@
---
icon: material/incognito
---
# AnyTLS 客户端元数据
AnyTLS 协议具有设计缺陷:其 settings 帧要求客户端向服务器发送软件名称和版本,且协议规范要求客户端不得伪装此信息。
此字段不承担协议功能——AnyTLS 已有独立的版本字段用于兼容性协商,且开源服务端实现不使用客户端元数据。然而,此字段使得供应商可以收集并统计客户端类型,对于某些平台特定的客户端,还可能推断出操作系统类型与版本范围等隐私信息,而这不应该,也不是被用户预期的,在一个反审查协议中出现。我们收到报告,有商业代理提供商利用此信息识别和阻止来自 sing-box 使用的、由 AnyTLS 提供的用于 sing-box 集成的官方代码库的连接,据传原因是恶意用户使用 sing-box 或使用相同官方代码库的客户端连接到服务器,这表明客户端元数据在实践中已被用于收集和区别对待。
协议规范称「伪装它没有任何意义」。我们不同意:这类似于浏览器实现 TLS ECH GREASE——如果没有这一机制保护隐私的客户端会被识别并受到差别对待。
## 状态
### 2025-02-20
我们合并了[添加此协议的 PR](https://github.com/SagerNet/sing-box/pull/2615)。由于在供我们使用的实现中metadata 被固定在 `sing-anytls/<library version>`,且我们没有仔细审查协议规范和其他实现,我们错误地认为这不是隐私信息。
### 2025-04-05
协议文档[加入](https://github.com/anytls/anytls-go/commit/8812aae7ab29dd88bb89067b9ca676e2e7e29171)了要求第三方实现填写真实软件名称与版本号的条款,并声称「伪装它没有任何意义」。
### 2026-07-18
[向 sing-box 提出的 PR](https://github.com/SagerNet/sing-box/pull/4311) 被发现额外上传了 `sing-box` 和实际版本的字符串,随后此更改被回退,没有发布。
### 2026-08-03
发布了 sing-box 1.13.16 和 1.14.0-beta.5,现在 AnyTLS 请求中的客户端元数据默认为空。出于兼容性考虑,[client_metadata](/zh/configuration/outbound/anytls/#client_metadata) 出站选项允许用户自定义此值。
由于开源服务端实现不使用此信息,且它没有合理用途,这不被视为破坏性更改。
## 建议
我们建议 AnyTLS 协议移除客户端元数据,或将其替换为非默认提供、且用户可以自定义的选项;并建议其他客户端实现也采取行动,共同阻止基于客户端元数据的统计和区别对待。

View File

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

View File

@@ -0,0 +1,34 @@
{
"log": {
"level": "info"
},
"dns": {
"servers": [
{ "type": "local", "tag": "default" }
]
},
"inbounds": [
{
"type": "call",
"tag": "call-in",
"platform": "dion",
"read_buffer": 32768,
"cookies": [
{ "name": "vc-refresh-token", "value": "" }
],
// optional: re-login if refresh cookie fails
"email": "",
"password": "",
// empty = create new call
"join_link": ""
}
],
"outbounds": [
{ "type": "direct", "tag": "direct" }
],
"route": {
"final": "direct",
"default_domain_resolver": "default",
"auto_detect_interface": true
}
}

View File

@@ -0,0 +1,31 @@
{
"log": {
"level": "info"
},
"dns": {
"servers": [
{ "type": "local", "tag": "default" }
]
},
"inbounds": [
{
"type": "socks",
"listen": "127.0.0.1",
"listen_port": 1080
}
],
"outbounds": [
{
"type": "call",
"tag": "call-out",
"platform": "dion",
"read_buffer": 32768,
"join_link": ""
}
],
"route": {
"final": "call-out",
"default_domain_resolver": "default",
"auto_detect_interface": true
}
}

View File

@@ -0,0 +1,32 @@
{
"log": {
"level": "info"
},
"dns": {
"servers": [
{ "type": "local", "tag": "default" }
]
},
"inbounds": [
{
"type": "call",
"tag": "call-in",
"platform": "telemost",
"read_buffer": 32768,
"cookies": [
{ "name": "Session_id", "value": "" },
{ "name": "sessionid2", "value": "" }
],
// empty = create new call
"join_link": ""
}
],
"outbounds": [
{ "type": "direct", "tag": "direct" }
],
"route": {
"final": "direct",
"default_domain_resolver": "default",
"auto_detect_interface": true
}
}

View File

@@ -0,0 +1,31 @@
{
"log": {
"level": "info"
},
"dns": {
"servers": [
{ "type": "local", "tag": "default" }
]
},
"inbounds": [
{
"type": "socks",
"listen": "127.0.0.1",
"listen_port": 1080
}
],
"outbounds": [
{
"type": "call",
"tag": "call-out",
"platform": "telemost",
"read_buffer": 32768,
"join_link": ""
}
],
"route": {
"final": "call-out",
"default_domain_resolver": "default",
"auto_detect_interface": true
}
}

View File

@@ -0,0 +1,33 @@
{
"log": {
"level": "info"
},
"dns": {
"servers": [
{ "type": "local", "tag": "default" }
]
},
"inbounds": [
{
"type": "call",
"tag": "call-in",
"platform": "vk",
"read_buffer": 32768,
"cookies": [
{ "name": "remixsid", "value": "" },
{ "name": "remixnsid", "value": "" },
{ "name": "p", "value": "" }
],
// empty = create new call
"join_link": ""
}
],
"outbounds": [
{ "type": "direct", "tag": "direct" }
],
"route": {
"final": "direct",
"default_domain_resolver": "default",
"auto_detect_interface": true
}
}

View File

@@ -0,0 +1,31 @@
{
"log": {
"level": "info"
},
"dns": {
"servers": [
{ "type": "local", "tag": "default" }
]
},
"inbounds": [
{
"type": "socks",
"listen": "127.0.0.1",
"listen_port": 1080
}
],
"outbounds": [
{
"type": "call",
"tag": "call-out",
"platform": "vk",
"read_buffer": 32768,
"join_link": ""
}
],
"route": {
"final": "call-out",
"default_domain_resolver": "default",
"auto_detect_interface": true
}
}

View File

@@ -0,0 +1,37 @@
{
"log": {
"level": "info"
},
"dns": {
"servers": [
{ "type": "local", "tag": "default" }
]
},
"inbounds": [
{
"type": "call",
"tag": "call-in",
"platform": "wbstream",
// dc = fast data channel, video = slow VP8-smuggled (default)
"mode": "dc",
"read_buffer": 32768,
"cookies": [
{ "name": "__wb_device_id", "value": "" },
{ "name": "wbx-refresh", "value": "" },
{ "name": "x_wbaas_token", "value": "" },
{ "name": "_wbauid", "value": "" },
{ "name": "wbx-validation-key", "value": "" }
],
// empty = create new call
"join_link": ""
}
],
"outbounds": [
{ "type": "direct", "tag": "direct" }
],
"route": {
"final": "direct",
"default_domain_resolver": "default",
"auto_detect_interface": true
}
}

View File

@@ -0,0 +1,33 @@
{
"log": {
"level": "info"
},
"dns": {
"servers": [
{ "type": "local", "tag": "default" }
]
},
"inbounds": [
{
"type": "socks",
"listen": "127.0.0.1",
"listen_port": 1080
}
],
"outbounds": [
{
"type": "call",
"tag": "call-out",
"platform": "wbstream",
// dc = fast data channel, video = slow VP8-smuggled (default)
"mode": "dc",
"read_buffer": 32768,
"join_link": ""
}
],
"route": {
"final": "call-out",
"default_domain_resolver": "default",
"auto_detect_interface": true
}
}

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

@@ -25,8 +25,9 @@
{
"type": "parser",
"tag": "vless-out",
// Supported protocols: hysteria, hysteria2, shadowsocks, trojan, tuic, vless, vmess
// Supported protocols: hysteria, hysteria2, shadowsocks, trojan, tuic, vless, vmess, anytls
"link": "vless://b5e41c8c-c437-4689-b863-76208a3efb4b@0.0.0.0:443?..."
// Dial Fields
}
],
"route": {
@@ -34,4 +35,4 @@
"default_domain_resolver": "default",
"auto_detect_interface": true
}
}
}

View File

@@ -46,7 +46,7 @@
// - sing-box JSON ({ "outbounds": [...] })
// - Clash YAML
// - SIP008 (shadowsocks)
// - Raw shareable links (vless://, vmess://, ss://, trojan://, ...)
// - Raw shareable links (vless://, vmess://, ss://, trojan://, anytls://, ...)
"path": "subscriptions/my-sub.txt",
// Remove emoji flags from proxy names.
"remove_emojis": true,

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",

44
examples/rmux/client.json Normal file
View File

@@ -0,0 +1,44 @@
{
"log": {
"level": "error"
},
"dns": {
"servers": [
{
"type": "local",
"tag": "default"
}
]
},
"inbounds": [
{
"type": "mixed",
"tag": "mixed-in",
"listen_port": 7897
}
],
"outbounds": [
{
"type": "direct",
"tag": "direct"
},
{
"type": "vless",
"tag": "vless-out",
"server": "example.com",
"server_port": 443,
"uuid": "9b65b7e1-04c8-4717-8f45-2aa61fd25937",
"multiplex": {
"enabled": true,
"protocol": "rmux",
"max_connections": 4,
"min_streams": 4
}
}
],
"route": {
"final": "vless-out",
"default_domain_resolver": "default",
"auto_detect_interface": true
}
}

41
examples/rmux/server.json Normal file
View File

@@ -0,0 +1,41 @@
{
"log": {
"level": "error"
},
"dns": {
"servers": [
{
"type": "local",
"tag": "default"
}
]
},
"inbounds": [
{
"type": "vless",
"tag": "vless-in",
"listen": "0.0.0.0",
"listen_port": 443,
"users": [
{
"name": "user",
"uuid": "9b65b7e1-04c8-4717-8f45-2aa61fd25937"
}
],
"multiplex": {
"enabled": true
}
}
],
"outbounds": [
{
"type": "direct",
"tag": "direct"
}
],
"route": {
"final": "direct",
"default_domain_resolver": "default",
"auto_detect_interface": true
}
}

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
}

View File

@@ -3,11 +3,13 @@ package deprecated
import (
"os"
"strconv"
"sync"
"github.com/sagernet/sing/common/logger"
)
type stderrManager struct {
access sync.Mutex
logger logger.Logger
reported map[string]bool
}
@@ -20,6 +22,8 @@ func NewStderrManager(logger logger.Logger) Manager {
}
func (f *stderrManager) ReportDeprecated(feature Note) {
f.access.Lock()
defer f.access.Unlock()
if f.reported[feature.Name] {
return
}

View File

@@ -13,7 +13,6 @@ import (
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/common/task"
mDNS "github.com/miekg/dns"
)
@@ -58,24 +57,23 @@ func (p *platformTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*m
if err != nil {
return nil, err
}
var responseMessage *mDNS.Msg
var group task.Group
group.Append0(func(ctx context.Context) error {
err = p.iif.Exchange(response, messageBytes)
done := make(chan error, 1)
go func() {
exchangeErr := p.iif.Exchange(response, messageBytes)
if exchangeErr == nil {
exchangeErr = response.error
}
done <- exchangeErr
}()
select {
case err = <-done:
if err != nil {
return err
return nil, err
}
if response.error != nil {
return response.error
}
responseMessage = &response.message
return nil
})
err = group.Run(ctx)
if err != nil {
return nil, err
return &response.message, nil
case <-ctx.Done():
return nil, ctx.Err()
}
return responseMessage, nil
} else {
question := message.Question[0]
var network string
@@ -87,24 +85,23 @@ func (p *platformTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*m
default:
return nil, E.New("only IP queries are supported by current version of Android")
}
var responseAddrs []netip.Addr
var group task.Group
group.Append0(func(ctx context.Context) error {
err := p.iif.Lookup(response, network, question.Name)
done := make(chan error, 1)
go func() {
lookupErr := p.iif.Lookup(response, network, question.Name)
if lookupErr == nil {
lookupErr = response.error
}
done <- lookupErr
}()
select {
case err := <-done:
if err != nil {
return err
return nil, err
}
if response.error != nil {
return response.error
}
responseAddrs = response.addresses
return nil
})
err := group.Run(ctx)
if err != nil {
return nil, err
return dns.FixedResponse(message.Id, question, response.addresses, C.DefaultDNSTTL), nil
case <-ctx.Done():
return nil, ctx.Err()
}
return dns.FixedResponse(message.Id, question, responseAddrs, C.DefaultDNSTTL), nil
}
}

146
go.mod
View File

@@ -7,10 +7,11 @@ require (
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/caddyserver/certmagic v0.25.3-0.20260421143802-60d9d8b415d6
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/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa
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
@@ -19,6 +20,8 @@ require (
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
@@ -32,26 +35,31 @@ require (
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/quic-go/quic-go v0.60.0
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/cronet-go v0.0.0-20260712143338-d22f2ea3630e
github.com/sagernet/cronet-go/all v0.0.0-20260712143338-d22f2ea3630e
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.11
github.com/sagernet/sing v0.8.12-0.20260726145744-ef2df370afca
github.com/sagernet/sing-mux v0.3.5
github.com/sagernet/sing-quic v0.6.1
github.com/sagernet/sing-quic v0.6.4-0.20260803041914-d83826c306d7
github.com/sagernet/sing-shadowsocks v0.2.8
github.com/sagernet/sing-shadowsocks2 v0.2.1
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
github.com/sagernet/sing-tun v0.8.11
github.com/sagernet/sing-shadowtls v0.2.1
github.com/sagernet/sing-tun v0.8.12-0.20260727151122-3a09076491df
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/tailscale v1.92.4-sing-box-1.13-mod.8
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
@@ -59,15 +67,16 @@ require (
github.com/spf13/cobra v1.10.2
github.com/stretchr/testify v1.11.1
github.com/vishvananda/netns v0.0.5
github.com/xtaci/kcp-go/v5 v5.6.72
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,19 +90,37 @@ 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/klauspost/reedsolomon v1.12.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
github.com/quic-go/quic-go v0.59.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/pkg/errors v0.9.1 // indirect
github.com/redis/go-redis/v9 v9.8.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/tjfoc/gmsm v1.4.1 // 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.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,16 +136,15 @@ 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
github.com/database64128/netx-go v0.1.1 // 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/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 +161,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 +170,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,43 +178,44 @@ 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
github.com/quic-go/qpack v0.6.0 // indirect
github.com/safchain/ethtool v0.3.0 // 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/cronet-go/lib/android_386 v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260712142643-1e5048bd5587 // indirect
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
github.com/sagernet/nftables v0.3.0-mod.2 // indirect
github.com/shtorm-7/rmux v1.0.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
@@ -209,10 +235,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/time v0.12.0
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.14.0
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
@@ -220,15 +246,13 @@ require (
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/wireguard-go => github.com/shtorm-7/wireguard-go v0.0.2-beta.1-extended-1.5.0
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-vmess => github.com/shtorm-7/sing-vmess v0.2.8-extended-1.0.0
replace github.com/dolonet/mtg-multi => github.com/shtorm-7/mtg-multi v1.11.0-extended-1.0.0
@@ -237,3 +261,5 @@ replace github.com/Diniboy1123/connect-ip-go => github.com/shtorm-7/connect-ip-g
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-mux => github.com/shtorm-7/sing-mux v0.3.4-extended-1.1.0

365
go.sum
View File

@@ -1,3 +1,4 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
code.pfad.fr/check v1.1.0 h1:GWvjdzhSEgHvEHe2uJujDcpmZoySKuHQNrZMfzfO0bE=
code.pfad.fr/check v1.1.0/go.mod h1:NiUH13DtYsb7xp5wll0U4SXx7KhXQVCtRgdC96IPfoM=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
@@ -6,8 +7,9 @@ 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/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
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 +22,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=
@@ -34,16 +36,19 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/caddyserver/certmagic v0.25.2 h1:D7xcS7ggX/WEY54x0czj7ioTkmDWKIgxtIi2OcQclUc=
github.com/caddyserver/certmagic v0.25.2/go.mod h1:llW/CvsNmza8S6hmsuggsZeiX+uS27dkqY27wDIuBWg=
github.com/caddyserver/certmagic v0.25.3-0.20260421143802-60d9d8b415d6 h1:LYSB6VgWzKtNrcxElw3c97BP40Oc7bizKxA9K1Vi/5k=
github.com/caddyserver/certmagic v0.25.3-0.20260421143802-60d9d8b415d6/go.mod h1:llW/CvsNmza8S6hmsuggsZeiX+uS27dkqY27wDIuBWg=
github.com/caddyserver/zerossl v0.1.5 h1:dkvOjBAEEtY6LIGAHei7sw2UgqSD6TrWweXpV7lvEvE=
github.com/caddyserver/zerossl v0.1.5/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk=
github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
@@ -79,18 +84,21 @@ 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/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/florianl/go-nfqueue/v2 v2.0.2 h1:FL5lQTeetgpCvac1TRwSfgaXUn0YSO7WzGvWNIp3JPE=
@@ -139,12 +147,27 @@ github.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0=
github.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA=
github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
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.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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=
@@ -156,6 +179,8 @@ github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17k
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/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
@@ -189,10 +214,12 @@ 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/klauspost/reedsolomon v1.12.0 h1:I5FEp3xSwVCcEh3F5A7dofEfhXdF/bWhQWPH+XwBFno=
github.com/klauspost/reedsolomon v1.12.0/go.mod h1:EPLZJeh4l27pUGC3aXOjheaoh1I9yut7xTURiW3LQ9Y=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -233,8 +260,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 +280,42 @@ 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/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/v3 v3.1.1 h1:Tr684+fnnKlhPceU+ICdrw6KKkTms+5qHMgw6bIkYOM=
github.com/pion/transport/v3 v3.1.1/go.mod h1:+c2eewC5WJQHiAA46fkMMzoYZSuGzA/7E2FPrOYHctQ=
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=
@@ -264,10 +325,13 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4=
github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/quic-go/go-ossfuzz-seeds v0.1.0 h1:APacT+iIaNF6fd8AGEiN3bT/Jtkd2jz4v4TzM7MFjy0=
github.com/quic-go/go-ossfuzz-seeds v0.1.0/go.mod h1:3IOHRbJIc+L6YKMwfDtJAM9Vj9k0YY4muhuyUYk5tbk=
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/quic-go/quic-go v0.60.0 h1:xcQioE8OM66UQLeUMHltK1CCcOu3JbVB4JAQdDQSB+0=
github.com/quic-go/quic-go v0.60.0/go.mod h1:wpKpjmPpftl30sL6pFh7REVpjbcCVy4zt2vDyK1TuJk=
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=
@@ -287,68 +351,68 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk
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-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/cronet-go v0.0.0-20260712143338-d22f2ea3630e h1:Y5mhsZrYuZ9jraIqg7hg1fw4zoVreae81fWvmozbCsQ=
github.com/sagernet/cronet-go v0.0.0-20260712143338-d22f2ea3630e/go.mod h1:T/mwtrpC4JlWfScw73CmSBvHzIvc7BatQ1MhRr+cYNw=
github.com/sagernet/cronet-go/all v0.0.0-20260712143338-d22f2ea3630e h1:rdNlS1dRSi7jQe/ingFf7QmV9ZCUZMbxAfHnBrdVW7g=
github.com/sagernet/cronet-go/all v0.0.0-20260712143338-d22f2ea3630e/go.mod h1:WNl4xfTNuR+f7SObmuBtrk0p4MhlmvuuiWYoty3U52E=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260712142643-1e5048bd5587 h1:ENmDXbGH92/jsMwhjIxK2a0URkA8ILC3npjqmTGj0Yc=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260712142643-1e5048bd5587/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260712142643-1e5048bd5587 h1:5xn/EZOO5LriSEih91thvTuR+gxb59jNxNQiB/KQPEc=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260712142643-1e5048bd5587/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260712142643-1e5048bd5587 h1:2/UN0LvWnAM0Sc9B/zE2qWylGrX2hQXhknyQyTlvz4k=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260712142643-1e5048bd5587/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260712142643-1e5048bd5587 h1:SDULc9o0HkneJD38H1G+HRLby69zfdtyQk5qaKtn/tU=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260712142643-1e5048bd5587/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260712142643-1e5048bd5587 h1:hfcM9YccWN4O2LENHN16Jgm4g1/1PRouV0RmvvrS1f0=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260712142643-1e5048bd5587/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260712142643-1e5048bd5587 h1:arY9CL3C7lwJfG2Cdz2ZLvHLzT1wnzCVyAomNER6CrY=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260712142643-1e5048bd5587/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260712142643-1e5048bd5587 h1:HrtCf6KPJsW9KJ4L4T8HMW1vx+3xefLRLObpjZEtzF4=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260712142643-1e5048bd5587/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260712142643-1e5048bd5587 h1:Inzzp4hyvcC0lawhndaK8iwEN0vGLDJLCThbaKZpksg=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260712142643-1e5048bd5587/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260712142643-1e5048bd5587 h1:qN6vqr9nFnZqjZXhLez+7tMcbm3FMfhaJRWNMlK3SLI=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260712142643-1e5048bd5587/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260712142643-1e5048bd5587 h1:Zwzpw6555p3rWw844JxNZ+5iRqli6ZBOEtMH3qq1c7s=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260712142643-1e5048bd5587/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260712142643-1e5048bd5587 h1:CwsGHfo1HwvEhA2Wnh3O8WxazN3d4Un44LXhiuIvA/w=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260712142643-1e5048bd5587/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260712142643-1e5048bd5587 h1:Pn6vsVFOJkj9q/XKBOZosfuDLB6luNMLkqq6YLUPXEk=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260712142643-1e5048bd5587/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260712142643-1e5048bd5587 h1:vgRWcEr2jlgICj28XwDMXPQcy8mTob1ZcO+tPdiZjes=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260712142643-1e5048bd5587/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260712142643-1e5048bd5587 h1:uiO62HvSAdRJR3d1Jc4duxWig3kkdwHBSQ3TmUFqw48=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260712142643-1e5048bd5587/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260712142643-1e5048bd5587 h1:mXioRdq9h2YlIr9XGM51kXgIkToywwVfnGmJiaz/uzM=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260712142643-1e5048bd5587/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260712142643-1e5048bd5587 h1:oOlfOL+sq0KNZRsk06+5KgvtKw2TEXl2EZnLakTx+WM=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260712142643-1e5048bd5587/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260712142643-1e5048bd5587 h1:UDCa0lYiSUXD4wbxA/G5pGPSXhJaesCQCh5IEiZKb3M=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260712142643-1e5048bd5587/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260712142643-1e5048bd5587 h1:Yg2Ut7mPs0GK4W6p9LDh8RrDOnhTe4YpvG/WeJyUqMo=
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260712142643-1e5048bd5587/go.mod h1:Wt5uFdU3tnmm8YzobYewwdF7Mt6SucRQg6xeTNWC3Tk=
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260712142643-1e5048bd5587 h1:NtagC/YHvucD0Azh86aVghOk4z5f7oOAAy25Uw4knXQ=
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260712142643-1e5048bd5587/go.mod h1:lyIF6wKBLwWa5ZXaAKbAoewewl+yCHo2iYev39Mbj4E=
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260712142643-1e5048bd5587 h1:INzfLHBKjgJxoUDBeCaiB9hYqjhn5yfudkMz2phYypA=
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260712142643-1e5048bd5587/go.mod h1:H46PnSTTZNcZokLLiDeMDaHiS1l14PH3tzWi0eykjD8=
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260712142643-1e5048bd5587 h1:IX5NCEV9nojHdjpOkxKVN4L5FUuA5nwawXlSTdFXjCE=
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260712142643-1e5048bd5587/go.mod h1:RBhSUDAKWq7fswtV4nQUQhuaTLcX3ettR7teA7/yf2w=
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260712142643-1e5048bd5587 h1:pzgA94sR7kvrP+H86/to2oN3efYORQmh0Q3b6AyfRJQ=
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260712142643-1e5048bd5587/go.mod h1:wRzoIOGG4xbpp3Gh3triLKwMwYriScXzFtunLYhY4w0=
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260712142643-1e5048bd5587 h1:nkS6jhF90E24PW37Xemhs6+hUM0l2iRcQcZFhPJL8R8=
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260712142643-1e5048bd5587/go.mod h1:LNiZXmWil1OPwKCheqQjtakZlJuKGFz+iv2eGF76Hhs=
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260712142643-1e5048bd5587 h1:EbydHlp6vWdqhb8e8zBPVJv/F3HPob+FgO6rsSdNSr0=
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260712142643-1e5048bd5587/go.mod h1:YFDGKTkpkJGc5+hnX/RYosZyTWg9h+68VB55fYRRLYc=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260712142643-1e5048bd5587 h1:sSfVTswgqQZJqh9wTP0Acvvo5/qYARAoHegRYwZ+gyU=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260712142643-1e5048bd5587/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260712142643-1e5048bd5587 h1:lHqqbALbKdJdq/1rcI4yyg3zvibHDw7wmhDYVbjy498=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260712142643-1e5048bd5587/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260712142643-1e5048bd5587 h1:23GyWjb58Nk9a7WXgRfFUiTrMD9kvYSRHx73AaBthYc=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260712142643-1e5048bd5587/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260712142643-1e5048bd5587 h1:64EMjgVuZMD4TX5b7oWUfWRVp8aVl3hg4aWrriQKOWo=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260712142643-1e5048bd5587/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260712142643-1e5048bd5587 h1:x8cvgMQUs0EgVwt3iT/isRQ9KImvXvPobLKO5bHTN4o=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260712142643-1e5048bd5587/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 h1:XwzjZaclFF96deLqwAgK8gU3w0M2A8qxgDmhV+A0wjg=
@@ -361,16 +425,16 @@ github.com/sagernet/nftables v0.3.0-mod.2 h1:ck2KMU02OxL1eDFgGaWYglMDpoOZ7OHzxje
github.com/sagernet/nftables v0.3.0-mod.2/go.mod h1:8kslHG4VvYNihcco+i6uxIX7qbT8A56T0y5q7U44ZaQ=
github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 h1:6qvrUW79S+CrPwWz6cMePXohgjHoKxLo3c+MDhNwc3o=
github.com/sagernet/quic-go v0.59.0-sing-box-mod.4/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4=
github.com/sagernet/sing-quic v0.6.1 h1:lx0tcm99wIA1RkyvILNzRSsMy1k7TTQYIhx71E/WBlw=
github.com/sagernet/sing-quic v0.6.1/go.mod h1:K5bWvITOm4vE10fwLfrWpw27bCoVJ+tfQ79tOWg+Ko8=
github.com/sagernet/sing-quic v0.6.4-0.20260803041914-d83826c306d7 h1:D46kmyvKMNVFvL3KXdq3T4vy8r29xCMmSqNuQHJBybE=
github.com/sagernet/sing-quic v0.6.4-0.20260803041914-d83826c306d7/go.mod h1:K5bWvITOm4vE10fwLfrWpw27bCoVJ+tfQ79tOWg+Ko8=
github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE=
github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI=
github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo=
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.11 h1:BFu4+8LNl2JiTQtto5f+5AbkH90qgdoZEAqUbGiEXCg=
github.com/sagernet/sing-tun v0.8.11/go.mod h1:QvarqUtHfj1ULaRR+6kZOS/OoCE+pYGq67A5tyIy+dQ=
github.com/sagernet/sing-shadowtls v0.2.1 h1:ZiHZdnEnP+YS73NMsxiZmIFCwNd0M4k7PkGCKNXhbaM=
github.com/sagernet/sing-shadowtls v0.2.1/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
github.com/sagernet/sing-tun v0.8.12-0.20260727151122-3a09076491df h1:IVG68QmUeO9xlvrBMB/0u/prBot+jIiEjCsNterk7qs=
github.com/sagernet/sing-tun v0.8.12-0.20260727151122-3a09076491df/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=
@@ -383,16 +447,18 @@ github.com/shtorm-7/go-cache/v2 v2.1.0-extended-1.2.0 h1:aOd9Vy2LGSwgMM+4805AgLB
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/rmux v1.0.0 h1:oNXshcZVUEDU9u5ylqh3VBFQwus5LFH5yZD9KMTkSSw=
github.com/shtorm-7/rmux v1.0.0/go.mod h1:6tVwUpgjMcCTi3iami7le2/rqhfR6aFPhwuyFzGNQcw=
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=
github.com/shtorm-7/sing-vmess v0.2.7-extended-1.0.0/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs=
github.com/shtorm-7/sing-mux v0.3.4-extended-1.1.0 h1:rSDID4on/Z9OherBpvsvKqyuj7dM2b4q+YBJFcpLGpI=
github.com/shtorm-7/sing-mux v0.3.4-extended-1.1.0/go.mod h1:1qHy7cnbDQSY2OWL7CybproWC0t5Ia/DIuNHAzB6ZCA=
github.com/shtorm-7/sing-vmess v0.2.8-extended-1.0.0 h1:OjvqZOhYSi9eIJGYC0iPDPqvgo/asujvhAGkFzbZ5/Y=
github.com/shtorm-7/sing-vmess v0.2.8-extended-1.0.0/go.mod h1:P11scgTxMxVVQ8dlM27yNm3Cro40mD0+gHbnqrNGDuY=
github.com/shtorm-7/tailscale v1.92.4-sing-box-1.13-mod.7-extended-1.0.2 h1:hSMjh97OszszOd8HrzpaYUQH9dWRRBluJCbwQyz8ZOk=
github.com/shtorm-7/tailscale v1.92.4-sing-box-1.13-mod.7-extended-1.0.2/go.mod h1:TYIIqO5sZpWq873rLIeO2usszSMUpR3h6WdqVVs65ug=
github.com/shtorm-7/wireguard-go v0.0.2-beta.1-extended-1.4.3 h1:jtOA73D4F5qRV70//ahOt20KBnWvQimAFjtIiOtt0ps=
github.com/shtorm-7/wireguard-go v0.0.2-beta.1-extended-1.4.3/go.mod h1:Me2JlCDYHxnd0mnuX7L5LXAeDHCltI7vSKq3eTE6SVE=
github.com/shtorm-7/wireguard-go v0.0.2-beta.1-extended-1.5.0 h1:7YhTkPhDUK81OV9mRMH26Efobh0VCGlig/HgHAlsf5U=
github.com/shtorm-7/wireguard-go v0.0.2-beta.1-extended-1.5.0/go.mod h1:Me2JlCDYHxnd0mnuX7L5LXAeDHCltI7vSKq3eTE6SVE=
github.com/shtorm-7/workerpool v0.5.0 h1:NPZuNgyH0EUm4aQsTL09xR1iV+7GCFw6jX9Z4aAVp2s=
github.com/shtorm-7/workerpool v0.5.0/go.mod h1:NI0pUZgmGu0BdKO9j3mct1DNZmgXbyTS9foorljdH6E=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
@@ -434,6 +500,8 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
github.com/txthinking/runnergroup v0.0.0-20250224021307-5864ffeb65ae h1:ArVM1jICfm7g4E4dBet+KHUFMLuxmj1Nxdp/tr3ByCU=
github.com/txthinking/runnergroup v0.0.0-20250224021307-5864ffeb65ae/go.mod h1:cldYm15/XHcGt7ndItnEWHwFZo7dinU+2QoyjfErhsI=
github.com/txthinking/socks5 v0.0.0-20251011041537-5c31f201a10e h1:xA7GVlbz6teIF4FdvuqwbX6C4tiqNk2PH7FRPIDerao=
@@ -445,8 +513,14 @@ 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/xtaci/kcp-go/v5 v5.6.72 h1:FLaQPalgpufJYQRk0OK+gErEhXGLUPjv6FSRPrFR8Lk=
github.com/xtaci/kcp-go/v5 v5.6.72/go.mod h1:9O3D8WR+cyyUjGiTILYfg17vn72otWuXK2AFfqIe6CM=
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
@@ -461,71 +535,98 @@ 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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
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/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
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.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
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-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-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-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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-20200930185726-fdedc70b468f/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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.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.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
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=
@@ -537,10 +638,24 @@ golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -555,6 +670,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gvisor.dev/gvisor v0.0.0-20260408064518-65a410b0d584 h1:QyFROp5Ew7XZWKPtp8ap78z4gpY6xHpJIEdHgVA4bzA=
gvisor.dev/gvisor v0.0.0-20260408064518-65a410b0d584/go.mod h1:xQ2PWgHmWJA/Ph4i1q1jBm39BKhc3W0DXqWoDSyuBOY=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM=
howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=

17
include/call.go Normal file
View File

@@ -0,0 +1,17 @@
//go:build with_call
package include
import (
"github.com/sagernet/sing-box/adapter/inbound"
"github.com/sagernet/sing-box/adapter/outbound"
"github.com/sagernet/sing-box/protocol/call"
)
func registerCallInbound(registry *inbound.Registry) {
call.RegisterInbound(registry)
}
func registerCallOutbound(registry *outbound.Registry) {
call.RegisterOutbound(registry)
}

27
include/call_stub.go Normal file
View File

@@ -0,0 +1,27 @@
//go:build !with_call
package include
import (
"context"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/adapter/inbound"
"github.com/sagernet/sing-box/adapter/outbound"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions"
)
func registerCallInbound(registry *inbound.Registry) {
inbound.Register[option.CallInboundOptions](registry, C.TypeCall, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.CallInboundOptions) (adapter.Inbound, error) {
return nil, E.New(`Call is not included in this build, rebuild with -tags with_call`)
})
}
func registerCallOutbound(registry *outbound.Registry) {
outbound.Register[option.CallOutboundOptions](registry, C.TypeCall, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.CallOutboundOptions) (adapter.Outbound, error) {
return nil, E.New(`Call is not included in this build, rebuild with -tags with_call`)
})
}

View File

@@ -92,6 +92,7 @@ func InboundRegistry() *inbound.Registry {
registerMTProxyInbound(registry)
registerSudokuInbound(registry)
registerSnellInbound(registry)
registerCallInbound(registry)
return registry
}
@@ -137,6 +138,7 @@ func OutboundRegistry() *outbound.Registry {
registerStubForRemovedOutbounds(registry)
registerSudokuOutbound(registry)
registerSnellOutbound(registry)
registerCallOutbound(registry)
return registry
}

View File

@@ -75,6 +75,7 @@ nav:
- Hysteria 2: manual/proxy-protocol/hysteria2.md
- Misc:
- TunnelVision: manual/misc/tunnelvision.md
- AnyTLS client metadata: manual/misc/anytls-client-metadata.md
- Configuration:
- configuration/index.md
- Log:

View File

@@ -22,4 +22,5 @@ type AnyTLSOutboundOptions struct {
IdleSessionCheckInterval badoption.Duration `json:"idle_session_check_interval,omitempty"`
IdleSessionTimeout badoption.Duration `json:"idle_session_timeout,omitempty"`
MinIdleSession int `json:"min_idle_session,omitempty"`
ClientMetadata string `json:"client_metadata,omitempty"`
}

78
option/call.go Normal file
View File

@@ -0,0 +1,78 @@
package option
import "strings"
// CallCookie is a single cookie entry provided inline in the configuration as
// JSON, matching the browser-exported {name, value} format.
type CallCookie struct {
Name string `json:"name"`
Value string `json:"value"`
}
// CallCookieList is the list of cookies provided in the configuration.
type CallCookieList []CallCookie
// Header renders the cookie list into a single "name=value; name=value"
// header string. Entries with an empty name are skipped.
func (l CallCookieList) Header() string {
if len(l) == 0 {
return ""
}
parts := make([]string, 0, len(l))
for _, c := range l {
if c.Name == "" {
continue
}
parts = append(parts, c.Name+"="+c.Value)
}
return strings.Join(parts, "; ")
}
// ParseCookieHeader parses a "name=value; name=value" cookie header string into
// a CallCookieList.
func ParseCookieHeader(header string) CallCookieList {
header = strings.TrimSpace(header)
if header == "" {
return nil
}
var list CallCookieList
for _, part := range strings.Split(header, ";") {
part = strings.TrimSpace(part)
if part == "" {
continue
}
name, value, _ := strings.Cut(part, "=")
name = strings.TrimSpace(name)
if name == "" {
continue
}
list = append(list, CallCookie{Name: name, Value: strings.TrimSpace(value)})
}
return list
}
type CallCommonOptions struct {
Platform string `json:"platform,omitempty"`
Mode string `json:"mode,omitempty"`
ReadBuffer int `json:"read_buffer,omitempty"`
MaxBufferedAmount int `json:"max_buffered_amount,omitempty"`
MemoryLimit int64 `json:"memory_limit,omitempty"`
}
type CallInboundOptions struct {
DialerOptions
CallCommonOptions
Cookies CallCookieList `json:"cookies,omitempty"`
JoinLink string `json:"join_link,omitempty"`
// Email and Password are used to re-authenticate with the dion.vc
// platform when the refresh cookie is missing or rejected.
Email string `json:"email,omitempty"`
Password string `json:"password,omitempty"`
}
type CallOutboundOptions struct {
DialerOptions
CallCommonOptions
JoinLink string `json:"join_link"`
Cookies CallCookieList `json:"cookies,omitempty"`
}

View File

@@ -23,9 +23,9 @@ type FallbackOutboundOptions struct {
}
type GroupCommonOption struct {
Outbounds []string `json:"outbounds"`
Providers []string `json:"providers"`
Exclude *badoption.Regexp `json:"exclude,omitempty"`
Include *badoption.Regexp `json:"include,omitempty"`
UseAllProviders bool `json:"use_all_providers,omitempty"`
Outbounds []string `json:"outbounds"`
Providers badoption.Listable[string] `json:"providers,omitempty"`
Exclude *badoption.Regexp `json:"exclude,omitempty"`
Include *badoption.Regexp `json:"include,omitempty"`
UseAllProviders bool `json:"use_all_providers,omitempty"`
}

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

@@ -90,7 +90,7 @@ type DERPMeshOptions struct {
}
type _DERPSTUNListenOptions struct {
Enabled bool
Enabled bool `json:"enabled,omitempty"`
ListenOptions
}

View File

@@ -118,13 +118,13 @@ type V2RayXHTTPBaseOptions struct {
Path string `json:"path,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"`
XPaddingBytes badoption.Range[int] `json:"x_padding_bytes"`
XPaddingBytes badoption.Range[int] `json:"x_padding_bytes"`
NoGRPCHeader bool `json:"no_grpc_header,omitempty"`
NoSSEHeader bool `json:"no_sse_header,omitempty"`
ScMaxEachPostBytes *badoption.Range[int] `json:"sc_max_each_post_bytes"`
ScMinPostsIntervalMs *badoption.Range[int] `json:"sc_min_posts_interval_ms"`
ScMaxEachPostBytes *badoption.Range[int] `json:"sc_max_each_post_bytes"`
ScMinPostsIntervalMs *badoption.Range[int] `json:"sc_min_posts_interval_ms"`
ScMaxBufferedPosts int64 `json:"sc_max_buffered_posts,omitempty"`
ScStreamUpServerSecs *badoption.Range[int] `json:"sc_stream_up_server_secs"`
ScStreamUpServerSecs *badoption.Range[int] `json:"sc_stream_up_server_secs"`
ServerMaxHeaderBytes int `json:"server_max_header_bytes"`
TrustedXForwardedFor badoption.Listable[string] `json:"trusted_x_forwarded_for,omitempty"`
Xmux *V2RayXHTTPXmuxOptions `json:"xmux"`
@@ -140,9 +140,9 @@ type V2RayXHTTPBaseOptions struct {
SeqKey string `json:"seq_key,omitempty"`
UplinkDataPlacement string `json:"uplink_data_placement,omitempty"`
UplinkDataKey string `json:"uplink_data_key,omitempty"`
UplinkChunkSize *badoption.Range[int] `json:"uplink_chunk_size,omitempty"`
UplinkChunkSize *badoption.Range[int] `json:"uplink_chunk_size,omitempty"`
SessionIDTable string `json:"session_id_table,omitempty"`
SessionIDLength badoption.Range[int] `json:"session_id_length,omitempty"`
SessionIDLength badoption.Range[int] `json:"session_id_length,omitempty"`
CongestionController string `json:"congestion_controller,omitempty"`
CWND int `json:"cwnd,omitempty"`
}
@@ -497,7 +497,7 @@ type V2RayXHTTPXmuxOptions struct {
CMaxReuseTimes badoption.Range[int] `json:"c_max_reuse_times"`
HMaxRequestTimes badoption.Range[int] `json:"h_max_request_times"`
HMaxReusableSecs badoption.Range[int] `json:"h_max_reusable_secs"`
HKeepAlivePeriod int64 `json:"h_keep_alive_period"`
HKeepAlivePeriod int64 `json:"h_keep_alive_period"`
}
func (m *V2RayXHTTPXmuxOptions) GetNormalizedMaxConcurrency() badoption.Range[int] {

View File

@@ -7,16 +7,22 @@ import (
)
type VPNClientEndpointOptions struct {
Address netip.Addr `json:"address"`
Key string `json:"key"`
Outbound Outbound `json:"outbound"`
Address netip.Addr `json:"address"`
Key string `json:"key"`
Outbound Outbound `json:"outbound"`
PoolSize uint8 `json:"pool_size,omitempty"`
ReconnectDelay badoption.Duration `json:"reconnect_delay,omitempty"`
RejectDelay badoption.Duration `json:"reject_delay,omitempty"`
DefaultGateway netip.Addr `json:"default_gateway,omitempty"`
}
type VPNServerEndpointOptions struct {
Address netip.Addr `json:"address"`
Users []VPNUser `json:"users"`
Inbounds []Inbound `json:"inbounds"`
PoolSize uint8 `json:"pool_size,omitempty"`
ConnectTimeout badoption.Duration `json:"connect_timeout,omitempty"`
DefaultGateway netip.Addr `json:"default_gateway,omitempty"`
}
type VPNUser struct {

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"`

63
parser/link/anytls.go Normal file
View File

@@ -0,0 +1,63 @@
package link
import (
"net/url"
"strings"
"github.com/sagernet/sing-box/common"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions"
)
func parseAnyTLSLink(link string) (option.Outbound, error) {
linkURL, err := url.Parse(link)
if err != nil {
return option.Outbound{}, err
}
if linkURL.User == nil || linkURL.User.Username() == "" {
return option.Outbound{}, E.New("missing password")
}
var options option.AnyTLSOutboundOptions
TLSOptions := option.OutboundTLSOptions{
Enabled: true,
ECH: &option.OutboundECHOptions{},
UTLS: &option.OutboundUTLSOptions{},
Reality: &option.OutboundRealityOptions{},
}
options.Server = linkURL.Hostname()
TLSOptions.ServerName = linkURL.Hostname()
options.ServerPort = common.StringToType[uint16](linkURL.Port())
options.Password = linkURL.User.Username()
proxy := map[string]string{}
for key, values := range linkURL.Query() {
value := values[0]
proxy[key] = value
}
for key, value := range proxy {
switch key {
case "insecure":
if value == "1" || value == "true" {
TLSOptions.Insecure = true
}
case "sni":
TLSOptions.ServerName = value
case "alpn":
TLSOptions.ALPN = strings.Split(value, ",")
case "fp":
TLSOptions.UTLS.Enabled = true
TLSOptions.UTLS.Fingerprint = value
case "tfo", "tcp-fast-open", "tcp_fast_open":
if value == "1" || value == "true" {
options.TCPFastOpen = true
}
}
}
outbound := option.Outbound{
Type: C.TypeAnyTLS,
Tag: linkURL.Fragment,
}
options.TLS = &TLSOptions
outbound.Options = &options
return outbound, nil
}

View File

@@ -28,6 +28,8 @@ func ParseSubscriptionLink(link string) (option.Outbound, error) {
return parseHysteriaLink(link)
case "hy2", "hysteria2":
return parseHysteria2Link(link)
case "anytls":
return parseAnyTLSLink(link)
}
result[3], _ = common.DecodeBase64URLSafe(result[3])
link = strings.Join(result[1:], "")

View File

@@ -0,0 +1,64 @@
package anytls
import (
"encoding/binary"
"net"
"reflect"
"strings"
"sync"
"unsafe"
"github.com/sagernet/sing/common"
anytls "github.com/anytls/sing-anytls"
"github.com/anytls/sing-anytls/session"
)
const (
commandSettings = 4
frameHeaderSize = 7
)
var (
clientSessionField, _ = reflect.TypeFor[anytls.Client]().FieldByName("sessionClient")
streamSessionField, _ = reflect.TypeFor[session.Stream]().FieldByName("sess")
sessionConnLockField, _ = reflect.TypeFor[session.Session]().FieldByName("connLock")
sessionBufferField, _ = reflect.TypeFor[session.Session]().FieldByName("buffer")
)
func sessionClientOf(client *anytls.Client) *session.Client {
return *(**session.Client)(unsafe.Add(unsafe.Pointer(client), clientSessionField.Offset))
}
func (h *Outbound) rewriteClientMetadata(conn net.Conn) {
sess := *(**session.Session)(unsafe.Add(unsafe.Pointer(conn.(*session.Stream)), streamSessionField.Offset))
connLock := (*sync.Mutex)(unsafe.Add(unsafe.Pointer(sess), sessionConnLockField.Offset))
bufferPointer := (*[]byte)(unsafe.Add(unsafe.Pointer(sess), sessionBufferField.Offset))
connLock.Lock()
defer connLock.Unlock()
buffer := *bufferPointer
offset := 0
for offset+frameHeaderSize <= len(buffer) {
dataLength := int(binary.BigEndian.Uint16(buffer[offset+5 : offset+7]))
frameEnd := offset + frameHeaderSize + dataLength
if frameEnd > len(buffer) {
return
}
if buffer[offset] == commandSettings {
data := []byte(strings.Join(common.Map(strings.Split(string(buffer[offset+frameHeaderSize:frameEnd]), "\n"), func(line string) string {
if strings.HasPrefix(line, "client=") {
return "client=" + h.clientMetadata
}
return line
}), "\n"))
newBuffer := make([]byte, 0, offset+frameHeaderSize+len(data)+len(buffer)-frameEnd)
newBuffer = append(newBuffer, buffer[:offset+5]...)
newBuffer = binary.BigEndian.AppendUint16(newBuffer, uint16(len(data)))
newBuffer = append(newBuffer, data...)
newBuffer = append(newBuffer, buffer[frameEnd:]...)
*bufferPointer = newBuffer
return
}
offset = frameEnd
}
}

View File

@@ -19,20 +19,25 @@ import (
"github.com/sagernet/sing/common/uot"
anytls "github.com/anytls/sing-anytls"
"github.com/anytls/sing-anytls/session"
)
func RegisterOutbound(registry *outbound.Registry) {
outbound.Register[option.AnyTLSOutboundOptions](registry, C.TypeAnyTLS, NewOutbound)
}
var _ adapter.OutboundWithMultiplex = (*Outbound)(nil)
type Outbound struct {
outbound.Adapter
dialer tls.Dialer
server M.Socksaddr
tlsConfig tls.Config
client *anytls.Client
uotClient *uot.Client
logger log.ContextLogger
dialer tls.Dialer
server M.Socksaddr
tlsConfig tls.Config
clientMetadata string
client *anytls.Client
sessionClient *session.Client
uotClient *uot.Client
logger log.ContextLogger
}
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.AnyTLSOutboundOptions) (adapter.Outbound, error) {
@@ -81,14 +86,30 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
return nil, err
}
outbound.client = client
outbound.clientMetadata = options.ClientMetadata
outbound.sessionClient = sessionClientOf(client)
outbound.uotClient = &uot.Client{
Dialer: anytlsDialer(client.CreateProxy),
Dialer: (anytlsDialer)(outbound.createProxy),
Version: uot.Version,
}
return outbound, nil
}
func (h *Outbound) createProxy(ctx context.Context, destination M.Socksaddr) (net.Conn, error) {
conn, err := h.sessionClient.CreateStream(ctx)
if err != nil {
return nil, err
}
h.rewriteClientMetadata(conn)
err = M.SocksaddrSerializer.WriteAddrPort(conn, destination)
if err != nil {
conn.Close()
return nil, err
}
return conn, nil
}
type anytlsDialer func(ctx context.Context, destination M.Socksaddr) (net.Conn, error)
func (d anytlsDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
@@ -103,6 +124,10 @@ func (h *Outbound) dialOut(ctx context.Context) (net.Conn, error) {
return h.dialer.DialTLSContext(ctx, h.server)
}
func (h *Outbound) MultiplexEnabled() bool {
return true
}
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
ctx, metadata := adapter.ExtendContext(ctx)
metadata.Outbound = h.Tag()
@@ -110,7 +135,7 @@ func (h *Outbound) DialContext(ctx context.Context, network string, destination
switch N.NetworkName(network) {
case N.NetworkTCP:
h.logger.InfoContext(ctx, "outbound connection to ", destination)
return h.client.CreateProxy(ctx, destination)
return h.createProxy(ctx, destination)
case N.NetworkUDP:
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
return h.uotClient.DialContext(ctx, network, destination)

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)

122
protocol/call/inbound.go Normal file
View File

@@ -0,0 +1,122 @@
package call
import (
"context"
"net"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/adapter/inbound"
"github.com/sagernet/sing-box/common/dialer"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/transport/call"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/service"
)
func RegisterInbound(registry *inbound.Registry) {
inbound.Register[option.CallInboundOptions](registry, C.TypeCall, NewInbound)
}
type Inbound struct {
inbound.Adapter
ctx context.Context
router adapter.ConnectionRouterEx
logger logger.ContextLogger
options option.CallInboundOptions
dialer N.Dialer
bridge *call.Bridge
}
func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.CallInboundOptions) (adapter.Inbound, error) {
if options.Platform == "" {
return nil, E.New("missing platform")
}
outboundDialer, err := dialer.New(ctx, options.DialerOptions, true)
if err != nil {
return nil, err
}
return &Inbound{
Adapter: inbound.NewAdapter(C.TypeCall, tag),
ctx: ctx,
router: router,
logger: logger,
options: options,
dialer: outboundDialer,
}, nil
}
func (h *Inbound) Start(stage adapter.StartStage) error {
if stage != adapter.StartStatePostStart {
return nil
}
go h.run()
return nil
}
func (h *Inbound) Close() error {
if h.bridge == nil {
return nil
}
return h.bridge.Close()
}
func (h *Inbound) run() {
dnsRouter := service.FromContext[adapter.DNSRouter](h.ctx)
bridge, err := call.Connect(h.ctx, call.Config{
Platform: h.options.Platform,
Mode: h.options.Mode,
JoinLink: h.options.JoinLink,
CookieString: h.options.Cookies.Header(),
Email: h.options.Email,
Password: h.options.Password,
ReadBuffer: h.options.ReadBuffer,
Role: call.RoleCreator,
Dialer: h.dialer,
DNSRouter: dnsRouter,
Logger: h.logger,
})
if err != nil {
h.logger.ErrorContext(h.ctx, err)
return
}
h.bridge = bridge
bridge.SetAcceptHandler(func(conn net.Conn, destination string) {
h.handleConnection(conn, M.ParseSocksaddr(destination))
})
bridge.SetUDPAcceptHandler(func(conn net.Conn, destination string) {
h.handlePacketConnection(bufio.NewUnbindPacketConnWithAddr(conn, M.ParseSocksaddr(destination)), M.ParseSocksaddr(destination))
})
}
func (h *Inbound) handleConnection(conn net.Conn, destination M.Socksaddr) {
ctx := log.ContextWithNewID(h.ctx)
var metadata adapter.InboundContext
metadata.Inbound = h.Tag()
metadata.InboundType = h.Type()
metadata.Source = M.Socksaddr{}
metadata.Destination = destination
h.logger.InfoContext(ctx, "inbound connection to ", destination)
h.router.RouteConnectionEx(ctx, deadline.NewConn(conn), metadata, N.OnceClose(func(it error) {
conn.Close()
}))
}
func (h *Inbound) handlePacketConnection(conn N.PacketConn, destination M.Socksaddr) {
ctx := log.ContextWithNewID(h.ctx)
var metadata adapter.InboundContext
metadata.Inbound = h.Tag()
metadata.InboundType = h.Type()
metadata.Source = M.Socksaddr{}
metadata.Destination = destination
h.logger.InfoContext(ctx, "inbound packet connection to ", destination)
h.router.RoutePacketConnectionEx(ctx, conn, metadata, N.OnceClose(func(it error) {
conn.Close()
}))
}

134
protocol/call/outbound.go Normal file
View File

@@ -0,0 +1,134 @@
package call
import (
"context"
"net"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/adapter/outbound"
"github.com/sagernet/sing-box/common/dialer"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/transport/call"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/service"
)
func RegisterOutbound(registry *outbound.Registry) {
outbound.Register[option.CallOutboundOptions](registry, C.TypeCall, NewOutbound)
}
type Outbound struct {
outbound.Adapter
ctx context.Context
logger logger.ContextLogger
options option.CallOutboundOptions
dialer N.Dialer
bridge *call.Bridge
startHandler func()
await chan struct{}
}
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.CallOutboundOptions) (adapter.Outbound, error) {
if options.JoinLink == "" {
return nil, E.New("missing join_link")
}
if options.Platform == "" {
return nil, E.New("missing platform")
}
outboundDialer, err := dialer.New(ctx, options.DialerOptions, true)
if err != nil {
return nil, err
}
ob := &Outbound{
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeCall, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions),
ctx: ctx,
logger: logger,
options: options,
dialer: outboundDialer,
await: make(chan struct{}),
}
dnsRouter := service.FromContext[adapter.DNSRouter](ctx)
ob.startHandler = func() {
defer close(ob.await)
bridge, err := call.Connect(ctx, call.Config{
Platform: options.Platform,
Mode: options.Mode,
JoinLink: options.JoinLink,
CookieString: options.Cookies.Header(),
ReadBuffer: options.ReadBuffer,
Role: call.RoleJoiner,
Dialer: outboundDialer,
DNSRouter: dnsRouter,
Logger: logger,
})
if err != nil {
logger.ErrorContext(ctx, err)
return
}
ob.bridge = bridge
}
return ob, nil
}
func (o *Outbound) Start(stage adapter.StartStage) error {
if stage != adapter.StartStatePostStart {
return nil
}
go o.startHandler()
return nil
}
func (o *Outbound) Close() error {
if o.bridge == nil {
return nil
}
return o.bridge.Close()
}
func (o *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
if err := o.awaitBridge(ctx); err != nil {
return nil, err
}
switch N.NetworkName(network) {
case N.NetworkTCP:
o.logger.InfoContext(ctx, "outbound connection to ", destination)
conn, err := o.bridge.DialContext(ctx, destination.String())
if err != nil {
return nil, err
}
return deadline.NewConn(conn), nil
default:
return nil, E.New("call: unsupported network: ", network)
}
}
func (o *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
if err := o.awaitBridge(ctx); err != nil {
return nil, err
}
o.logger.InfoContext(ctx, "outbound packet connection to ", destination)
conn, err := o.bridge.ListenPacket(ctx, destination.String())
if err != nil {
return nil, err
}
return bufio.NewUnbindPacketConnWithAddr(conn, destination), nil
}
func (o *Outbound) awaitBridge(ctx context.Context) error {
select {
case <-o.await:
case <-ctx.Done():
return ctx.Err()
}
if o.bridge == nil {
return E.New("call: tunnel not initialized")
}
return nil
}

View File

@@ -108,7 +108,10 @@ func (h *Outbound) fetchMyAddresses() {
func (h *Outbound) isMyLoopbackAddress(addresses ...netip.Addr) bool {
for _, prefix := range h.myAddresses.Load() {
for _, address := range addresses {
if prefix.Addr() != address && prefix.Contains(address) {
if !C.IsDarwin && prefix.Addr() == address {
continue
}
if prefix.Contains(address) {
return true
}
}

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

@@ -20,19 +20,14 @@ func newConnWithUploadTrafficLimiter(ctx context.Context, conn net.Conn, limiter
}
func (conn *connWithTrafficLimiter) Write(p []byte) (int, error) {
err := conn.limiter.Can(uint64(len(p)))
if err != nil {
reserved, err := conn.limiter.Reserve(uint64(len(p)))
if reserved < uint64(len(p)) {
conn.limiter.Commit(reserved, 0)
return 0, err
}
n, err := conn.Conn.Write(p)
if err != nil {
return 0, err
}
err = conn.limiter.Add(uint64(n))
if err != nil {
return 0, err
}
return n, nil
conn.limiter.Commit(reserved, uint64(n))
return n, err
}
type connWithUploadTrafficLimiter struct {
@@ -42,19 +37,16 @@ type connWithUploadTrafficLimiter struct {
}
func (conn *connWithUploadTrafficLimiter) Read(p []byte) (int, error) {
err := conn.limiter.Can(1)
if err != nil {
reserved, err := conn.limiter.Reserve(uint64(len(p)))
if reserved == 0 {
return 0, err
}
if reserved < uint64(len(p)) {
p = p[:reserved]
}
n, err := conn.Conn.Read(p)
if err != nil {
return 0, err
}
err = conn.limiter.Add(uint64(n))
if err != nil {
return 0, err
}
return n, nil
conn.limiter.Commit(reserved, uint64(n))
return n, err
}
type packetConnWithTrafficLimiter struct {
@@ -72,19 +64,14 @@ func newPacketConnWithUploadTrafficLimiter(ctx context.Context, conn net.PacketC
}
func (conn *packetConnWithTrafficLimiter) WriteTo(p []byte, addr net.Addr) (int, error) {
err := conn.limiter.Can(uint64(len(p)))
if err != nil {
reserved, err := conn.limiter.Reserve(uint64(len(p)))
if reserved < uint64(len(p)) {
conn.limiter.Commit(reserved, 0)
return 0, err
}
n, err := conn.PacketConn.WriteTo(p, addr)
if err != nil {
return 0, err
}
err = conn.limiter.Add(uint64(n))
if err != nil {
return 0, err
}
return n, nil
conn.limiter.Commit(reserved, uint64(n))
return n, err
}
type packetConnWithUploadTrafficLimiter struct {
@@ -94,19 +81,16 @@ type packetConnWithUploadTrafficLimiter struct {
}
func (conn *packetConnWithUploadTrafficLimiter) ReadFrom(p []byte) (int, net.Addr, error) {
err := conn.limiter.Can(1)
if err != nil {
reserved, err := conn.limiter.Reserve(uint64(len(p)))
if reserved == 0 {
return 0, nil, err
}
if reserved < uint64(len(p)) {
p = p[:reserved]
}
n, addr, err := conn.PacketConn.ReadFrom(p)
if err != nil {
return n, nil, err
}
err = conn.limiter.Add(uint64(n))
if err != nil {
return 0, nil, err
}
return n, addr, nil
conn.limiter.Commit(reserved, uint64(n))
return n, addr, err
}
func connWithDownloadTrafficWrapper(ctx context.Context, conn net.Conn, limiter TrafficLimiter, reverse bool) net.Conn {

View File

@@ -1,6 +1,6 @@
package traffic
type TrafficLimiter interface {
Can(n uint64) error
Add(n uint64) error
Reserve(n uint64) (uint64, error)
Commit(reserved uint64, n uint64)
}

View File

@@ -39,7 +39,7 @@ func (s *DefaultWrapStrategy) wrapConn(ctx context.Context, conn net.Conn, metad
if err != nil {
return conn, err
}
err = limiter.Can(1)
_, err = limiter.Reserve(0)
if err != nil {
return conn, err
}
@@ -51,7 +51,7 @@ func (s *DefaultWrapStrategy) wrapPacketConn(ctx context.Context, conn net.Packe
if err != nil {
return conn, err
}
err = limiter.Can(1)
_, err = limiter.Reserve(0)
if err != nil {
return conn, 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

@@ -47,7 +47,7 @@ type Outbound struct {
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.MASQUEOutboundOptions) (adapter.Outbound, error) {
outbound := &Outbound{
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeMASQUE, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, options.DialerOptions),
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeMASQUE, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions),
ctx: ctx,
dnsRouter: service.FromContext[adapter.DNSRouter](ctx),
logger: logger,
@@ -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

@@ -102,10 +102,9 @@ func (n *Inbound) Start(stage adapter.StartStage) error {
}
func (n *Inbound) Close() error {
err := common.Close(&n.listener)
n.proxy.Shutdown()
return common.Close(
&n.listener,
)
return err
}
func (h *Inbound) UpdateUsers(users []option.MTProxyUser) {

View File

@@ -225,7 +225,7 @@ func (n *Inbound) newConnection(ctx context.Context, waitForClose bool, conn net
} else {
done := make(chan struct{})
wrapper := v2rayhttp.NewHTTP2Wrapper(conn)
n.router.RouteConnectionEx(ctx, conn, metadata, N.OnceClose(func(it error) {
n.router.RouteConnectionEx(ctx, wrapper, metadata, N.OnceClose(func(it error) {
close(done)
}))
<-done

View File

@@ -26,6 +26,8 @@ func RegisterOutbound(registry *outbound.Registry) {
outbound.Register[option.ShadowsocksOutboundOptions](registry, C.TypeShadowsocks, NewOutbound)
}
var _ adapter.OutboundWithMultiplex = (*Outbound)(nil)
type Outbound struct {
outbound.Adapter
logger logger.ContextLogger
@@ -124,6 +126,10 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
}
}
func (h *Outbound) MultiplexEnabled() bool {
return h.multiplexDialer != nil
}
func (h *Outbound) InterfaceUpdated() {
if h.multiplexDialer != nil {
h.multiplexDialer.Reset()

View File

@@ -103,7 +103,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
for _, hostKey := range options.HostKey {
key, _, _, _, err := ssh.ParseAuthorizedKey([]byte(hostKey))
if err != nil {
return nil, E.New("parse host key ", key)
return nil, E.Cause(err, "parse host key: ", hostKey)
}
outbound.hostKey = append(outbound.hostKey, key)
}

View File

@@ -161,8 +161,9 @@ func (t *DNSTransport) updateDNSServers(routeConfig *router.Config, dnsConfig *n
func (t *DNSTransport) createResolver(directDialer func() N.Dialer, resolver *dnstype.Resolver) (adapter.DNSTransport, error) {
serverURL, parseURLErr := url.Parse(resolver.Addr)
isHTTPScheme := parseURLErr == nil && (serverURL.Scheme == "http" || serverURL.Scheme == "https")
var myDialer N.Dialer
if parseURLErr == nil && serverURL.Scheme == "http" {
if isHTTPScheme && serverURL.Scheme == "http" {
myDialer = t.endpoint
} else {
myDialer = directDialer()
@@ -170,36 +171,39 @@ func (t *DNSTransport) createResolver(directDialer func() N.Dialer, resolver *dn
if len(resolver.BootstrapResolution) > 0 {
bootstrapTransport := transport.NewUDPRaw(t.logger, t.TransportAdapter, myDialer, M.SocksaddrFrom(resolver.BootstrapResolution[0], 53))
myDialer = dialer.NewResolveDialer(t.ctx, myDialer, false, "", adapter.DNSQueryOptions{Transport: bootstrapTransport}, 0)
}
if serverAddr := M.ParseSocksaddr(resolver.Addr); serverAddr.IsValid() {
if serverAddr.Port == 0 {
serverAddr.Port = 53
}
return transport.NewUDPRaw(t.logger, t.TransportAdapter, myDialer, serverAddr), nil
} else if parseURLErr != nil {
return nil, E.Cause(parseURLErr, "parse resolver address")
} else {
myDialer = dialer.NewResolveDialer(t.ctx, myDialer, false, "", t.endpoint.queryOptions, 0)
}
if isHTTPScheme {
serverAddr := M.ParseSocksaddrHostPortStr(serverURL.Hostname(), serverURL.Port())
switch serverURL.Scheme {
case "https":
serverAddr = M.ParseSocksaddrHostPortStr(serverURL.Hostname(), serverURL.Port())
if serverAddr.Port == 0 {
serverAddr.Port = 443
}
tlsConfig := common.Must1(tls.NewClient(t.ctx, t.logger, serverAddr.AddrString(), option.OutboundTLSOptions{
ALPN: []string{http2.NextProtoTLS, "http/1.1"},
Enabled: true,
ALPN: []string{http2.NextProtoTLS, "http/1.1"},
}))
return transport.NewHTTPSRaw(t.TransportAdapter, t.logger, myDialer, serverURL, http.Header{}, serverAddr, tlsConfig), nil
case "http":
serverAddr = M.ParseSocksaddrHostPortStr(serverURL.Hostname(), serverURL.Port())
if serverAddr.Port == 0 {
serverAddr.Port = 80
}
return transport.NewHTTPSRaw(t.TransportAdapter, t.logger, myDialer, serverURL, http.Header{}, serverAddr, nil), nil
// case "tls":
default:
return nil, E.New("unknown resolver scheme: ", serverURL.Scheme)
}
}
serverAddr := M.ParseSocksaddr(resolver.Addr)
if !serverAddr.IsValid() {
if parseURLErr != nil {
return nil, E.Cause(parseURLErr, "parse resolver address")
}
return nil, E.New("invalid resolver address: ", resolver.Addr)
}
if serverAddr.Port == 0 {
serverAddr.Port = 53
}
return transport.NewUDPRaw(t.logger, t.TransportAdapter, myDialer, serverAddr), nil
}
func buildRoutePrefixes(routeConfig *router.Config) []netip.Prefix {
@@ -279,7 +283,7 @@ func (t *DNSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.M
}
}
for domainSuffix, transports := range routes {
if strings.HasSuffix(question.Name, domainSuffix) {
if mDNS.IsSubDomain(domainSuffix, question.Name) {
if len(transports) == 0 {
return &mDNS.Msg{
MsgHdr: mDNS.MsgHdr{

View File

@@ -9,7 +9,6 @@ import (
"net"
"net/http"
"net/netip"
"net/url"
"os"
"path/filepath"
"reflect"
@@ -71,7 +70,7 @@ var (
)
func init() {
version.SetVersion(tailscaleroot.VersionDotTxt + " (sing-box " + C.Version + ")")
version.SetVersion(strings.TrimSpace(tailscaleroot.VersionDotTxt) + "-0-(sing-box " + C.Version + ")")
}
func RegisterEndpoint(registry *endpoint.Registry) {
@@ -83,6 +82,7 @@ type Endpoint struct {
ctx context.Context
router adapter.Router
logger logger.ContextLogger
queryOptions adapter.DNSQueryOptions
dnsRouter adapter.DNSRouter
network adapter.NetworkManager
platformInterface adapter.PlatformInterface
@@ -93,6 +93,7 @@ type Endpoint struct {
onReconfigHook wgengine.ReconfigListener
cfg *wgcfg.Config
routerCfg *router.Config
dnsCfg *tsDNS.Config
routeDomains common.TypedValue[map[string]bool]
routePrefixes atomic.Pointer[netipx.IPSet]
@@ -188,27 +189,17 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
} else {
udpTimeout = C.UDPTimeout
}
var remoteIsDomain bool
if options.ControlURL != "" {
controlURL, err := url.Parse(options.ControlURL)
if err != nil {
return nil, E.Cause(err, "parse control URL")
}
remoteIsDomain = M.ParseSocksaddr(controlURL.Hostname()).IsDomain()
} else {
// controlplane.tailscale.com
remoteIsDomain = true
}
outboundDialer, err := dialer.NewWithOptions(dialer.Options{
Context: ctx,
Options: options.DialerOptions,
RemoteIsDomain: remoteIsDomain,
RemoteIsDomain: true,
ResolverOnDetour: true,
NewDialer: true,
})
if err != nil {
return nil, err
}
dialerQueryOptions := outboundDialer.(dialer.ResolveDialer).QueryOptions()
dnsRouter := service.FromContext[adapter.DNSRouter](ctx)
server := &tsnet.Server{
Dir: stateDirectory,
@@ -225,7 +216,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
AdvertiseTags: options.AdvertiseTags,
Dialer: &endpointDialer{Dialer: outboundDialer, logger: logger},
LookupHook: func(ctx context.Context, host string) ([]netip.Addr, error) {
return dnsRouter.Lookup(ctx, host, outboundDialer.(dialer.ResolveDialer).QueryOptions())
return dnsRouter.Lookup(ctx, host, dialerQueryOptions)
},
DNS: &dnsConfigurtor{},
HTTPClient: &http.Client{
@@ -242,10 +233,11 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
},
}
return &Endpoint{
Adapter: endpoint.NewAdapter(C.TypeTailscale, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, nil),
Adapter: endpoint.NewAdapterWithDialerOptions(C.TypeTailscale, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, options.DialerOptions),
ctx: ctx,
router: router,
logger: logger,
queryOptions: dialerQueryOptions,
dnsRouter: dnsRouter,
network: service.FromContext[adapter.NetworkManager](ctx),
platformInterface: service.FromContext[adapter.PlatformInterface](ctx),
@@ -704,12 +696,17 @@ func (t *Endpoint) NewConnectionEx(ctx context.Context, conn net.Conn, source M.
metadata.Inbound = t.Tag()
metadata.InboundType = t.Type()
metadata.Source = source
addr4, addr6 := t.server.TailscaleIPs()
switch destination.Addr {
case addr4:
destination.Addr = netip.AddrFrom4([4]uint8{127, 0, 0, 1})
case addr6:
destination.Addr = netip.IPv6Loopback()
destinationAddress := tsaddr.UnmapVia(destination.Addr)
if destinationAddress != destination.Addr {
destination.Addr = destinationAddress
} else {
addr4, addr6 := t.server.TailscaleIPs()
switch destination.Addr {
case addr4:
destination.Addr = netip.AddrFrom4([4]uint8{127, 0, 0, 1})
case addr6:
destination.Addr = netip.IPv6Loopback()
}
}
metadata.Destination = destination
t.logger.InfoContext(ctx, "inbound connection from ", source)
@@ -722,16 +719,22 @@ func (t *Endpoint) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn,
metadata.Inbound = t.Tag()
metadata.InboundType = t.Type()
metadata.Source = source
addr4, addr6 := t.server.TailscaleIPs()
switch destination.Addr {
case addr4:
metadata.OriginDestination = destination
destination.Addr = netip.AddrFrom4([4]uint8{127, 0, 0, 1})
conn = bufio.NewNATPacketConn(bufio.NewNetPacketConn(conn), metadata.OriginDestination, destination)
case addr6:
metadata.OriginDestination = destination
destination.Addr = netip.IPv6Loopback()
conn = bufio.NewNATPacketConn(bufio.NewNetPacketConn(conn), metadata.OriginDestination, destination)
originDestination := destination
destinationAddress := tsaddr.UnmapVia(destination.Addr)
if destinationAddress != destination.Addr {
destination.Addr = destinationAddress
} else {
addr4, addr6 := t.server.TailscaleIPs()
switch destination.Addr {
case addr4:
destination.Addr = netip.AddrFrom4([4]uint8{127, 0, 0, 1})
case addr6:
destination.Addr = netip.IPv6Loopback()
}
}
if destination != originDestination {
metadata.OriginDestination = originDestination
conn = bufio.NewNATPacketConn(bufio.NewNetPacketConn(conn), originDestination, destination)
}
metadata.Destination = destination
t.logger.InfoContext(ctx, "inbound packet connection from ", source)
@@ -797,7 +800,9 @@ func (t *Endpoint) onReconfig(cfg *wgcfg.Config, routerCfg *router.Config, dnsCf
if cfg == nil || dnsCfg == nil {
return
}
if (t.cfg != nil && reflect.DeepEqual(t.cfg, cfg)) && (t.dnsCfg != nil && reflect.DeepEqual(t.dnsCfg, dnsCfg)) {
if t.cfg != nil && reflect.DeepEqual(t.cfg, cfg) &&
t.routerCfg != nil && reflect.DeepEqual(t.routerCfg, routerCfg) &&
t.dnsCfg != nil && reflect.DeepEqual(t.dnsCfg, dnsCfg) {
return
}
var inet4Address, inet6Address netip.Addr
@@ -810,6 +815,7 @@ func (t *Endpoint) onReconfig(cfg *wgcfg.Config, routerCfg *router.Config, dnsCf
}
t.icmpForwarder.SetLocalAddresses(inet4Address, inet6Address)
t.cfg = cfg
t.routerCfg = routerCfg
t.dnsCfg = dnsCfg
routeDomains := make(map[string]bool)

View File

@@ -11,6 +11,9 @@ import (
singTun "github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common/logger"
wgTun "github.com/sagernet/wireguard-go/tun"
"github.com/dblohm7/wingoes/com"
"golang.org/x/sys/windows/svc"
)
type tunDeviceAdapter struct {
@@ -21,7 +24,23 @@ type tunDeviceAdapter struct {
closeOnce sync.Once
}
func newTunDeviceAdapter(tun singTun.Tun, mtu int, _ logger.ContextLogger) (wgTun.Device, error) {
var comRuntimeOnce sync.Once
func newTunDeviceAdapter(tun singTun.Tun, mtu int, contextLogger logger.ContextLogger) (wgTun.Device, error) {
// wgengine/router/osrouter/ifconfig_windows.go setPrivateNetwork assumes COM
// is initialized process-wide, which upstream performs only in tailscaled's
// main package; library consumers must do it themselves.
comRuntimeOnce.Do(func() {
processType := com.ConsoleApp
isService, serviceErr := svc.IsWindowsService()
if serviceErr == nil && isService {
processType = com.Service
}
err := com.StartRuntime(processType)
if err != nil {
contextLogger.Warn("initialize COM runtime: ", err)
}
})
winTun, ok := tun.(singTun.WinTun)
if !ok {
return nil, errors.New("not a windows tun device")

View File

@@ -26,6 +26,8 @@ func RegisterOutbound(registry *outbound.Registry) {
outbound.Register[option.TrojanOutboundOptions](registry, C.TypeTrojan, NewOutbound)
}
var _ adapter.OutboundWithMultiplex = (*Outbound)(nil)
type Outbound struct {
outbound.Adapter
logger logger.ContextLogger
@@ -107,6 +109,10 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
}
}
func (h *Outbound) MultiplexEnabled() bool {
return h.multiplexDialer != nil
}
func (h *Outbound) InterfaceUpdated() {
if h.transport != nil {
h.transport.Close()

View File

@@ -198,6 +198,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
IncludePackage: options.IncludePackage,
ExcludePackage: options.ExcludePackage,
InterfaceMonitor: networkManager.InterfaceMonitor(),
Logger: logger,
EXP_MultiPendingPackets: multiPendingPackets,
},
udpTimeout: udpTimeout,

View File

@@ -33,6 +33,8 @@ func RegisterOutbound(registry *outbound.Registry) {
outbound.Register[option.VLESSOutboundOptions](registry, C.TypeVLESS, NewOutbound)
}
var _ adapter.OutboundWithMultiplex = (*Outbound)(nil)
type Outbound struct {
outbound.Adapter
logger logger.ContextLogger
@@ -152,6 +154,10 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
}
}
func (h *Outbound) MultiplexEnabled() bool {
return h.multiplexDialer != nil
}
func (h *Outbound) InterfaceUpdated() {
if h.transport != nil {
h.transport.Close()

Some files were not shown because too many files have changed in this diff Show More