mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-11 17:47:20 +10:00
Add naiveproxy outbound
This commit is contained in:
11
.github/setup_musl_cross.sh
vendored
Executable file
11
.github/setup_musl_cross.sh
vendored
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
set -xeuo pipefail
|
||||
|
||||
TARGET="$1"
|
||||
|
||||
# Download musl-cross toolchain from musl.cc
|
||||
cd "$HOME"
|
||||
wget -q "https://musl.cc/${TARGET}-cross.tgz"
|
||||
mkdir -p musl-cross
|
||||
tar -xf "${TARGET}-cross.tgz" -C musl-cross --strip-components=1
|
||||
rm "${TARGET}-cross.tgz"
|
||||
7
.github/update_cronet.sh
vendored
Executable file
7
.github/update_cronet.sh
vendored
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
PROJECTS=$(dirname "$0")/../..
|
||||
git -C $PROJECTS/cronet-go fetch origin go
|
||||
go get -x github.com/sagernet/cronet-go/all@$(git -C $PROJECTS/cronet-go rev-parse origin/go)
|
||||
|
||||
go mod tidy
|
||||
128
.github/workflows/build.yml
vendored
128
.github/workflows/build.yml
vendored
@@ -143,6 +143,9 @@ jobs:
|
||||
run: |
|
||||
set -xeuo pipefail
|
||||
TAGS='with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,badlinkname,tfogo_checklinkname0'
|
||||
if [[ "${{ matrix.os }}" == "android" ]]; then
|
||||
TAGS="${TAGS},with_naive_outbound"
|
||||
fi
|
||||
echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}"
|
||||
- name: Build
|
||||
if: matrix.os != 'android'
|
||||
@@ -315,7 +318,7 @@ jobs:
|
||||
- name: Set build tags
|
||||
run: |
|
||||
set -xeuo pipefail
|
||||
TAGS='with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,badlinkname,tfogo_checklinkname0'
|
||||
TAGS='with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_naive_outbound,badlinkname,tfogo_checklinkname0'
|
||||
echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}"
|
||||
- name: Build
|
||||
run: |
|
||||
@@ -352,6 +355,128 @@ jobs:
|
||||
with:
|
||||
name: binary-darwin_${{ matrix.arch }}${{ matrix.legacy_name && format('-legacy-{0}', matrix.legacy_name) }}
|
||||
path: "dist"
|
||||
build_naive_linux:
|
||||
name: Build Linux with naive outbound
|
||||
if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Binary'
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- calculate_version
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
# Linux glibc (dynamic linking with Debian Bullseye sysroot)
|
||||
- { arch: amd64, sysroot_arch: amd64, sysroot_sha: "36a164623d03f525e3dfb783a5e9b8a00e98e1ddd2b5cff4e449bd016dd27e50", cc_target: "x86_64-linux-gnu", suffix: "-naive" }
|
||||
- { arch: arm64, sysroot_arch: arm64, sysroot_sha: "2f915d821eec27515c0c6d21b69898e23762908d8d7ccc1aa2a8f5f25e8b7e18", cc_target: "aarch64-linux-gnu", suffix: "-naive" }
|
||||
- { arch: "386", sysroot_arch: i386, sysroot_sha: "63f0e5128b84f7b0421956a4a40affa472be8da0e58caf27e9acbc84072daee7", cc_target: "i686-linux-gnu", suffix: "-naive" }
|
||||
- { arch: arm, goarm: "7", sysroot_arch: armhf, sysroot_sha: "47b3a0b161ca011b2b33d4fc1ef6ef269b8208a0b7e4c900700c345acdfd1814", cc_target: "arm-linux-gnueabihf", suffix: "-naive" }
|
||||
# Linux musl (static linking)
|
||||
- { arch: amd64, musl: true, cc_target: "x86_64-linux-musl", suffix: "-naive-musl" }
|
||||
- { arch: arm64, musl: true, cc_target: "aarch64-linux-musl", suffix: "-naive-musl" }
|
||||
- { arch: "386", musl: true, cc_target: "i686-linux-musl", suffix: "-naive-musl" }
|
||||
- { arch: arm, goarm: "7", musl: true, cc_target: "arm-linux-musleabihf", suffix: "-naive-musl" }
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25.4
|
||||
- name: Set tag
|
||||
run: |-
|
||||
git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
|
||||
git tag v${{ needs.calculate_version.outputs.version }} -f
|
||||
- name: Download sysroot (glibc)
|
||||
if: ${{ ! matrix.musl }}
|
||||
run: |
|
||||
set -xeuo pipefail
|
||||
wget -q "https://commondatastorage.googleapis.com/chrome-linux-sysroot/${{ matrix.sysroot_sha }}" -O sysroot.tar.xz
|
||||
mkdir -p /tmp/sysroot
|
||||
tar -xf sysroot.tar.xz -C /tmp/sysroot
|
||||
- name: Install cross compiler (glibc)
|
||||
if: ${{ ! matrix.musl }}
|
||||
run: |
|
||||
set -xeuo pipefail
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y clang lld
|
||||
if [[ "${{ matrix.arch }}" == "arm64" ]]; then
|
||||
sudo apt-get install -y libc6-dev-arm64-cross
|
||||
elif [[ "${{ matrix.arch }}" == "386" ]]; then
|
||||
sudo apt-get install -y libc6-dev-i386-cross
|
||||
elif [[ "${{ matrix.arch }}" == "arm" ]]; then
|
||||
sudo apt-get install -y libc6-dev-armhf-cross
|
||||
fi
|
||||
- name: Install musl cross compiler
|
||||
if: matrix.musl
|
||||
run: |
|
||||
set -xeuo pipefail
|
||||
.github/setup_musl_cross.sh "${{ matrix.cc_target }}"
|
||||
echo "PATH=$HOME/musl-cross/bin:$PATH" >> $GITHUB_ENV
|
||||
- name: Set build tags
|
||||
run: |
|
||||
set -xeuo pipefail
|
||||
TAGS='with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_naive_outbound,badlinkname,tfogo_checklinkname0'
|
||||
if [[ "${{ matrix.musl }}" == "true" ]]; then
|
||||
TAGS="${TAGS},with_musl"
|
||||
fi
|
||||
echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}"
|
||||
- name: Build (glibc)
|
||||
if: ${{ ! matrix.musl }}
|
||||
run: |
|
||||
set -xeuo pipefail
|
||||
mkdir -p dist
|
||||
go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
|
||||
-ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0 -linkmode=external -extldflags "-fuse-ld=lld --sysroot=/tmp/sysroot"' \
|
||||
./cmd/sing-box
|
||||
env:
|
||||
CGO_ENABLED: "1"
|
||||
GOOS: linux
|
||||
GOARCH: ${{ matrix.arch }}
|
||||
GOARM: ${{ matrix.goarm }}
|
||||
CC: "clang --target=${{ matrix.cc_target }} --sysroot=/tmp/sysroot"
|
||||
CXX: "clang++ --target=${{ matrix.cc_target }} --sysroot=/tmp/sysroot"
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build (musl)
|
||||
if: matrix.musl
|
||||
run: |
|
||||
set -xeuo pipefail
|
||||
mkdir -p dist
|
||||
go build -v -trimpath -o dist/sing-box -tags "${BUILD_TAGS}" \
|
||||
-ldflags '-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0 -linkmode=external -extldflags "-static"' \
|
||||
./cmd/sing-box
|
||||
env:
|
||||
CGO_ENABLED: "1"
|
||||
GOOS: linux
|
||||
GOARCH: ${{ matrix.arch }}
|
||||
GOARM: ${{ matrix.goarm }}
|
||||
CC: "${{ matrix.cc_target }}-gcc"
|
||||
CXX: "${{ matrix.cc_target }}-g++"
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Set name
|
||||
run: |-
|
||||
DIR_NAME="sing-box-${{ needs.calculate_version.outputs.version }}-linux-${{ matrix.arch }}"
|
||||
if [[ -n "${{ matrix.goarm }}" ]]; then
|
||||
DIR_NAME="${DIR_NAME}v${{ matrix.goarm }}"
|
||||
fi
|
||||
DIR_NAME="${DIR_NAME}${{ matrix.suffix }}"
|
||||
echo "DIR_NAME=${DIR_NAME}" >> "${GITHUB_ENV}"
|
||||
- name: Archive
|
||||
run: |
|
||||
set -xeuo pipefail
|
||||
cd dist
|
||||
mkdir -p "${DIR_NAME}"
|
||||
cp ../LICENSE "${DIR_NAME}"
|
||||
cp sing-box "${DIR_NAME}"
|
||||
tar -czvf "${DIR_NAME}.tar.gz" "${DIR_NAME}"
|
||||
rm -r "${DIR_NAME}"
|
||||
- name: Cleanup
|
||||
run: rm dist/sing-box
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: binary-linux_${{ matrix.arch }}${{ matrix.goarm && format('v{0}', matrix.goarm) }}${{ matrix.suffix }}
|
||||
path: "dist"
|
||||
build_android:
|
||||
name: Build Android
|
||||
if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Android'
|
||||
@@ -687,6 +812,7 @@ jobs:
|
||||
- calculate_version
|
||||
- build
|
||||
- build_darwin
|
||||
- build_naive_linux
|
||||
- build_android
|
||||
- build_apple
|
||||
steps:
|
||||
|
||||
20
go.mod
20
go.mod
@@ -25,6 +25,8 @@ require (
|
||||
github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
|
||||
github.com/sagernet/cors v1.2.1
|
||||
github.com/sagernet/cronet-go v0.0.0-20251209141152-67502c396ef4
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20251209141601-d8f29fa5b269
|
||||
github.com/sagernet/fswatch v0.1.1
|
||||
github.com/sagernet/gomobile v0.1.8
|
||||
github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1
|
||||
@@ -104,6 +106,24 @@ require (
|
||||
github.com/prometheus-community/pro-bing v0.4.0 // indirect
|
||||
github.com/quic-go/qpack v0.6.0 // indirect
|
||||
github.com/safchain/ethtool v0.3.0 // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251209141152-67502c396ef4 // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
|
||||
github.com/sagernet/nftables v0.3.0-beta.4 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
|
||||
40
go.sum
40
go.sum
@@ -150,6 +150,46 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
|
||||
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
|
||||
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
|
||||
github.com/sagernet/cronet-go v0.0.0-20251209141152-67502c396ef4 h1:BfitgSppBdvn5gqwRLNA5Nhu67YvZxQKM9n3b1j1dgI=
|
||||
github.com/sagernet/cronet-go v0.0.0-20251209141152-67502c396ef4/go.mod h1:l5IZJLEWpDGJbrF0qBHgxAVBPsAxKOLa1BYDh6B2sdI=
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20251209141601-d8f29fa5b269 h1:dA79nNuqhUIGcw7DP3ifRXtJq39rE/UWZPfmQ6QS40w=
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20251209141601-d8f29fa5b269/go.mod h1:iLjzAv2hALBTxeC10i99ludp7jU6U3dw/yXbn0x3Ek8=
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251209141152-67502c396ef4 h1:eN1EtBxDDOvWW7Q0+a1UzBcnYs6u2EqgHgLYOPFwHSE=
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251209141152-67502c396ef4/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251209141152-67502c396ef4 h1:mQSHDat1i4Q5/+CvvRGTAAvT2vaYtci671/v5nC4FIM=
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251209141152-67502c396ef4/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251209141152-67502c396ef4 h1:TLVfFFNvGEPBZzFUecr1r32A0hsS6oeiEQWVQlDys+g=
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251209141152-67502c396ef4/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251209141152-67502c396ef4 h1:fCk6J6Shm+47s21JIpZuKLA0GD29HsGmUOCB3QkM7wc=
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251209141152-67502c396ef4/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251209141152-67502c396ef4 h1:lFaYkrltdVGtHoTtcTGCNP0lwGnwcCvZxJOCOyMtVcg=
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251209141152-67502c396ef4/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251209141152-67502c396ef4 h1:AdaoXuHTt5PnXUyDR/jcz2lBoA0osvOvORH9zUkTYtw=
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251209141152-67502c396ef4/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251209141152-67502c396ef4 h1:d5qnUEz2E3GBiZTf0FcUx6zH70rxqHN6rKifhv3ww0g=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251209141152-67502c396ef4/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251209141152-67502c396ef4 h1:SBgtdbs/VPOlKZmh+ieSvg1FAhqZgah27u9U1TNqzLk=
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251209141152-67502c396ef4/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251209141152-67502c396ef4 h1:N4hzsQK1RMT/1cZdlVXgWJLnThM1SqSd8xKqMGVe2BM=
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251209141152-67502c396ef4/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251209141152-67502c396ef4 h1:nnms0N+jFr78znmeTXNEZT3oa9M7QNJ3BZyKlh6xxPU=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251209141152-67502c396ef4/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251209141152-67502c396ef4 h1:tQsiwZZO13yXPVG10FRKRvABMzVMta3HTMEyrKGVitg=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251209141152-67502c396ef4/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251209141152-67502c396ef4 h1:/FAmfFm+22TIYAabODI6INOF6XgVoKiJrvo4JJk1QHI=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251209141152-67502c396ef4/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251209141152-67502c396ef4 h1:c/mtA2g+ScCBGBfa26hakxAVXurD4nhFW/RI0yb4KVM=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251209141152-67502c396ef4/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251209141152-67502c396ef4 h1:iRq0SWRDfCf1sKN9R4+5EHWYak0Zfla5li0jhRwBCBA=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251209141152-67502c396ef4/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251209141152-67502c396ef4 h1:GAQrA1S/cSNxmEeIcQU3jLVbPAU0GlJAM2iDcsKpphA=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251209141152-67502c396ef4/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
|
||||
github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251209141152-67502c396ef4 h1:Wix35ah7sy4oLTp06kjIqIX0CvtL2o05LXgaZLdDmzg=
|
||||
github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251209141152-67502c396ef4/go.mod h1:rnS7D+ULJX2PrP0Cy+05GS0mRZ2PP6+gVSroZKt8fjk=
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251209141152-67502c396ef4 h1:RA5r4IkF/Zvlq+4CwuWqZkb7xt3Fpj2HYUkzcSae1fQ=
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251209141152-67502c396ef4/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251209141152-67502c396ef4 h1:7lD3/vGXsmyfOuZN17yZe2u/UFVmOJpb9J7vz/cD0b8=
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251209141152-67502c396ef4/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
|
||||
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
|
||||
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
|
||||
github.com/sagernet/gomobile v0.1.8 h1:vXgoN0pjsMONAaYCTdsKBX2T1kxuS7sbT/mZ7PElGoo=
|
||||
|
||||
12
include/naive_outbound.go
Normal file
12
include/naive_outbound.go
Normal file
@@ -0,0 +1,12 @@
|
||||
//go:build with_naive_outbound
|
||||
|
||||
package include
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing-box/adapter/outbound"
|
||||
"github.com/sagernet/sing-box/protocol/naive"
|
||||
)
|
||||
|
||||
func registerNaiveOutbound(registry *outbound.Registry) {
|
||||
naive.RegisterOutbound(registry)
|
||||
}
|
||||
20
include/naive_outbound_stub.go
Normal file
20
include/naive_outbound_stub.go
Normal file
@@ -0,0 +1,20 @@
|
||||
//go:build !with_naive_outbound
|
||||
|
||||
package include
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/adapter/outbound"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
|
||||
func registerNaiveOutbound(registry *outbound.Registry) {
|
||||
outbound.Register[option.NaiveOutboundOptions](registry, C.TypeNaive, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.NaiveOutboundOptions) (adapter.Outbound, error) {
|
||||
return nil, E.New(`naive outbound is not included in this build, rebuild with -tags with_naive_outbound`)
|
||||
})
|
||||
}
|
||||
@@ -86,6 +86,7 @@ func OutboundRegistry() *outbound.Registry {
|
||||
shadowsocks.RegisterOutbound(registry)
|
||||
vmess.RegisterOutbound(registry)
|
||||
trojan.RegisterOutbound(registry)
|
||||
registerNaiveOutbound(registry)
|
||||
tor.RegisterOutbound(registry)
|
||||
ssh.RegisterOutbound(registry)
|
||||
shadowtls.RegisterOutbound(registry)
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package option
|
||||
|
||||
import "github.com/sagernet/sing/common/auth"
|
||||
import (
|
||||
"github.com/sagernet/sing/common/auth"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
)
|
||||
|
||||
type NaiveInboundOptions struct {
|
||||
ListenOptions
|
||||
@@ -8,3 +11,13 @@ type NaiveInboundOptions struct {
|
||||
Network NetworkList `json:"network,omitempty"`
|
||||
InboundTLSOptionsContainer
|
||||
}
|
||||
|
||||
type NaiveOutboundOptions struct {
|
||||
DialerOptions
|
||||
ServerOptions
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
InsecureConcurrency int `json:"insecure_concurrency,omitempty"`
|
||||
ExtraHeaders badoption.HTTPHeader `json:"extra_headers,omitempty"`
|
||||
OutboundTLSOptionsContainer
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ package naive
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
@@ -22,7 +22,11 @@ import (
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
aTLS "github.com/sagernet/sing/common/tls"
|
||||
sHttp "github.com/sagernet/sing/protocol/http"
|
||||
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
)
|
||||
|
||||
var ConfigureHTTP3ListenerFunc func(listener *listener.Listener, handler http.Handler, tlsConfig tls.ServerConfig, logger logger.Logger) (io.Closer, error)
|
||||
@@ -82,16 +86,11 @@ func (n *Inbound) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
var tlsConfig *tls.STDConfig
|
||||
if n.tlsConfig != nil {
|
||||
err := n.tlsConfig.Start()
|
||||
if err != nil {
|
||||
return E.Cause(err, "create TLS config")
|
||||
}
|
||||
tlsConfig, err = n.tlsConfig.STDConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if common.Contains(n.network, N.NetworkTCP) {
|
||||
tcpListener, err := n.listener.ListenTCP()
|
||||
@@ -99,20 +98,23 @@ func (n *Inbound) Start(stage adapter.StartStage) error {
|
||||
return err
|
||||
}
|
||||
n.httpServer = &http.Server{
|
||||
Handler: n,
|
||||
TLSConfig: tlsConfig,
|
||||
Handler: h2c.NewHandler(n, &http2.Server{}),
|
||||
BaseContext: func(listener net.Listener) context.Context {
|
||||
return n.ctx
|
||||
},
|
||||
}
|
||||
go func() {
|
||||
var sErr error
|
||||
if tlsConfig != nil {
|
||||
sErr = n.httpServer.ServeTLS(tcpListener, "", "")
|
||||
} else {
|
||||
sErr = n.httpServer.Serve(tcpListener)
|
||||
var listener net.Listener = tcpListener
|
||||
if n.tlsConfig != nil {
|
||||
if len(n.tlsConfig.NextProtos()) == 0 {
|
||||
n.tlsConfig.SetNextProtos([]string{http2.NextProtoTLS, "http/1.1"})
|
||||
} else if !common.Contains(n.tlsConfig.NextProtos(), http2.NextProtoTLS) {
|
||||
n.tlsConfig.SetNextProtos(append([]string{http2.NextProtoTLS}, n.tlsConfig.NextProtos()...))
|
||||
}
|
||||
listener = aTLS.NewListener(tcpListener, n.tlsConfig)
|
||||
}
|
||||
if sErr != nil && !E.IsClosedOrCanceled(sErr) {
|
||||
sErr := n.httpServer.Serve(listener)
|
||||
if sErr != nil && !errors.Is(sErr, http.ErrServerClosed) {
|
||||
n.logger.Error("http server serve error: ", sErr)
|
||||
}
|
||||
}()
|
||||
@@ -161,13 +163,16 @@ func (n *Inbound) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||
n.badRequest(ctx, request, E.New("authorization failed"))
|
||||
return
|
||||
}
|
||||
writer.Header().Set("Padding", generateNaivePaddingHeader())
|
||||
writer.Header().Set("Padding", generatePaddingHeader())
|
||||
writer.WriteHeader(http.StatusOK)
|
||||
writer.(http.Flusher).Flush()
|
||||
|
||||
hostPort := request.URL.Host
|
||||
hostPort := request.Header.Get("-connect-authority")
|
||||
if hostPort == "" {
|
||||
hostPort = request.Host
|
||||
hostPort = request.URL.Host
|
||||
if hostPort == "" {
|
||||
hostPort = request.Host
|
||||
}
|
||||
}
|
||||
source := sHttp.SourceAddress(request)
|
||||
destination := M.ParseSocksaddr(hostPort).Unwrap()
|
||||
@@ -178,9 +183,14 @@ func (n *Inbound) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||
n.badRequest(ctx, request, E.New("hijack failed"))
|
||||
return
|
||||
}
|
||||
n.newConnection(ctx, false, &naiveH1Conn{Conn: conn}, userName, source, destination)
|
||||
n.newConnection(ctx, false, &naiveConn{Conn: conn}, userName, source, destination)
|
||||
} else {
|
||||
n.newConnection(ctx, true, &naiveH2Conn{reader: request.Body, writer: writer, flusher: writer.(http.Flusher)}, userName, source, destination)
|
||||
n.newConnection(ctx, true, &naiveH2Conn{
|
||||
reader: request.Body,
|
||||
writer: writer,
|
||||
flusher: writer.(http.Flusher),
|
||||
remoteAddress: source,
|
||||
}, userName, source, destination)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,18 +246,3 @@ func rejectHTTP(writer http.ResponseWriter, statusCode int) {
|
||||
}
|
||||
conn.Close()
|
||||
}
|
||||
|
||||
func generateNaivePaddingHeader() string {
|
||||
paddingLen := rand.Intn(32) + 30
|
||||
padding := make([]byte, paddingLen)
|
||||
bits := rand.Uint64()
|
||||
for i := 0; i < 16; i++ {
|
||||
// Codes that won't be Huffman coded.
|
||||
padding[i] = "!#$()+<>?@[]^`{}"[bits&15]
|
||||
bits >>= 4
|
||||
}
|
||||
for i := 16; i < paddingLen; i++ {
|
||||
padding[i] = '~'
|
||||
}
|
||||
return string(padding)
|
||||
}
|
||||
|
||||
@@ -7,417 +7,242 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/baderror"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
"github.com/sagernet/sing/common/rw"
|
||||
)
|
||||
|
||||
const kFirstPaddings = 8
|
||||
const paddingCount = 8
|
||||
|
||||
type naiveH1Conn struct {
|
||||
net.Conn
|
||||
func generatePaddingHeader() string {
|
||||
paddingLen := rand.Intn(32) + 30
|
||||
padding := make([]byte, paddingLen)
|
||||
bits := rand.Uint64()
|
||||
for i := 0; i < 16; i++ {
|
||||
padding[i] = "!#$()+<>?@[]^`{}"[bits&15]
|
||||
bits >>= 4
|
||||
}
|
||||
for i := 16; i < paddingLen; i++ {
|
||||
padding[i] = '~'
|
||||
}
|
||||
return string(padding)
|
||||
}
|
||||
|
||||
type paddingConn struct {
|
||||
readPadding int
|
||||
writePadding int
|
||||
readRemaining int
|
||||
paddingRemaining int
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) Read(p []byte) (n int, err error) {
|
||||
n, err = c.read(p)
|
||||
return n, wrapHttpError(err)
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) read(p []byte) (n int, err error) {
|
||||
if c.readRemaining > 0 {
|
||||
if len(p) > c.readRemaining {
|
||||
p = p[:c.readRemaining]
|
||||
func (p *paddingConn) readWithPadding(reader io.Reader, buffer []byte) (n int, err error) {
|
||||
if p.readRemaining > 0 {
|
||||
if len(buffer) > p.readRemaining {
|
||||
buffer = buffer[:p.readRemaining]
|
||||
}
|
||||
n, err = c.Conn.Read(p)
|
||||
n, err = reader.Read(buffer)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.readRemaining -= n
|
||||
p.readRemaining -= n
|
||||
return
|
||||
}
|
||||
if c.paddingRemaining > 0 {
|
||||
err = rw.SkipN(c.Conn, c.paddingRemaining)
|
||||
if p.paddingRemaining > 0 {
|
||||
err = rw.SkipN(reader, p.paddingRemaining)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.paddingRemaining = 0
|
||||
p.paddingRemaining = 0
|
||||
}
|
||||
if c.readPadding < kFirstPaddings {
|
||||
var paddingHdr []byte
|
||||
if len(p) >= 3 {
|
||||
paddingHdr = p[:3]
|
||||
if p.readPadding < paddingCount {
|
||||
var paddingHeader []byte
|
||||
if len(buffer) >= 3 {
|
||||
paddingHeader = buffer[:3]
|
||||
} else {
|
||||
paddingHdr = make([]byte, 3)
|
||||
paddingHeader = make([]byte, 3)
|
||||
}
|
||||
_, err = io.ReadFull(c.Conn, paddingHdr)
|
||||
_, err = io.ReadFull(reader, paddingHeader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
originalDataSize := int(binary.BigEndian.Uint16(paddingHdr[:2]))
|
||||
paddingSize := int(paddingHdr[2])
|
||||
if len(p) > originalDataSize {
|
||||
p = p[:originalDataSize]
|
||||
originalDataSize := int(binary.BigEndian.Uint16(paddingHeader[:2]))
|
||||
paddingSize := int(paddingHeader[2])
|
||||
if len(buffer) > originalDataSize {
|
||||
buffer = buffer[:originalDataSize]
|
||||
}
|
||||
n, err = c.Conn.Read(p)
|
||||
n, err = reader.Read(buffer)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.readPadding++
|
||||
c.readRemaining = originalDataSize - n
|
||||
c.paddingRemaining = paddingSize
|
||||
p.readPadding++
|
||||
p.readRemaining = originalDataSize - n
|
||||
p.paddingRemaining = paddingSize
|
||||
return
|
||||
}
|
||||
return c.Conn.Read(p)
|
||||
return reader.Read(buffer)
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) Write(p []byte) (n int, err error) {
|
||||
for pLen := len(p); pLen > 0; {
|
||||
var data []byte
|
||||
if pLen > 65535 {
|
||||
data = p[:65535]
|
||||
p = p[65535:]
|
||||
pLen -= 65535
|
||||
} else {
|
||||
data = p
|
||||
pLen = 0
|
||||
}
|
||||
var writeN int
|
||||
writeN, err = c.write(data)
|
||||
n += writeN
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return n, wrapHttpError(err)
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) write(p []byte) (n int, err error) {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
func (p *paddingConn) writeWithPadding(writer io.Writer, data []byte) (n int, err error) {
|
||||
if p.writePadding < paddingCount {
|
||||
paddingSize := rand.Intn(256)
|
||||
|
||||
buffer := buf.NewSize(3 + len(p) + paddingSize)
|
||||
buffer := buf.NewSize(3 + len(data) + paddingSize)
|
||||
defer buffer.Release()
|
||||
header := buffer.Extend(3)
|
||||
binary.BigEndian.PutUint16(header, uint16(len(p)))
|
||||
binary.BigEndian.PutUint16(header, uint16(len(data)))
|
||||
header[2] = byte(paddingSize)
|
||||
|
||||
common.Must1(buffer.Write(p))
|
||||
_, err = c.Conn.Write(buffer.Bytes())
|
||||
common.Must1(buffer.Write(data))
|
||||
_, err = writer.Write(buffer.Bytes())
|
||||
if err == nil {
|
||||
n = len(p)
|
||||
n = len(data)
|
||||
}
|
||||
c.writePadding++
|
||||
p.writePadding++
|
||||
return
|
||||
}
|
||||
return c.Conn.Write(p)
|
||||
return writer.Write(data)
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) FrontHeadroom() int {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
return 3
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) RearHeadroom() int {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
return 255
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) WriterMTU() int {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
return 65535
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) WriteBuffer(buffer *buf.Buffer) error {
|
||||
defer buffer.Release()
|
||||
if c.writePadding < kFirstPaddings {
|
||||
func (p *paddingConn) writeBufferWithPadding(writer io.Writer, buffer *buf.Buffer) error {
|
||||
if p.writePadding < paddingCount {
|
||||
bufferLen := buffer.Len()
|
||||
if bufferLen > 65535 {
|
||||
return common.Error(c.Write(buffer.Bytes()))
|
||||
_, err := p.writeChunked(writer, buffer.Bytes())
|
||||
return err
|
||||
}
|
||||
paddingSize := rand.Intn(256)
|
||||
header := buffer.ExtendHeader(3)
|
||||
binary.BigEndian.PutUint16(header, uint16(bufferLen))
|
||||
header[2] = byte(paddingSize)
|
||||
buffer.Extend(paddingSize)
|
||||
c.writePadding++
|
||||
p.writePadding++
|
||||
}
|
||||
return wrapHttpError(common.Error(c.Conn.Write(buffer.Bytes())))
|
||||
return common.Error(writer.Write(buffer.Bytes()))
|
||||
}
|
||||
|
||||
// FIXME
|
||||
/*func (c *naiveH1Conn) WriteTo(w io.Writer) (n int64, err error) {
|
||||
if c.readPadding < kFirstPaddings {
|
||||
n, err = bufio.WriteToN(c, w, kFirstPaddings-c.readPadding)
|
||||
} else {
|
||||
n, err = bufio.Copy(w, c.Conn)
|
||||
}
|
||||
return n, wrapHttpError(err)
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
n, err = bufio.ReadFromN(c, r, kFirstPaddings-c.writePadding)
|
||||
} else {
|
||||
n, err = bufio.Copy(c.Conn, r)
|
||||
}
|
||||
return n, wrapHttpError(err)
|
||||
}
|
||||
*/
|
||||
|
||||
func (c *naiveH1Conn) Upstream() any {
|
||||
return c.Conn
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) ReaderReplaceable() bool {
|
||||
return c.readPadding == kFirstPaddings
|
||||
}
|
||||
|
||||
func (c *naiveH1Conn) WriterReplaceable() bool {
|
||||
return c.writePadding == kFirstPaddings
|
||||
}
|
||||
|
||||
type naiveH2Conn struct {
|
||||
reader io.Reader
|
||||
writer io.Writer
|
||||
flusher http.Flusher
|
||||
rAddr net.Addr
|
||||
readPadding int
|
||||
writePadding int
|
||||
readRemaining int
|
||||
paddingRemaining int
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) Read(p []byte) (n int, err error) {
|
||||
n, err = c.read(p)
|
||||
return n, wrapHttpError(err)
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) read(p []byte) (n int, err error) {
|
||||
if c.readRemaining > 0 {
|
||||
if len(p) > c.readRemaining {
|
||||
p = p[:c.readRemaining]
|
||||
}
|
||||
n, err = c.reader.Read(p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.readRemaining -= n
|
||||
return
|
||||
}
|
||||
if c.paddingRemaining > 0 {
|
||||
err = rw.SkipN(c.reader, c.paddingRemaining)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.paddingRemaining = 0
|
||||
}
|
||||
if c.readPadding < kFirstPaddings {
|
||||
var paddingHdr []byte
|
||||
if len(p) >= 3 {
|
||||
paddingHdr = p[:3]
|
||||
func (p *paddingConn) writeChunked(writer io.Writer, data []byte) (n int, err error) {
|
||||
for len(data) > 0 {
|
||||
var chunk []byte
|
||||
if len(data) > 65535 {
|
||||
chunk = data[:65535]
|
||||
data = data[65535:]
|
||||
} else {
|
||||
paddingHdr = make([]byte, 3)
|
||||
chunk = data
|
||||
data = nil
|
||||
}
|
||||
_, err = io.ReadFull(c.reader, paddingHdr)
|
||||
var written int
|
||||
written, err = p.writeWithPadding(writer, chunk)
|
||||
n += written
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
originalDataSize := int(binary.BigEndian.Uint16(paddingHdr[:2]))
|
||||
paddingSize := int(paddingHdr[2])
|
||||
if len(p) > originalDataSize {
|
||||
p = p[:originalDataSize]
|
||||
}
|
||||
n, err = c.reader.Read(p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.readPadding++
|
||||
c.readRemaining = originalDataSize - n
|
||||
c.paddingRemaining = paddingSize
|
||||
return
|
||||
}
|
||||
return c.reader.Read(p)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) Write(p []byte) (n int, err error) {
|
||||
for pLen := len(p); pLen > 0; {
|
||||
var data []byte
|
||||
if pLen > 65535 {
|
||||
data = p[:65535]
|
||||
p = p[65535:]
|
||||
pLen -= 65535
|
||||
} else {
|
||||
data = p
|
||||
pLen = 0
|
||||
}
|
||||
var writeN int
|
||||
writeN, err = c.write(data)
|
||||
n += writeN
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
c.flusher.Flush()
|
||||
}
|
||||
return n, wrapHttpError(err)
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) write(p []byte) (n int, err error) {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
paddingSize := rand.Intn(256)
|
||||
|
||||
buffer := buf.NewSize(3 + len(p) + paddingSize)
|
||||
defer buffer.Release()
|
||||
header := buffer.Extend(3)
|
||||
binary.BigEndian.PutUint16(header, uint16(len(p)))
|
||||
header[2] = byte(paddingSize)
|
||||
|
||||
common.Must1(buffer.Write(p))
|
||||
_, err = c.writer.Write(buffer.Bytes())
|
||||
if err == nil {
|
||||
n = len(p)
|
||||
}
|
||||
c.writePadding++
|
||||
return
|
||||
}
|
||||
return c.writer.Write(p)
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) FrontHeadroom() int {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
func (p *paddingConn) frontHeadroom() int {
|
||||
if p.writePadding < paddingCount {
|
||||
return 3
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) RearHeadroom() int {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
func (p *paddingConn) rearHeadroom() int {
|
||||
if p.writePadding < paddingCount {
|
||||
return 255
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) WriterMTU() int {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
func (p *paddingConn) writerMTU() int {
|
||||
if p.writePadding < paddingCount {
|
||||
return 65535
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (p *paddingConn) readerReplaceable() bool {
|
||||
return p.readPadding == paddingCount
|
||||
}
|
||||
|
||||
func (p *paddingConn) writerReplaceable() bool {
|
||||
return p.writePadding == paddingCount
|
||||
}
|
||||
|
||||
type naiveConn struct {
|
||||
net.Conn
|
||||
paddingConn
|
||||
}
|
||||
|
||||
func (c *naiveConn) Read(p []byte) (n int, err error) {
|
||||
n, err = c.readWithPadding(c.Conn, p)
|
||||
return n, baderror.WrapH2(err)
|
||||
}
|
||||
|
||||
func (c *naiveConn) Write(p []byte) (n int, err error) {
|
||||
n, err = c.writeChunked(c.Conn, p)
|
||||
return n, baderror.WrapH2(err)
|
||||
}
|
||||
|
||||
func (c *naiveConn) WriteBuffer(buffer *buf.Buffer) error {
|
||||
defer buffer.Release()
|
||||
err := c.writeBufferWithPadding(c.Conn, buffer)
|
||||
return baderror.WrapH2(err)
|
||||
}
|
||||
|
||||
func (c *naiveConn) FrontHeadroom() int { return c.frontHeadroom() }
|
||||
func (c *naiveConn) RearHeadroom() int { return c.rearHeadroom() }
|
||||
func (c *naiveConn) WriterMTU() int { return c.writerMTU() }
|
||||
func (c *naiveConn) Upstream() any { return c.Conn }
|
||||
func (c *naiveConn) ReaderReplaceable() bool { return c.readerReplaceable() }
|
||||
func (c *naiveConn) WriterReplaceable() bool { return c.writerReplaceable() }
|
||||
|
||||
type naiveH2Conn struct {
|
||||
reader io.Reader
|
||||
writer io.Writer
|
||||
flusher http.Flusher
|
||||
remoteAddress net.Addr
|
||||
paddingConn
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) Read(p []byte) (n int, err error) {
|
||||
n, err = c.readWithPadding(c.reader, p)
|
||||
return n, baderror.WrapH2(err)
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) Write(p []byte) (n int, err error) {
|
||||
n, err = c.writeChunked(c.writer, p)
|
||||
if err == nil {
|
||||
c.flusher.Flush()
|
||||
}
|
||||
return n, baderror.WrapH2(err)
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) WriteBuffer(buffer *buf.Buffer) error {
|
||||
defer buffer.Release()
|
||||
if c.writePadding < kFirstPaddings {
|
||||
bufferLen := buffer.Len()
|
||||
if bufferLen > 65535 {
|
||||
return common.Error(c.Write(buffer.Bytes()))
|
||||
}
|
||||
paddingSize := rand.Intn(256)
|
||||
header := buffer.ExtendHeader(3)
|
||||
binary.BigEndian.PutUint16(header, uint16(bufferLen))
|
||||
header[2] = byte(paddingSize)
|
||||
buffer.Extend(paddingSize)
|
||||
c.writePadding++
|
||||
}
|
||||
err := common.Error(c.writer.Write(buffer.Bytes()))
|
||||
err := c.writeBufferWithPadding(c.writer, buffer)
|
||||
if err == nil {
|
||||
c.flusher.Flush()
|
||||
}
|
||||
return wrapHttpError(err)
|
||||
return baderror.WrapH2(err)
|
||||
}
|
||||
|
||||
// FIXME
|
||||
/*func (c *naiveH2Conn) WriteTo(w io.Writer) (n int64, err error) {
|
||||
if c.readPadding < kFirstPaddings {
|
||||
n, err = bufio.WriteToN(c, w, kFirstPaddings-c.readPadding)
|
||||
} else {
|
||||
n, err = bufio.Copy(w, c.reader)
|
||||
}
|
||||
return n, wrapHttpError(err)
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
if c.writePadding < kFirstPaddings {
|
||||
n, err = bufio.ReadFromN(c, r, kFirstPaddings-c.writePadding)
|
||||
} else {
|
||||
n, err = bufio.Copy(c.writer, r)
|
||||
}
|
||||
return n, wrapHttpError(err)
|
||||
}*/
|
||||
|
||||
func (c *naiveH2Conn) Close() error {
|
||||
return common.Close(
|
||||
c.reader,
|
||||
c.writer,
|
||||
)
|
||||
return common.Close(c.reader, c.writer)
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) LocalAddr() net.Addr {
|
||||
return M.Socksaddr{}
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) RemoteAddr() net.Addr {
|
||||
return c.rAddr
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) SetDeadline(t time.Time) error {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) SetReadDeadline(t time.Time) error {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) SetWriteDeadline(t time.Time) error {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) NeedAdditionalReadDeadline() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) UpstreamReader() any {
|
||||
return c.reader
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) UpstreamWriter() any {
|
||||
return c.writer
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) ReaderReplaceable() bool {
|
||||
return c.readPadding == kFirstPaddings
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) WriterReplaceable() bool {
|
||||
return c.writePadding == kFirstPaddings
|
||||
}
|
||||
|
||||
func wrapHttpError(err error) error {
|
||||
if err == nil {
|
||||
return err
|
||||
}
|
||||
if strings.Contains(err.Error(), "client disconnected") {
|
||||
return net.ErrClosed
|
||||
}
|
||||
if strings.Contains(err.Error(), "body closed by handler") {
|
||||
return net.ErrClosed
|
||||
}
|
||||
if strings.Contains(err.Error(), "canceled with error code 268") {
|
||||
return io.EOF
|
||||
}
|
||||
return err
|
||||
}
|
||||
func (c *naiveH2Conn) LocalAddr() net.Addr { return M.Socksaddr{} }
|
||||
func (c *naiveH2Conn) RemoteAddr() net.Addr { return c.remoteAddress }
|
||||
func (c *naiveH2Conn) SetDeadline(t time.Time) error { return os.ErrInvalid }
|
||||
func (c *naiveH2Conn) SetReadDeadline(t time.Time) error { return os.ErrInvalid }
|
||||
func (c *naiveH2Conn) SetWriteDeadline(t time.Time) error { return os.ErrInvalid }
|
||||
func (c *naiveH2Conn) NeedAdditionalReadDeadline() bool { return true }
|
||||
func (c *naiveH2Conn) UpstreamReader() any { return c.reader }
|
||||
func (c *naiveH2Conn) UpstreamWriter() any { return c.writer }
|
||||
func (c *naiveH2Conn) FrontHeadroom() int { return c.frontHeadroom() }
|
||||
func (c *naiveH2Conn) RearHeadroom() int { return c.rearHeadroom() }
|
||||
func (c *naiveH2Conn) WriterMTU() int { return c.writerMTU() }
|
||||
func (c *naiveH2Conn) ReaderReplaceable() bool { return c.readerReplaceable() }
|
||||
func (c *naiveH2Conn) WriterReplaceable() bool { return c.writerReplaceable() }
|
||||
|
||||
179
protocol/naive/outbound.go
Normal file
179
protocol/naive/outbound.go
Normal file
@@ -0,0 +1,179 @@
|
||||
//go:build with_naive_outbound
|
||||
|
||||
package naive
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/cronet-go"
|
||||
_ "github.com/sagernet/cronet-go/all"
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/adapter/outbound"
|
||||
"github.com/sagernet/sing-box/common/dialer"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
func RegisterOutbound(registry *outbound.Registry) {
|
||||
outbound.Register[option.NaiveOutboundOptions](registry, C.TypeNaive, NewOutbound)
|
||||
}
|
||||
|
||||
type Outbound struct {
|
||||
outbound.Adapter
|
||||
ctx context.Context
|
||||
logger logger.ContextLogger
|
||||
client *cronet.NaiveClient
|
||||
}
|
||||
|
||||
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.NaiveOutboundOptions) (adapter.Outbound, error) {
|
||||
if options.TLS == nil || !options.TLS.Enabled {
|
||||
return nil, C.ErrTLSRequired
|
||||
}
|
||||
if options.TLS.DisableSNI {
|
||||
return nil, E.New("disable_sni is not supported on naive outbound")
|
||||
}
|
||||
if options.TLS.Insecure {
|
||||
return nil, E.New("insecure is not supported on naive outbound")
|
||||
}
|
||||
if len(options.TLS.ALPN) > 0 {
|
||||
return nil, E.New("alpn is not supported on naive outbound")
|
||||
}
|
||||
if options.TLS.MinVersion != "" {
|
||||
return nil, E.New("min_version is not supported on naive outbound")
|
||||
}
|
||||
if options.TLS.MaxVersion != "" {
|
||||
return nil, E.New("max_version is not supported on naive outbound")
|
||||
}
|
||||
if len(options.TLS.CipherSuites) > 0 {
|
||||
return nil, E.New("cipher_suites is not supported on naive outbound")
|
||||
}
|
||||
if len(options.TLS.CurvePreferences) > 0 {
|
||||
return nil, E.New("curve_preferences is not supported on naive outbound")
|
||||
}
|
||||
if len(options.TLS.ClientCertificate) > 0 || options.TLS.ClientCertificatePath != "" {
|
||||
return nil, E.New("client_certificate is not supported on naive outbound")
|
||||
}
|
||||
if len(options.TLS.ClientKey) > 0 || options.TLS.ClientKeyPath != "" {
|
||||
return nil, E.New("client_key is not supported on naive outbound")
|
||||
}
|
||||
if options.TLS.Fragment || options.TLS.RecordFragment {
|
||||
return nil, E.New("fragment is not supported on naive outbound")
|
||||
}
|
||||
if options.TLS.KernelTx || options.TLS.KernelRx {
|
||||
return nil, E.New("kernel TLS is not supported on naive outbound")
|
||||
}
|
||||
if options.TLS.ECH != nil && options.TLS.ECH.Enabled {
|
||||
return nil, E.New("ECH is not currently supported on naive outbound")
|
||||
}
|
||||
if options.TLS.UTLS != nil && options.TLS.UTLS.Enabled {
|
||||
return nil, E.New("uTLS is not supported on naive outbound")
|
||||
}
|
||||
if options.TLS.Reality != nil && options.TLS.Reality.Enabled {
|
||||
return nil, E.New("reality is not supported on naive outbound")
|
||||
}
|
||||
|
||||
serverAddress := options.ServerOptions.Build()
|
||||
|
||||
var serverName string
|
||||
if options.TLS.ServerName != "" {
|
||||
serverName = options.TLS.ServerName
|
||||
} else {
|
||||
serverName = serverAddress.AddrString()
|
||||
}
|
||||
|
||||
outboundDialer, err := dialer.NewWithOptions(dialer.Options{
|
||||
Context: ctx,
|
||||
Options: options.DialerOptions,
|
||||
RemoteIsDomain: true,
|
||||
ResolverOnDetour: true,
|
||||
NewDialer: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var trustedRootCertificates string
|
||||
if len(options.TLS.Certificate) > 0 {
|
||||
trustedRootCertificates = strings.Join(options.TLS.Certificate, "\n")
|
||||
} else if options.TLS.CertificatePath != "" {
|
||||
content, err := os.ReadFile(options.TLS.CertificatePath)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "read certificate")
|
||||
}
|
||||
trustedRootCertificates = string(content)
|
||||
}
|
||||
|
||||
extraHeaders := make(map[string]string)
|
||||
for key, values := range options.ExtraHeaders.Build() {
|
||||
if len(values) > 0 {
|
||||
extraHeaders[key] = values[0]
|
||||
}
|
||||
}
|
||||
|
||||
client, err := cronet.NewNaiveClient(cronet.NaiveClientConfig{
|
||||
Context: ctx,
|
||||
ServerAddress: serverAddress,
|
||||
ServerName: serverName,
|
||||
Username: options.Username,
|
||||
Password: options.Password,
|
||||
Concurrency: options.InsecureConcurrency,
|
||||
ExtraHeaders: extraHeaders,
|
||||
TrustedRootCertificates: trustedRootCertificates,
|
||||
CertificatePublicKeySHA256: options.TLS.CertificatePublicKeySHA256,
|
||||
Dialer: outboundDialer,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Outbound{
|
||||
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeNaive, tag, []string{N.NetworkTCP}, options.DialerOptions),
|
||||
ctx: ctx,
|
||||
logger: logger,
|
||||
client: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (o *Outbound) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
err := o.client.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.logger.Info("NaiveProxy started, version: ", o.client.Engine().Version())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
ctx, metadata := adapter.ExtendContext(ctx)
|
||||
metadata.Outbound = o.Tag()
|
||||
metadata.Destination = destination
|
||||
o.logger.InfoContext(ctx, "outbound connection to ", destination)
|
||||
return o.client.DialContext(ctx, destination)
|
||||
}
|
||||
|
||||
func (o *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
|
||||
func (o *Outbound) Close() error {
|
||||
return o.client.Close()
|
||||
}
|
||||
|
||||
func (o *Outbound) StartNetLogToFile(fileName string, logAll bool) bool {
|
||||
return o.client.Engine().StartNetLogToFile(fileName, logAll)
|
||||
}
|
||||
|
||||
func (o *Outbound) StopNetLog() {
|
||||
o.client.Engine().StopNetLog()
|
||||
}
|
||||
@@ -88,7 +88,7 @@ func testSuit(t *testing.T, clientPort uint16, testPort uint16) {
|
||||
func testQUIC(t *testing.T, clientPort uint16) {
|
||||
dialer := socks.NewClient(N.SystemDialer, M.ParseSocksaddrHostPort("127.0.0.1", clientPort), socks.Version5, "", "")
|
||||
client := &http.Client{
|
||||
Transport: &http3.RoundTripper{
|
||||
Transport: &http3.Transport{
|
||||
Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (*quic.Conn, error) {
|
||||
destination := M.ParseSocksaddr(addr)
|
||||
udpConn, err := dialer.DialContext(ctx, N.NetworkUDP, destination)
|
||||
|
||||
85
test/go.mod
85
test/go.mod
@@ -1,8 +1,6 @@
|
||||
module test
|
||||
|
||||
go 1.23.1
|
||||
|
||||
toolchain go1.24.0
|
||||
go 1.24.7
|
||||
|
||||
require github.com/sagernet/sing-box v0.0.0
|
||||
|
||||
@@ -12,15 +10,15 @@ require (
|
||||
github.com/docker/docker v27.3.1+incompatible
|
||||
github.com/docker/go-connections v0.5.0
|
||||
github.com/gofrs/uuid/v5 v5.3.2
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1
|
||||
github.com/sagernet/sing v0.7.8-0.20250909124511-ab3827767cea
|
||||
github.com/sagernet/sing-quic v0.5.2-0.20250909100920-da23407a63d5
|
||||
github.com/sagernet/quic-go v0.57.1-sing-box-mod.1
|
||||
github.com/sagernet/sing v0.8.0-beta.6.0.20251207063731-56fd482ce1c6
|
||||
github.com/sagernet/sing-quic v0.6.0-beta.5
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1
|
||||
github.com/spyzhov/ajson v0.9.4
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
go.uber.org/goleak v1.3.0
|
||||
golang.org/x/net v0.43.0
|
||||
golang.org/x/net v0.44.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -30,14 +28,16 @@ require (
|
||||
github.com/akutz/memconn v0.1.0 // indirect
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/anytls/sing-anytls v0.0.8 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.13.0 // indirect
|
||||
github.com/anthropics/anthropic-sdk-go v1.14.0 // indirect
|
||||
github.com/anytls/sing-anytls v0.0.11 // indirect
|
||||
github.com/caddyserver/certmagic v0.23.0 // indirect
|
||||
github.com/caddyserver/zerossl v0.1.3 // indirect
|
||||
github.com/coder/websocket v1.8.13 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect
|
||||
github.com/cretz/bine v0.2.0 // indirect
|
||||
github.com/database64128/netx-go v0.1.1 // indirect
|
||||
github.com/database64128/tfo-go/v2 v2.3.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
|
||||
github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect
|
||||
@@ -46,10 +46,10 @@ require (
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gaissmai/bart v0.11.1 // indirect
|
||||
github.com/gaissmai/bart v0.18.0 // indirect
|
||||
github.com/go-chi/chi/v5 v5.2.2 // indirect
|
||||
github.com/go-chi/render v1.0.3 // indirect
|
||||
github.com/go-json-experiment/json v0.0.0-20250103232110-6a9a0fde9288 // indirect
|
||||
github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
@@ -62,16 +62,14 @@ require (
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/csrf v1.7.3-0.20250123201450-9dd6af1f6d30 // indirect
|
||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||
github.com/hashicorp/yamux v0.1.2 // indirect
|
||||
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
|
||||
github.com/illarion/gonotify/v2 v2.0.3 // indirect
|
||||
github.com/illarion/gonotify/v3 v3.0.2 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250417080101-5f8cf70e8c5f // indirect
|
||||
github.com/jsimonetti/rtnetlink v1.4.0 // indirect
|
||||
github.com/keybase/go-keychain v0.0.1 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a // indirect
|
||||
github.com/libdns/alidns v1.0.5-libdns.v1.beta1 // indirect
|
||||
github.com/libdns/cloudflare v0.2.2-0.20250708034226-c574dccb31a6 // indirect
|
||||
github.com/libdns/libdns v1.1.0 // indirect
|
||||
@@ -80,8 +78,7 @@ require (
|
||||
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect
|
||||
github.com/mdlayher/sdnotify v1.0.0 // indirect
|
||||
github.com/mdlayher/socket v0.5.1 // indirect
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 // indirect
|
||||
github.com/metacubex/utls v1.8.0 // indirect
|
||||
github.com/metacubex/utls v1.8.3 // indirect
|
||||
github.com/mholt/acmez/v3 v3.1.2 // indirect
|
||||
github.com/miekg/dns v1.1.67 // indirect
|
||||
github.com/mitchellh/go-ps v1.0.0 // indirect
|
||||
@@ -94,30 +91,54 @@ require (
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus-community/pro-bing v0.4.0 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/qpack v0.6.0 // indirect
|
||||
github.com/safchain/ethtool v0.3.0 // indirect
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect
|
||||
github.com/sagernet/cors v1.2.1 // indirect
|
||||
github.com/sagernet/cronet-go v0.0.0-20251209105322-5fda1568c42f // indirect
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20251209105322-5fda1568c42f // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251209104729-fbe170b6824a // indirect
|
||||
github.com/sagernet/fswatch v0.1.1 // indirect
|
||||
github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237 // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
|
||||
github.com/sagernet/nftables v0.3.0-beta.4 // indirect
|
||||
github.com/sagernet/sing-mux v0.3.3 // indirect
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 // indirect
|
||||
github.com/sagernet/sing-tun v0.8.0-beta.1.0.20250909100419-a8cb01e6df93 // indirect
|
||||
github.com/sagernet/sing-tun v0.8.0-beta.11 // indirect
|
||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 // indirect
|
||||
github.com/sagernet/smux v1.5.34-mod.2 // indirect
|
||||
github.com/sagernet/tailscale v1.80.3-sing-box-1.13-mod.1 // indirect
|
||||
github.com/sagernet/wireguard-go v0.0.1-beta.7 // indirect
|
||||
github.com/sagernet/tailscale v1.86.5-sing-box-1.13-mod.4 // indirect
|
||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288 // indirect
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect
|
||||
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect
|
||||
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect
|
||||
github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4 // indirect
|
||||
github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect
|
||||
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a // indirect
|
||||
github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 // indirect
|
||||
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect
|
||||
github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 // indirect
|
||||
github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da // indirect
|
||||
github.com/tidwall/gjson v1.18.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
@@ -133,15 +154,15 @@ require (
|
||||
go.uber.org/zap/exp v0.3.0 // indirect
|
||||
go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/crypto v0.41.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
|
||||
golang.org/x/mod v0.27.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
golang.org/x/term v0.34.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
golang.org/x/time v0.9.0 // indirect
|
||||
golang.org/x/tools v0.36.0 // indirect
|
||||
golang.org/x/crypto v0.42.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250911091902-df9299821621 // indirect
|
||||
golang.org/x/mod v0.28.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.36.0 // indirect
|
||||
golang.org/x/term v0.35.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.37.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect
|
||||
|
||||
172
test/go.sum
172
test/go.sum
@@ -12,10 +12,10 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7V
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/anytls/sing-anytls v0.0.8 h1:1u/fnH1HoeeMV5mX7/eUOjLBvPdkd1UJRmXiRi6Vymc=
|
||||
github.com/anytls/sing-anytls v0.0.8/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8=
|
||||
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
|
||||
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/anthropics/anthropic-sdk-go v1.14.0 h1:EzNQvnZlaDHe2UPkoUySDz3ixRgNbwKdH8KtFpv7pi4=
|
||||
github.com/anthropics/anthropic-sdk-go v1.14.0/go.mod h1:WTz31rIUHUHqai2UslPpw5CwXrQP3geYBioRV4WOLvE=
|
||||
github.com/anytls/sing-anytls v0.0.11 h1:w8e9Uj1oP3m4zxkyZDewPk0EcQbvVxb7Nn+rapEx4fc=
|
||||
github.com/anytls/sing-anytls v0.0.11/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8=
|
||||
github.com/caddyserver/certmagic v0.23.0 h1:CfpZ/50jMfG4+1J/u2LV6piJq4HOfO6ppOnOf7DkFEU=
|
||||
github.com/caddyserver/certmagic v0.23.0/go.mod h1:9mEZIWqqWoI+Gf+4Trh04MOVPD0tGSxtqsxg87hAIH4=
|
||||
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
|
||||
@@ -32,6 +32,10 @@ github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6
|
||||
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
||||
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
|
||||
github.com/database64128/netx-go v0.1.1 h1:dT5LG7Gs7zFZBthFBbzWE6K8wAHjSNAaK7wCYZT7NzM=
|
||||
github.com/database64128/netx-go v0.1.1/go.mod h1:LNlYVipaYkQArRFDNNJ02VkNV+My9A5XR/IGS7sIBQc=
|
||||
github.com/database64128/tfo-go/v2 v2.3.1 h1:EGE+ELd5/AQ0X6YBlQ9RgKs8+kciNhgN3d8lRvfEJQw=
|
||||
github.com/database64128/tfo-go/v2 v2.3.1/go.mod h1:k9wcpg/8i5zenspBkc9jUEYehpZZccBnCElzOJB++bU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
@@ -54,16 +58,16 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/gaissmai/bart v0.11.1 h1:5Uv5XwsaFBRo4E5VBcb9TzY8B7zxFf+U7isDxqOrRfc=
|
||||
github.com/gaissmai/bart v0.11.1/go.mod h1:KHeYECXQiBjTzQz/om2tqn3sZF1J7hw9m6z41ftj3fg=
|
||||
github.com/gaissmai/bart v0.18.0 h1:jQLBT/RduJu0pv/tLwXE+xKPgtWJejbxuXAR+wLJafo=
|
||||
github.com/gaissmai/bart v0.18.0/go.mod h1:JJzMAhNF5Rjo4SF4jWBrANuJfqY+FvsFhW7t1UZJ+XY=
|
||||
github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I=
|
||||
github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo=
|
||||
github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
|
||||
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
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-json-experiment/json v0.0.0-20250103232110-6a9a0fde9288 h1:KbX3Z3CgiYlbaavUq3Cj9/MjpO+88S7/AGXzynVDv84=
|
||||
github.com/go-json-experiment/json v0.0.0-20250103232110-6a9a0fde9288/go.mod h1:BWmvoE1Xia34f3l/ibJweyhrT+aROb/FQ6d+37F0e2s=
|
||||
github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 h1:F8d1AJ6M9UQCavhwmO6ZsrYLfG8zVFWfEfMS2MXPkSY=
|
||||
github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
@@ -89,36 +93,30 @@ github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdFk6Vl1yPGtSRtwGpVkWyZww1OCil2MI=
|
||||
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/csrf v1.7.3-0.20250123201450-9dd6af1f6d30 h1:fiJdrgVBkjZ5B1HJ2WQwNOaXB+QyYcNXTA3t1XYLz0M=
|
||||
github.com/gorilla/csrf v1.7.3-0.20250123201450-9dd6af1f6d30/go.mod h1:F1Fj3KG23WYHE6gozCmBAezKookxbIvUJT+121wTuLk=
|
||||
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
||||
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
|
||||
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
|
||||
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
|
||||
github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU=
|
||||
github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo=
|
||||
github.com/illarion/gonotify/v2 v2.0.3 h1:B6+SKPo/0Sw8cRJh1aLzNEeNVFfzE3c6N+o+vyxM+9A=
|
||||
github.com/illarion/gonotify/v2 v2.0.3/go.mod h1:38oIJTgFqupkEydkkClkbL6i5lXV/bxdH9do5TALPEE=
|
||||
github.com/illarion/gonotify/v3 v3.0.2 h1:O7S6vcopHexutmpObkeWsnzMJt/r1hONIEogeVNmJMk=
|
||||
github.com/illarion/gonotify/v3 v3.0.2/go.mod h1:HWGPdPe817GfvY3w7cx6zkbzNZfi3QjcBm/wgVvEL1U=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250417080101-5f8cf70e8c5f h1:dd33oobuIv9PcBVqvbEiCXEbNTomOHyj3WFuC5YiPRU=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20250417080101-5f8cf70e8c5f/go.mod h1:zhFlBeJssZ1YBCMZ5Lzu1pX4vhftDvU10WUVb1uXKtM=
|
||||
github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUFKrq2I=
|
||||
github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E=
|
||||
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
|
||||
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a h1:+RR6SqnTkDLWyICxS1xpjCi/3dhyV+TgZwA6Ww3KncQ=
|
||||
github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a/go.mod h1:YTtCCM3ryyfiu4F7t8HQ1mxvp1UBdWM2r6Xa+nGWvDk=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -140,10 +138,8 @@ github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ
|
||||
github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE=
|
||||
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
|
||||
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 h1:j1VRTiC9JLR4nUbSikx9OGdu/3AgFDqgcLj4GoqyQkc=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
|
||||
github.com/metacubex/utls v1.8.0 h1:mSYi6FMnmc5riARl5UZDmWVy710z+P5b7xuGW0lV9ac=
|
||||
github.com/metacubex/utls v1.8.0/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ=
|
||||
github.com/metacubex/utls v1.8.3 h1:0m/yCxm3SK6kWve2lKiFb1pue1wHitJ8sQQD4Ikqde4=
|
||||
github.com/metacubex/utls v1.8.3/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko=
|
||||
github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc=
|
||||
github.com/mholt/acmez/v3 v3.1.2/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ=
|
||||
github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0=
|
||||
@@ -171,8 +167,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4=
|
||||
github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0=
|
||||
@@ -181,6 +177,46 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
|
||||
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
|
||||
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
|
||||
github.com/sagernet/cronet-go v0.0.0-20251209105322-5fda1568c42f h1:t21xtGXGuCNAFGVcFIqi+c+RANTe9J8nbWfdZUglKDo=
|
||||
github.com/sagernet/cronet-go v0.0.0-20251209105322-5fda1568c42f/go.mod h1:l5IZJLEWpDGJbrF0qBHgxAVBPsAxKOLa1BYDh6B2sdI=
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20251209105322-5fda1568c42f h1:bvHw+A54OGC0FhLVPNfhVz76vPfC4MS+YZ89PbpkdSY=
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20251209105322-5fda1568c42f/go.mod h1:AgwG7INaHB65NL1Jti5pRUMyN3e/8q+CIfgYQzBogKg=
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251209104729-fbe170b6824a h1:vBsGqf9KbfW40So9W90o8gJjokOrBkGUYzqcwtkdUtY=
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251209104729-fbe170b6824a/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251209104729-fbe170b6824a h1:KUmCNxHmQLqekUeGsiKU3uvd6KXpANb6SbLyMGkbSCo=
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251209104729-fbe170b6824a/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251209104729-fbe170b6824a h1:kJi9gU3znoL82BV1ie5v25jbcNP3faPQjsVdsl3BlrY=
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251209104729-fbe170b6824a/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251209104729-fbe170b6824a h1:y0odF2cQviQFByRorA/XczaoxL60vISwX9si4oRiREw=
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251209104729-fbe170b6824a/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251209104729-fbe170b6824a h1:Uft47JfHxyZGYBh4oZsOSk6ZGq0ShUfMegoRxfmnW8A=
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251209104729-fbe170b6824a/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251209104729-fbe170b6824a h1:WyR+mvnGnGySZKCq4lFB4kA+eugr10Wm2oVa0A4eefk=
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251209104729-fbe170b6824a/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251209104729-fbe170b6824a h1:M15EObCrQkGOYkCSa7xelNEl/rkzHp/ekoTW0J90naY=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251209104729-fbe170b6824a/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251209104729-fbe170b6824a h1:kYXvKGBGtWAV85UcL015M6t/vfLKWeqgQTtnSCyFoO0=
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251209104729-fbe170b6824a/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251209104729-fbe170b6824a h1:5vzeO3jUzvYlSL9Ov4Zmm0+Rv0Wu+Yf2B6Q1aj7jKFE=
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251209104729-fbe170b6824a/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251209104729-fbe170b6824a h1:D7HZteO5APBtMd+YvmugvDoOR1scKPZCcmKW7GYY8iQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251209104729-fbe170b6824a/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251209104729-fbe170b6824a h1:mky6g8OXDa2jDe+7cYEFNaCY50SMfdJKkKRj8Xy1Zxo=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251209104729-fbe170b6824a/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251209104729-fbe170b6824a h1:ps9wsaJdjg+i2HebFzH8zle7NRG/OukYpsyceEgAaR8=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251209104729-fbe170b6824a/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251209104729-fbe170b6824a h1:zAg5miXnoT56/WcLp19pDsq+oigBf7WIGe6HZ6BVAuM=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251209104729-fbe170b6824a/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251209104729-fbe170b6824a h1:EWwQ9RQpHYwxb7GeBadFHoyPt3AL/cXd10fyXPpYk/w=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251209104729-fbe170b6824a/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251209104729-fbe170b6824a h1:CxY/o/IjRFMjncGb3PA4hQRQ7xWcrPbqt7pAnBe7JCY=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251209104729-fbe170b6824a/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
|
||||
github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251209104729-fbe170b6824a h1:a3cD0jh7Ute8fkxUxuSCqsXmixkl/iu6GhGn946NIgQ=
|
||||
github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251209104729-fbe170b6824a/go.mod h1:rnS7D+ULJX2PrP0Cy+05GS0mRZ2PP6+gVSroZKt8fjk=
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251209104729-fbe170b6824a h1:yJiwftlutei2sQms2JLF6OaOUCvXLV2Uow0VHYHNtB0=
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251209104729-fbe170b6824a/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251209104729-fbe170b6824a h1:Wo0WzyvWUt4jnTKTFUW73SHRYsWrz7u3rX3f3oQIq68=
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251209104729-fbe170b6824a/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
|
||||
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
|
||||
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
|
||||
github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237 h1:SUPFNB+vSP4RBPrSEgNII+HkfqC8hKMpYLodom4o4EU=
|
||||
@@ -189,31 +225,31 @@ github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZN
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
|
||||
github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1 h1:hWkojLg64zjV+MJOvJU/kOeWndm3tiEfBLx5foisszs=
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4=
|
||||
github.com/sagernet/quic-go v0.57.1-sing-box-mod.1 h1:6fhKbfA0b7L1CVekayV1g87uJFtMXFE0rFXR48SRrWI=
|
||||
github.com/sagernet/quic-go v0.57.1-sing-box-mod.1/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4=
|
||||
github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.7.8-0.20250909124511-ab3827767cea h1:vkWFzPVlqnKq3FMpmh43ZVDbqHWapbv0Sh3vQc8oo7o=
|
||||
github.com/sagernet/sing v0.7.8-0.20250909124511-ab3827767cea/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.8.0-beta.6.0.20251207063731-56fd482ce1c6 h1:EYaDzllFzNYnzQ9xH/ieSAXct4wQ8pD45kgNMo7RPZc=
|
||||
github.com/sagernet/sing v0.8.0-beta.6.0.20251207063731-56fd482ce1c6/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-mux v0.3.3 h1:YFgt9plMWzH994BMZLmyKL37PdIVaIilwP0Jg+EcLfw=
|
||||
github.com/sagernet/sing-mux v0.3.3/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA=
|
||||
github.com/sagernet/sing-quic v0.5.2-0.20250909100920-da23407a63d5 h1:vnRNLE0bBnz5NNbBoFH7NA7mlvNSa2Z4w+1Eb8pyX48=
|
||||
github.com/sagernet/sing-quic v0.5.2-0.20250909100920-da23407a63d5/go.mod h1:gi/sGED8gTWgTAp3GlzXo2D7mXYY+ERoxtGvSkNx3sI=
|
||||
github.com/sagernet/sing-quic v0.6.0-beta.5 h1:kZfRLmsPxAgl0usZUgomDurLn7ZZ26lJWIpGow9ZWR4=
|
||||
github.com/sagernet/sing-quic v0.6.0-beta.5/go.mod h1:9D9GANrK33NjWCe1VkU5L5+8MxU39WrduBSmHuHz8GA=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
|
||||
github.com/sagernet/sing-tun v0.8.0-beta.1.0.20250909100419-a8cb01e6df93 h1:jGkwe0Uk5litEUnvHO/c0nukm2FqvdwKHJio4kJIOxM=
|
||||
github.com/sagernet/sing-tun v0.8.0-beta.1.0.20250909100419-a8cb01e6df93/go.mod h1:LokZYuEV3crByjQc/XRohLgfNvybtXdx5qe/I4W6S7k=
|
||||
github.com/sagernet/sing-tun v0.8.0-beta.11 h1:xVi8VcVkvz2o+3v1PLv5MOkFpiVCwjLjucVlmigDi5c=
|
||||
github.com/sagernet/sing-tun v0.8.0-beta.11/go.mod h1:eWETzl4AwaxGKiZTpDIDVJLTBz9cfIdoZwaZY1jlSjg=
|
||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 h1:aSwUNYUkVyVvdmBSufR8/nRFonwJeKSIROxHcm5br9o=
|
||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1/go.mod h1:P11scgTxMxVVQ8dlM27yNm3Cro40mD0+gHbnqrNGDuY=
|
||||
github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4=
|
||||
github.com/sagernet/smux v1.5.34-mod.2/go.mod h1:0KW0+R+ycvA2INW4gbsd7BNyg+HEfLIAxa5N02/28Zc=
|
||||
github.com/sagernet/tailscale v1.80.3-sing-box-1.13-mod.1 h1:cWM1iPwqIE1t06ft80wpvFB4xbhOpIFI+TFnTw2gnbs=
|
||||
github.com/sagernet/tailscale v1.80.3-sing-box-1.13-mod.1/go.mod h1:EBxXsWu4OH2ELbQLq32WoBeIubG8KgDrg4/Oaxjs6lI=
|
||||
github.com/sagernet/wireguard-go v0.0.1-beta.7 h1:ltgBwYHfr+9Wz1eG59NiWnHrYEkDKHG7otNZvu85DXI=
|
||||
github.com/sagernet/wireguard-go v0.0.1-beta.7/go.mod h1:jGXij2Gn2wbrWuYNUmmNhf1dwcZtvyAvQoe8Xd8MbUo=
|
||||
github.com/sagernet/tailscale v1.86.5-sing-box-1.13-mod.4 h1:Ceg+9Ug+qAFgEchGodlHmMOY2h7KktQQDAyuoIsPbos=
|
||||
github.com/sagernet/tailscale v1.86.5-sing-box-1.13-mod.4/go.mod h1:YdN/avjce8sqPFLT9E1uEh8gPewNSnC41U4ZhBJ+ACw=
|
||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288 h1:E2tZFeg9mGYGQ7E7BbxMv1cU35HxwgRm6tPKI2Pp7DA=
|
||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288/go.mod h1:WUxgxUDZoCF2sxVmW+STSxatP02Qn3FcafTiI2BLtE0=
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
@@ -229,14 +265,12 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ=
|
||||
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4=
|
||||
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4=
|
||||
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55/go.mod h1:4k4QO+dQ3R5FofL+SanAUZe+/QfeK0+OIuwDIRu2vSg=
|
||||
github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4 h1:rXZGgEa+k2vJM8xT0PoSKfVXwFGPQ3z3CJfmnHJkZZw=
|
||||
github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4/go.mod h1:ikbF+YT089eInTp9f2vmvy4+ZVnW5hzX1q2WknxSprQ=
|
||||
github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 h1:4chzWmimtJPxRs2O36yuGRW3f9SYV+bMTTvMBI0EKio=
|
||||
github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05/go.mod h1:PdCqy9JzfWMJf1H5UJW2ip33/d4YkoKN0r67yKH1mG8=
|
||||
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw=
|
||||
@@ -247,8 +281,20 @@ github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc h1:24heQPtnFR+y
|
||||
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc/go.mod h1:f93CXfllFsO9ZQVq+Zocb1Gp4G5Fz0b0rXHLOzt/Djc=
|
||||
github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 h1:UBPHPtv8+nEAy2PD8RyAhOYvau1ek0HDJqLS/Pysi14=
|
||||
github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976/go.mod h1:agQPE6y6ldqCOui2gkIh7ZMztTkIQKH049tv8siLuNQ=
|
||||
github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da h1:jVRUZPRs9sqyKlYHHzHjAqKN+6e/Vog6NpHYeNPJqOw=
|
||||
github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da/go.mod h1:BOm5fXUBFM+m9woLNBoxI9TaBXXhGNP50LX/TGIvGb4=
|
||||
github.com/tc-hib/winres v0.2.1 h1:YDE0FiP0VmtRaDn7+aaChp1KiF4owBiJa5l964l5ujA=
|
||||
github.com/tc-hib/winres v0.2.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM=
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA=
|
||||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
@@ -300,30 +346,30 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
|
||||
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
|
||||
golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68=
|
||||
golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY=
|
||||
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
|
||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||
golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU=
|
||||
golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk=
|
||||
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
|
||||
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
|
||||
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-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
|
||||
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
|
||||
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.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -335,24 +381,24 @@ golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
|
||||
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
|
||||
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
|
||||
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
|
||||
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.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
||||
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
|
||||
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
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.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.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
|
||||
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
||||
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=
|
||||
@@ -377,6 +423,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 h1:2gap+Kh/3F47cO6hAu3idFvsJ0ue6TRcEi2IUkv/F8k=
|
||||
gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633/go.mod h1:5DMfjtclAbTIjbXqO1qCe2K5GKKxWz2JHvCChuTcJEM=
|
||||
lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
|
||||
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
|
||||
software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k=
|
||||
|
||||
442
test/naive_self_test.go
Normal file
442
test/naive_self_test.go
Normal file
@@ -0,0 +1,442 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/sagernet/sing-box/common/tls"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-box/protocol/naive"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/auth"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
"github.com/sagernet/sing/common/network"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNaiveSelf(t *testing.T) {
|
||||
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
|
||||
caPemContent, err := os.ReadFile(caPem)
|
||||
require.NoError(t, err)
|
||||
startInstance(t, option.Options{
|
||||
Inbounds: []option.Inbound{
|
||||
{
|
||||
Type: C.TypeMixed,
|
||||
Tag: "mixed-in",
|
||||
Options: &option.HTTPMixedInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
|
||||
ListenPort: clientPort,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: C.TypeNaive,
|
||||
Tag: "naive-in",
|
||||
Options: &option.NaiveInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
|
||||
ListenPort: serverPort,
|
||||
},
|
||||
Users: []auth.User{
|
||||
{
|
||||
Username: "sekai",
|
||||
Password: "password",
|
||||
},
|
||||
},
|
||||
Network: network.NetworkTCP,
|
||||
InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{
|
||||
TLS: &option.InboundTLSOptions{
|
||||
Enabled: true,
|
||||
ServerName: "example.org",
|
||||
CertificatePath: certPem,
|
||||
KeyPath: keyPem,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Outbounds: []option.Outbound{
|
||||
{
|
||||
Type: C.TypeDirect,
|
||||
},
|
||||
{
|
||||
Type: C.TypeNaive,
|
||||
Tag: "naive-out",
|
||||
Options: &option.NaiveOutboundOptions{
|
||||
ServerOptions: option.ServerOptions{
|
||||
Server: "127.0.0.1",
|
||||
ServerPort: serverPort,
|
||||
},
|
||||
Username: "sekai",
|
||||
Password: "password",
|
||||
OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{
|
||||
TLS: &option.OutboundTLSOptions{
|
||||
Enabled: true,
|
||||
ServerName: "example.org",
|
||||
Certificate: []string{string(caPemContent)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Route: &option.RouteOptions{
|
||||
Rules: []option.Rule{
|
||||
{
|
||||
Type: C.RuleTypeDefault,
|
||||
DefaultOptions: option.DefaultRule{
|
||||
RawDefaultRule: option.RawDefaultRule{
|
||||
Inbound: []string{"mixed-in"},
|
||||
},
|
||||
RuleAction: option.RuleAction{
|
||||
Action: C.RuleActionTypeRoute,
|
||||
RouteOptions: option.RouteActionOptions{
|
||||
Outbound: "naive-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
testTCP(t, clientPort, testPort)
|
||||
}
|
||||
|
||||
func TestNaiveSelfPublicKeySHA256(t *testing.T) {
|
||||
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
|
||||
|
||||
// Read and parse the server certificate to get its public key SHA256
|
||||
certPemContent, err := os.ReadFile(certPem)
|
||||
require.NoError(t, err)
|
||||
block, _ := pem.Decode(certPemContent)
|
||||
require.NotNil(t, block)
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Calculate SHA256 of SPKI (Subject Public Key Info)
|
||||
spkiBytes, err := x509.MarshalPKIXPublicKey(cert.PublicKey)
|
||||
require.NoError(t, err)
|
||||
pinHash := sha256.Sum256(spkiBytes)
|
||||
|
||||
startInstance(t, option.Options{
|
||||
Inbounds: []option.Inbound{
|
||||
{
|
||||
Type: C.TypeMixed,
|
||||
Tag: "mixed-in",
|
||||
Options: &option.HTTPMixedInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
|
||||
ListenPort: clientPort,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: C.TypeNaive,
|
||||
Tag: "naive-in",
|
||||
Options: &option.NaiveInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
|
||||
ListenPort: serverPort,
|
||||
},
|
||||
Users: []auth.User{
|
||||
{
|
||||
Username: "sekai",
|
||||
Password: "password",
|
||||
},
|
||||
},
|
||||
Network: network.NetworkTCP,
|
||||
InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{
|
||||
TLS: &option.InboundTLSOptions{
|
||||
Enabled: true,
|
||||
ServerName: "example.org",
|
||||
CertificatePath: certPem,
|
||||
KeyPath: keyPem,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Outbounds: []option.Outbound{
|
||||
{
|
||||
Type: C.TypeDirect,
|
||||
},
|
||||
{
|
||||
Type: C.TypeNaive,
|
||||
Tag: "naive-out",
|
||||
Options: &option.NaiveOutboundOptions{
|
||||
ServerOptions: option.ServerOptions{
|
||||
Server: "127.0.0.1",
|
||||
ServerPort: serverPort,
|
||||
},
|
||||
Username: "sekai",
|
||||
Password: "password",
|
||||
OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{
|
||||
TLS: &option.OutboundTLSOptions{
|
||||
Enabled: true,
|
||||
ServerName: "example.org",
|
||||
CertificatePublicKeySHA256: [][]byte{pinHash[:]},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Route: &option.RouteOptions{
|
||||
Rules: []option.Rule{
|
||||
{
|
||||
Type: C.RuleTypeDefault,
|
||||
DefaultOptions: option.DefaultRule{
|
||||
RawDefaultRule: option.RawDefaultRule{
|
||||
Inbound: []string{"mixed-in"},
|
||||
},
|
||||
RuleAction: option.RuleAction{
|
||||
Action: C.RuleActionTypeRoute,
|
||||
RouteOptions: option.RouteActionOptions{
|
||||
Outbound: "naive-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
testTCP(t, clientPort, testPort)
|
||||
}
|
||||
|
||||
func TestNaiveSelfECH(t *testing.T) {
|
||||
t.Skip("TODO: ECH is not currently supported on naive outbound")
|
||||
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
|
||||
caPemContent, err := os.ReadFile(caPem)
|
||||
require.NoError(t, err)
|
||||
echConfig, echKey := common.Must2(tls.ECHKeygenDefault("not.example.org"))
|
||||
instance := startInstance(t, option.Options{
|
||||
Inbounds: []option.Inbound{
|
||||
{
|
||||
Type: C.TypeMixed,
|
||||
Tag: "mixed-in",
|
||||
Options: &option.HTTPMixedInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
|
||||
ListenPort: clientPort,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: C.TypeNaive,
|
||||
Tag: "naive-in",
|
||||
Options: &option.NaiveInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
|
||||
ListenPort: serverPort,
|
||||
},
|
||||
Users: []auth.User{
|
||||
{
|
||||
Username: "sekai",
|
||||
Password: "password",
|
||||
},
|
||||
},
|
||||
Network: network.NetworkTCP,
|
||||
InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{
|
||||
TLS: &option.InboundTLSOptions{
|
||||
Enabled: true,
|
||||
ServerName: "example.org",
|
||||
CertificatePath: certPem,
|
||||
KeyPath: keyPem,
|
||||
ECH: &option.InboundECHOptions{
|
||||
Enabled: true,
|
||||
Key: []string{echKey},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Outbounds: []option.Outbound{
|
||||
{
|
||||
Type: C.TypeDirect,
|
||||
},
|
||||
{
|
||||
Type: C.TypeNaive,
|
||||
Tag: "naive-out",
|
||||
Options: &option.NaiveOutboundOptions{
|
||||
ServerOptions: option.ServerOptions{
|
||||
Server: "127.0.0.1",
|
||||
ServerPort: serverPort,
|
||||
},
|
||||
Username: "sekai",
|
||||
Password: "password",
|
||||
OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{
|
||||
TLS: &option.OutboundTLSOptions{
|
||||
Enabled: true,
|
||||
ServerName: "example.org",
|
||||
Certificate: []string{string(caPemContent)},
|
||||
ECH: &option.OutboundECHOptions{
|
||||
Enabled: true,
|
||||
Config: []string{echConfig},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Route: &option.RouteOptions{
|
||||
Rules: []option.Rule{
|
||||
{
|
||||
Type: C.RuleTypeDefault,
|
||||
DefaultOptions: option.DefaultRule{
|
||||
RawDefaultRule: option.RawDefaultRule{
|
||||
Inbound: []string{"mixed-in"},
|
||||
},
|
||||
RuleAction: option.RuleAction{
|
||||
Action: C.RuleActionTypeRoute,
|
||||
RouteOptions: option.RouteActionOptions{
|
||||
Outbound: "naive-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
naiveOut, ok := instance.Outbound().Outbound("naive-out")
|
||||
require.True(t, ok)
|
||||
naiveOutbound := naiveOut.(*naive.Outbound)
|
||||
|
||||
netLogPath := "/tmp/naive_ech_netlog.json"
|
||||
require.True(t, naiveOutbound.StartNetLogToFile(netLogPath, true))
|
||||
defer naiveOutbound.StopNetLog()
|
||||
|
||||
testTCP(t, clientPort, testPort)
|
||||
|
||||
naiveOutbound.StopNetLog()
|
||||
|
||||
logContent, err := os.ReadFile(netLogPath)
|
||||
require.NoError(t, err)
|
||||
logStr := string(logContent)
|
||||
|
||||
require.True(t, strings.Contains(logStr, `"encrypted_client_hello":true`),
|
||||
"ECH should be accepted in TLS handshake. NetLog saved to: %s", netLogPath)
|
||||
}
|
||||
|
||||
func TestNaiveSelfInsecureConcurrency(t *testing.T) {
|
||||
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
|
||||
caPemContent, err := os.ReadFile(caPem)
|
||||
require.NoError(t, err)
|
||||
|
||||
instance := startInstance(t, option.Options{
|
||||
Inbounds: []option.Inbound{
|
||||
{
|
||||
Type: C.TypeMixed,
|
||||
Tag: "mixed-in",
|
||||
Options: &option.HTTPMixedInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
|
||||
ListenPort: clientPort,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: C.TypeNaive,
|
||||
Tag: "naive-in",
|
||||
Options: &option.NaiveInboundOptions{
|
||||
ListenOptions: option.ListenOptions{
|
||||
Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
|
||||
ListenPort: serverPort,
|
||||
},
|
||||
Users: []auth.User{
|
||||
{
|
||||
Username: "sekai",
|
||||
Password: "password",
|
||||
},
|
||||
},
|
||||
Network: network.NetworkTCP,
|
||||
InboundTLSOptionsContainer: option.InboundTLSOptionsContainer{
|
||||
TLS: &option.InboundTLSOptions{
|
||||
Enabled: true,
|
||||
ServerName: "example.org",
|
||||
CertificatePath: certPem,
|
||||
KeyPath: keyPem,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Outbounds: []option.Outbound{
|
||||
{
|
||||
Type: C.TypeDirect,
|
||||
},
|
||||
{
|
||||
Type: C.TypeNaive,
|
||||
Tag: "naive-out",
|
||||
Options: &option.NaiveOutboundOptions{
|
||||
ServerOptions: option.ServerOptions{
|
||||
Server: "127.0.0.1",
|
||||
ServerPort: serverPort,
|
||||
},
|
||||
Username: "sekai",
|
||||
Password: "password",
|
||||
InsecureConcurrency: 3,
|
||||
OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{
|
||||
TLS: &option.OutboundTLSOptions{
|
||||
Enabled: true,
|
||||
ServerName: "example.org",
|
||||
Certificate: []string{string(caPemContent)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Route: &option.RouteOptions{
|
||||
Rules: []option.Rule{
|
||||
{
|
||||
Type: C.RuleTypeDefault,
|
||||
DefaultOptions: option.DefaultRule{
|
||||
RawDefaultRule: option.RawDefaultRule{
|
||||
Inbound: []string{"mixed-in"},
|
||||
},
|
||||
RuleAction: option.RuleAction{
|
||||
Action: C.RuleActionTypeRoute,
|
||||
RouteOptions: option.RouteActionOptions{
|
||||
Outbound: "naive-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
naiveOut, ok := instance.Outbound().Outbound("naive-out")
|
||||
require.True(t, ok)
|
||||
naiveOutbound := naiveOut.(*naive.Outbound)
|
||||
|
||||
netLogPath := "/tmp/naive_concurrency_netlog.json"
|
||||
require.True(t, naiveOutbound.StartNetLogToFile(netLogPath, true))
|
||||
defer naiveOutbound.StopNetLog()
|
||||
|
||||
// Send multiple sequential connections to trigger round-robin
|
||||
// With insecure_concurrency=3, connections will be distributed to 3 pools
|
||||
for i := 0; i < 6; i++ {
|
||||
testTCP(t, clientPort, testPort)
|
||||
}
|
||||
|
||||
naiveOutbound.StopNetLog()
|
||||
|
||||
// Verify NetLog contains multiple independent HTTP/2 sessions
|
||||
logContent, err := os.ReadFile(netLogPath)
|
||||
require.NoError(t, err)
|
||||
logStr := string(logContent)
|
||||
|
||||
// Count HTTP2_SESSION_INITIALIZED events to verify connection pool isolation
|
||||
// NetLog stores event types as numeric IDs, HTTP2_SESSION_INITIALIZED = 249
|
||||
sessionCount := strings.Count(logStr, `"type":249`)
|
||||
require.GreaterOrEqual(t, sessionCount, 3,
|
||||
"Expected at least 3 HTTP/2 sessions with insecure_concurrency=3. NetLog: %s", netLogPath)
|
||||
}
|
||||
Reference in New Issue
Block a user