mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-08-06 22:05:20 +03:00
Compare commits
75 Commits
v1.13.14-e
...
v1.13.16-e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00d3ed46bf | ||
|
|
d6b9f693c4 | ||
|
|
051e928b01 | ||
|
|
b644e671c2 | ||
|
|
17ec3c71af | ||
|
|
6849e26ee7 | ||
|
|
fd7cd31d21 | ||
|
|
d763884442 | ||
|
|
a29b4ea1e8 | ||
|
|
4d0eedd474 | ||
|
|
256d42ad18 | ||
|
|
cb88d94d6d | ||
|
|
2979fe6e7f | ||
|
|
a22671d7c4 | ||
|
|
1dd63d4dcb | ||
|
|
9d1745d29d | ||
|
|
7da573f187 | ||
|
|
9d103249e2 | ||
|
|
3708fa1876 | ||
|
|
dba80e614e | ||
|
|
c8f76760be | ||
|
|
c9e81856e5 | ||
|
|
9791fa52fb | ||
|
|
62cc3959b9 | ||
|
|
1533244d34 | ||
|
|
890544e88b | ||
|
|
51531186d0 | ||
|
|
513910462e | ||
|
|
1f1d6d9a87 | ||
|
|
cb0051d64d | ||
|
|
397fb4d20a | ||
|
|
67a600dbfb | ||
|
|
9d7e9b9562 | ||
|
|
3c4a5a6ed3 | ||
|
|
d72f0ec1c7 | ||
|
|
79bc79eeef | ||
|
|
c8c41c2038 | ||
|
|
4056231e5c | ||
|
|
ee808c46be | ||
|
|
7b9439f761 | ||
|
|
dcfdd8a184 | ||
|
|
dc4ca85cbb | ||
|
|
61ede421b4 | ||
|
|
cb74ad78de | ||
|
|
b6e554e4c0 | ||
|
|
95f2d6302f | ||
|
|
0df408d807 | ||
|
|
abdaa55e17 | ||
|
|
c243a5b6e5 | ||
|
|
b4ec688f1a | ||
|
|
2e083b2d8f | ||
|
|
909f19640c | ||
|
|
a79e16c03c | ||
|
|
d2805ffcc9 | ||
|
|
7c19b660b4 | ||
|
|
33907d2e23 | ||
|
|
ea48501b1d | ||
|
|
ff11f007ec | ||
|
|
dc4170ad6b | ||
|
|
03f2be2ee6 | ||
|
|
6941854ce2 | ||
|
|
09d2dca3c3 | ||
|
|
425bfaf779 | ||
|
|
df39546485 | ||
|
|
4624fd51b1 | ||
|
|
7067276170 | ||
|
|
b19e232df2 | ||
|
|
0f1763877c | ||
|
|
1e826a201d | ||
|
|
a27453e4f7 | ||
|
|
2a77348470 | ||
|
|
1ae82a483a | ||
|
|
31acf60eca | ||
|
|
7bfad732e2 | ||
|
|
2cbc7691f0 |
2
.github/CRONET_GO_VERSION
vendored
2
.github/CRONET_GO_VERSION
vendored
@@ -1 +1 @@
|
||||
98d539ce67568fb911654e66a14cf4247ed833ec
|
||||
617d38f41f935b46a68f550d9add2e38abb3f168
|
||||
|
||||
2
.github/setup_go_for_macos1013.sh
vendored
2
.github/setup_go_for_macos1013.sh
vendored
@@ -2,7 +2,7 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
VERSION="1.25.10"
|
||||
VERSION="1.25.12"
|
||||
PATCH_COMMITS=(
|
||||
"afe69d3cec1c6dcf0f1797b20546795730850070"
|
||||
"1ed289b0cf87dc5aae9c6fe1aa5f200a83412938"
|
||||
|
||||
14
.github/setup_go_for_windows7.sh
vendored
14
.github/setup_go_for_windows7.sh
vendored
@@ -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
|
||||
|
||||
789
.github/workflows/build.yml
vendored
789
.github/workflows/build.yml
vendored
File diff suppressed because it is too large
Load Diff
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
@@ -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: |
|
||||
|
||||
5
.github/workflows/linux.yml
vendored
5
.github/workflows/linux.yml
vendored
@@ -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}" \
|
||||
|
||||
@@ -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
|
||||
|
||||
19
Dockerfile
19
Dockerfile
@@ -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 \
|
||||
|
||||
2
Makefile
2
Makefile
@@ -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
|
||||
|
||||
11
README.md
11
README.md
@@ -3,7 +3,7 @@
|
||||
[](LICENSE)
|
||||
[](go.mod)
|
||||
[](https://codeberg.org/shtorm-7/sing-box-extended)
|
||||
[](https://t.me/sing_box_extended)
|
||||
[](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 (v1–v5) 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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 == "" {
|
||||
|
||||
@@ -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")
|
||||
|
||||
165
cmd/internal/merge_aar/main.go
Normal file
165
cmd/internal/merge_aar/main.go
Normal 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
|
||||
}
|
||||
172
cmd/internal/merge_apple_xcframework/main.go
Normal file
172
cmd/internal/merge_apple_xcframework/main.go
Normal 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
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
66
common/interrupt/group_test.go
Normal file
66
common/interrupt/group_test.go
Normal 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package sqlite
|
||||
package sql
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
29
common/sql/json.go
Normal file
29
common/sql/json.go
Normal 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
53
common/sql/timestamp.go
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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==
|
||||
|
||||
@@ -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
|
||||
|
||||
==必填==
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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。
|
||||
|
||||
|
||||
67
docs/manual/misc/anytls-client-metadata.md
Normal file
67
docs/manual/misc/anytls-client-metadata.md
Normal 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.
|
||||
35
docs/manual/misc/anytls-client-metadata.zh.md
Normal file
35
docs/manual/misc/anytls-client-metadata.zh.md
Normal 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 协议移除客户端元数据,或将其替换为非默认提供、且用户可以自定义的选项;并建议其他客户端实现也采取行动,共同阻止基于客户端元数据的统计和区别对待。
|
||||
@@ -66,7 +66,7 @@
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"final": "connection-limiter"
|
||||
"final": "traffic-limiter"
|
||||
},
|
||||
"services": [
|
||||
{
|
||||
|
||||
34
examples/call/dion/creator.json
Normal file
34
examples/call/dion/creator.json
Normal 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
|
||||
}
|
||||
}
|
||||
31
examples/call/dion/joiner.json
Normal file
31
examples/call/dion/joiner.json
Normal 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
|
||||
}
|
||||
}
|
||||
32
examples/call/telemost/creator.json
Normal file
32
examples/call/telemost/creator.json
Normal 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
|
||||
}
|
||||
}
|
||||
31
examples/call/telemost/joiner.json
Normal file
31
examples/call/telemost/joiner.json
Normal 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
|
||||
}
|
||||
}
|
||||
33
examples/call/vk/creator.json
Normal file
33
examples/call/vk/creator.json
Normal 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
|
||||
}
|
||||
}
|
||||
31
examples/call/vk/joiner.json
Normal file
31
examples/call/vk/joiner.json
Normal 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
|
||||
}
|
||||
}
|
||||
37
examples/call/wbstream/creator.json
Normal file
37
examples/call/wbstream/creator.json
Normal 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
|
||||
}
|
||||
}
|
||||
33
examples/call/wbstream/joiner.json
Normal file
33
examples/call/wbstream/joiner.json
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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": [],
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
44
examples/rmux/client.json
Normal 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
41
examples/rmux/server.json
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
146
go.mod
@@ -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
365
go.sum
@@ -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
17
include/call.go
Normal 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
27
include/call_stub.go
Normal 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`)
|
||||
})
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
78
option/call.go
Normal 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"`
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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"`
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ type DERPMeshOptions struct {
|
||||
}
|
||||
|
||||
type _DERPSTUNListenOptions struct {
|
||||
Enabled bool
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
ListenOptions
|
||||
}
|
||||
|
||||
|
||||
@@ -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] {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
63
parser/link/anytls.go
Normal 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
|
||||
}
|
||||
@@ -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:], "")
|
||||
|
||||
64
protocol/anytls/client_metadata.go
Normal file
64
protocol/anytls/client_metadata.go
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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
122
protocol/call/inbound.go
Normal 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
134
protocol/call/outbound.go
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user