mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-12 18:17:18 +10:00
Compare commits
67 Commits
v1.4.0-bet
...
v1.4.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77848906c8 | ||
|
|
c21f5fe772 | ||
|
|
76f32869e2 | ||
|
|
57814da0f9 | ||
|
|
592f76bb9f | ||
|
|
652ebdf241 | ||
|
|
b8a0d1fe59 | ||
|
|
a184902817 | ||
|
|
f64e25cbb1 | ||
|
|
552d0efe13 | ||
|
|
448c722aed | ||
|
|
be61ca64d4 | ||
|
|
efe33cf48d | ||
|
|
fe8d46cce5 | ||
|
|
b1f289bce5 | ||
|
|
a8beb80876 | ||
|
|
ff209471d8 | ||
|
|
806f7d0a2b | ||
|
|
6b943caf37 | ||
|
|
4ea2d460f4 | ||
|
|
c84c18f960 | ||
|
|
1402bdab41 | ||
|
|
7082cf277e | ||
|
|
b9310154a7 | ||
|
|
55c34e3fb0 | ||
|
|
68f2202eec | ||
|
|
5057e50bb8 | ||
|
|
23e1a69955 | ||
|
|
b83c6c9d20 | ||
|
|
67deac6d44 | ||
|
|
ea3731162b | ||
|
|
c75e32e722 | ||
|
|
e7b35be5f6 | ||
|
|
5a309266f0 | ||
|
|
05669eaaad | ||
|
|
e91a6e5439 | ||
|
|
43f72a6419 | ||
|
|
6dcacf3b5e | ||
|
|
edad4d1ce7 | ||
|
|
262842c87d | ||
|
|
376f527742 | ||
|
|
c0bbb3849d | ||
|
|
738c25d818 | ||
|
|
027af4d4ee | ||
|
|
6011f4483a | ||
|
|
fc22466e3b | ||
|
|
975e13a313 | ||
|
|
f46732bc0e | ||
|
|
5c5c25e3ad | ||
|
|
53a0bf2d11 | ||
|
|
7b79d98f59 | ||
|
|
1dd2c26f31 | ||
|
|
d14170348d | ||
|
|
9f94b21687 | ||
|
|
cf57e46d69 | ||
|
|
b459001600 | ||
|
|
73267fd6ad | ||
|
|
1019ecfdcf | ||
|
|
81b847faca | ||
|
|
ce4c76cdd2 | ||
|
|
917420e79a | ||
|
|
0b14dc3228 | ||
|
|
cbdaf3272b | ||
|
|
d51ab2b0a7 | ||
|
|
1363e16312 | ||
|
|
f43d0141f3 | ||
|
|
90b3aad83a |
8
.github/workflows/debug.yml
vendored
8
.github/workflows/debug.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Get latest go version
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -199,7 +199,7 @@ jobs:
|
||||
TAGS: with_clash_api,with_quic
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Get latest go version
|
||||
|
||||
12
.github/workflows/docker.yml
vendored
12
.github/workflows/docker.yml
vendored
@@ -9,20 +9,20 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Setup QEMU for Docker Buildx
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Docker metadata
|
||||
id: metadata
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/sagernet/sing-box
|
||||
- name: Get tag to build
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
echo "versioned=ghcr.io/sagernet/sing-box:${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Build and release Docker images
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
platforms: linux/386,linux/amd64,linux/arm64,linux/s390x
|
||||
target: dist
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Get latest go version
|
||||
|
||||
20
.github/workflows/mkdocs.yml
vendored
20
.github/workflows/mkdocs.yml
vendored
@@ -1,20 +0,0 @@
|
||||
name: Generate Documents
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- docs/**
|
||||
- .github/workflows/mkdocs.yml
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.x
|
||||
- run: |
|
||||
pip install mkdocs-material=="9.*" mkdocs-static-i18n=="0.53"
|
||||
- run: |
|
||||
mkdocs gh-deploy -m "{sha}" --force --ignore-version --no-history
|
||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v7
|
||||
- uses: actions/stale@v8
|
||||
with:
|
||||
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days'
|
||||
days-before-stale: 60
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.20-alpine AS builder
|
||||
FROM golang:1.21-alpine AS builder
|
||||
LABEL maintainer="nekohasekai <contact-git@sekai.icu>"
|
||||
COPY . /go/src/github.com/sagernet/sing-box
|
||||
WORKDIR /go/src/github.com/sagernet/sing-box
|
||||
|
||||
107
Makefile
107
Makefile
@@ -1,7 +1,8 @@
|
||||
NAME = sing-box
|
||||
COMMIT = $(shell git rev-parse --short HEAD)
|
||||
TAGS_GO118 = with_gvisor,with_dhcp,with_wireguard,with_utls,with_reality_server,with_clash_api
|
||||
TAGS_GO120 ?= with_quic
|
||||
TAGS_GO120 = with_quic
|
||||
TAGS ?= $(TAGS_GO118),$(TAGS_GO120)
|
||||
TAGS_TEST ?= with_gvisor,with_quic,with_wireguard,with_grpc,with_ech,with_utls,with_reality_server,with_shadowsocksr
|
||||
|
||||
GOHOSTOS = $(shell go env GOHOSTOS)
|
||||
@@ -9,7 +10,7 @@ GOHOSTARCH = $(shell go env GOHOSTARCH)
|
||||
VERSION=$(shell CGO_ENABLED=0 GOOS=$(GOHOSTOS) GOARCH=$(GOHOSTARCH) go run ./cmd/internal/read_tag)
|
||||
|
||||
PARAMS = -v -trimpath -ldflags "-X 'github.com/sagernet/sing-box/constant.Version=$(VERSION)' -s -w -buildid="
|
||||
MAIN_PARAMS = $(PARAMS) -tags "$(TAGS_GO118),$(TAGS_GO120)"
|
||||
MAIN_PARAMS = $(PARAMS) -tags $(TAGS)
|
||||
MAIN = ./cmd/sing-box
|
||||
PREFIX ?= $(shell go env GOPATH)
|
||||
|
||||
@@ -57,24 +58,102 @@ proto_install:
|
||||
go install -v google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||||
go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
|
||||
|
||||
snapshot:
|
||||
go run ./cmd/internal/build goreleaser release --clean --snapshot || exit 1
|
||||
mkdir dist/release
|
||||
mv dist/*.tar.gz dist/*.zip dist/*.deb dist/*.rpm dist/release
|
||||
ghr --delete --draft --prerelease -p 1 nightly dist/release
|
||||
rm -r dist
|
||||
|
||||
release:
|
||||
go run ./cmd/internal/build goreleaser release --clean --skip-publish || exit 1
|
||||
mkdir dist/release
|
||||
mv dist/*.tar.gz dist/*.zip dist/*.deb dist/*.rpm dist/release
|
||||
ghr --delete --draft --prerelease -p 3 $(shell git describe --tags) dist/release
|
||||
ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release
|
||||
rm -r dist
|
||||
|
||||
release_install:
|
||||
go install -v github.com/goreleaser/goreleaser@latest
|
||||
go install -v github.com/tcnksm/ghr@latest
|
||||
|
||||
update_android_version:
|
||||
go run ./cmd/internal/update_android_version
|
||||
|
||||
build_android:
|
||||
cd ../sing-box-for-android && ./gradlew :app:assembleRelease && ./gradlew --stop
|
||||
|
||||
upload_android:
|
||||
mkdir -p dist/release_android
|
||||
cp ../sing-box-for-android/app/build/outputs/apk/release/*.apk dist/release_android
|
||||
ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release_android
|
||||
rm -rf dist/release_android
|
||||
|
||||
release_android: lib_android update_android_version build_android upload_android
|
||||
|
||||
publish_android:
|
||||
cd ../sing-box-for-android && ./gradlew :app:appCenterAssembleAndUploadRelease && ./gradlew --stop
|
||||
|
||||
build_ios:
|
||||
cd ../sing-box-for-apple && \
|
||||
rm -rf build/SFI.xcarchive && \
|
||||
xcodebuild archive -scheme SFI -configuration Release -archivePath build/SFI.xcarchive
|
||||
|
||||
upload_ios_app_store:
|
||||
cd ../sing-box-for-apple && \
|
||||
xcodebuild -exportArchive -archivePath build/SFI.xcarchive -exportOptionsPlist SFI/Upload.plist
|
||||
|
||||
release_ios: build_ios upload_ios_app_store
|
||||
|
||||
build_macos:
|
||||
cd ../sing-box-for-apple && \
|
||||
rm -rf build/SFM.xcarchive && \
|
||||
xcodebuild archive -scheme SFM -configuration Release -archivePath build/SFM.xcarchive
|
||||
|
||||
upload_macos_app_store:
|
||||
cd ../sing-box-for-apple && \
|
||||
xcodebuild -exportArchive -archivePath build/SFM.xcarchive -exportOptionsPlist SFI/Upload.plist
|
||||
|
||||
release_macos: build_macos upload_macos_app_store
|
||||
|
||||
build_macos_independent:
|
||||
cd ../sing-box-for-apple && \
|
||||
rm -rf build/SFT.System.xcarchive && \
|
||||
xcodebuild archive -scheme SFM.System -configuration Release -archivePath build/SFM.System.xcarchive
|
||||
|
||||
notarize_macos_independent:
|
||||
cd ../sing-box-for-apple && \
|
||||
xcodebuild -exportArchive -archivePath "build/SFM.System.xcarchive" -exportOptionsPlist SFM.System/Upload.plist
|
||||
|
||||
wait_notarize_macos_independent:
|
||||
sleep 60
|
||||
|
||||
export_macos_independent:
|
||||
rm -rf dist/SFM
|
||||
mkdir -p dist/SFM
|
||||
cd ../sing-box-for-apple && \
|
||||
xcodebuild -exportNotarizedApp -archivePath build/SFM.System.xcarchive -exportPath "../sing-box/dist/SFM"
|
||||
|
||||
upload_macos_independent:
|
||||
cd dist/SFM && \
|
||||
rm -f *.zip && \
|
||||
zip -ry "SFM-${VERSION}-universal.zip" SFM.app && \
|
||||
ghr --replace --draft --prerelease "v${VERSION}" *.zip
|
||||
|
||||
release_macos_independent: build_macos_independent notarize_macos_independent wait_notarize_macos_independent export_macos_independent upload_macos_independent
|
||||
|
||||
build_tvos:
|
||||
cd ../sing-box-for-apple && \
|
||||
rm -rf build/SFT.xcarchive && \
|
||||
xcodebuild archive -scheme SFT -configuration Release -archivePath build/SFT.xcarchive
|
||||
|
||||
upload_tvos_app_store:
|
||||
cd ../sing-box-for-apple && \
|
||||
xcodebuild -exportArchive -archivePath "build/SFT.xcarchive" -exportOptionsPlist SFI/Upload.plist
|
||||
|
||||
release_tvos: build_tvos upload_tvos_app_store
|
||||
|
||||
update_apple_version:
|
||||
go run ./cmd/internal/update_apple_version
|
||||
|
||||
release_apple: lib_ios update_apple_version release_ios release_macos release_tvos release_macos_independent
|
||||
rm -rf dist
|
||||
|
||||
release_apple_beta: update_apple_version release_ios release_macos release_tvos
|
||||
rm -rf dist
|
||||
|
||||
test:
|
||||
@go test -v ./... && \
|
||||
cd test && \
|
||||
@@ -87,10 +166,10 @@ test_stdio:
|
||||
go mod tidy && \
|
||||
go test -v -tags "$(TAGS_TEST),force_stdio" .
|
||||
|
||||
android:
|
||||
lib_android:
|
||||
go run ./cmd/internal/build_libbox -target android
|
||||
|
||||
ios:
|
||||
lib_ios:
|
||||
go run ./cmd/internal/build_libbox -target ios
|
||||
|
||||
lib:
|
||||
@@ -99,8 +178,8 @@ lib:
|
||||
|
||||
lib_install:
|
||||
go get -v -d
|
||||
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.0.0-20230728014906-3de089147f59
|
||||
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.0.0-20230728014906-3de089147f59
|
||||
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.0.0-20230915142329-c6740b6d2950
|
||||
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.0.0-20230915142329-c6740b6d2950
|
||||
|
||||
clean:
|
||||
rm -rf bin dist sing-box
|
||||
|
||||
@@ -12,6 +12,7 @@ type ClashServer interface {
|
||||
Service
|
||||
PreStarter
|
||||
Mode() string
|
||||
ModeList() []string
|
||||
StoreSelected() bool
|
||||
StoreFakeIP() bool
|
||||
CacheFile() ClashCacheFile
|
||||
@@ -21,6 +22,8 @@ type ClashServer interface {
|
||||
}
|
||||
|
||||
type ClashCacheFile interface {
|
||||
LoadMode() string
|
||||
StoreMode(mode string) error
|
||||
LoadSelected(group string) string
|
||||
StoreSelected(group string, selected string) error
|
||||
LoadGroupExpand(group string) (isExpand bool, loaded bool)
|
||||
|
||||
@@ -32,6 +32,7 @@ type Router interface {
|
||||
Exchange(ctx context.Context, message *mdns.Msg) (*mdns.Msg, error)
|
||||
Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error)
|
||||
LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error)
|
||||
ClearDNSCache()
|
||||
|
||||
InterfaceFinder() control.InterfaceFinder
|
||||
UpdateInterfaces() error
|
||||
|
||||
4
box.go
4
box.go
@@ -145,7 +145,9 @@ func New(options Options) (*Box, error) {
|
||||
preServices := make(map[string]adapter.Service)
|
||||
postServices := make(map[string]adapter.Service)
|
||||
if needClashAPI {
|
||||
clashServer, err := experimental.NewClashServer(ctx, router, logFactory.(log.ObservableFactory), common.PtrValueOrDefault(experimentalOptions.ClashAPI))
|
||||
clashAPIOptions := common.PtrValueOrDefault(experimentalOptions.ClashAPI)
|
||||
clashAPIOptions.ModeList = experimental.CalculateClashModeList(options.Options)
|
||||
clashServer, err := experimental.NewClashServer(ctx, router, logFactory.(log.ObservableFactory), clashAPIOptions)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "create clash api server")
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package build_shared
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing-box/common/badversion"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/shell"
|
||||
)
|
||||
|
||||
@@ -21,3 +22,15 @@ func ReadTag() (string, error) {
|
||||
}
|
||||
return version.String() + "-" + shortCommit, nil
|
||||
}
|
||||
|
||||
func ReadTagVersion() (badversion.Version, error) {
|
||||
currentTag := common.Must1(shell.Exec("git", "describe", "--tags").ReadOutput())
|
||||
currentTagRev := common.Must1(shell.Exec("git", "describe", "--tags", "--abbrev=0").ReadOutput())
|
||||
version := badversion.Parse(currentTagRev[1:])
|
||||
if currentTagRev != currentTag {
|
||||
if version.PreReleaseIdentifier == "" {
|
||||
version.Patch++
|
||||
}
|
||||
}
|
||||
return version, nil
|
||||
}
|
||||
|
||||
51
cmd/internal/update_android_version/main.go
Normal file
51
cmd/internal/update_android_version/main.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/cmd/internal/build_shared"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing/common"
|
||||
)
|
||||
|
||||
func main() {
|
||||
newVersion := common.Must1(build_shared.ReadTagVersion())
|
||||
androidPath, err := filepath.Abs("../sing-box-for-android")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
common.Must(os.Chdir(androidPath))
|
||||
localProps := common.Must1(os.ReadFile("local.properties"))
|
||||
var propsList [][]string
|
||||
for _, propLine := range strings.Split(string(localProps), "\n") {
|
||||
propsList = append(propsList, strings.Split(propLine, "="))
|
||||
}
|
||||
for _, propPair := range propsList {
|
||||
if propPair[0] == "VERSION_NAME" {
|
||||
if propPair[1] == newVersion.String() {
|
||||
log.Info("version not changed")
|
||||
return
|
||||
}
|
||||
propPair[1] = newVersion.String()
|
||||
log.Info("updated version to ", newVersion.String())
|
||||
}
|
||||
}
|
||||
for _, propPair := range propsList {
|
||||
switch propPair[0] {
|
||||
case "VERSION_CODE":
|
||||
versionCode := common.Must1(strconv.ParseInt(propPair[1], 10, 64))
|
||||
propPair[1] = strconv.Itoa(int(versionCode + 1))
|
||||
log.Info("updated version code to ", propPair[1])
|
||||
case "RELEASE_NOTES":
|
||||
propPair[1] = "sing-box " + newVersion.String()
|
||||
}
|
||||
}
|
||||
var newProps []string
|
||||
for _, propPair := range propsList {
|
||||
newProps = append(newProps, strings.Join(propPair, "="))
|
||||
}
|
||||
common.Must(os.WriteFile("local.properties", []byte(strings.Join(newProps, "\n")), 0o644))
|
||||
}
|
||||
80
cmd/internal/update_apple_version/main.go
Normal file
80
cmd/internal/update_apple_version/main.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/cmd/internal/build_shared"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing/common"
|
||||
|
||||
"howett.net/plist"
|
||||
)
|
||||
|
||||
func main() {
|
||||
newVersion := common.Must1(build_shared.ReadTagVersion())
|
||||
applePath, err := filepath.Abs("../sing-box-for-apple")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
common.Must(os.Chdir(applePath))
|
||||
projectFile := common.Must1(os.Open("sing-box.xcodeproj/project.pbxproj"))
|
||||
var project map[string]any
|
||||
decoder := plist.NewDecoder(projectFile)
|
||||
common.Must(decoder.Decode(&project))
|
||||
objectsMap := project["objects"].(map[string]any)
|
||||
projectContent := string(common.Must1(os.ReadFile("sing-box.xcodeproj/project.pbxproj")))
|
||||
newContent, updated0 := findAndReplace(objectsMap, projectContent, []string{"io.nekohasekai.sfa"}, newVersion.VersionString())
|
||||
newContent, updated1 := findAndReplace(objectsMap, newContent, []string{"io.nekohasekai.sfa.independent", "io.nekohasekai.sfa.system"}, newVersion.String())
|
||||
if updated0 || updated1 {
|
||||
log.Info("updated version to ", newVersion.VersionString())
|
||||
common.Must(os.WriteFile("sing-box.xcodeproj/project.pbxproj.bak", []byte(projectContent), 0o644))
|
||||
common.Must(os.WriteFile("sing-box.xcodeproj/project.pbxproj", []byte(newContent), 0o644))
|
||||
} else {
|
||||
log.Info("version not changed")
|
||||
}
|
||||
}
|
||||
|
||||
func findAndReplace(objectsMap map[string]any, projectContent string, bundleIDList []string, newVersion string) (string, bool) {
|
||||
objectKeyList := findObjectKey(objectsMap, bundleIDList)
|
||||
var updated bool
|
||||
for _, objectKey := range objectKeyList {
|
||||
matchRegexp := common.Must1(regexp.Compile(objectKey + ".*= \\{"))
|
||||
indexes := matchRegexp.FindStringIndex(projectContent)
|
||||
if len(indexes) < 2 {
|
||||
println(projectContent)
|
||||
log.Fatal("failed to find object key ", objectKey, ": ", strings.Index(projectContent, objectKey))
|
||||
}
|
||||
indexStart := indexes[1]
|
||||
indexEnd := indexStart + strings.Index(projectContent[indexStart:], "}")
|
||||
versionStart := indexStart + strings.Index(projectContent[indexStart:indexEnd], "MARKETING_VERSION = ") + 20
|
||||
versionEnd := versionStart + strings.Index(projectContent[versionStart:indexEnd], ";")
|
||||
version := projectContent[versionStart:versionEnd]
|
||||
if version == newVersion {
|
||||
continue
|
||||
}
|
||||
updated = true
|
||||
projectContent = projectContent[:versionStart] + newVersion + projectContent[versionEnd:]
|
||||
}
|
||||
return projectContent, updated
|
||||
}
|
||||
|
||||
func findObjectKey(objectsMap map[string]any, bundleIDList []string) []string {
|
||||
var objectKeyList []string
|
||||
for objectKey, object := range objectsMap {
|
||||
buildSettings := object.(map[string]any)["buildSettings"]
|
||||
if buildSettings == nil {
|
||||
continue
|
||||
}
|
||||
bundleIDObject := buildSettings.(map[string]any)["PRODUCT_BUNDLE_IDENTIFIER"]
|
||||
if bundleIDObject == nil {
|
||||
continue
|
||||
}
|
||||
if common.Contains(bundleIDList, bundleIDObject.(string)) {
|
||||
objectKeyList = append(objectKeyList, objectKey)
|
||||
}
|
||||
}
|
||||
return objectKeyList
|
||||
}
|
||||
@@ -143,14 +143,16 @@ func create() (*box.Box, context.CancelFunc, error) {
|
||||
signal.Stop(osSignals)
|
||||
close(osSignals)
|
||||
}()
|
||||
|
||||
startCtx, finishStart := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
_, loaded := <-osSignals
|
||||
if loaded {
|
||||
cancel()
|
||||
closeMonitor(startCtx)
|
||||
}
|
||||
}()
|
||||
err = instance.Start()
|
||||
finishStart()
|
||||
if err != nil {
|
||||
cancel()
|
||||
return nil, nil, E.Cause(err, "start service")
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
package baderror
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
|
||||
func Contains(err error, msgList ...string) bool {
|
||||
for _, msg := range msgList {
|
||||
if strings.Contains(err.Error(), msg) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func WrapH2(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
err = E.Unwrap(err)
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
return io.EOF
|
||||
}
|
||||
if Contains(err, "client disconnected", "body closed by handler", "response body closed", "; CANCEL") {
|
||||
return net.ErrClosed
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func WrapGRPC(err error) error {
|
||||
// grpc uses stupid internal error types
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if Contains(err, "EOF") {
|
||||
return io.EOF
|
||||
}
|
||||
if Contains(err, "Canceled") {
|
||||
return context.Canceled
|
||||
}
|
||||
if Contains(err,
|
||||
"the client connection is closing",
|
||||
"server closed the stream without sending trailers") {
|
||||
return net.ErrClosed
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func WrapQUIC(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if Contains(err, "canceled by local with error code 0") {
|
||||
return net.ErrClosed
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -57,6 +57,10 @@ func (v Version) After(anotherVersion Version) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (v Version) VersionString() string {
|
||||
return F.ToString(v.Major, ".", v.Minor, ".", v.Patch)
|
||||
}
|
||||
|
||||
func (v Version) String() string {
|
||||
version := F.ToString(v.Major, ".", v.Minor, ".", v.Patch)
|
||||
if v.PreReleaseIdentifier != "" {
|
||||
|
||||
@@ -17,7 +17,7 @@ func NewConn(conn net.Conn) (net.Conn, error) {
|
||||
element := openConnection.PushBack(conn)
|
||||
connAccess.Unlock()
|
||||
if KillerEnabled {
|
||||
err := killerCheck()
|
||||
err := KillerCheck()
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
@@ -1,20 +1,20 @@
|
||||
package conntrack
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
runtimeDebug "runtime/debug"
|
||||
"time"
|
||||
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/memory"
|
||||
)
|
||||
|
||||
var (
|
||||
KillerEnabled bool
|
||||
MemoryLimit int64
|
||||
MemoryLimit uint64
|
||||
killerLastCheck time.Time
|
||||
)
|
||||
|
||||
func killerCheck() error {
|
||||
func KillerCheck() error {
|
||||
if !KillerEnabled {
|
||||
return nil
|
||||
}
|
||||
@@ -23,10 +23,7 @@ func killerCheck() error {
|
||||
return nil
|
||||
}
|
||||
killerLastCheck = nowTime
|
||||
var memStats runtime.MemStats
|
||||
runtime.ReadMemStats(&memStats)
|
||||
inuseMemory := int64(memStats.StackInuse + memStats.HeapInuse + memStats.HeapIdle - memStats.HeapReleased)
|
||||
if inuseMemory > MemoryLimit {
|
||||
if memory.Total() > MemoryLimit {
|
||||
Close()
|
||||
go func() {
|
||||
time.Sleep(time.Second)
|
||||
@@ -18,7 +18,7 @@ func NewPacketConn(conn net.PacketConn) (net.PacketConn, error) {
|
||||
element := openConnection.PushBack(conn)
|
||||
connAccess.Unlock()
|
||||
if KillerEnabled {
|
||||
err := killerCheck()
|
||||
err := KillerCheck()
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
@@ -6,19 +6,18 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/dialer/conntrack"
|
||||
"github.com/sagernet/sing-box/common/conntrack"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/tfo-go"
|
||||
)
|
||||
|
||||
type DefaultDialer struct {
|
||||
dialer4 tfo.Dialer
|
||||
dialer6 tfo.Dialer
|
||||
dialer4 tcpDialer
|
||||
dialer6 tcpDialer
|
||||
udpDialer4 net.Dialer
|
||||
udpDialer6 net.Dialer
|
||||
udpListener net.ListenConfig
|
||||
@@ -94,14 +93,22 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
|
||||
udpAddr6 = M.SocksaddrFrom(bindAddr, 0).String()
|
||||
}
|
||||
if options.TCPMultiPath {
|
||||
if !multipathTCPAvailable {
|
||||
if !go121Available {
|
||||
return nil, E.New("MultiPath TCP requires go1.21, please recompile your binary.")
|
||||
}
|
||||
setMultiPathTCP(&dialer4)
|
||||
}
|
||||
tcpDialer4, err := newTCPDialer(dialer4, options.TCPFastOpen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tcpDialer6, err := newTCPDialer(dialer6, options.TCPFastOpen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &DefaultDialer{
|
||||
tfo.Dialer{Dialer: dialer4, DisableTFO: !options.TCPFastOpen},
|
||||
tfo.Dialer{Dialer: dialer6, DisableTFO: !options.TCPFastOpen},
|
||||
tcpDialer4,
|
||||
tcpDialer6,
|
||||
udpDialer4,
|
||||
udpDialer6,
|
||||
listener,
|
||||
|
||||
15
common/dialer/default_go1.20.go
Normal file
15
common/dialer/default_go1.20.go
Normal file
@@ -0,0 +1,15 @@
|
||||
//go:build go1.20
|
||||
|
||||
package dialer
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/sagernet/tfo-go"
|
||||
)
|
||||
|
||||
type tcpDialer = tfo.Dialer
|
||||
|
||||
func newTCPDialer(dialer net.Dialer, tfoEnabled bool) (tcpDialer, error) {
|
||||
return tfo.Dialer{Dialer: dialer, DisableTFO: !tfoEnabled}, nil
|
||||
}
|
||||
@@ -4,7 +4,7 @@ package dialer
|
||||
|
||||
import "net"
|
||||
|
||||
const multipathTCPAvailable = true
|
||||
const go121Available = true
|
||||
|
||||
func setMultiPathTCP(dialer *net.Dialer) {
|
||||
dialer.SetMultipathTCP(true)
|
||||
|
||||
18
common/dialer/default_nongo1.20.go
Normal file
18
common/dialer/default_nongo1.20.go
Normal file
@@ -0,0 +1,18 @@
|
||||
//go:build !go1.20
|
||||
|
||||
package dialer
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
|
||||
type tcpDialer = net.Dialer
|
||||
|
||||
func newTCPDialer(dialer net.Dialer, tfoEnabled bool) (tcpDialer, error) {
|
||||
if tfoEnabled {
|
||||
return dialer, E.New("TCP Fast Open requires go1.20, please recompile your binary.")
|
||||
}
|
||||
return dialer, nil
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"net"
|
||||
)
|
||||
|
||||
const multipathTCPAvailable = false
|
||||
const go121Available = false
|
||||
|
||||
func setMultiPathTCP(dialer *net.Dialer) {
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build go1.20
|
||||
|
||||
package dialer
|
||||
|
||||
import (
|
||||
@@ -5,6 +7,7 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing/common"
|
||||
@@ -22,10 +25,11 @@ type slowOpenConn struct {
|
||||
destination M.Socksaddr
|
||||
conn net.Conn
|
||||
create chan struct{}
|
||||
access sync.Mutex
|
||||
err error
|
||||
}
|
||||
|
||||
func DialSlowContext(dialer *tfo.Dialer, ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
func DialSlowContext(dialer *tcpDialer, ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
if dialer.DisableTFO || N.NetworkName(network) != N.NetworkTCP {
|
||||
switch N.NetworkName(network) {
|
||||
case N.NetworkTCP, N.NetworkUDP:
|
||||
@@ -58,15 +62,26 @@ func (c *slowOpenConn) Read(b []byte) (n int, err error) {
|
||||
}
|
||||
|
||||
func (c *slowOpenConn) Write(b []byte) (n int, err error) {
|
||||
if c.conn == nil {
|
||||
c.conn, err = c.dialer.DialContext(c.ctx, c.network, c.destination.String(), b)
|
||||
if err != nil {
|
||||
c.err = E.Cause(err, "dial tcp fast open")
|
||||
}
|
||||
close(c.create)
|
||||
return
|
||||
if c.conn != nil {
|
||||
return c.conn.Write(b)
|
||||
}
|
||||
return c.conn.Write(b)
|
||||
c.access.Lock()
|
||||
defer c.access.Unlock()
|
||||
select {
|
||||
case <-c.create:
|
||||
if c.err != nil {
|
||||
return 0, c.err
|
||||
}
|
||||
return c.conn.Write(b)
|
||||
default:
|
||||
}
|
||||
c.conn, err = c.dialer.DialContext(c.ctx, c.network, c.destination.String(), b)
|
||||
if err != nil {
|
||||
c.conn = nil
|
||||
c.err = E.Cause(err, "dial tcp fast open")
|
||||
}
|
||||
close(c.create)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *slowOpenConn) Close() error {
|
||||
|
||||
20
common/dialer/tfo_stub.go
Normal file
20
common/dialer/tfo_stub.go
Normal file
@@ -0,0 +1,20 @@
|
||||
//go:build !go1.20
|
||||
|
||||
package dialer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
func DialSlowContext(dialer *tcpDialer, ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
switch N.NetworkName(network) {
|
||||
case N.NetworkTCP, N.NetworkUDP:
|
||||
return dialer.DialContext(ctx, network, destination.String())
|
||||
default:
|
||||
return dialer.DialContext(ctx, network, destination.AddrString())
|
||||
}
|
||||
}
|
||||
158
common/humanize/bytes.go
Normal file
158
common/humanize/bytes.go
Normal file
@@ -0,0 +1,158 @@
|
||||
package humanize
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// IEC Sizes.
|
||||
// kibis of bits
|
||||
const (
|
||||
Byte = 1 << (iota * 10)
|
||||
KiByte
|
||||
MiByte
|
||||
GiByte
|
||||
TiByte
|
||||
PiByte
|
||||
EiByte
|
||||
)
|
||||
|
||||
// SI Sizes.
|
||||
const (
|
||||
IByte = 1
|
||||
KByte = IByte * 1000
|
||||
MByte = KByte * 1000
|
||||
GByte = MByte * 1000
|
||||
TByte = GByte * 1000
|
||||
PByte = TByte * 1000
|
||||
EByte = PByte * 1000
|
||||
)
|
||||
|
||||
var defaultSizeTable = map[string]uint64{
|
||||
"b": Byte,
|
||||
"kib": KiByte,
|
||||
"kb": KByte,
|
||||
"mib": MiByte,
|
||||
"mb": MByte,
|
||||
"gib": GiByte,
|
||||
"gb": GByte,
|
||||
"tib": TiByte,
|
||||
"tb": TByte,
|
||||
"pib": PiByte,
|
||||
"pb": PByte,
|
||||
"eib": EiByte,
|
||||
"eb": EByte,
|
||||
// Without suffix
|
||||
"": Byte,
|
||||
"ki": KiByte,
|
||||
"k": KByte,
|
||||
"mi": MiByte,
|
||||
"m": MByte,
|
||||
"gi": GiByte,
|
||||
"g": GByte,
|
||||
"ti": TiByte,
|
||||
"t": TByte,
|
||||
"pi": PiByte,
|
||||
"p": PByte,
|
||||
"ei": EiByte,
|
||||
"e": EByte,
|
||||
}
|
||||
|
||||
var memorysSizeTable = map[string]uint64{
|
||||
"b": Byte,
|
||||
"kb": KiByte,
|
||||
"mb": MiByte,
|
||||
"gb": GiByte,
|
||||
"tb": TiByte,
|
||||
"pb": PiByte,
|
||||
"eb": EiByte,
|
||||
"": Byte,
|
||||
"k": KiByte,
|
||||
"m": MiByte,
|
||||
"g": GiByte,
|
||||
"t": TiByte,
|
||||
"p": PiByte,
|
||||
"e": EiByte,
|
||||
}
|
||||
|
||||
var (
|
||||
defaultSizes = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"}
|
||||
iSizes = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}
|
||||
)
|
||||
|
||||
func Bytes(s uint64) string {
|
||||
return humanateBytes(s, 1000, defaultSizes)
|
||||
}
|
||||
|
||||
func MemoryBytes(s uint64) string {
|
||||
return humanateBytes(s, 1024, defaultSizes)
|
||||
}
|
||||
|
||||
func IBytes(s uint64) string {
|
||||
return humanateBytes(s, 1024, iSizes)
|
||||
}
|
||||
|
||||
func logn(n, b float64) float64 {
|
||||
return math.Log(n) / math.Log(b)
|
||||
}
|
||||
|
||||
func humanateBytes(s uint64, base float64, sizes []string) string {
|
||||
if s < 10 {
|
||||
return fmt.Sprintf("%d B", s)
|
||||
}
|
||||
e := math.Floor(logn(float64(s), base))
|
||||
suffix := sizes[int(e)]
|
||||
val := math.Floor(float64(s)/math.Pow(base, e)*10+0.5) / 10
|
||||
f := "%.0f %s"
|
||||
if val < 10 {
|
||||
f = "%.1f %s"
|
||||
}
|
||||
|
||||
return fmt.Sprintf(f, val, suffix)
|
||||
}
|
||||
|
||||
func ParseBytes(s string) (uint64, error) {
|
||||
return parseBytes0(s, defaultSizeTable)
|
||||
}
|
||||
|
||||
func ParseMemoryBytes(s string) (uint64, error) {
|
||||
return parseBytes0(s, memorysSizeTable)
|
||||
}
|
||||
|
||||
func parseBytes0(s string, sizeTable map[string]uint64) (uint64, error) {
|
||||
lastDigit := 0
|
||||
hasComma := false
|
||||
for _, r := range s {
|
||||
if !(unicode.IsDigit(r) || r == '.' || r == ',') {
|
||||
break
|
||||
}
|
||||
if r == ',' {
|
||||
hasComma = true
|
||||
}
|
||||
lastDigit++
|
||||
}
|
||||
|
||||
num := s[:lastDigit]
|
||||
if hasComma {
|
||||
num = strings.Replace(num, ",", "", -1)
|
||||
}
|
||||
|
||||
f, err := strconv.ParseFloat(num, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
|
||||
if m, ok := sizeTable[extra]; ok {
|
||||
f *= float64(m)
|
||||
if f >= math.MaxUint64 {
|
||||
return 0, fmt.Errorf("too large: %v", s)
|
||||
}
|
||||
return uint64(f), nil
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("unhandled size name: %v", extra)
|
||||
}
|
||||
@@ -22,23 +22,29 @@ func PeekStream(ctx context.Context, conn net.Conn, buffer *buf.Buffer, timeout
|
||||
if timeout == 0 {
|
||||
timeout = C.ReadPayloadTimeout
|
||||
}
|
||||
err := conn.SetReadDeadline(time.Now().Add(timeout))
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "set read deadline")
|
||||
}
|
||||
_, err = buffer.ReadOnceFrom(conn)
|
||||
err = E.Errors(err, conn.SetReadDeadline(time.Time{}))
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "read payload")
|
||||
}
|
||||
var metadata *adapter.InboundContext
|
||||
deadline := time.Now().Add(timeout)
|
||||
var errors []error
|
||||
for _, sniffer := range sniffers {
|
||||
metadata, err = sniffer(ctx, bytes.NewReader(buffer.Bytes()))
|
||||
if metadata != nil {
|
||||
return metadata, nil
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
err := conn.SetReadDeadline(deadline)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "set read deadline")
|
||||
}
|
||||
_, err = buffer.ReadOnceFrom(conn)
|
||||
err = E.Errors(err, conn.SetReadDeadline(time.Time{}))
|
||||
if err != nil {
|
||||
if i > 0 {
|
||||
break
|
||||
}
|
||||
return nil, E.Cause(err, "read payload")
|
||||
}
|
||||
for _, sniffer := range sniffers {
|
||||
metadata, err := sniffer(ctx, bytes.NewReader(buffer.Bytes()))
|
||||
if metadata != nil {
|
||||
return metadata, nil
|
||||
}
|
||||
errors = append(errors, err)
|
||||
}
|
||||
errors = append(errors, err)
|
||||
}
|
||||
return nil, E.Errors(errors...)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
)
|
||||
|
||||
type History struct {
|
||||
@@ -21,7 +20,7 @@ type History struct {
|
||||
type HistoryStorage struct {
|
||||
access sync.RWMutex
|
||||
delayHistory map[string]*History
|
||||
callbacks list.List[func()]
|
||||
updateHook chan<- struct{}
|
||||
}
|
||||
|
||||
func NewHistoryStorage() *HistoryStorage {
|
||||
@@ -30,16 +29,8 @@ func NewHistoryStorage() *HistoryStorage {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *HistoryStorage) AddListener(listener func()) *list.Element[func()] {
|
||||
s.access.Lock()
|
||||
defer s.access.Unlock()
|
||||
return s.callbacks.PushBack(listener)
|
||||
}
|
||||
|
||||
func (s *HistoryStorage) RemoveListener(element *list.Element[func()]) {
|
||||
s.access.Lock()
|
||||
defer s.access.Unlock()
|
||||
s.callbacks.Remove(element)
|
||||
func (s *HistoryStorage) SetHook(hook chan<- struct{}) {
|
||||
s.updateHook = hook
|
||||
}
|
||||
|
||||
func (s *HistoryStorage) LoadURLTestHistory(tag string) *History {
|
||||
@@ -66,13 +57,20 @@ func (s *HistoryStorage) StoreURLTestHistory(tag string, history *History) {
|
||||
}
|
||||
|
||||
func (s *HistoryStorage) notifyUpdated() {
|
||||
s.access.RLock()
|
||||
defer s.access.RUnlock()
|
||||
for element := s.callbacks.Front(); element != nil; element = element.Next() {
|
||||
element.Value()
|
||||
updateHook := s.updateHook
|
||||
if updateHook != nil {
|
||||
select {
|
||||
case updateHook <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *HistoryStorage) Close() error {
|
||||
s.updateHook = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func URLTest(ctx context.Context, link string, detour N.Dialer) (t uint16, err error) {
|
||||
if link == "" {
|
||||
link = "https://www.gstatic.com/generate_204"
|
||||
|
||||
@@ -5,7 +5,7 @@ package box
|
||||
import (
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/sagernet/sing-box/common/dialer/conntrack"
|
||||
"github.com/sagernet/sing-box/common/conntrack"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
)
|
||||
|
||||
@@ -28,7 +28,7 @@ func applyDebugOptions(options option.DebugOptions) {
|
||||
}
|
||||
if options.MemoryLimit != 0 {
|
||||
// debug.SetMemoryLimit(int64(options.MemoryLimit))
|
||||
conntrack.MemoryLimit = int64(options.MemoryLimit)
|
||||
conntrack.MemoryLimit = uint64(options.MemoryLimit)
|
||||
}
|
||||
if options.OOMKiller != nil {
|
||||
conntrack.KillerEnabled = *options.OOMKiller
|
||||
|
||||
@@ -5,7 +5,7 @@ package box
|
||||
import (
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/sagernet/sing-box/common/dialer/conntrack"
|
||||
"github.com/sagernet/sing-box/common/conntrack"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
)
|
||||
|
||||
@@ -27,8 +27,8 @@ func applyDebugOptions(options option.DebugOptions) {
|
||||
debug.SetTraceback(options.TraceBack)
|
||||
}
|
||||
if options.MemoryLimit != 0 {
|
||||
debug.SetMemoryLimit(int64(options.MemoryLimit))
|
||||
conntrack.MemoryLimit = int64(options.MemoryLimit)
|
||||
debug.SetMemoryLimit(int64(float64(options.MemoryLimit) / 1.5))
|
||||
conntrack.MemoryLimit = uint64(options.MemoryLimit)
|
||||
}
|
||||
if options.OOMKiller != nil {
|
||||
conntrack.KillerEnabled = *options.OOMKiller
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/sagernet/sing-box/common/badjson"
|
||||
"github.com/sagernet/sing-box/common/humanize"
|
||||
"github.com/sagernet/sing-box/common/json"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
@@ -37,9 +37,9 @@ func applyDebugListenOption(options option.DebugOptions) {
|
||||
runtime.ReadMemStats(&memStats)
|
||||
|
||||
var memObject badjson.JSONObject
|
||||
memObject.Put("heap", humanize.IBytes(memStats.HeapInuse))
|
||||
memObject.Put("stack", humanize.IBytes(memStats.StackInuse))
|
||||
memObject.Put("idle", humanize.IBytes(memStats.HeapIdle-memStats.HeapReleased))
|
||||
memObject.Put("heap", humanize.MemoryBytes(memStats.HeapInuse))
|
||||
memObject.Put("stack", humanize.MemoryBytes(memStats.StackInuse))
|
||||
memObject.Put("idle", humanize.MemoryBytes(memStats.HeapIdle-memStats.HeapReleased))
|
||||
memObject.Put("goroutines", runtime.NumGoroutine())
|
||||
memObject.Put("rss", rusageMaxRSS())
|
||||
|
||||
|
||||
@@ -1,3 +1,69 @@
|
||||
#### 1.4.1
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.4.0
|
||||
|
||||
* Fix bugs and update dependencies
|
||||
|
||||
Important changes since 1.3:
|
||||
|
||||
* Add TUIC support **1**
|
||||
* Add `udp_over_stream` option for TUIC client **2**
|
||||
* Add MultiPath TCP support **3**
|
||||
* Add `include_interface` and `exclude_interface` options for tun inbound
|
||||
* Pause recurring tasks when no network or device idle
|
||||
* Improve Android and Apple platform clients
|
||||
|
||||
*1*:
|
||||
|
||||
See [TUIC inbound](/configuration/inbound/tuic)
|
||||
and [TUIC outbound](/configuration/outbound/tuic)
|
||||
|
||||
**2**:
|
||||
|
||||
This is the TUIC port of the [UDP over TCP protocol](/configuration/shared/udp-over-tcp), designed to provide a QUIC
|
||||
stream based UDP relay mode that TUIC does not provide. Since it is an add-on protocol, you will need to use sing-box or
|
||||
another program compatible with the protocol as a server.
|
||||
|
||||
This mode has no positive effect in a proper UDP proxy scenario and should only be applied to relay streaming UDP
|
||||
traffic (basically QUIC streams).
|
||||
|
||||
*3*:
|
||||
|
||||
Requires sing-box to be compiled with Go 1.21.
|
||||
|
||||
#### 1.4.0-rc.3
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.4.0-rc.2
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.4.0-rc.1
|
||||
|
||||
* Fix TUIC UDP
|
||||
|
||||
#### 1.4.0-beta.6
|
||||
|
||||
* Add `udp_over_stream` option for TUIC client **1**
|
||||
* Add `include_interface` and `exclude_interface` options for tun inbound
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
This is the TUIC port of the [UDP over TCP protocol](/configuration/shared/udp-over-tcp), designed to provide a QUIC
|
||||
stream based UDP relay mode that TUIC does not provide. Since it is an add-on protocol, you will need to use sing-box or
|
||||
another program compatible with the protocol as a server.
|
||||
|
||||
This mode has no positive effect in a proper UDP proxy scenario and should only be applied to relay streaming UDP
|
||||
traffic (basically QUIC streams).
|
||||
|
||||
#### 1.4.0-beta.5
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.4.0-beta.4
|
||||
|
||||
* Graphical clients: Persistence group expansion state
|
||||
@@ -41,13 +107,16 @@ and [TUIC outbound](/configuration/outbound/tuic)
|
||||
|
||||
**1**:
|
||||
|
||||
Due to the requirement of tvOS 17, the app cannot be submitted to the App Store for the time being, and can only be downloaded through TestFlight.
|
||||
Due to the requirement of tvOS 17, the app cannot be submitted to the App Store for the time being, and can only be
|
||||
downloaded through TestFlight.
|
||||
|
||||
#### 1.3.4
|
||||
|
||||
* Fixes and improvements
|
||||
* We're now on the [App Store](https://apps.apple.com/us/app/sing-box/id6451272673), always free! It should be noted that due to stricter and slower review, the release of Store versions will be delayed.
|
||||
* We've made a standalone version of the macOS client (the original Application Extension relies on App Store distribution), which you can download as SFM-version-universal.zip in the release artifacts.
|
||||
* We're now on the [App Store](https://apps.apple.com/us/app/sing-box/id6451272673), always free! It should be noted
|
||||
that due to stricter and slower review, the release of Store versions will be delayed.
|
||||
* We've made a standalone version of the macOS client (the original Application Extension relies on App Store
|
||||
distribution), which you can download as SFM-version-universal.zip in the release artifacts.
|
||||
|
||||
#### 1.3.3
|
||||
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
"external_ui_download_detour": "",
|
||||
"secret": "",
|
||||
"default_mode": "",
|
||||
"store_mode": false,
|
||||
"store_selected": false,
|
||||
"store_fakeip": false,
|
||||
"cache_file": "",
|
||||
"cache_id": ""
|
||||
},
|
||||
@@ -80,6 +82,10 @@ Default mode in clash, `rule` will be used if empty.
|
||||
|
||||
This setting has no direct effect, but can be used in routing and DNS rules via the `clash_mode` rule item.
|
||||
|
||||
#### store_mode
|
||||
|
||||
Store Clash mode in cache file.
|
||||
|
||||
#### store_selected
|
||||
|
||||
!!! note ""
|
||||
@@ -88,6 +94,10 @@ This setting has no direct effect, but can be used in routing and DNS rules via
|
||||
|
||||
Store selected outbound for the `Selector` outbound in cache file.
|
||||
|
||||
#### store_fakeip
|
||||
|
||||
Store fakeip in cache file.
|
||||
|
||||
#### cache_file
|
||||
|
||||
Cache file path, `cache.db` will be used if empty.
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
"external_ui_download_detour": "",
|
||||
"secret": "",
|
||||
"default_mode": "",
|
||||
"store_mode": false,
|
||||
"store_selected": false,
|
||||
"store_fakeip": false,
|
||||
"cache_file": "",
|
||||
"cache_id": ""
|
||||
},
|
||||
@@ -78,6 +80,10 @@ Clash 中的默认模式,默认使用 `rule`。
|
||||
|
||||
此设置没有直接影响,但可以通过 `clash_mode` 规则项在路由和 DNS 规则中使用。
|
||||
|
||||
#### store_mode
|
||||
|
||||
将 Clash 模式存储在缓存文件中。
|
||||
|
||||
#### store_selected
|
||||
|
||||
!!! note ""
|
||||
@@ -86,6 +92,10 @@ Clash 中的默认模式,默认使用 `rule`。
|
||||
|
||||
将 `Selector` 中出站的选定的目标出站存储在缓存文件中。
|
||||
|
||||
#### store_fakeip
|
||||
|
||||
将 fakeip 存储在缓存文件中。
|
||||
|
||||
#### cache_file
|
||||
|
||||
缓存文件路径,默认使用`cache.db`。
|
||||
|
||||
@@ -24,6 +24,12 @@
|
||||
],
|
||||
"endpoint_independent_nat": false,
|
||||
"stack": "system",
|
||||
"include_interface": [
|
||||
"lan0"
|
||||
],
|
||||
"exclude_interface": [
|
||||
"lan1"
|
||||
],
|
||||
"include_uid": [
|
||||
0
|
||||
],
|
||||
@@ -153,6 +159,22 @@ TCP/IP stack.
|
||||
|
||||
gVisor and LWIP stacks is not included by default, see [Installation](/#installation).
|
||||
|
||||
#### include_interface
|
||||
|
||||
!!! error ""
|
||||
|
||||
Interface rules are only supported on Linux and require auto_route.
|
||||
|
||||
Limit interfaces in route. Not limited by default.
|
||||
|
||||
Conflict with `exclude_interface`.
|
||||
|
||||
#### exclude_interface
|
||||
|
||||
Exclude interfaces in route.
|
||||
|
||||
Conflict with `include_interface`.
|
||||
|
||||
#### include_uid
|
||||
|
||||
!!! error ""
|
||||
|
||||
@@ -24,6 +24,12 @@
|
||||
],
|
||||
"endpoint_independent_nat": false,
|
||||
"stack": "system",
|
||||
"include_interface": [
|
||||
"lan0"
|
||||
],
|
||||
"exclude_interface": [
|
||||
"lan1"
|
||||
],
|
||||
"include_uid": [
|
||||
0
|
||||
],
|
||||
@@ -149,6 +155,22 @@ TCP/IP 栈。
|
||||
|
||||
默认安装不包含 gVisor 和 LWIP 栈,请参阅 [安装](/zh/#_2)。
|
||||
|
||||
#### include_interface
|
||||
|
||||
!!! error ""
|
||||
|
||||
接口规则仅在 Linux 下被支持,并且需要 `auto_route`。
|
||||
|
||||
限制被路由的接口。默认不限制。
|
||||
|
||||
与 `exclude_interface` 冲突。
|
||||
|
||||
#### exclude_interface
|
||||
|
||||
排除路由的接口。
|
||||
|
||||
与 `include_interface` 冲突。
|
||||
|
||||
#### include_uid
|
||||
|
||||
!!! error ""
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"password": "hello",
|
||||
"congestion_control": "cubic",
|
||||
"udp_relay_mode": "native",
|
||||
"udp_over_stream": false,
|
||||
"zero_rtt_handshake": false,
|
||||
"heartbeat": "10s",
|
||||
"network": "tcp",
|
||||
@@ -67,6 +68,19 @@ UDP packet relay mode
|
||||
|
||||
`native` is used by default.
|
||||
|
||||
Conflict with `udp_over_stream`.
|
||||
|
||||
#### udp_over_stream
|
||||
|
||||
This is the TUIC port of the [UDP over TCP protocol](/configuration/shared/udp-over-tcp), designed to provide a QUIC
|
||||
stream based UDP relay mode that TUIC does not provide. Since it is an add-on protocol, you will need to use sing-box or
|
||||
another program compatible with the protocol as a server.
|
||||
|
||||
This mode has no positive effect in a proper UDP proxy scenario and should only be applied to relay streaming UDP
|
||||
traffic (basically QUIC streams).
|
||||
|
||||
Conflict with `udp_relay_mode`.
|
||||
|
||||
#### network
|
||||
|
||||
Enabled network
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"password": "hello",
|
||||
"congestion_control": "cubic",
|
||||
"udp_relay_mode": "native",
|
||||
"udp_over_stream": false,
|
||||
"zero_rtt_handshake": false,
|
||||
"heartbeat": "10s",
|
||||
"network": "tcp",
|
||||
@@ -65,6 +66,15 @@ UDP 包中继模式
|
||||
| native | 原生 UDP |
|
||||
| quic | 使用 QUIC 流的无损 UDP 中继,引入了额外的开销 |
|
||||
|
||||
与 `udp_over_stream` 冲突。
|
||||
|
||||
#### udp_over_stream
|
||||
|
||||
这是 TUIC 的 [UDP over TCP 协议](/configuration/shared/udp-over-tcp) 移植, 旨在提供 TUIC 不提供的 基于 QUIC 流的 UDP 中继模式。 由于它是一个附加协议,因此您需要使用 sing-box 或其他兼容的程序作为服务器。
|
||||
|
||||
此模式在正确的 UDP 代理场景中没有任何积极作用,仅适用于中继流式 UDP 流量(基本上是 QUIC 流)。
|
||||
|
||||
与 `udp_relay_mode` 冲突。
|
||||
|
||||
#### zero_rtt_handshake
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|------------|-------------------------|
|
||||
| `geoip` | [GeoIP](./geoip) |
|
||||
| `geosite` | [GeoSite](./geosite) |
|
||||
| `ip_rules` | 一组 [IP 路由规则](./ip-rule) |
|
||||
| `rules` | 一组 [路由规则](./rule) |
|
||||
|
||||
#### final
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
### Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"route": {
|
||||
"ip_rules": [
|
||||
{
|
||||
"inbound": [
|
||||
"mixed-in"
|
||||
],
|
||||
"ip_version": 6,
|
||||
"network": [
|
||||
"tcp"
|
||||
],
|
||||
"domain": [
|
||||
"test.com"
|
||||
],
|
||||
"domain_suffix": [
|
||||
".cn"
|
||||
],
|
||||
"domain_keyword": [
|
||||
"test"
|
||||
],
|
||||
"domain_regex": [
|
||||
"^stun\\..+"
|
||||
],
|
||||
"geosite": [
|
||||
"cn"
|
||||
],
|
||||
"source_geoip": [
|
||||
"private"
|
||||
],
|
||||
"geoip": [
|
||||
"cn"
|
||||
],
|
||||
"source_ip_cidr": [
|
||||
"10.0.0.0/24",
|
||||
"192.168.0.1"
|
||||
],
|
||||
"ip_cidr": [
|
||||
"10.0.0.0/24",
|
||||
"192.168.0.1"
|
||||
],
|
||||
"source_port": [
|
||||
12345
|
||||
],
|
||||
"source_port_range": [
|
||||
"1000:2000",
|
||||
":3000",
|
||||
"4000:"
|
||||
],
|
||||
"port": [
|
||||
80,
|
||||
443
|
||||
],
|
||||
"port_range": [
|
||||
"1000:2000",
|
||||
":3000",
|
||||
"4000:"
|
||||
],
|
||||
"invert": false,
|
||||
"action": "direct",
|
||||
"outbound": "wireguard"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "and",
|
||||
"rules": [],
|
||||
"invert": false,
|
||||
"action": "direct",
|
||||
"outbound": "wireguard"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
!!! note ""
|
||||
|
||||
You can ignore the JSON Array [] tag when the content is only one item
|
||||
|
||||
### Default Fields
|
||||
|
||||
!!! note ""
|
||||
|
||||
The default rule uses the following matching logic:
|
||||
(`domain` || `domain_suffix` || `domain_keyword` || `domain_regex` || `geosite` || `geoip` || `ip_cidr`) &&
|
||||
(`port` || `port_range`) &&
|
||||
(`source_geoip` || `source_ip_cidr`) &&
|
||||
(`source_port` || `source_port_range`) &&
|
||||
`other fields`
|
||||
|
||||
#### inbound
|
||||
|
||||
Tags of [Inbound](/configuration/inbound).
|
||||
|
||||
#### ip_version
|
||||
|
||||
4 or 6.
|
||||
|
||||
Not limited if empty.
|
||||
|
||||
#### network
|
||||
|
||||
Match network protocol.
|
||||
|
||||
Available values:
|
||||
|
||||
* `tcp`
|
||||
* `udp`
|
||||
* `icmpv4`
|
||||
* `icmpv6`
|
||||
|
||||
#### domain
|
||||
|
||||
Match full domain.
|
||||
|
||||
#### domain_suffix
|
||||
|
||||
Match domain suffix.
|
||||
|
||||
#### domain_keyword
|
||||
|
||||
Match domain using keyword.
|
||||
|
||||
#### domain_regex
|
||||
|
||||
Match domain using regular expression.
|
||||
|
||||
#### geosite
|
||||
|
||||
Match geosite.
|
||||
|
||||
#### source_geoip
|
||||
|
||||
Match source geoip.
|
||||
|
||||
#### geoip
|
||||
|
||||
Match geoip.
|
||||
|
||||
#### source_ip_cidr
|
||||
|
||||
Match source ip cidr.
|
||||
|
||||
#### ip_cidr
|
||||
|
||||
Match ip cidr.
|
||||
|
||||
#### source_port
|
||||
|
||||
Match source port.
|
||||
|
||||
#### source_port_range
|
||||
|
||||
Match source port range.
|
||||
|
||||
#### port
|
||||
|
||||
Match port.
|
||||
|
||||
#### port_range
|
||||
|
||||
Match port range.
|
||||
|
||||
#### invert
|
||||
|
||||
Invert match result.
|
||||
|
||||
#### action
|
||||
|
||||
==Required==
|
||||
|
||||
| Action | Description |
|
||||
|--------|--------------------------------------------------------------------|
|
||||
| return | Stop IP routing and assemble the connection to the transport layer |
|
||||
| block | Block the connection |
|
||||
| direct | Directly forward the connection |
|
||||
|
||||
#### outbound
|
||||
|
||||
==Required if action is direct==
|
||||
|
||||
Tag of the target outbound.
|
||||
|
||||
Only outbound which supports IP connection can be used, see [Outbounds that support IP connection](/configuration/outbound/#outbounds-that-support-ip-connection).
|
||||
|
||||
### Logical Fields
|
||||
|
||||
#### type
|
||||
|
||||
`logical`
|
||||
|
||||
#### mode
|
||||
|
||||
==Required==
|
||||
|
||||
`and` or `or`
|
||||
|
||||
#### rules
|
||||
|
||||
==Required==
|
||||
|
||||
Included default rules.
|
||||
@@ -1,204 +0,0 @@
|
||||
### 结构
|
||||
|
||||
```json
|
||||
{
|
||||
"route": {
|
||||
"ip_rules": [
|
||||
{
|
||||
"inbound": [
|
||||
"mixed-in"
|
||||
],
|
||||
"ip_version": 6,
|
||||
"network": [
|
||||
"tcp"
|
||||
],
|
||||
"domain": [
|
||||
"test.com"
|
||||
],
|
||||
"domain_suffix": [
|
||||
".cn"
|
||||
],
|
||||
"domain_keyword": [
|
||||
"test"
|
||||
],
|
||||
"domain_regex": [
|
||||
"^stun\\..+"
|
||||
],
|
||||
"geosite": [
|
||||
"cn"
|
||||
],
|
||||
"source_geoip": [
|
||||
"private"
|
||||
],
|
||||
"geoip": [
|
||||
"cn"
|
||||
],
|
||||
"source_ip_cidr": [
|
||||
"10.0.0.0/24",
|
||||
"192.168.0.1"
|
||||
],
|
||||
"ip_cidr": [
|
||||
"10.0.0.0/24",
|
||||
"192.168.0.1"
|
||||
],
|
||||
"source_port": [
|
||||
12345
|
||||
],
|
||||
"source_port_range": [
|
||||
"1000:2000",
|
||||
":3000",
|
||||
"4000:"
|
||||
],
|
||||
"port": [
|
||||
80,
|
||||
443
|
||||
],
|
||||
"port_range": [
|
||||
"1000:2000",
|
||||
":3000",
|
||||
"4000:"
|
||||
],
|
||||
"invert": false,
|
||||
"action": "direct",
|
||||
"outbound": "wireguard"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "and",
|
||||
"rules": [],
|
||||
"invert": false,
|
||||
"action": "direct",
|
||||
"outbound": "wireguard"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
!!! note ""
|
||||
|
||||
当内容只有一项时,可以忽略 JSON 数组 [] 标签。
|
||||
|
||||
### Default Fields
|
||||
|
||||
!!! note ""
|
||||
|
||||
默认规则使用以下匹配逻辑:
|
||||
(`domain` || `domain_suffix` || `domain_keyword` || `domain_regex` || `geosite` || `geoip` || `ip_cidr`) &&
|
||||
(`port` || `port_range`) &&
|
||||
(`source_geoip` || `source_ip_cidr`) &&
|
||||
(`source_port` || `source_port_range`) &&
|
||||
`other fields`
|
||||
|
||||
#### inbound
|
||||
|
||||
[入站](/zh/configuration/inbound) 标签。
|
||||
|
||||
#### ip_version
|
||||
|
||||
4 或 6。
|
||||
|
||||
默认不限制。
|
||||
|
||||
#### network
|
||||
|
||||
匹配网络协议。
|
||||
|
||||
可用值:
|
||||
|
||||
* `tcp`
|
||||
* `udp`
|
||||
* `icmpv4`
|
||||
* `icmpv6`
|
||||
|
||||
#### domain
|
||||
|
||||
匹配完整域名。
|
||||
|
||||
#### domain_suffix
|
||||
|
||||
匹配域名后缀。
|
||||
|
||||
#### domain_keyword
|
||||
|
||||
匹配域名关键字。
|
||||
|
||||
#### domain_regex
|
||||
|
||||
匹配域名正则表达式。
|
||||
|
||||
#### geosite
|
||||
|
||||
匹配 GeoSite。
|
||||
|
||||
#### source_geoip
|
||||
|
||||
匹配源 GeoIP。
|
||||
|
||||
#### geoip
|
||||
|
||||
匹配 GeoIP。
|
||||
|
||||
#### source_ip_cidr
|
||||
|
||||
匹配源 IP CIDR。
|
||||
|
||||
#### ip_cidr
|
||||
|
||||
匹配 IP CIDR。
|
||||
|
||||
#### source_port
|
||||
|
||||
匹配源端口。
|
||||
|
||||
#### source_port_range
|
||||
|
||||
匹配源端口范围。
|
||||
|
||||
#### port
|
||||
|
||||
匹配端口。
|
||||
|
||||
#### port_range
|
||||
|
||||
匹配端口范围。
|
||||
|
||||
#### invert
|
||||
|
||||
反选匹配结果。
|
||||
|
||||
#### action
|
||||
|
||||
==必填==
|
||||
|
||||
| Action | 描述 |
|
||||
|--------|---------------------|
|
||||
| return | 停止 IP 路由并将该连接组装到传输层 |
|
||||
| block | 屏蔽该连接 |
|
||||
| direct | 直接转发该连接 |
|
||||
|
||||
|
||||
#### outbound
|
||||
|
||||
==action 为 direct 则必填==
|
||||
|
||||
目标出站的标签。
|
||||
|
||||
### 逻辑字段
|
||||
|
||||
#### type
|
||||
|
||||
`logical`
|
||||
|
||||
#### mode
|
||||
|
||||
==必填==
|
||||
|
||||
`and` 或 `or`
|
||||
|
||||
#### rules
|
||||
|
||||
==必填==
|
||||
|
||||
包括的默认规则。
|
||||
@@ -8,5 +8,4 @@ Configuration examples for sing-box.
|
||||
* [Shadowsocks](./shadowsocks)
|
||||
* [ShadowTLS](./shadowtls)
|
||||
* [Clash API](./clash-api)
|
||||
* [WireGuard Direct](./wireguard-direct)
|
||||
* [FakeIP](./fakeip)
|
||||
|
||||
@@ -8,5 +8,4 @@ sing-box 的配置示例。
|
||||
* [Shadowsocks](./shadowsocks)
|
||||
* [ShadowTLS](./shadowtls)
|
||||
* [Clash API](./clash-api)
|
||||
* [WireGuard Direct](./wireguard-direct)
|
||||
* [FakeIP](./fakeip)
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
# WireGuard Direct
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"tag": "google",
|
||||
"address": "tls://8.8.8.8"
|
||||
},
|
||||
{
|
||||
"tag": "local",
|
||||
"address": "223.5.5.5",
|
||||
"detour": "direct"
|
||||
}
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"geoip": "cn",
|
||||
"server": "direct"
|
||||
}
|
||||
],
|
||||
"reverse_mapping": true
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "tun",
|
||||
"tag": "tun",
|
||||
"inet4_address": "172.19.0.1/30",
|
||||
"auto_route": true,
|
||||
"sniff": true,
|
||||
"stack": "system"
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "wireguard",
|
||||
"tag": "wg",
|
||||
"server": "127.0.0.1",
|
||||
"server_port": 2345,
|
||||
"local_address": [
|
||||
"172.19.0.1/128"
|
||||
],
|
||||
"private_key": "KLTnpPY03pig/WC3zR8U7VWmpANHPFh2/4pwICGJ5Fk=",
|
||||
"peer_public_key": "uvNabcamf6Rs0vzmcw99jsjTJbxo6eWGOykSY66zsUk="
|
||||
},
|
||||
{
|
||||
"type": "dns",
|
||||
"tag": "dns"
|
||||
},
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "block",
|
||||
"tag": "block"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"ip_rules": [
|
||||
{
|
||||
"port": 53,
|
||||
"action": "return"
|
||||
},
|
||||
{
|
||||
"geoip": "cn",
|
||||
"geosite": "cn",
|
||||
"action": "return"
|
||||
},
|
||||
{
|
||||
"action": "direct",
|
||||
"outbound": "wg"
|
||||
}
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"protocol": "dns",
|
||||
"outbound": "dns"
|
||||
},
|
||||
{
|
||||
"geoip": "cn",
|
||||
"geosite": "cn",
|
||||
"outbound": "direct"
|
||||
}
|
||||
],
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -9,7 +9,7 @@ Experimental Android client for sing-box.
|
||||
#### Download
|
||||
|
||||
* [AppCenter](https://install.appcenter.ms/users/nekohasekai/apps/sfa/distribution_groups/publictest)
|
||||
* [Github Releases](https://SagerNet/sing-box/releases)
|
||||
* [Github Releases](https://github.com/SagerNet/sing-box/releases)
|
||||
|
||||
#### Note
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#### 下载
|
||||
|
||||
* [AppCenter](https://install.appcenter.ms/users/nekohasekai/apps/sfa/distribution_groups/publictest)
|
||||
* [Github Releases](https://SagerNet/sing-box/releases)
|
||||
* [Github Releases](https://github.com/SagerNet/sing-box/releases)
|
||||
|
||||
#### 注意事项
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
)
|
||||
|
||||
type ClashServerConstructor = func(ctx context.Context, router adapter.Router, logFactory log.ObservableFactory, options option.ClashAPIOptions) (adapter.ClashServer, error)
|
||||
@@ -23,3 +24,28 @@ func NewClashServer(ctx context.Context, router adapter.Router, logFactory log.O
|
||||
}
|
||||
return clashServerConstructor(ctx, router, logFactory, options)
|
||||
}
|
||||
|
||||
func CalculateClashModeList(options option.Options) []string {
|
||||
var clashMode []string
|
||||
for _, dnsRule := range common.PtrValueOrDefault(options.DNS).Rules {
|
||||
if dnsRule.DefaultOptions.ClashMode != "" && !common.Contains(clashMode, dnsRule.DefaultOptions.ClashMode) {
|
||||
clashMode = append(clashMode, dnsRule.DefaultOptions.ClashMode)
|
||||
}
|
||||
for _, defaultRule := range dnsRule.LogicalOptions.Rules {
|
||||
if defaultRule.ClashMode != "" && !common.Contains(clashMode, defaultRule.ClashMode) {
|
||||
clashMode = append(clashMode, defaultRule.ClashMode)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, rule := range common.PtrValueOrDefault(options.Route).Rules {
|
||||
if rule.DefaultOptions.ClashMode != "" && !common.Contains(clashMode, rule.DefaultOptions.ClashMode) {
|
||||
clashMode = append(clashMode, rule.DefaultOptions.ClashMode)
|
||||
}
|
||||
for _, defaultRule := range rule.LogicalOptions.Rules {
|
||||
if defaultRule.ClashMode != "" && !common.Contains(clashMode, defaultRule.ClashMode) {
|
||||
clashMode = append(clashMode, defaultRule.ClashMode)
|
||||
}
|
||||
}
|
||||
}
|
||||
return clashMode
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing/common"
|
||||
|
||||
"go.etcd.io/bbolt"
|
||||
)
|
||||
@@ -15,6 +16,15 @@ import (
|
||||
var (
|
||||
bucketSelected = []byte("selected")
|
||||
bucketExpand = []byte("group_expand")
|
||||
bucketMode = []byte("clash_mode")
|
||||
|
||||
bucketNameList = []string{
|
||||
string(bucketSelected),
|
||||
string(bucketExpand),
|
||||
string(bucketMode),
|
||||
}
|
||||
|
||||
cacheIDDefault = []byte("default")
|
||||
)
|
||||
|
||||
var _ adapter.ClashCacheFile = (*CacheFile)(nil)
|
||||
@@ -52,14 +62,14 @@ func Open(path string, cacheID string) (*CacheFile, error) {
|
||||
if name[0] == 0 {
|
||||
return b.ForEachBucket(func(k []byte) error {
|
||||
bucketName := string(k)
|
||||
if !(bucketName == string(bucketSelected) || bucketName == string(bucketExpand)) {
|
||||
if !(common.Contains(bucketNameList, bucketName)) {
|
||||
_ = b.DeleteBucket(name)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
} else {
|
||||
bucketName := string(name)
|
||||
if !(bucketName == string(bucketSelected) || bucketName == string(bucketExpand) || strings.HasPrefix(bucketName, fakeipBucketPrefix)) {
|
||||
if !(common.Contains(bucketNameList, bucketName) || strings.HasPrefix(bucketName, fakeipBucketPrefix)) {
|
||||
_ = tx.DeleteBucket(name)
|
||||
}
|
||||
}
|
||||
@@ -78,6 +88,39 @@ func Open(path string, cacheID string) (*CacheFile, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *CacheFile) LoadMode() string {
|
||||
var mode string
|
||||
c.DB.View(func(t *bbolt.Tx) error {
|
||||
bucket := t.Bucket(bucketMode)
|
||||
if bucket == nil {
|
||||
return nil
|
||||
}
|
||||
var modeBytes []byte
|
||||
if len(c.cacheID) > 0 {
|
||||
modeBytes = bucket.Get(c.cacheID)
|
||||
} else {
|
||||
modeBytes = bucket.Get(cacheIDDefault)
|
||||
}
|
||||
mode = string(modeBytes)
|
||||
return nil
|
||||
})
|
||||
return mode
|
||||
}
|
||||
|
||||
func (c *CacheFile) StoreMode(mode string) error {
|
||||
return c.DB.Batch(func(t *bbolt.Tx) error {
|
||||
bucket, err := t.CreateBucketIfNotExists(bucketMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(c.cacheID) > 0 {
|
||||
return bucket.Put(c.cacheID, []byte(mode))
|
||||
} else {
|
||||
return bucket.Put(cacheIDDefault, []byte(mode))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CacheFile) bucket(t *bbolt.Tx, key []byte) *bbolt.Bucket {
|
||||
if c.cacheID == nil {
|
||||
return t.Bucket(key)
|
||||
|
||||
@@ -2,7 +2,6 @@ package clashapi
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/log"
|
||||
|
||||
@@ -10,11 +9,11 @@ import (
|
||||
"github.com/go-chi/render"
|
||||
)
|
||||
|
||||
func configRouter(server *Server, logFactory log.Factory, logger log.Logger) http.Handler {
|
||||
func configRouter(server *Server, logFactory log.Factory) http.Handler {
|
||||
r := chi.NewRouter()
|
||||
r.Get("/", getConfigs(server, logFactory))
|
||||
r.Put("/", updateConfigs)
|
||||
r.Patch("/", patchConfigs(server, logger))
|
||||
r.Patch("/", patchConfigs(server))
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -48,7 +47,7 @@ func getConfigs(server *Server, logFactory log.Factory) func(w http.ResponseWrit
|
||||
}
|
||||
}
|
||||
|
||||
func patchConfigs(server *Server, logger log.Logger) func(w http.ResponseWriter, r *http.Request) {
|
||||
func patchConfigs(server *Server) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var newConfig configSchema
|
||||
err := render.DecodeJSON(r.Body, &newConfig)
|
||||
@@ -58,11 +57,7 @@ func patchConfigs(server *Server, logger log.Logger) func(w http.ResponseWriter,
|
||||
return
|
||||
}
|
||||
if newConfig.Mode != "" {
|
||||
mode := strings.ToLower(newConfig.Mode)
|
||||
if server.mode != mode {
|
||||
server.mode = mode
|
||||
logger.Info("updated mode: ", mode)
|
||||
}
|
||||
server.SetMode(newConfig.Mode)
|
||||
}
|
||||
render.NoContent(w, r)
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@ type Server struct {
|
||||
trafficManager *trafficontrol.Manager
|
||||
urlTestHistory *urltest.HistoryStorage
|
||||
mode string
|
||||
modeList []string
|
||||
modeUpdateHook chan<- struct{}
|
||||
storeMode bool
|
||||
storeSelected bool
|
||||
storeFakeIP bool
|
||||
cacheFilePath string
|
||||
@@ -70,9 +73,10 @@ func NewServer(ctx context.Context, router adapter.Router, logFactory log.Observ
|
||||
Handler: chiRouter,
|
||||
},
|
||||
trafficManager: trafficManager,
|
||||
mode: strings.ToLower(options.DefaultMode),
|
||||
storeSelected: options.StoreSelected,
|
||||
modeList: options.ModeList,
|
||||
externalController: options.ExternalController != "",
|
||||
storeMode: options.StoreMode,
|
||||
storeSelected: options.StoreSelected,
|
||||
storeFakeIP: options.StoreFakeIP,
|
||||
externalUIDownloadURL: options.ExternalUIDownloadURL,
|
||||
externalUIDownloadDetour: options.ExternalUIDownloadDetour,
|
||||
@@ -81,10 +85,15 @@ func NewServer(ctx context.Context, router adapter.Router, logFactory log.Observ
|
||||
if server.urlTestHistory == nil {
|
||||
server.urlTestHistory = urltest.NewHistoryStorage()
|
||||
}
|
||||
if server.mode == "" {
|
||||
server.mode = "rule"
|
||||
defaultMode := "Rule"
|
||||
if options.DefaultMode != "" {
|
||||
defaultMode = options.DefaultMode
|
||||
}
|
||||
if options.StoreSelected || options.StoreFakeIP {
|
||||
if !common.Contains(server.modeList, defaultMode) {
|
||||
server.modeList = append([]string{defaultMode}, server.modeList...)
|
||||
}
|
||||
server.mode = defaultMode
|
||||
if options.StoreMode || options.StoreSelected || options.StoreFakeIP || options.ExternalController == "" {
|
||||
cachePath := os.ExpandEnv(options.CacheFile)
|
||||
if cachePath == "" {
|
||||
cachePath = "cache.db"
|
||||
@@ -110,7 +119,7 @@ func NewServer(ctx context.Context, router adapter.Router, logFactory log.Observ
|
||||
r.Get("/logs", getLogs(logFactory))
|
||||
r.Get("/traffic", traffic(trafficManager))
|
||||
r.Get("/version", version)
|
||||
r.Mount("/configs", configRouter(server, logFactory, server.logger))
|
||||
r.Mount("/configs", configRouter(server, logFactory))
|
||||
r.Mount("/proxies", proxyRouter(server, router))
|
||||
r.Mount("/rules", ruleRouter(router))
|
||||
r.Mount("/connections", connectionRouter(router, trafficManager))
|
||||
@@ -143,6 +152,14 @@ func (s *Server) PreStart() error {
|
||||
return E.Cause(err, "open cache file")
|
||||
}
|
||||
s.cacheFile = cacheFile
|
||||
if s.storeMode {
|
||||
mode := s.cacheFile.LoadMode()
|
||||
if common.Any(s.modeList, func(it string) bool {
|
||||
return strings.EqualFold(it, mode)
|
||||
}) {
|
||||
s.mode = mode
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -170,6 +187,7 @@ func (s *Server) Close() error {
|
||||
common.PtrOrNil(s.httpServer),
|
||||
s.trafficManager,
|
||||
s.cacheFile,
|
||||
s.urlTestHistory,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -177,6 +195,43 @@ func (s *Server) Mode() string {
|
||||
return s.mode
|
||||
}
|
||||
|
||||
func (s *Server) ModeList() []string {
|
||||
return s.modeList
|
||||
}
|
||||
|
||||
func (s *Server) SetModeUpdateHook(hook chan<- struct{}) {
|
||||
s.modeUpdateHook = hook
|
||||
}
|
||||
|
||||
func (s *Server) SetMode(newMode string) {
|
||||
if !common.Contains(s.modeList, newMode) {
|
||||
newMode = common.Find(s.modeList, func(it string) bool {
|
||||
return strings.EqualFold(it, newMode)
|
||||
})
|
||||
}
|
||||
if !common.Contains(s.modeList, newMode) {
|
||||
return
|
||||
}
|
||||
if newMode == s.mode {
|
||||
return
|
||||
}
|
||||
s.mode = newMode
|
||||
if s.modeUpdateHook != nil {
|
||||
select {
|
||||
case s.modeUpdateHook <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
s.router.ClearDNSCache()
|
||||
if s.storeMode {
|
||||
err := s.cacheFile.StoreMode(newMode)
|
||||
if err != nil {
|
||||
s.logger.Error(E.Cause(err, "save mode"))
|
||||
}
|
||||
}
|
||||
s.logger.Info("updated mode: ", newMode)
|
||||
}
|
||||
|
||||
func (s *Server) StoreSelected() bool {
|
||||
return s.storeSelected
|
||||
}
|
||||
|
||||
@@ -9,4 +9,8 @@ const (
|
||||
CommandSelectOutbound
|
||||
CommandURLTest
|
||||
CommandGroupExpand
|
||||
CommandClashMode
|
||||
CommandSetClashMode
|
||||
CommandGetSystemProxyStatus
|
||||
CommandSetSystemProxyEnabled
|
||||
)
|
||||
|
||||
135
experimental/libbox/command_clash_mode.go
Normal file
135
experimental/libbox/command_clash_mode.go
Normal file
@@ -0,0 +1,135 @@
|
||||
package libbox
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/experimental/clashapi"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/rw"
|
||||
)
|
||||
|
||||
func (c *CommandClient) SetClashMode(newMode string) error {
|
||||
conn, err := c.directConnect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
err = binary.Write(conn, binary.BigEndian, uint8(CommandSetClashMode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = rw.WriteVString(conn, newMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return readError(conn)
|
||||
}
|
||||
|
||||
func (s *CommandServer) handleSetClashMode(conn net.Conn) error {
|
||||
defer conn.Close()
|
||||
newMode, err := rw.ReadVString(conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
service := s.service
|
||||
if service == nil {
|
||||
return writeError(conn, E.New("service not ready"))
|
||||
}
|
||||
clashServer := service.instance.Router().ClashServer()
|
||||
if clashServer == nil {
|
||||
return writeError(conn, E.New("Clash API disabled"))
|
||||
}
|
||||
clashServer.(*clashapi.Server).SetMode(newMode)
|
||||
return writeError(conn, nil)
|
||||
}
|
||||
|
||||
func (c *CommandClient) handleModeConn(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
for {
|
||||
newMode, err := rw.ReadVString(conn)
|
||||
if err != nil {
|
||||
c.handler.Disconnected(err.Error())
|
||||
return
|
||||
}
|
||||
c.handler.UpdateClashMode(newMode)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CommandServer) handleModeConn(conn net.Conn) error {
|
||||
defer conn.Close()
|
||||
ctx := connKeepAlive(conn)
|
||||
for s.service == nil {
|
||||
select {
|
||||
case <-time.After(time.Second):
|
||||
continue
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
clashServer := s.service.instance.Router().ClashServer()
|
||||
if clashServer == nil {
|
||||
defer conn.Close()
|
||||
return binary.Write(conn, binary.BigEndian, uint16(0))
|
||||
}
|
||||
err := writeClashModeList(conn, clashServer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-s.modeUpdate:
|
||||
err = rw.WriteVString(conn, clashServer.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readClashModeList(reader io.Reader) (modeList []string, currentMode string, err error) {
|
||||
var modeListLength uint16
|
||||
err = binary.Read(reader, binary.BigEndian, &modeListLength)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if modeListLength == 0 {
|
||||
return
|
||||
}
|
||||
modeList = make([]string, modeListLength)
|
||||
for i := 0; i < int(modeListLength); i++ {
|
||||
modeList[i], err = rw.ReadVString(reader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
currentMode, err = rw.ReadVString(reader)
|
||||
return
|
||||
}
|
||||
|
||||
func writeClashModeList(writer io.Writer, clashServer adapter.ClashServer) error {
|
||||
modeList := clashServer.ModeList()
|
||||
err := binary.Write(writer, binary.BigEndian, uint16(len(modeList)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(modeList) > 0 {
|
||||
for _, mode := range modeList {
|
||||
err = rw.WriteVString(writer, mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = rw.WriteVString(writer, clashServer.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -3,7 +3,9 @@ package libbox
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
@@ -26,13 +28,15 @@ type CommandClientHandler interface {
|
||||
WriteLog(message string)
|
||||
WriteStatus(message *StatusMessage)
|
||||
WriteGroups(message OutboundGroupIterator)
|
||||
InitializeClashMode(modeList StringIterator, currentMode string)
|
||||
UpdateClashMode(newMode string)
|
||||
}
|
||||
|
||||
func NewStandaloneCommandClient() *CommandClient {
|
||||
return new(CommandClient)
|
||||
}
|
||||
|
||||
func NewCommandClient(sharedDirectory string, handler CommandClientHandler, options *CommandClientOptions) *CommandClient {
|
||||
func NewCommandClient(handler CommandClientHandler, options *CommandClientOptions) *CommandClient {
|
||||
return &CommandClient{
|
||||
handler: handler,
|
||||
options: common.PtrValueOrDefault(options),
|
||||
@@ -50,9 +54,24 @@ func (c *CommandClient) directConnect() (net.Conn, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CommandClient) directConnectWithRetry() (net.Conn, error) {
|
||||
var (
|
||||
conn net.Conn
|
||||
err error
|
||||
)
|
||||
for i := 0; i < 10; i++ {
|
||||
conn, err = c.directConnect()
|
||||
if err == nil {
|
||||
return conn, nil
|
||||
}
|
||||
time.Sleep(time.Duration(100+i*50) * time.Millisecond)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (c *CommandClient) Connect() error {
|
||||
common.Close(c.conn)
|
||||
conn, err := c.directConnect()
|
||||
conn, err := c.directConnectWithRetry()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -79,6 +98,23 @@ func (c *CommandClient) Connect() error {
|
||||
}
|
||||
c.handler.Connected()
|
||||
go c.handleGroupConn(conn)
|
||||
case CommandClashMode:
|
||||
var (
|
||||
modeList []string
|
||||
currentMode string
|
||||
)
|
||||
modeList, currentMode, err = readClashModeList(conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.handler.Connected()
|
||||
c.handler.InitializeClashMode(newIterator(modeList), currentMode)
|
||||
if len(modeList) == 0 {
|
||||
conn.Close()
|
||||
c.handler.Disconnected(os.ErrInvalid.Error())
|
||||
return nil
|
||||
}
|
||||
go c.handleModeConn(conn)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
runtimeDebug "runtime/debug"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/common/dialer/conntrack"
|
||||
"github.com/sagernet/sing-box/common/conntrack"
|
||||
)
|
||||
|
||||
func (c *CommandClient) CloseConnections() error {
|
||||
|
||||
@@ -19,7 +19,7 @@ type OutboundGroup struct {
|
||||
Type string
|
||||
Selectable bool
|
||||
Selected string
|
||||
isExpand int8
|
||||
IsExpand bool
|
||||
items []*OutboundGroupItem
|
||||
}
|
||||
|
||||
@@ -27,19 +27,6 @@ func (g *OutboundGroup) GetItems() OutboundGroupItemIterator {
|
||||
return newIterator(g.items)
|
||||
}
|
||||
|
||||
func (g *OutboundGroup) IsExpand(defaultValue bool) bool {
|
||||
switch g.isExpand {
|
||||
case -1:
|
||||
return defaultValue
|
||||
case 0:
|
||||
return false
|
||||
case 1:
|
||||
return false
|
||||
default:
|
||||
panic("unexpected expand value")
|
||||
}
|
||||
}
|
||||
|
||||
type OutboundGroupIterator interface {
|
||||
Next() *OutboundGroup
|
||||
HasNext() bool
|
||||
@@ -129,7 +116,7 @@ func readGroups(reader io.Reader) (OutboundGroupIterator, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = binary.Read(reader, binary.BigEndian, &group.isExpand)
|
||||
err = binary.Read(reader, binary.BigEndian, &group.IsExpand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -192,12 +179,8 @@ func writeGroups(writer io.Writer, boxService *BoxService) error {
|
||||
_, group.Selectable = iGroup.(*outbound.Selector)
|
||||
group.Selected = iGroup.Now()
|
||||
if cacheFile != nil {
|
||||
if isExpand, loaded := cacheFile.LoadGroupExpand(group.Tag); !loaded {
|
||||
group.isExpand = -1
|
||||
} else if isExpand {
|
||||
group.isExpand = 1
|
||||
} else {
|
||||
group.isExpand = 0
|
||||
if isExpand, loaded := cacheFile.LoadGroupExpand(group.Tag); loaded {
|
||||
group.IsExpand = isExpand
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,6 +199,9 @@ func writeGroups(writer io.Writer, boxService *BoxService) error {
|
||||
}
|
||||
group.items = append(group.items, &item)
|
||||
}
|
||||
if len(group.items) < 2 {
|
||||
continue
|
||||
}
|
||||
groups = append(groups, group)
|
||||
}
|
||||
|
||||
@@ -240,7 +226,7 @@ func writeGroups(writer io.Writer, boxService *BoxService) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(writer, binary.BigEndian, group.isExpand)
|
||||
err = binary.Write(writer, binary.BigEndian, group.IsExpand)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-box/common/urltest"
|
||||
"github.com/sagernet/sing-box/experimental/clashapi"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/debug"
|
||||
@@ -28,12 +29,14 @@ type CommandServer struct {
|
||||
observer *observable.Observer[string]
|
||||
service *BoxService
|
||||
|
||||
urlTestListener *list.Element[func()]
|
||||
urlTestUpdate chan struct{}
|
||||
urlTestUpdate chan struct{}
|
||||
modeUpdate chan struct{}
|
||||
}
|
||||
|
||||
type CommandServerHandler interface {
|
||||
ServiceReload() error
|
||||
GetSystemProxyStatus() *SystemProxyStatus
|
||||
SetSystemProxyEnabled(isEnabled bool) error
|
||||
}
|
||||
|
||||
func NewCommandServer(handler CommandServerHandler, maxLines int32) *CommandServer {
|
||||
@@ -43,20 +46,18 @@ func NewCommandServer(handler CommandServerHandler, maxLines int32) *CommandServ
|
||||
maxLines: int(maxLines),
|
||||
subscriber: observable.NewSubscriber[string](128),
|
||||
urlTestUpdate: make(chan struct{}, 1),
|
||||
modeUpdate: make(chan struct{}, 1),
|
||||
}
|
||||
server.observer = observable.NewObserver[string](server.subscriber, 64)
|
||||
return server
|
||||
}
|
||||
|
||||
func (s *CommandServer) SetService(newService *BoxService) {
|
||||
if s.service != nil && s.listener != nil {
|
||||
service.PtrFromContext[urltest.HistoryStorage](s.service.ctx).RemoveListener(s.urlTestListener)
|
||||
s.urlTestListener = nil
|
||||
if newService != nil {
|
||||
service.PtrFromContext[urltest.HistoryStorage](newService.ctx).SetHook(s.urlTestUpdate)
|
||||
newService.instance.Router().ClashServer().(*clashapi.Server).SetModeUpdateHook(s.modeUpdate)
|
||||
}
|
||||
s.service = newService
|
||||
if newService != nil {
|
||||
s.urlTestListener = service.PtrFromContext[urltest.HistoryStorage](newService.ctx).AddListener(s.notifyURLTestUpdate)
|
||||
}
|
||||
s.notifyURLTestUpdate()
|
||||
}
|
||||
|
||||
@@ -156,6 +157,14 @@ func (s *CommandServer) handleConnection(conn net.Conn) error {
|
||||
return s.handleURLTest(conn)
|
||||
case CommandGroupExpand:
|
||||
return s.handleSetGroupExpand(conn)
|
||||
case CommandClashMode:
|
||||
return s.handleModeConn(conn)
|
||||
case CommandSetClashMode:
|
||||
return s.handleSetClashMode(conn)
|
||||
case CommandGetSystemProxyStatus:
|
||||
return s.handleGetSystemProxyStatus(conn)
|
||||
case CommandSetSystemProxyEnabled:
|
||||
return s.handleSetSystemProxyEnabled(conn)
|
||||
default:
|
||||
return E.New("unknown command: ", command)
|
||||
}
|
||||
|
||||
@@ -6,13 +6,15 @@ import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/common/dialer/conntrack"
|
||||
"github.com/sagernet/sing-box/common/conntrack"
|
||||
"github.com/sagernet/sing-box/experimental/clashapi"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/memory"
|
||||
)
|
||||
|
||||
type StatusMessage struct {
|
||||
Memory int64
|
||||
MemoryInuse int64
|
||||
Goroutines int32
|
||||
ConnectionsIn int32
|
||||
ConnectionsOut int32
|
||||
@@ -24,10 +26,8 @@ type StatusMessage struct {
|
||||
}
|
||||
|
||||
func (s *CommandServer) readStatus() StatusMessage {
|
||||
var memStats runtime.MemStats
|
||||
runtime.ReadMemStats(&memStats)
|
||||
var message StatusMessage
|
||||
message.Memory = int64(memStats.StackInuse + memStats.HeapInuse + memStats.HeapIdle - memStats.HeapReleased)
|
||||
message.Memory = int64(memory.Inuse())
|
||||
message.Goroutines = int32(runtime.NumGoroutine())
|
||||
message.ConnectionsOut = int32(conntrack.Count())
|
||||
|
||||
|
||||
82
experimental/libbox/command_system_proxy.go
Normal file
82
experimental/libbox/command_system_proxy.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package libbox
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
)
|
||||
|
||||
type SystemProxyStatus struct {
|
||||
Available bool
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
func (c *CommandClient) GetSystemProxyStatus() (*SystemProxyStatus, error) {
|
||||
conn, err := c.directConnectWithRetry()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
err = binary.Write(conn, binary.BigEndian, uint8(CommandGetSystemProxyStatus))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var status SystemProxyStatus
|
||||
err = binary.Read(conn, binary.BigEndian, &status.Available)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if status.Available {
|
||||
err = binary.Read(conn, binary.BigEndian, &status.Enabled)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &status, nil
|
||||
}
|
||||
|
||||
func (s *CommandServer) handleGetSystemProxyStatus(conn net.Conn) error {
|
||||
defer conn.Close()
|
||||
status := s.handler.GetSystemProxyStatus()
|
||||
err := binary.Write(conn, binary.BigEndian, status.Available)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if status.Available {
|
||||
err = binary.Write(conn, binary.BigEndian, status.Enabled)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CommandClient) SetSystemProxyEnabled(isEnabled bool) error {
|
||||
conn, err := c.directConnect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
err = binary.Write(conn, binary.BigEndian, uint8(CommandSetSystemProxyEnabled))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(conn, binary.BigEndian, isEnabled)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return readError(conn)
|
||||
}
|
||||
|
||||
func (s *CommandServer) handleSetSystemProxyEnabled(conn net.Conn) error {
|
||||
defer conn.Close()
|
||||
var isEnabled bool
|
||||
err := binary.Read(conn, binary.BigEndian, &isEnabled)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.handler.SetSystemProxyEnabled(isEnabled)
|
||||
if err != nil {
|
||||
return writeError(conn, err)
|
||||
}
|
||||
return writeError(conn, nil)
|
||||
}
|
||||
@@ -49,6 +49,9 @@ func (p *platformLocalDNSTransport) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *platformLocalDNSTransport) Reset() {
|
||||
}
|
||||
|
||||
func (p *platformLocalDNSTransport) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ package libbox
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
@@ -18,12 +19,14 @@ func RedirectStderr(path string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sUserID > 0 {
|
||||
err = outputFile.Chown(sUserID, sGroupID)
|
||||
if err != nil {
|
||||
outputFile.Close()
|
||||
os.Remove(outputFile.Name())
|
||||
return err
|
||||
if runtime.GOOS != "android" {
|
||||
if sUserID > 0 {
|
||||
err = outputFile.Chown(sUserID, sGroupID)
|
||||
if err != nil {
|
||||
outputFile.Close()
|
||||
os.Remove(outputFile.Name())
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
err = unix.Dup2(int(outputFile.Fd()), int(os.Stderr.Fd()))
|
||||
|
||||
@@ -4,14 +4,15 @@ import (
|
||||
"math"
|
||||
runtimeDebug "runtime/debug"
|
||||
|
||||
"github.com/sagernet/sing-box/common/dialer/conntrack"
|
||||
"github.com/sagernet/sing-box/common/conntrack"
|
||||
)
|
||||
|
||||
func SetMemoryLimit(enabled bool) {
|
||||
const memoryLimit = 30 * 1024 * 1024
|
||||
const memoryLimit = 45 * 1024 * 1024
|
||||
const memoryLimitGo = memoryLimit / 1.5
|
||||
if enabled {
|
||||
runtimeDebug.SetGCPercent(10)
|
||||
runtimeDebug.SetMemoryLimit(memoryLimit)
|
||||
runtimeDebug.SetMemoryLimit(memoryLimitGo)
|
||||
conntrack.KillerEnabled = true
|
||||
conntrack.MemoryLimit = memoryLimit
|
||||
} else {
|
||||
|
||||
@@ -19,6 +19,7 @@ type PlatformInterface interface {
|
||||
UsePlatformInterfaceGetter() bool
|
||||
GetInterfaces() (NetworkInterfaceIterator, error)
|
||||
UnderNetworkExtension() bool
|
||||
ClearDNSCache()
|
||||
}
|
||||
|
||||
type TunInterface interface {
|
||||
|
||||
@@ -23,6 +23,7 @@ type Interface interface {
|
||||
UsePlatformInterfaceGetter() bool
|
||||
Interfaces() ([]NetworkInterface, error)
|
||||
UnderNetworkExtension() bool
|
||||
ClearDNSCache()
|
||||
process.Searcher
|
||||
io.Writer
|
||||
}
|
||||
|
||||
@@ -163,25 +163,29 @@ func DecodeProfileContentRequest(data []byte) (*ProfileContentRequest, error) {
|
||||
}
|
||||
|
||||
type ProfileContent struct {
|
||||
Name string
|
||||
Type int32
|
||||
Config string
|
||||
RemotePath string
|
||||
AutoUpdate bool
|
||||
LastUpdated int64
|
||||
Name string
|
||||
Type int32
|
||||
Config string
|
||||
RemotePath string
|
||||
AutoUpdate bool
|
||||
AutoUpdateInterval int32
|
||||
LastUpdated int64
|
||||
}
|
||||
|
||||
func (c *ProfileContent) Encode() []byte {
|
||||
buffer := new(bytes.Buffer)
|
||||
buffer.WriteByte(MessageTypeProfileContent)
|
||||
buffer.WriteByte(0)
|
||||
buffer.WriteByte(1)
|
||||
writer := gzip.NewWriter(buffer)
|
||||
rw.WriteVString(writer, c.Name)
|
||||
binary.Write(writer, binary.BigEndian, c.Type)
|
||||
rw.WriteVString(writer, c.Config)
|
||||
if c.Type != ProfileTypeLocal {
|
||||
rw.WriteVString(writer, c.RemotePath)
|
||||
}
|
||||
if c.Type == ProfileTypeRemote {
|
||||
binary.Write(writer, binary.BigEndian, c.AutoUpdate)
|
||||
binary.Write(writer, binary.BigEndian, c.AutoUpdateInterval)
|
||||
binary.Write(writer, binary.BigEndian, c.LastUpdated)
|
||||
}
|
||||
writer.Flush()
|
||||
@@ -202,12 +206,8 @@ func DecodeProfileContent(data []byte) (*ProfileContent, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if version == 0 {
|
||||
reader, err = gzip.NewReader(reader)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "unsupported profile")
|
||||
}
|
||||
} else {
|
||||
reader, err = gzip.NewReader(reader)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "unsupported profile")
|
||||
}
|
||||
var content ProfileContent
|
||||
@@ -228,10 +228,18 @@ func DecodeProfileContent(data []byte) (*ProfileContent, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if content.Type == ProfileTypeRemote || (version == 0 && content.Type != ProfileTypeLocal) {
|
||||
err = binary.Read(reader, binary.BigEndian, &content.AutoUpdate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if version >= 1 {
|
||||
err = binary.Read(reader, binary.BigEndian, &content.AutoUpdateInterval)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
err = binary.Read(reader, binary.BigEndian, &content.LastUpdated)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -3,6 +3,7 @@ package libbox
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
runtimeDebug "runtime/debug"
|
||||
"syscall"
|
||||
|
||||
"github.com/sagernet/sing-box"
|
||||
@@ -24,10 +25,11 @@ import (
|
||||
)
|
||||
|
||||
type BoxService struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
instance *box.Box
|
||||
pauseManager pause.Manager
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
instance *box.Box
|
||||
pauseManager pause.Manager
|
||||
urlTestHistoryStorage *urltest.HistoryStorage
|
||||
}
|
||||
|
||||
func NewService(configContent string, platformInterface PlatformInterface) (*BoxService, error) {
|
||||
@@ -35,11 +37,13 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
runtimeDebug.FreeOSMemory()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID)
|
||||
ctx = service.ContextWithPtr(ctx, urltest.NewHistoryStorage())
|
||||
sleepManager := pause.NewDefaultManager(ctx)
|
||||
ctx = pause.ContextWithManager(ctx, sleepManager)
|
||||
urlTestHistoryStorage := urltest.NewHistoryStorage()
|
||||
ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage)
|
||||
pauseManager := pause.NewDefaultManager(ctx)
|
||||
ctx = pause.ContextWithManager(ctx, pauseManager)
|
||||
instance, err := box.New(box.Options{
|
||||
Context: ctx,
|
||||
Options: options,
|
||||
@@ -49,11 +53,13 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
|
||||
cancel()
|
||||
return nil, E.Cause(err, "create service")
|
||||
}
|
||||
runtimeDebug.FreeOSMemory()
|
||||
return &BoxService{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
instance: instance,
|
||||
pauseManager: sleepManager,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
instance: instance,
|
||||
urlTestHistoryStorage: urlTestHistoryStorage,
|
||||
pauseManager: pauseManager,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -63,6 +69,7 @@ func (s *BoxService) Start() error {
|
||||
|
||||
func (s *BoxService) Close() error {
|
||||
s.cancel()
|
||||
s.urlTestHistoryStorage.Close()
|
||||
return s.instance.Close()
|
||||
}
|
||||
|
||||
@@ -191,3 +198,7 @@ func (w *platformInterfaceWrapper) Interfaces() ([]platform.NetworkInterface, er
|
||||
func (w *platformInterfaceWrapper) UnderNetworkExtension() bool {
|
||||
return w.iif.UnderNetworkExtension()
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) ClearDNSCache() {
|
||||
w.iif.ClearDNSCache()
|
||||
}
|
||||
|
||||
@@ -5,9 +5,8 @@ import (
|
||||
"os/user"
|
||||
"strconv"
|
||||
|
||||
"github.com/sagernet/sing-box/common/humanize"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -46,7 +45,11 @@ func Version() string {
|
||||
}
|
||||
|
||||
func FormatBytes(length int64) string {
|
||||
return humanize.IBytes(uint64(length))
|
||||
return humanize.Bytes(uint64(length))
|
||||
}
|
||||
|
||||
func FormatMemoryBytes(length int64) string {
|
||||
return humanize.MemoryBytes(uint64(length))
|
||||
}
|
||||
|
||||
func ProxyDisplayType(proxyType string) string {
|
||||
|
||||
47
go.mod
47
go.mod
@@ -1,40 +1,39 @@
|
||||
module github.com/sagernet/sing-box
|
||||
|
||||
go 1.18
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
berty.tech/go-libtor v1.0.385
|
||||
github.com/Dreamacro/clash v1.17.0
|
||||
github.com/caddyserver/certmagic v0.19.1
|
||||
github.com/caddyserver/certmagic v0.19.2
|
||||
github.com/cretz/bine v0.2.0
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
github.com/go-chi/chi/v5 v5.0.10
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/go-chi/render v1.0.3
|
||||
github.com/gofrs/uuid/v5 v5.0.0
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230816195147-b3ca2534940d
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/mholt/acmez v1.2.0
|
||||
github.com/miekg/dns v1.1.55
|
||||
github.com/ooni/go-libtor v1.1.8
|
||||
github.com/oschwald/maxminddb-golang v1.12.0
|
||||
github.com/pires/go-proxyproto v0.7.0
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0
|
||||
github.com/sagernet/gomobile v0.0.0-20230728014906-3de089147f59
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a
|
||||
github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950
|
||||
github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2
|
||||
github.com/sagernet/quic-go v0.0.0-20230811130919-d6f54a117913
|
||||
github.com/sagernet/quic-go v0.0.0-20230911082307-390b7c274032
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||
github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a
|
||||
github.com/sagernet/sing-dns v0.1.9-0.20230731012726-ad50da89b659
|
||||
github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c
|
||||
github.com/sagernet/sing-shadowsocks v0.2.4
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.3
|
||||
github.com/sagernet/sing v0.2.10-0.20230925102642-b0e07300a98c
|
||||
github.com/sagernet/sing-dns v0.1.9-0.20230925101650-9cc09becd01e
|
||||
github.com/sagernet/sing-mux v0.1.3-0.20230907005326-7befbadbf314
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5-0.20230907005610-126234728ca0
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.4-0.20230907005906-5d2917b29248
|
||||
github.com/sagernet/sing-shadowtls v0.1.4
|
||||
github.com/sagernet/sing-tun v0.1.12-0.20230812113806-10d98f26797a
|
||||
github.com/sagernet/sing-vmess v0.1.7
|
||||
github.com/sagernet/sing-tun v0.1.12-0.20230925100705-ef831c3485cf
|
||||
github.com/sagernet/sing-vmess v0.1.8-0.20230907010359-161fb0ac716b
|
||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37
|
||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9
|
||||
github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6
|
||||
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2
|
||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e
|
||||
github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f
|
||||
@@ -42,14 +41,15 @@ require (
|
||||
github.com/stretchr/testify v1.8.4
|
||||
go.etcd.io/bbolt v1.3.7
|
||||
go.uber.org/zap v1.25.0
|
||||
go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28
|
||||
go4.org/netipx v0.0.0-20230824141953-6213f710f925
|
||||
golang.org/x/crypto v0.12.0
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df
|
||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
|
||||
golang.org/x/net v0.14.0
|
||||
golang.org/x/sys v0.11.0
|
||||
golang.org/x/sys v0.12.0
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||
google.golang.org/grpc v1.57.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
howett.net/plist v1.0.0
|
||||
)
|
||||
|
||||
//replace github.com/sagernet/sing => ../sing
|
||||
@@ -58,11 +58,10 @@ require (
|
||||
github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158 // indirect
|
||||
github.com/ajg/form v1.5.1 // indirect
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/cloudflare/circl v1.2.1-0.20221019164342-6ab4dfed8f3c // indirect
|
||||
github.com/cloudflare/circl v1.3.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
@@ -77,7 +76,7 @@ require (
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.3.1 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3 // indirect
|
||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
|
||||
github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect
|
||||
@@ -86,10 +85,10 @@ require (
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/mod v0.11.0 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/text v0.12.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.10.0 // indirect
|
||||
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
113
go.sum
113
go.sum
@@ -9,13 +9,13 @@ github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||
github.com/caddyserver/certmagic v0.19.1 h1:4jyOYm2DHvQI8YM0sk6qm62Gl5XznHxiMBMWjMTlQkw=
|
||||
github.com/caddyserver/certmagic v0.19.1/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG+MIO4ztnmG/zz8=
|
||||
github.com/caddyserver/certmagic v0.19.2 h1:HZd1AKLx4592MalEGQS39DKs2ZOAJCEM/xYPMQ2/ui0=
|
||||
github.com/caddyserver/certmagic v0.19.2/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG+MIO4ztnmG/zz8=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cloudflare/circl v1.2.1-0.20221019164342-6ab4dfed8f3c h1:K1VdSnBZiGapczwcUKnE1qcsMBclA84DUOD2NG/78VY=
|
||||
github.com/cloudflare/circl v1.2.1-0.20221019164342-6ab4dfed8f3c/go.mod h1:+CauBF6R70Jqcyl8N2hC8pAXYbWkGIezuSbuGLtRhnw=
|
||||
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
|
||||
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||
@@ -23,8 +23,6 @@ github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbe
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
|
||||
@@ -34,14 +32,12 @@ github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vz
|
||||
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
||||
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
|
||||
github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
@@ -56,8 +52,9 @@ github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbg
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c h1:P/3mFnHCv1A/ej4m8pF5EB6FUt9qEL2Q9lfrcUNwCYs=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230816195147-b3ca2534940d h1:Ka64cclWedOkGzm9M2/XYuwJUdmWRUozmsxW0PyKA3A=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230816195147-b3ca2534940d/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
@@ -94,45 +91,45 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.1 h1:O4BLOM3hwfVF3AcktIylQXyl7Yi2iBNVy5QsV+ySxbg=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 h1:KyhtFFt1Jtp5vW2ohNvstvQffTOQ/s5vENuGXzdA+TM=
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0/go.mod h1:D4SFEOkJK+4W1v86ZhX0jPM0rAL498fyQAChqMtes/I=
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a h1:wZHruBxZCsQLXHAozWpnJBL3wJ/XufDpz0qKtgpSnA4=
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a/go.mod h1:dNV1ZP9y3qx5ltULeKaQZTZWTLHflgW5DES+Ses7cMI=
|
||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA=
|
||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
|
||||
github.com/sagernet/gomobile v0.0.0-20230728014906-3de089147f59 h1:vN4divY6LYHcYmiTsCHNPmGZtEsEKJzh81LyvgAQfEQ=
|
||||
github.com/sagernet/gomobile v0.0.0-20230728014906-3de089147f59/go.mod h1:5YE39YkJkCcMsfq1jMKkjsrM2GfBoF9JVWnvU89hmvU=
|
||||
github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950 h1:hUz/2mJLgi7l2H36JGpDY+jou9FmI6kAm0ZkU+xPpgE=
|
||||
github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950/go.mod h1:5YE39YkJkCcMsfq1jMKkjsrM2GfBoF9JVWnvU89hmvU=
|
||||
github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 h1:dnkKrzapqtAwjTSWt6hdPrARORfoYvuUczynvRLrueo=
|
||||
github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2/go.mod h1:1JUiV7nGuf++YFm9eWZ8q2lrwHmhcUGzptMl/vL1+LA=
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/quic-go v0.0.0-20230811130919-d6f54a117913 h1:4dyzZWAEo9BNQN7yJsVSiN/Pm1hmUfkGJdEyWMkUnVE=
|
||||
github.com/sagernet/quic-go v0.0.0-20230811130919-d6f54a117913/go.mod h1:w+nln6f/ZtyPpGbFxmgd5iYFVMmgS+gpD5hu5GAqC1I=
|
||||
github.com/sagernet/quic-go v0.0.0-20230911082307-390b7c274032 h1:J900zKCRGU+0gnPLIj+qXdmun4/AQ3iUmNREJ9fNdHQ=
|
||||
github.com/sagernet/quic-go v0.0.0-20230911082307-390b7c274032/go.mod h1:O4Cj7TmMOvqD6S0XMqJRZfcYzA3m0H0ARbbaJFB0p7A=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||
github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
|
||||
github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a h1:b89t6Mjgk4rJ5lrNMnCzy1/J116XkhgdB3YNd9FHyF4=
|
||||
github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA=
|
||||
github.com/sagernet/sing-dns v0.1.9-0.20230731012726-ad50da89b659 h1:1DAKccGNqTYJ8nsBR765FS0LVBVXfuFlFAHqKsGN3EI=
|
||||
github.com/sagernet/sing-dns v0.1.9-0.20230731012726-ad50da89b659/go.mod h1:W7GHTZFS8RkoLI3bA2LFY27/0E+uoQESWtMFLepO/JA=
|
||||
github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c h1:35/FowAvt3Z62mck0TXzVc4jS5R5CWq62qcV2P1cp0I=
|
||||
github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c/go.mod h1:TKxqIvfQQgd36jp2tzsPavGjYTVZilV+atip1cssjIY=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.4 h1:s/CqXlvFAZhlIoHWUwPw5CoNnQ9Ibki9pckjuugtVfY=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.4/go.mod h1:80fNKP0wnqlu85GZXV1H1vDPC/2t+dQbFggOw4XuFUM=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.3 h1:WXoLvCFi5JTFBRYorf1YePGYIQyJ/zbsBM6Fwbl5kGA=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.3/go.mod h1:DOhJc/cLeqRv0wuePrQso+iUmDxOnWF4eT/oMcRzYFw=
|
||||
github.com/sagernet/sing v0.2.10-0.20230925102642-b0e07300a98c h1:Vb5aH/BPW1elmMx9Miz8SqzoqlVRCzikttyMo7wEQUM=
|
||||
github.com/sagernet/sing v0.2.10-0.20230925102642-b0e07300a98c/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA=
|
||||
github.com/sagernet/sing-dns v0.1.9-0.20230925101650-9cc09becd01e h1:h903oI5Z2dIZv/lGLvQ67cC8O79uaeGrFhdxVssvh5c=
|
||||
github.com/sagernet/sing-dns v0.1.9-0.20230925101650-9cc09becd01e/go.mod h1:Kg98PBJEg/08jsNFtmZWmPomhskn9Ausn50ecNm4M+8=
|
||||
github.com/sagernet/sing-mux v0.1.3-0.20230907005326-7befbadbf314 h1:P5+NZGMH8KSI3L8lKw1znxdRi0tIpWbGYjmv8GrFHrQ=
|
||||
github.com/sagernet/sing-mux v0.1.3-0.20230907005326-7befbadbf314/go.mod h1:TKxqIvfQQgd36jp2tzsPavGjYTVZilV+atip1cssjIY=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5-0.20230907005610-126234728ca0 h1:9wHYWxH+fcs01PM2+DylA8LNNY3ElnZykQo9rysng8U=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5-0.20230907005610-126234728ca0/go.mod h1:80fNKP0wnqlu85GZXV1H1vDPC/2t+dQbFggOw4XuFUM=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.4-0.20230907005906-5d2917b29248 h1:JTFfy/LDmVFEK4KZJEujmC1iO8+aoF4unYhhZZRzRq4=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.4-0.20230907005906-5d2917b29248/go.mod h1:DOhJc/cLeqRv0wuePrQso+iUmDxOnWF4eT/oMcRzYFw=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
|
||||
github.com/sagernet/sing-tun v0.1.12-0.20230812113806-10d98f26797a h1:YZ20/ohB4wDQlOd2SMaL+qnAoWyM2yuXIUOVjUqj87U=
|
||||
github.com/sagernet/sing-tun v0.1.12-0.20230812113806-10d98f26797a/go.mod h1:XsyIVKd/Qp+2SdLZWGbavHtcpE7J7XU3S1zJmcoj9Ck=
|
||||
github.com/sagernet/sing-vmess v0.1.7 h1:TM8FFLsXmlXH9XT8/oDgc6PC5BOzrg6OzyEe01is2r4=
|
||||
github.com/sagernet/sing-vmess v0.1.7/go.mod h1:1qkC1L1T2sxnS/NuO6HU72S8TkltV+EXoKGR29m/Yss=
|
||||
github.com/sagernet/sing-tun v0.1.12-0.20230925100705-ef831c3485cf h1:7migLbdEzt57BCCzBxpTbmyszhjsoebMxKyT24Wu0Y8=
|
||||
github.com/sagernet/sing-tun v0.1.12-0.20230925100705-ef831c3485cf/go.mod h1:+YImslQMLgMQcVgZZ9IK4ue1o/605VSU90amHUcp4hA=
|
||||
github.com/sagernet/sing-vmess v0.1.8-0.20230907010359-161fb0ac716b h1:2ezfJtH5JosiEwJhVa+rimQ6ps/t2+7h+mOzMoiaZnA=
|
||||
github.com/sagernet/sing-vmess v0.1.8-0.20230907010359-161fb0ac716b/go.mod h1:1qkC1L1T2sxnS/NuO6HU72S8TkltV+EXoKGR29m/Yss=
|
||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
|
||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0=
|
||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE=
|
||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9/go.mod h1:FUyTEc5ye5NjKnDTDMuiLF2M6T4BE6y6KZuax//UCEg=
|
||||
github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 h1:Px+hN4Vzgx+iCGVnWH5A8eR7JhNnIV3rGQmBxA7cw6Q=
|
||||
github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6/go.mod h1:zovq6vTvEM6ECiqE3Eeb9rpIylPpamPcmrJ9tv0Bt0M=
|
||||
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4=
|
||||
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM=
|
||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
|
||||
@@ -155,7 +152,6 @@ github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gV
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264=
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
|
||||
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
|
||||
@@ -169,48 +165,35 @@ 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.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c=
|
||||
go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk=
|
||||
go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28 h1:zLxFnORHDFTSkJPawMU7LzsuGQJ4MUFS653jJHpORow=
|
||||
go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28/go.mod h1:TQvodOM+hJTioNQJilmLXu08JNb8i+ccq418+KWu1/Y=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ=
|
||||
go4.org/netipx v0.0.0-20230824141953-6213f710f925/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
|
||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
|
||||
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.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
||||
@@ -218,14 +201,9 @@ golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
|
||||
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E=
|
||||
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE=
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
|
||||
@@ -239,8 +217,11 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
|
||||
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||
lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
|
||||
lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
|
||||
|
||||
@@ -10,24 +10,26 @@ import (
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/tfo-go"
|
||||
)
|
||||
|
||||
func (a *myInboundAdapter) ListenTCP() (net.Listener, error) {
|
||||
var err error
|
||||
bindAddr := M.SocksaddrFrom(a.listenOptions.Listen.Build(), a.listenOptions.ListenPort)
|
||||
var tcpListener net.Listener
|
||||
if !a.listenOptions.TCPFastOpen {
|
||||
var listenConfig net.ListenConfig
|
||||
if a.listenOptions.TCPMultiPath {
|
||||
if !multipathTCPAvailable {
|
||||
return nil, E.New("MultiPath TCP requires go1.21, please recompile your binary.")
|
||||
}
|
||||
setMultiPathTCP(&listenConfig)
|
||||
var listenConfig net.ListenConfig
|
||||
if a.listenOptions.TCPMultiPath {
|
||||
if !go121Available {
|
||||
return nil, E.New("MultiPath TCP requires go1.21, please recompile your binary.")
|
||||
}
|
||||
tcpListener, err = listenConfig.Listen(a.ctx, M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.String())
|
||||
setMultiPathTCP(&listenConfig)
|
||||
}
|
||||
if a.listenOptions.TCPFastOpen {
|
||||
if !go120Available {
|
||||
return nil, E.New("TCP Fast Open requires go1.20, please recompile your binary.")
|
||||
}
|
||||
tcpListener, err = listenTFO(listenConfig, a.ctx, M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.String())
|
||||
} else {
|
||||
tcpListener, err = tfo.ListenTCP(M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.TCPAddr())
|
||||
tcpListener, err = listenConfig.Listen(a.ctx, M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.String())
|
||||
}
|
||||
if err == nil {
|
||||
a.logger.Info("tcp server started at ", tcpListener.Addr())
|
||||
|
||||
18
inbound/default_tcp_go1.20.go
Normal file
18
inbound/default_tcp_go1.20.go
Normal file
@@ -0,0 +1,18 @@
|
||||
//go:build go1.20
|
||||
|
||||
package inbound
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"github.com/sagernet/tfo-go"
|
||||
)
|
||||
|
||||
const go120Available = true
|
||||
|
||||
func listenTFO(listenConfig net.ListenConfig, ctx context.Context, network string, address string) (net.Listener, error) {
|
||||
var tfoConfig tfo.ListenConfig
|
||||
tfoConfig.ListenConfig = listenConfig
|
||||
return tfoConfig.Listen(ctx, network, address)
|
||||
}
|
||||
@@ -4,7 +4,7 @@ package inbound
|
||||
|
||||
import "net"
|
||||
|
||||
const multipathTCPAvailable = true
|
||||
const go121Available = true
|
||||
|
||||
func setMultiPathTCP(listenConfig *net.ListenConfig) {
|
||||
listenConfig.SetMultipathTCP(true)
|
||||
|
||||
15
inbound/default_tcp_nongo1.20.go
Normal file
15
inbound/default_tcp_nongo1.20.go
Normal file
@@ -0,0 +1,15 @@
|
||||
//go:build !go1.20
|
||||
|
||||
package inbound
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
)
|
||||
|
||||
const go120Available = false
|
||||
|
||||
func listenTFO(listenConfig net.ListenConfig, ctx context.Context, network string, address string) (net.Listener, error) {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
@@ -4,7 +4,7 @@ package inbound
|
||||
|
||||
import "net"
|
||||
|
||||
const multipathTCPAvailable = false
|
||||
const go121Available = false
|
||||
|
||||
func setMultiPathTCP(listenConfig *net.ListenConfig) {
|
||||
}
|
||||
|
||||
@@ -582,7 +582,7 @@ func (c *naiveH2Conn) Close() error {
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) LocalAddr() net.Addr {
|
||||
return nil
|
||||
return M.Socksaddr{}
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) RemoteAddr() net.Addr {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-shadowtls"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/auth"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
@@ -66,7 +67,7 @@ func NewShadowTLS(ctx context.Context, router adapter.Router, logger log.Context
|
||||
},
|
||||
HandshakeForServerName: handshakeForServerName,
|
||||
StrictMode: options.StrictMode,
|
||||
Handler: inbound.upstreamContextHandler(),
|
||||
Handler: adapter.NewUpstreamContextHandler(inbound.newConnection, nil, inbound),
|
||||
Logger: logger,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -80,3 +81,13 @@ func NewShadowTLS(ctx context.Context, router adapter.Router, logger log.Context
|
||||
func (h *ShadowTLS) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
return h.service.NewConnection(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata))
|
||||
}
|
||||
|
||||
func (h *ShadowTLS) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
if userName, _ := auth.UserFromContext[string](ctx); userName != "" {
|
||||
metadata.User = userName
|
||||
h.logger.InfoContext(ctx, "[", userName, "] inbound connection to ", metadata.Destination)
|
||||
} else {
|
||||
h.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
|
||||
}
|
||||
return h.router.RouteConnection(ctx, conn, metadata)
|
||||
}
|
||||
|
||||
@@ -84,7 +84,6 @@ func NewTUIC(ctx context.Context, router adapter.Router, logger log.ContextLogge
|
||||
|
||||
func (h *TUIC) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
ctx = log.ContextWithNewID(ctx)
|
||||
h.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
|
||||
metadata = h.createMetadata(conn, metadata)
|
||||
metadata.User, _ = auth.UserFromContext[string](ctx)
|
||||
return h.router.RouteConnection(ctx, conn, metadata)
|
||||
@@ -99,6 +98,12 @@ func (h *TUIC) newPacketConnection(ctx context.Context, conn N.PacketConn, metad
|
||||
}
|
||||
|
||||
func (h *TUIC) Start() error {
|
||||
if h.tlsConfig != nil {
|
||||
err := h.tlsConfig.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
packetConn, err := h.myInboundAdapter.ListenUDP()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -77,6 +77,8 @@ func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger
|
||||
Inet6Address: common.Map(options.Inet6Address, option.ListenPrefix.Build),
|
||||
AutoRoute: options.AutoRoute,
|
||||
StrictRoute: options.StrictRoute,
|
||||
IncludeInterface: options.IncludeInterface,
|
||||
ExcludeInterface: options.ExcludeInterface,
|
||||
Inet4RouteAddress: common.Map(options.Inet4RouteAddress, option.ListenPrefix.Build),
|
||||
Inet6RouteAddress: common.Map(options.Inet6RouteAddress, option.ListenPrefix.Build),
|
||||
IncludeUID: includeUID,
|
||||
|
||||
@@ -86,6 +86,7 @@ nav:
|
||||
- Hysteria: configuration/inbound/hysteria.md
|
||||
- ShadowTLS: configuration/inbound/shadowtls.md
|
||||
- VLESS: configuration/inbound/vless.md
|
||||
- TUIC: configuration/inbound/tuic.md
|
||||
- Tun: configuration/inbound/tun.md
|
||||
- Redirect: configuration/inbound/redirect.md
|
||||
- TProxy: configuration/inbound/tproxy.md
|
||||
@@ -103,6 +104,7 @@ nav:
|
||||
- ShadowTLS: configuration/outbound/shadowtls.md
|
||||
- ShadowsocksR: configuration/outbound/shadowsocksr.md
|
||||
- VLESS: configuration/outbound/vless.md
|
||||
- TUIC: configuration/outbound/tuic.md
|
||||
- Tor: configuration/outbound/tor.md
|
||||
- SSH: configuration/outbound/ssh.md
|
||||
- DNS: configuration/outbound/dns.md
|
||||
@@ -120,7 +122,6 @@ nav:
|
||||
- Shadowsocks: examples/shadowsocks.md
|
||||
- ShadowTLS: examples/shadowtls.md
|
||||
- Clash API: examples/clash-api.md
|
||||
- WireGuard Direct: examples/wireguard-direct.md
|
||||
- FakeIP: examples/fakeip.md
|
||||
- Contributing:
|
||||
- contributing/index.md
|
||||
|
||||
@@ -7,10 +7,13 @@ type ClashAPIOptions struct {
|
||||
ExternalUIDownloadDetour string `json:"external_ui_download_detour,omitempty"`
|
||||
Secret string `json:"secret,omitempty"`
|
||||
DefaultMode string `json:"default_mode,omitempty"`
|
||||
StoreMode bool `json:"store_mode,omitempty"`
|
||||
StoreSelected bool `json:"store_selected,omitempty"`
|
||||
StoreFakeIP bool `json:"store_fakeip,omitempty"`
|
||||
CacheFile string `json:"cache_file,omitempty"`
|
||||
CacheID string `json:"cache_id,omitempty"`
|
||||
|
||||
ModeList []string `json:"-"`
|
||||
}
|
||||
|
||||
type SelectorOutboundOptions struct {
|
||||
|
||||
@@ -3,7 +3,7 @@ package option
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/sagernet/sing-box/common/humanize"
|
||||
)
|
||||
|
||||
type DebugOptions struct {
|
||||
@@ -13,21 +13,21 @@ type DebugOptions struct {
|
||||
MaxThreads *int `json:"max_threads,omitempty"`
|
||||
PanicOnFault *bool `json:"panic_on_fault,omitempty"`
|
||||
TraceBack string `json:"trace_back,omitempty"`
|
||||
MemoryLimit BytesLength `json:"memory_limit,omitempty"`
|
||||
MemoryLimit MemoryBytes `json:"memory_limit,omitempty"`
|
||||
OOMKiller *bool `json:"oom_killer,omitempty"`
|
||||
}
|
||||
|
||||
type BytesLength int64
|
||||
type MemoryBytes uint64
|
||||
|
||||
func (l BytesLength) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(humanize.IBytes(uint64(l)))
|
||||
func (l MemoryBytes) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(humanize.MemoryBytes(uint64(l)))
|
||||
}
|
||||
|
||||
func (l *BytesLength) UnmarshalJSON(bytes []byte) error {
|
||||
func (l *MemoryBytes) UnmarshalJSON(bytes []byte) error {
|
||||
var valueInteger int64
|
||||
err := json.Unmarshal(bytes, &valueInteger)
|
||||
if err == nil {
|
||||
*l = BytesLength(valueInteger)
|
||||
*l = MemoryBytes(valueInteger)
|
||||
return nil
|
||||
}
|
||||
var valueString string
|
||||
@@ -35,10 +35,10 @@ func (l *BytesLength) UnmarshalJSON(bytes []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parsedValue, err := humanize.ParseBytes(valueString)
|
||||
parsedValue, err := humanize.ParseMemoryBytes(valueString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*l = BytesLength(parsedValue)
|
||||
*l = MemoryBytes(parsedValue)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ type TUICOutboundOptions struct {
|
||||
Password string `json:"password,omitempty"`
|
||||
CongestionControl string `json:"congestion_control,omitempty"`
|
||||
UDPRelayMode string `json:"udp_relay_mode,omitempty"`
|
||||
UDPOverStream bool `json:"udp_over_stream,omitempty"`
|
||||
ZeroRTTHandshake bool `json:"zero_rtt_handshake,omitempty"`
|
||||
Heartbeat Duration `json:"heartbeat,omitempty"`
|
||||
Network NetworkList `json:"network,omitempty"`
|
||||
|
||||
@@ -9,6 +9,8 @@ type TunInboundOptions struct {
|
||||
StrictRoute bool `json:"strict_route,omitempty"`
|
||||
Inet4RouteAddress Listable[ListenPrefix] `json:"inet4_route_address,omitempty"`
|
||||
Inet6RouteAddress Listable[ListenPrefix] `json:"inet6_route_address,omitempty"`
|
||||
IncludeInterface Listable[string] `json:"include_interface,omitempty"`
|
||||
ExcludeInterface Listable[string] `json:"exclude_interface,omitempty"`
|
||||
IncludeUID Listable[uint32] `json:"include_uid,omitempty"`
|
||||
IncludeUIDRange Listable[string] `json:"include_uid_range,omitempty"`
|
||||
ExcludeUID Listable[uint32] `json:"exclude_uid,omitempty"`
|
||||
|
||||
@@ -70,6 +70,28 @@ func NewConnection(ctx context.Context, this N.Dialer, conn net.Conn, metadata a
|
||||
return CopyEarlyConn(ctx, conn, outConn)
|
||||
}
|
||||
|
||||
func NewDirectConnection(ctx context.Context, router adapter.Router, this N.Dialer, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
ctx = adapter.WithContext(ctx, &metadata)
|
||||
var outConn net.Conn
|
||||
var err error
|
||||
if len(metadata.DestinationAddresses) > 0 {
|
||||
outConn, err = N.DialSerial(ctx, this, N.NetworkTCP, metadata.Destination, metadata.DestinationAddresses)
|
||||
} else if metadata.Destination.IsFqdn() {
|
||||
var destinationAddresses []netip.Addr
|
||||
destinationAddresses, err = router.LookupDefault(ctx, metadata.Destination.Fqdn)
|
||||
if err != nil {
|
||||
return N.HandshakeFailure(conn, err)
|
||||
}
|
||||
outConn, err = N.DialSerial(ctx, this, N.NetworkTCP, metadata.Destination, destinationAddresses)
|
||||
} else {
|
||||
outConn, err = this.DialContext(ctx, N.NetworkTCP, metadata.Destination)
|
||||
}
|
||||
if err != nil {
|
||||
return N.HandshakeFailure(conn, err)
|
||||
}
|
||||
return CopyEarlyConn(ctx, conn, outConn)
|
||||
}
|
||||
|
||||
func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||
ctx = adapter.WithContext(ctx, &metadata)
|
||||
var outConn net.PacketConn
|
||||
@@ -99,11 +121,48 @@ func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn,
|
||||
return bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(outConn))
|
||||
}
|
||||
|
||||
func NewDirectPacketConnection(ctx context.Context, router adapter.Router, this N.Dialer, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||
ctx = adapter.WithContext(ctx, &metadata)
|
||||
var outConn net.PacketConn
|
||||
var destinationAddress netip.Addr
|
||||
var err error
|
||||
if len(metadata.DestinationAddresses) > 0 {
|
||||
outConn, destinationAddress, err = N.ListenSerial(ctx, this, metadata.Destination, metadata.DestinationAddresses)
|
||||
} else if metadata.Destination.IsFqdn() {
|
||||
var destinationAddresses []netip.Addr
|
||||
destinationAddresses, err = router.LookupDefault(ctx, metadata.Destination.Fqdn)
|
||||
if err != nil {
|
||||
return N.HandshakeFailure(conn, err)
|
||||
}
|
||||
outConn, destinationAddress, err = N.ListenSerial(ctx, this, metadata.Destination, destinationAddresses)
|
||||
} else {
|
||||
outConn, err = this.ListenPacket(ctx, metadata.Destination)
|
||||
}
|
||||
if err != nil {
|
||||
return N.HandshakeFailure(conn, err)
|
||||
}
|
||||
if destinationAddress.IsValid() {
|
||||
if natConn, loaded := common.Cast[bufio.NATPacketConn](conn); loaded {
|
||||
natConn.UpdateDestination(destinationAddress)
|
||||
}
|
||||
}
|
||||
switch metadata.Protocol {
|
||||
case C.ProtocolSTUN:
|
||||
ctx, conn = canceler.NewPacketConn(ctx, conn, C.STUNTimeout)
|
||||
case C.ProtocolQUIC:
|
||||
ctx, conn = canceler.NewPacketConn(ctx, conn, C.QUICTimeout)
|
||||
case C.ProtocolDNS:
|
||||
ctx, conn = canceler.NewPacketConn(ctx, conn, C.DNSTimeout)
|
||||
}
|
||||
return bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(outConn))
|
||||
}
|
||||
|
||||
func CopyEarlyConn(ctx context.Context, conn net.Conn, serverConn net.Conn) error {
|
||||
if cachedReader, isCached := conn.(N.CachedReader); isCached {
|
||||
payload := cachedReader.ReadCached()
|
||||
if payload != nil && !payload.IsEmpty() {
|
||||
_, err := serverConn.Write(payload.Bytes())
|
||||
payload.Release()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -115,10 +174,12 @@ func CopyEarlyConn(ctx context.Context, conn net.Conn, serverConn net.Conn) erro
|
||||
err := conn.SetReadDeadline(time.Now().Add(C.ReadPayloadTimeout))
|
||||
if err != os.ErrInvalid {
|
||||
if err != nil {
|
||||
payload.Release()
|
||||
return err
|
||||
}
|
||||
_, err = payload.ReadOnceFrom(conn)
|
||||
if err != nil && !E.IsTimeout(err) {
|
||||
payload.Release()
|
||||
return E.Cause(err, "read payload")
|
||||
}
|
||||
err = conn.SetReadDeadline(time.Time{})
|
||||
@@ -128,10 +189,10 @@ func CopyEarlyConn(ctx context.Context, conn net.Conn, serverConn net.Conn) erro
|
||||
}
|
||||
}
|
||||
_, err = serverConn.Write(payload.Bytes())
|
||||
payload.Release()
|
||||
if err != nil {
|
||||
return N.HandshakeFailure(conn, err)
|
||||
}
|
||||
payload.Release()
|
||||
}
|
||||
return bufio.CopyConn(ctx, conn, serverConn)
|
||||
}
|
||||
|
||||
@@ -80,11 +80,11 @@ func (h *Socks) DialContext(ctx context.Context, network string, destination M.S
|
||||
return nil, E.Extend(N.ErrUnknownNetwork, network)
|
||||
}
|
||||
if h.resolve && destination.IsFqdn() {
|
||||
addrs, err := h.router.LookupDefault(ctx, destination.Fqdn)
|
||||
destinationAddresses, err := h.router.LookupDefault(ctx, destination.Fqdn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return N.DialSerial(ctx, h.client, network, destination, addrs)
|
||||
return N.DialSerial(ctx, h.client, network, destination, destinationAddresses)
|
||||
}
|
||||
return h.client.DialContext(ctx, network, destination)
|
||||
}
|
||||
@@ -97,14 +97,33 @@ func (h *Socks) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.
|
||||
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
||||
return h.uotClient.ListenPacket(ctx, destination)
|
||||
}
|
||||
if h.resolve && destination.IsFqdn() {
|
||||
destinationAddresses, err := h.router.LookupDefault(ctx, destination.Fqdn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
packetConn, _, err := N.ListenSerial(ctx, h.client, destination, destinationAddresses)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return packetConn, nil
|
||||
}
|
||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||
return h.client.ListenPacket(ctx, destination)
|
||||
}
|
||||
|
||||
func (h *Socks) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
return NewConnection(ctx, h, conn, metadata)
|
||||
if h.resolve {
|
||||
return NewDirectConnection(ctx, h.router, h, conn, metadata)
|
||||
} else {
|
||||
return NewConnection(ctx, h, conn, metadata)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Socks) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||
return NewPacketConnection(ctx, h, conn, metadata)
|
||||
if h.resolve {
|
||||
return NewDirectPacketConnection(ctx, h.router, h, conn, metadata)
|
||||
} else {
|
||||
return NewPacketConnection(ctx, h, conn, metadata)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/uot"
|
||||
|
||||
"github.com/gofrs/uuid/v5"
|
||||
)
|
||||
@@ -31,7 +32,8 @@ var (
|
||||
|
||||
type TUIC struct {
|
||||
myOutboundAdapter
|
||||
client *tuic.Client
|
||||
client *tuic.Client
|
||||
udpStream bool
|
||||
}
|
||||
|
||||
func NewTUIC(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TUICOutboundOptions) (*TUIC, error) {
|
||||
@@ -51,11 +53,14 @@ func NewTUIC(ctx context.Context, router adapter.Router, logger log.ContextLogge
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "invalid uuid")
|
||||
}
|
||||
var udpStream bool
|
||||
var tuicUDPStream bool
|
||||
if options.UDPOverStream && options.UDPRelayMode != "" {
|
||||
return nil, E.New("udp_over_stream is conflict with udp_relay_mode")
|
||||
}
|
||||
switch options.UDPRelayMode {
|
||||
case "native":
|
||||
case "quic":
|
||||
udpStream = true
|
||||
tuicUDPStream = true
|
||||
}
|
||||
outboundDialer, err := dialer.New(router, options.DialerOptions)
|
||||
if err != nil {
|
||||
@@ -69,7 +74,7 @@ func NewTUIC(ctx context.Context, router adapter.Router, logger log.ContextLogge
|
||||
UUID: userUUID,
|
||||
Password: options.Password,
|
||||
CongestionControl: options.CongestionControl,
|
||||
UDPStream: udpStream,
|
||||
UDPStream: tuicUDPStream,
|
||||
ZeroRTTHandshake: options.ZeroRTTHandshake,
|
||||
Heartbeat: time.Duration(options.Heartbeat),
|
||||
})
|
||||
@@ -85,7 +90,8 @@ func NewTUIC(ctx context.Context, router adapter.Router, logger log.ContextLogge
|
||||
tag: tag,
|
||||
dependencies: withDialerDependency(options.DialerOptions),
|
||||
},
|
||||
client: client,
|
||||
client: client,
|
||||
udpStream: options.UDPOverStream,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -95,19 +101,43 @@ func (h *TUIC) DialContext(ctx context.Context, network string, destination M.So
|
||||
h.logger.InfoContext(ctx, "outbound connection to ", destination)
|
||||
return h.client.DialConn(ctx, destination)
|
||||
case N.NetworkUDP:
|
||||
conn, err := h.ListenPacket(ctx, destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if h.udpStream {
|
||||
h.logger.InfoContext(ctx, "outbound stream packet connection to ", destination)
|
||||
streamConn, err := h.client.DialConn(ctx, uot.RequestDestination(uot.Version))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return uot.NewLazyConn(streamConn, uot.Request{
|
||||
IsConnect: true,
|
||||
Destination: destination,
|
||||
}), nil
|
||||
} else {
|
||||
conn, err := h.ListenPacket(ctx, destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bufio.NewBindPacketConn(conn, destination), nil
|
||||
}
|
||||
return bufio.NewBindPacketConn(conn, destination), nil
|
||||
default:
|
||||
return nil, E.New("unsupported network: ", network)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *TUIC) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||
return h.client.ListenPacket(ctx)
|
||||
if h.udpStream {
|
||||
h.logger.InfoContext(ctx, "outbound stream packet connection to ", destination)
|
||||
streamConn, err := h.client.DialConn(ctx, uot.RequestDestination(uot.Version))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return uot.NewLazyConn(streamConn, uot.Request{
|
||||
IsConnect: false,
|
||||
Destination: destination,
|
||||
}), nil
|
||||
} else {
|
||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||
return h.client.ListenPacket(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *TUIC) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
|
||||
@@ -202,26 +202,37 @@ func (w *WireGuard) DialContext(ctx context.Context, network string, destination
|
||||
w.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||
}
|
||||
if destination.IsFqdn() {
|
||||
addrs, err := w.router.LookupDefault(ctx, destination.Fqdn)
|
||||
destinationAddresses, err := w.router.LookupDefault(ctx, destination.Fqdn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return N.DialSerial(ctx, w.tunDevice, network, destination, addrs)
|
||||
return N.DialSerial(ctx, w.tunDevice, network, destination, destinationAddresses)
|
||||
}
|
||||
return w.tunDevice.DialContext(ctx, network, destination)
|
||||
}
|
||||
|
||||
func (w *WireGuard) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
w.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||
if destination.IsFqdn() {
|
||||
destinationAddresses, err := w.router.LookupDefault(ctx, destination.Fqdn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
packetConn, _, err := N.ListenSerial(ctx, w.tunDevice, destination, destinationAddresses)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return packetConn, err
|
||||
}
|
||||
return w.tunDevice.ListenPacket(ctx, destination)
|
||||
}
|
||||
|
||||
func (w *WireGuard) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
return NewConnection(ctx, w, conn, metadata)
|
||||
return NewDirectConnection(ctx, w.router, w, conn, metadata)
|
||||
}
|
||||
|
||||
func (w *WireGuard) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||
return NewPacketConnection(ctx, w, conn, metadata)
|
||||
return NewDirectPacketConnection(ctx, w.router, w, conn, metadata)
|
||||
}
|
||||
|
||||
func (w *WireGuard) Start() error {
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/conntrack"
|
||||
"github.com/sagernet/sing-box/common/dialer"
|
||||
"github.com/sagernet/sing-box/common/dialer/conntrack"
|
||||
"github.com/sagernet/sing-box/common/geoip"
|
||||
"github.com/sagernet/sing-box/common/geosite"
|
||||
"github.com/sagernet/sing-box/common/mux"
|
||||
@@ -521,7 +521,7 @@ func (r *Router) Close() error {
|
||||
return E.Cause(err, "close dns transport[", i, "]")
|
||||
})
|
||||
}
|
||||
if r.geositeReader != nil {
|
||||
if r.geoIPReader != nil {
|
||||
r.logger.Trace("closing geoip reader")
|
||||
err = E.Append(err, common.Close(r.geoIPReader), func(err error) error {
|
||||
return E.Cause(err, "close geoip reader")
|
||||
@@ -602,6 +602,7 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
|
||||
}
|
||||
return nil
|
||||
}
|
||||
conntrack.KillerCheck()
|
||||
metadata.Network = N.NetworkTCP
|
||||
switch metadata.Destination.Fqdn {
|
||||
case mux.Destination.Fqdn:
|
||||
@@ -636,6 +637,7 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
|
||||
if !loaded {
|
||||
return E.New("missing fakeip context")
|
||||
}
|
||||
metadata.OriginDestination = metadata.Destination
|
||||
metadata.Destination = M.Socksaddr{
|
||||
Fqdn: domain,
|
||||
Port: metadata.Destination.Port,
|
||||
@@ -737,15 +739,15 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
|
||||
}
|
||||
return nil
|
||||
}
|
||||
conntrack.KillerCheck()
|
||||
metadata.Network = N.NetworkUDP
|
||||
|
||||
var originAddress M.Socksaddr
|
||||
if r.fakeIPStore != nil && r.fakeIPStore.Contains(metadata.Destination.Addr) {
|
||||
domain, loaded := r.fakeIPStore.Lookup(metadata.Destination.Addr)
|
||||
if !loaded {
|
||||
return E.New("missing fakeip context")
|
||||
}
|
||||
originAddress = metadata.Destination
|
||||
metadata.OriginDestination = metadata.Destination
|
||||
metadata.Destination = M.Socksaddr{
|
||||
Fqdn: domain,
|
||||
Port: metadata.Destination.Port,
|
||||
@@ -759,7 +761,7 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
|
||||
conn = deadline.NewPacketConn(bufio.NewNetPacketConn(conn))
|
||||
}*/
|
||||
|
||||
if metadata.InboundOptions.SniffEnabled {
|
||||
if metadata.InboundOptions.SniffEnabled || metadata.Destination.Addr.IsUnspecified() {
|
||||
buffer := buf.NewPacket()
|
||||
buffer.FullReset()
|
||||
destination, err := conn.ReadPacket(buffer)
|
||||
@@ -767,20 +769,25 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
|
||||
buffer.Release()
|
||||
return err
|
||||
}
|
||||
sniffMetadata, _ := sniff.PeekPacket(ctx, buffer.Bytes(), sniff.DomainNameQuery, sniff.QUICClientHello, sniff.STUNMessage)
|
||||
if sniffMetadata != nil {
|
||||
metadata.Protocol = sniffMetadata.Protocol
|
||||
metadata.Domain = sniffMetadata.Domain
|
||||
if metadata.InboundOptions.SniffOverrideDestination && M.IsDomainName(metadata.Domain) {
|
||||
metadata.Destination = M.Socksaddr{
|
||||
Fqdn: metadata.Domain,
|
||||
Port: metadata.Destination.Port,
|
||||
if metadata.Destination.Addr.IsUnspecified() {
|
||||
metadata.Destination = destination
|
||||
}
|
||||
if metadata.InboundOptions.SniffEnabled {
|
||||
sniffMetadata, _ := sniff.PeekPacket(ctx, buffer.Bytes(), sniff.DomainNameQuery, sniff.QUICClientHello, sniff.STUNMessage)
|
||||
if sniffMetadata != nil {
|
||||
metadata.Protocol = sniffMetadata.Protocol
|
||||
metadata.Domain = sniffMetadata.Domain
|
||||
if metadata.InboundOptions.SniffOverrideDestination && M.IsDomainName(metadata.Domain) {
|
||||
metadata.Destination = M.Socksaddr{
|
||||
Fqdn: metadata.Domain,
|
||||
Port: metadata.Destination.Port,
|
||||
}
|
||||
}
|
||||
if metadata.Domain != "" {
|
||||
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain)
|
||||
} else {
|
||||
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol)
|
||||
}
|
||||
}
|
||||
if metadata.Domain != "" {
|
||||
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain)
|
||||
} else {
|
||||
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol)
|
||||
}
|
||||
}
|
||||
conn = bufio.NewCachedPacketConn(conn, buffer, destination)
|
||||
@@ -817,8 +824,8 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
|
||||
conn = statsService.RoutedPacketConnection(metadata.Inbound, detour.Tag(), metadata.User, conn)
|
||||
}
|
||||
}
|
||||
if originAddress.IsValid() {
|
||||
conn = fakeip.NewNATPacketConn(conn, originAddress, metadata.Destination)
|
||||
if metadata.FakeIP {
|
||||
conn = fakeip.NewNATPacketConn(conn, metadata.OriginDestination, metadata.Destination)
|
||||
}
|
||||
return detour.NewPacketConnection(ctx, conn, metadata)
|
||||
}
|
||||
@@ -910,13 +917,21 @@ func (r *Router) AutoDetectInterfaceFunc() control.Func {
|
||||
if r.platformInterface != nil && r.platformInterface.UsePlatformAutoDetectInterfaceControl() {
|
||||
return r.platformInterface.AutoDetectInterfaceControl()
|
||||
} else {
|
||||
return control.BindToInterfaceFunc(r.InterfaceFinder(), func(network string, address string) (interfaceName string, interfaceIndex int) {
|
||||
return control.BindToInterfaceFunc(r.InterfaceFinder(), func(network string, address string) (interfaceName string, interfaceIndex int, err error) {
|
||||
remoteAddr := M.ParseSocksaddr(address).Addr
|
||||
if C.IsLinux {
|
||||
return r.InterfaceMonitor().DefaultInterfaceName(remoteAddr), -1
|
||||
interfaceName = r.InterfaceMonitor().DefaultInterfaceName(remoteAddr)
|
||||
interfaceIndex = -1
|
||||
if interfaceName == "" {
|
||||
err = tun.ErrNoRoute
|
||||
}
|
||||
} else {
|
||||
return "", r.InterfaceMonitor().DefaultInterfaceIndex(remoteAddr)
|
||||
interfaceIndex = r.InterfaceMonitor().DefaultInterfaceIndex(remoteAddr)
|
||||
if interfaceIndex == -1 {
|
||||
err = tun.ErrNoRoute
|
||||
}
|
||||
}
|
||||
return
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1000,14 +1015,7 @@ func (r *Router) notifyNetworkUpdate(event int) {
|
||||
}
|
||||
}
|
||||
|
||||
conntrack.Close()
|
||||
|
||||
for _, outbound := range r.outbounds {
|
||||
listener, isListener := outbound.(adapter.InterfaceUpdateListener)
|
||||
if isListener {
|
||||
listener.InterfaceUpdated()
|
||||
}
|
||||
}
|
||||
r.ResetNetwork()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1020,5 +1028,9 @@ func (r *Router) ResetNetwork() error {
|
||||
listener.InterfaceUpdated()
|
||||
}
|
||||
}
|
||||
|
||||
for _, transport := range r.transports {
|
||||
transport.Reset()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -133,11 +133,11 @@ func (r *Router) Lookup(ctx context.Context, domain string, strategy dns.DomainS
|
||||
addrs, err := r.dnsClient.Lookup(ctx, transport, domain, strategy)
|
||||
if len(addrs) > 0 {
|
||||
r.dnsLogger.InfoContext(ctx, "lookup succeed for ", domain, ": ", strings.Join(F.MapToString(addrs), " "))
|
||||
} else {
|
||||
} else if err != nil {
|
||||
r.dnsLogger.ErrorContext(ctx, E.Cause(err, "lookup failed for ", domain))
|
||||
if err == nil {
|
||||
err = dns.RCodeNameError
|
||||
}
|
||||
} else {
|
||||
r.dnsLogger.ErrorContext(ctx, "lookup failed for ", domain, ": empty result")
|
||||
err = dns.RCodeNameError
|
||||
}
|
||||
return addrs, err
|
||||
}
|
||||
@@ -146,6 +146,13 @@ func (r *Router) LookupDefault(ctx context.Context, domain string) ([]netip.Addr
|
||||
return r.Lookup(ctx, domain, dns.DomainStrategyAsIS)
|
||||
}
|
||||
|
||||
func (r *Router) ClearDNSCache() {
|
||||
r.dnsClient.ClearCache()
|
||||
if r.platformInterface != nil {
|
||||
r.platformInterface.ClearDNSCache()
|
||||
}
|
||||
}
|
||||
|
||||
func LogDNSAnswers(logger log.ContextLogger, ctx context.Context, domain string, answers []mDNS.RR) {
|
||||
for _, answer := range answers {
|
||||
logger.InfoContext(ctx, "exchanged ", domain, " ", mDNS.Type(answer.Header().Rrtype).String(), " ", formatQuestion(answer.String()))
|
||||
|
||||
@@ -173,7 +173,11 @@ func (r *Router) downloadGeoIPDatabase(savePath string) error {
|
||||
},
|
||||
}
|
||||
defer httpClient.CloseIdleConnections()
|
||||
response, err := httpClient.Get(downloadURL)
|
||||
request, err := http.NewRequest("GET", downloadURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response, err := httpClient.Do(request.WithContext(r.ctx))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -221,7 +225,11 @@ func (r *Router) downloadGeositeDatabase(savePath string) error {
|
||||
},
|
||||
}
|
||||
defer httpClient.CloseIdleConnections()
|
||||
response, err := httpClient.Get(downloadURL)
|
||||
request, err := http.NewRequest("GET", downloadURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response, err := httpClient.Do(request.WithContext(r.ctx))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ type ClashModeItem struct {
|
||||
func NewClashModeItem(router adapter.Router, mode string) *ClashModeItem {
|
||||
return &ClashModeItem{
|
||||
router: router,
|
||||
mode: strings.ToLower(mode),
|
||||
mode: mode,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ func (r *ClashModeItem) Match(metadata *adapter.InboundContext) bool {
|
||||
if clashServer == nil {
|
||||
return false
|
||||
}
|
||||
return clashServer.Mode() == r.mode
|
||||
return strings.EqualFold(clashServer.Mode(), r.mode)
|
||||
}
|
||||
|
||||
func (r *ClashModeItem) String() string {
|
||||
|
||||
@@ -74,6 +74,21 @@ func testSuit(t *testing.T, clientPort uint16, testPort uint16) {
|
||||
// require.NoError(t, testPacketConnTimeout(t, dialUDP))
|
||||
}
|
||||
|
||||
func testSuitLargeUDP(t *testing.T, clientPort uint16, testPort uint16) {
|
||||
dialer := socks.NewClient(N.SystemDialer, M.ParseSocksaddrHostPort("127.0.0.1", clientPort), socks.Version5, "", "")
|
||||
dialTCP := func() (net.Conn, error) {
|
||||
return dialer.DialContext(context.Background(), "tcp", M.ParseSocksaddrHostPort("127.0.0.1", testPort))
|
||||
}
|
||||
dialUDP := func() (net.PacketConn, error) {
|
||||
return dialer.ListenPacket(context.Background(), M.ParseSocksaddrHostPort("127.0.0.1", testPort))
|
||||
}
|
||||
require.NoError(t, testPingPongWithConn(t, testPort, dialTCP))
|
||||
require.NoError(t, testPingPongWithPacketConn(t, testPort, dialUDP))
|
||||
require.NoError(t, testLargeDataWithConn(t, testPort, dialTCP))
|
||||
require.NoError(t, testLargeDataWithPacketConn(t, testPort, dialUDP))
|
||||
require.NoError(t, testLargeDataWithPacketConnSize(t, testPort, 5000, dialUDP))
|
||||
}
|
||||
|
||||
func testTCP(t *testing.T, clientPort uint16, testPort uint16) {
|
||||
dialer := socks.NewClient(N.SystemDialer, M.ParseSocksaddrHostPort("127.0.0.1", clientPort), socks.Version5, "", "")
|
||||
dialTCP := func() (net.Conn, error) {
|
||||
|
||||
@@ -38,8 +38,8 @@ const (
|
||||
ImageShadowsocksR = "teddysun/shadowsocks-r:latest"
|
||||
ImageXRayCore = "teddysun/xray:latest"
|
||||
ImageShadowsocksLegacy = "mritd/shadowsocks:latest"
|
||||
ImageTUICServer = ""
|
||||
ImageTUICClient = ""
|
||||
ImageTUICServer = "kilvn/tuic-server:latest"
|
||||
ImageTUICClient = "kilvn/tuic-client:latest"
|
||||
)
|
||||
|
||||
var allImages = []string{
|
||||
@@ -55,8 +55,8 @@ var allImages = []string{
|
||||
ImageShadowsocksR,
|
||||
ImageXRayCore,
|
||||
ImageShadowsocksLegacy,
|
||||
// ImageTUICServer,
|
||||
// ImageTUICClient,
|
||||
ImageTUICServer,
|
||||
ImageTUICClient,
|
||||
}
|
||||
|
||||
var localIP = netip.MustParseAddr("127.0.0.1")
|
||||
@@ -364,6 +364,10 @@ func testLargeDataWithConn(t *testing.T, port uint16, cc func() (net.Conn, error
|
||||
}
|
||||
|
||||
func testLargeDataWithPacketConn(t *testing.T, port uint16, pcc func() (net.PacketConn, error)) error {
|
||||
return testLargeDataWithPacketConnSize(t, port, 1500, pcc)
|
||||
}
|
||||
|
||||
func testLargeDataWithPacketConnSize(t *testing.T, port uint16, chunkSize int, pcc func() (net.PacketConn, error)) error {
|
||||
l, err := listenPacket("udp", ":"+F.ToString(port))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -373,31 +377,29 @@ func testLargeDataWithPacketConn(t *testing.T, port uint16, pcc func() (net.Pack
|
||||
rAddr := &net.UDPAddr{IP: localIP.AsSlice(), Port: int(port)}
|
||||
|
||||
times := 50
|
||||
chunkSize := int64(1024)
|
||||
|
||||
pingCh, pongCh, test := newLargeDataPair()
|
||||
writeRandData := func(pc net.PacketConn, addr net.Addr) (map[int][]byte, error) {
|
||||
hashMap := map[int][]byte{}
|
||||
mux := sync.Mutex{}
|
||||
for i := 0; i < times; i++ {
|
||||
go func(idx int) {
|
||||
buf := make([]byte, chunkSize)
|
||||
if _, err := rand.Read(buf[1:]); err != nil {
|
||||
t.Log(err.Error())
|
||||
return
|
||||
}
|
||||
buf[0] = byte(idx)
|
||||
buf := make([]byte, chunkSize)
|
||||
if _, err := rand.Read(buf[1:]); err != nil {
|
||||
t.Log(err.Error())
|
||||
continue
|
||||
}
|
||||
buf[0] = byte(i)
|
||||
|
||||
hash := md5.Sum(buf)
|
||||
mux.Lock()
|
||||
hashMap[idx] = hash[:]
|
||||
mux.Unlock()
|
||||
hash := md5.Sum(buf)
|
||||
mux.Lock()
|
||||
hashMap[i] = hash[:]
|
||||
mux.Unlock()
|
||||
|
||||
if _, err := pc.WriteTo(buf, addr); err != nil {
|
||||
t.Log(err.Error())
|
||||
return
|
||||
}
|
||||
}(i)
|
||||
if _, err := pc.WriteTo(buf, addr); err != nil {
|
||||
t.Log(err.Error())
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
return hashMap, nil
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"relay": {
|
||||
"server": "127.0.0.1:10000",
|
||||
"server": "example.org:10000",
|
||||
"ip": "127.0.0.1",
|
||||
"uuid": "FE35D05B-8803-45C4-BAE6-723AD2CD5D3D",
|
||||
"password": "tuic",
|
||||
"certificates": [
|
||||
@@ -8,7 +9,8 @@
|
||||
]
|
||||
},
|
||||
"local": {
|
||||
"server": "127.0.0.1:10001"
|
||||
"server": "127.0.0.1:10001",
|
||||
"max_packet_size": 65535
|
||||
},
|
||||
"log_level": "debug"
|
||||
}
|
||||
@@ -5,5 +5,6 @@
|
||||
},
|
||||
"certificate": "/etc/tuic/cert.pem",
|
||||
"private_key": "/etc/tuic/key.pem",
|
||||
"max_external_packet_size": 65535,
|
||||
"log_level": "debug"
|
||||
}
|
||||
51
test/go.mod
51
test/go.mod
@@ -1,21 +1,21 @@
|
||||
module test
|
||||
|
||||
go 1.18
|
||||
go 1.20
|
||||
|
||||
require github.com/sagernet/sing-box v0.0.0
|
||||
|
||||
replace github.com/sagernet/sing-box => ../
|
||||
|
||||
require (
|
||||
github.com/docker/docker v20.10.18+incompatible
|
||||
github.com/docker/docker v24.0.5+incompatible
|
||||
github.com/docker/go-connections v0.4.0
|
||||
github.com/gofrs/uuid/v5 v5.0.0
|
||||
github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a
|
||||
github.com/sagernet/sing-shadowsocks v0.2.4
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.3
|
||||
github.com/spyzhov/ajson v0.7.1
|
||||
github.com/sagernet/sing v0.2.10-0.20230925102642-b0e07300a98c
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5-0.20230907005610-126234728ca0
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.4-0.20230907005906-5d2917b29248
|
||||
github.com/spyzhov/ajson v0.9.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
go.uber.org/goleak v1.2.0
|
||||
go.uber.org/goleak v1.2.1
|
||||
golang.org/x/net v0.14.0
|
||||
)
|
||||
|
||||
@@ -26,26 +26,24 @@ require (
|
||||
github.com/Microsoft/go-winio v0.6.0 // indirect
|
||||
github.com/ajg/form v1.5.1 // indirect
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/caddyserver/certmagic v0.19.1 // indirect
|
||||
github.com/cloudflare/circl v1.2.1-0.20221019164342-6ab4dfed8f3c // indirect
|
||||
github.com/caddyserver/certmagic v0.19.2 // indirect
|
||||
github.com/cloudflare/circl v1.3.3 // indirect
|
||||
github.com/cretz/bine v0.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/go-chi/chi/v5 v5.0.10 // indirect
|
||||
github.com/go-chi/cors v1.2.1 // indirect
|
||||
github.com/go-chi/render v1.0.3 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230816195147-b3ca2534940d // indirect
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.15.15 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
@@ -65,39 +63,38 @@ require (
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.3.1 // indirect
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3 // indirect
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a // indirect
|
||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect
|
||||
github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
|
||||
github.com/sagernet/quic-go v0.0.0-20230811130919-d6f54a117913 // indirect
|
||||
github.com/sagernet/quic-go v0.0.0-20230911082307-390b7c274032 // indirect
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
|
||||
github.com/sagernet/sing-dns v0.1.9-0.20230731012726-ad50da89b659 // indirect
|
||||
github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c // indirect
|
||||
github.com/sagernet/sing-dns v0.1.9-0.20230925101650-9cc09becd01e // indirect
|
||||
github.com/sagernet/sing-mux v0.1.3-0.20230907005326-7befbadbf314 // indirect
|
||||
github.com/sagernet/sing-shadowtls v0.1.4 // indirect
|
||||
github.com/sagernet/sing-tun v0.1.12-0.20230812113806-10d98f26797a // indirect
|
||||
github.com/sagernet/sing-vmess v0.1.7 // indirect
|
||||
github.com/sagernet/sing-tun v0.1.12-0.20230925100705-ef831c3485cf // indirect
|
||||
github.com/sagernet/sing-vmess v0.1.8-0.20230907010359-161fb0ac716b // indirect
|
||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect
|
||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect
|
||||
github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 // indirect
|
||||
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect
|
||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect
|
||||
github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f // indirect
|
||||
github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
go.etcd.io/bbolt v1.3.7 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.25.0 // indirect
|
||||
go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28 // indirect
|
||||
go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect
|
||||
golang.org/x/crypto v0.12.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
|
||||
golang.org/x/mod v0.11.0 // indirect
|
||||
golang.org/x/sys v0.11.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/sys v0.12.0 // indirect
|
||||
golang.org/x/text v0.12.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.10.0 // indirect
|
||||
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
|
||||
google.golang.org/grpc v1.57.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
|
||||
117
test/go.sum
117
test/go.sum
@@ -12,13 +12,13 @@ github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||
github.com/caddyserver/certmagic v0.19.1 h1:4jyOYm2DHvQI8YM0sk6qm62Gl5XznHxiMBMWjMTlQkw=
|
||||
github.com/caddyserver/certmagic v0.19.1/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG+MIO4ztnmG/zz8=
|
||||
github.com/caddyserver/certmagic v0.19.2 h1:HZd1AKLx4592MalEGQS39DKs2ZOAJCEM/xYPMQ2/ui0=
|
||||
github.com/caddyserver/certmagic v0.19.2/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG+MIO4ztnmG/zz8=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cloudflare/circl v1.2.1-0.20221019164342-6ab4dfed8f3c h1:K1VdSnBZiGapczwcUKnE1qcsMBclA84DUOD2NG/78VY=
|
||||
github.com/cloudflare/circl v1.2.1-0.20221019164342-6ab4dfed8f3c/go.mod h1:+CauBF6R70Jqcyl8N2hC8pAXYbWkGIezuSbuGLtRhnw=
|
||||
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
|
||||
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
|
||||
@@ -27,14 +27,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
|
||||
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v20.10.18+incompatible h1:SN84VYXTBNGn92T/QwIRPlum9zfemfitN7pbsp26WSc=
|
||||
github.com/docker/docker v20.10.18+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY=
|
||||
github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
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/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
|
||||
@@ -44,16 +42,14 @@ github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vz
|
||||
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
||||
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
|
||||
github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
@@ -66,8 +62,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe
|
||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
||||
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c h1:P/3mFnHCv1A/ej4m8pF5EB6FUt9qEL2Q9lfrcUNwCYs=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230816195147-b3ca2534940d h1:Ka64cclWedOkGzm9M2/XYuwJUdmWRUozmsxW0PyKA3A=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230816195147-b3ca2534940d/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4=
|
||||
github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
@@ -113,60 +109,52 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.1 h1:O4BLOM3hwfVF3AcktIylQXyl7Yi2iBNVy5QsV+ySxbg=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 h1:KyhtFFt1Jtp5vW2ohNvstvQffTOQ/s5vENuGXzdA+TM=
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0/go.mod h1:D4SFEOkJK+4W1v86ZhX0jPM0rAL498fyQAChqMtes/I=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a h1:wZHruBxZCsQLXHAozWpnJBL3wJ/XufDpz0qKtgpSnA4=
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a/go.mod h1:dNV1ZP9y3qx5ltULeKaQZTZWTLHflgW5DES+Ses7cMI=
|
||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA=
|
||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
|
||||
github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 h1:dnkKrzapqtAwjTSWt6hdPrARORfoYvuUczynvRLrueo=
|
||||
github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2/go.mod h1:1JUiV7nGuf++YFm9eWZ8q2lrwHmhcUGzptMl/vL1+LA=
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/quic-go v0.0.0-20230809023643-d720ed35ac2b h1:+hpCW1zw03nnJDx+5tF9ETb6bKl2VSftv4KMGZAHC2Q=
|
||||
github.com/sagernet/quic-go v0.0.0-20230809023643-d720ed35ac2b/go.mod h1:w+nln6f/ZtyPpGbFxmgd5iYFVMmgS+gpD5hu5GAqC1I=
|
||||
github.com/sagernet/quic-go v0.0.0-20230811130919-d6f54a117913/go.mod h1:w+nln6f/ZtyPpGbFxmgd5iYFVMmgS+gpD5hu5GAqC1I=
|
||||
github.com/sagernet/quic-go v0.0.0-20230911082307-390b7c274032 h1:J900zKCRGU+0gnPLIj+qXdmun4/AQ3iUmNREJ9fNdHQ=
|
||||
github.com/sagernet/quic-go v0.0.0-20230911082307-390b7c274032/go.mod h1:O4Cj7TmMOvqD6S0XMqJRZfcYzA3m0H0ARbbaJFB0p7A=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||
github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
|
||||
github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a h1:b89t6Mjgk4rJ5lrNMnCzy1/J116XkhgdB3YNd9FHyF4=
|
||||
github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA=
|
||||
github.com/sagernet/sing-dns v0.1.9-0.20230731012726-ad50da89b659 h1:1DAKccGNqTYJ8nsBR765FS0LVBVXfuFlFAHqKsGN3EI=
|
||||
github.com/sagernet/sing-dns v0.1.9-0.20230731012726-ad50da89b659/go.mod h1:W7GHTZFS8RkoLI3bA2LFY27/0E+uoQESWtMFLepO/JA=
|
||||
github.com/sagernet/sing-mux v0.1.3-0.20230803070305-ea4a972acd21 h1:IQ7oBBKz+lwIqwI9IMStlQ9YSUu3eKJmNTip0aLbvOI=
|
||||
github.com/sagernet/sing-mux v0.1.3-0.20230803070305-ea4a972acd21/go.mod h1:TKxqIvfQQgd36jp2tzsPavGjYTVZilV+atip1cssjIY=
|
||||
github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c/go.mod h1:TKxqIvfQQgd36jp2tzsPavGjYTVZilV+atip1cssjIY=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.4 h1:s/CqXlvFAZhlIoHWUwPw5CoNnQ9Ibki9pckjuugtVfY=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.4/go.mod h1:80fNKP0wnqlu85GZXV1H1vDPC/2t+dQbFggOw4XuFUM=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.3 h1:WXoLvCFi5JTFBRYorf1YePGYIQyJ/zbsBM6Fwbl5kGA=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.3/go.mod h1:DOhJc/cLeqRv0wuePrQso+iUmDxOnWF4eT/oMcRzYFw=
|
||||
github.com/sagernet/sing v0.2.10-0.20230925102642-b0e07300a98c h1:Vb5aH/BPW1elmMx9Miz8SqzoqlVRCzikttyMo7wEQUM=
|
||||
github.com/sagernet/sing v0.2.10-0.20230925102642-b0e07300a98c/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA=
|
||||
github.com/sagernet/sing-dns v0.1.9-0.20230925101650-9cc09becd01e h1:h903oI5Z2dIZv/lGLvQ67cC8O79uaeGrFhdxVssvh5c=
|
||||
github.com/sagernet/sing-dns v0.1.9-0.20230925101650-9cc09becd01e/go.mod h1:Kg98PBJEg/08jsNFtmZWmPomhskn9Ausn50ecNm4M+8=
|
||||
github.com/sagernet/sing-mux v0.1.3-0.20230907005326-7befbadbf314 h1:P5+NZGMH8KSI3L8lKw1znxdRi0tIpWbGYjmv8GrFHrQ=
|
||||
github.com/sagernet/sing-mux v0.1.3-0.20230907005326-7befbadbf314/go.mod h1:TKxqIvfQQgd36jp2tzsPavGjYTVZilV+atip1cssjIY=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5-0.20230907005610-126234728ca0 h1:9wHYWxH+fcs01PM2+DylA8LNNY3ElnZykQo9rysng8U=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.5-0.20230907005610-126234728ca0/go.mod h1:80fNKP0wnqlu85GZXV1H1vDPC/2t+dQbFggOw4XuFUM=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.4-0.20230907005906-5d2917b29248 h1:JTFfy/LDmVFEK4KZJEujmC1iO8+aoF4unYhhZZRzRq4=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.4-0.20230907005906-5d2917b29248/go.mod h1:DOhJc/cLeqRv0wuePrQso+iUmDxOnWF4eT/oMcRzYFw=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
|
||||
github.com/sagernet/sing-tun v0.1.12-0.20230808120247-47ab78d303db h1:jOwG+7u4NtQVwXj5pFnGeNnDoa2cv83O5x4NLKN8y/c=
|
||||
github.com/sagernet/sing-tun v0.1.12-0.20230808120247-47ab78d303db/go.mod h1:XsyIVKd/Qp+2SdLZWGbavHtcpE7J7XU3S1zJmcoj9Ck=
|
||||
github.com/sagernet/sing-tun v0.1.12-0.20230811070056-38478f5fbcd2/go.mod h1:XsyIVKd/Qp+2SdLZWGbavHtcpE7J7XU3S1zJmcoj9Ck=
|
||||
github.com/sagernet/sing-tun v0.1.12-0.20230812113214-bc5a1f835a28/go.mod h1:XsyIVKd/Qp+2SdLZWGbavHtcpE7J7XU3S1zJmcoj9Ck=
|
||||
github.com/sagernet/sing-tun v0.1.12-0.20230812113806-10d98f26797a/go.mod h1:XsyIVKd/Qp+2SdLZWGbavHtcpE7J7XU3S1zJmcoj9Ck=
|
||||
github.com/sagernet/sing-vmess v0.1.7 h1:TM8FFLsXmlXH9XT8/oDgc6PC5BOzrg6OzyEe01is2r4=
|
||||
github.com/sagernet/sing-vmess v0.1.7/go.mod h1:1qkC1L1T2sxnS/NuO6HU72S8TkltV+EXoKGR29m/Yss=
|
||||
github.com/sagernet/sing-tun v0.1.12-0.20230925100705-ef831c3485cf h1:7migLbdEzt57BCCzBxpTbmyszhjsoebMxKyT24Wu0Y8=
|
||||
github.com/sagernet/sing-tun v0.1.12-0.20230925100705-ef831c3485cf/go.mod h1:+YImslQMLgMQcVgZZ9IK4ue1o/605VSU90amHUcp4hA=
|
||||
github.com/sagernet/sing-vmess v0.1.8-0.20230907010359-161fb0ac716b h1:2ezfJtH5JosiEwJhVa+rimQ6ps/t2+7h+mOzMoiaZnA=
|
||||
github.com/sagernet/sing-vmess v0.1.8-0.20230907010359-161fb0ac716b/go.mod h1:1qkC1L1T2sxnS/NuO6HU72S8TkltV+EXoKGR29m/Yss=
|
||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
|
||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0=
|
||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE=
|
||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9/go.mod h1:FUyTEc5ye5NjKnDTDMuiLF2M6T4BE6y6KZuax//UCEg=
|
||||
github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 h1:Px+hN4Vzgx+iCGVnWH5A8eR7JhNnIV3rGQmBxA7cw6Q=
|
||||
github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6/go.mod h1:zovq6vTvEM6ECiqE3Eeb9rpIylPpamPcmrJ9tv0Bt0M=
|
||||
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4=
|
||||
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM=
|
||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
|
||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY=
|
||||
github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 h1:g6QtRWQ2dKX7EQP++1JLNtw4C2TNxd4/ov8YUpOPOSo=
|
||||
github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77/go.mod h1:pJDdXzZIwJ+2vmnT0TKzmf8meeum+e2mTDSehw79eE0=
|
||||
github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f h1:Kvo8w8Y9lzFGB/7z09MJ3TR99TFtfI/IuY87Ygcycho=
|
||||
github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f/go.mod h1:mySs0abhpc/gLlvhoq7HP1RzOaRmIXVeZGCh++zoApk=
|
||||
github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg=
|
||||
github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spyzhov/ajson v0.7.1 h1:1MDIlPc6x0zjNtpa7tDzRAyFAvRX+X8ZsvtYz5lZg6A=
|
||||
github.com/spyzhov/ajson v0.7.1/go.mod h1:63V+CGM6f1Bu/p4nLIN8885ojBdt88TbLoSFzyqMuVA=
|
||||
github.com/spyzhov/ajson v0.9.0 h1:tF46gJGOenYVj+k9K1U1XpCxVWhmiyY5PsVCAs1+OJ0=
|
||||
github.com/spyzhov/ajson v0.9.0/go.mod h1:a6oSw0MMb7Z5aD2tPoPO+jq11ETKgXUr2XktHdT8Wt8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
@@ -179,7 +167,6 @@ github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695AP
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
|
||||
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
|
||||
@@ -188,14 +175,14 @@ 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.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
||||
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
||||
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.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c=
|
||||
go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk=
|
||||
go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28 h1:zLxFnORHDFTSkJPawMU7LzsuGQJ4MUFS653jJHpORow=
|
||||
go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28/go.mod h1:TQvodOM+hJTioNQJilmLXu08JNb8i+ccq418+KWu1/Y=
|
||||
go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ=
|
||||
go4.org/netipx v0.0.0-20230824141953-6213f710f925/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-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@@ -203,47 +190,40 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME=
|
||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
|
||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/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-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -258,9 +238,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
|
||||
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
|
||||
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E=
|
||||
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user