From cfdce7a96f64b92dd180e9cc42ebb1c0f69d6b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 16 Oct 2023 12:00:00 +0800 Subject: [PATCH 01/87] Fix bbolt panic on arm32 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 28e14f3638..20b63afe7e 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/ooni/go-libtor v1.1.8 github.com/oschwald/maxminddb-golang v1.12.0 github.com/pires/go-proxyproto v0.7.0 - github.com/sagernet/bbolt v0.0.0-20231008142710-b2d6e2f20458 + github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950 github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 diff --git a/go.sum b/go.sum index 16e086b211..dc170fbc58 100644 --- a/go.sum +++ b/go.sum @@ -98,8 +98,8 @@ github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1 github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sagernet/bbolt v0.0.0-20231008142710-b2d6e2f20458 h1:7NXD6FUQucBklrw/TLCqeAARyFuoK9fD5iJ+Y/EHHBQ= -github.com/sagernet/bbolt v0.0.0-20231008142710-b2d6e2f20458/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= +github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= +github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a h1:wZHruBxZCsQLXHAozWpnJBL3wJ/XufDpz0qKtgpSnA4= github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a/go.mod h1:dNV1ZP9y3qx5ltULeKaQZTZWTLHflgW5DES+Ses7cMI= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= From 2371f0fd51c80a4952eadbc837b1b27aef006fd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 16 Oct 2023 12:00:00 +0800 Subject: [PATCH 02/87] Update dependencies --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 20b63afe7e..8dd0d4d807 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.2.14-0.20231011040419-49f5dfd767e1 + github.com/sagernet/sing v0.2.14 github.com/sagernet/sing-dns v0.1.10 github.com/sagernet/sing-mux v0.1.3 github.com/sagernet/sing-quic v0.1.2 @@ -48,7 +48,7 @@ require ( go4.org/netipx v0.0.0-20230824141953-6213f710f925 golang.org/x/crypto v0.14.0 golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 - golang.org/x/net v0.16.0 + golang.org/x/net v0.17.0 golang.org/x/sys v0.13.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 google.golang.org/grpc v1.58.2 diff --git a/go.sum b/go.sum index dc170fbc58..edfb4cb77c 100644 --- a/go.sum +++ b/go.sum @@ -116,8 +116,8 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.14-0.20231011040419-49f5dfd767e1 h1:CFL0FLqKAsEdDx1nrNZ4mgG8Fd/nZ9nR4vZu8yKTHpk= -github.com/sagernet/sing v0.2.14-0.20231011040419-49f5dfd767e1/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= +github.com/sagernet/sing v0.2.14 h1:L3AXDh22nsOOYz2nTRU1JvpRsmzViWKI1B8TsQYG1eY= +github.com/sagernet/sing v0.2.14/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlTZCI= github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= @@ -183,8 +183,8 @@ golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= -golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From e5d191ca73eb9cd26465348b1e78679486293c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 16 Oct 2023 12:00:00 +0800 Subject: [PATCH 03/87] Add retry for bbolt open --- experimental/clashapi/cachefile/cache.go | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/experimental/clashapi/cachefile/cache.go b/experimental/clashapi/cachefile/cache.go index 9acdadf249..0b96fa5def 100644 --- a/experimental/clashapi/cachefile/cache.go +++ b/experimental/clashapi/cachefile/cache.go @@ -1,6 +1,7 @@ package cachefile import ( + "errors" "net/netip" "os" "strings" @@ -11,6 +12,7 @@ import ( bboltErrors "github.com/sagernet/bbolt/errors" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing/common" + E "github.com/sagernet/sing/common/exceptions" ) var ( @@ -42,13 +44,25 @@ type CacheFile struct { func Open(path string, cacheID string) (*CacheFile, error) { const fileMode = 0o666 options := bbolt.Options{Timeout: time.Second} - db, err := bbolt.Open(path, fileMode, &options) - switch err { - case bboltErrors.ErrInvalid, bboltErrors.ErrChecksum, bboltErrors.ErrVersionMismatch: - if err = os.Remove(path); err != nil { + var ( + db *bbolt.DB + err error + ) + for i := 0; i < 10; i++ { + db, err = bbolt.Open(path, fileMode, &options) + if err == nil { break } - db, err = bbolt.Open(path, 0o666, &options) + if errors.Is(err, bboltErrors.ErrTimeout) { + continue + } + if E.IsMulti(err, bboltErrors.ErrInvalid, bboltErrors.ErrChecksum, bboltErrors.ErrVersionMismatch) { + rmErr := os.Remove(path) + if rmErr != nil { + return nil, err + } + } + time.Sleep(100 * time.Millisecond) } if err != nil { return nil, err From a634830d85b884b73cd754aef93b73374479b7ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 21 Oct 2023 12:00:00 +0800 Subject: [PATCH 04/87] Fix invalid address check in UoT conn --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8dd0d4d807..f8b43aca7a 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.2.14 + github.com/sagernet/sing v0.2.15-0.20231021083548-570295cd12f5 github.com/sagernet/sing-dns v0.1.10 github.com/sagernet/sing-mux v0.1.3 github.com/sagernet/sing-quic v0.1.2 diff --git a/go.sum b/go.sum index edfb4cb77c..912c3a358c 100644 --- a/go.sum +++ b/go.sum @@ -116,8 +116,8 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.14 h1:L3AXDh22nsOOYz2nTRU1JvpRsmzViWKI1B8TsQYG1eY= -github.com/sagernet/sing v0.2.14/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= +github.com/sagernet/sing v0.2.15-0.20231021083548-570295cd12f5 h1:yab4g52MbW5MVzUkZwlh0632xwqO9dBWBT4jlr8hTZ0= +github.com/sagernet/sing v0.2.15-0.20231021083548-570295cd12f5/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlTZCI= github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= From 5291d43dc859a195466fdb99a0e760c74fdb5748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 21 Oct 2023 12:00:00 +0800 Subject: [PATCH 05/87] makefile: Add -allowProvisioningUpdates to Apple build commands --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index a1fe7c35f1..68e1f17d99 100644 --- a/Makefile +++ b/Makefile @@ -93,7 +93,7 @@ build_ios: upload_ios_app_store: cd ../sing-box-for-apple && \ - xcodebuild -exportArchive -archivePath build/SFI.xcarchive -exportOptionsPlist SFI/Upload.plist + xcodebuild -exportArchive -archivePath build/SFI.xcarchive -exportOptionsPlist SFI/Upload.plist -allowProvisioningUpdates release_ios: build_ios upload_ios_app_store @@ -104,7 +104,7 @@ build_macos: upload_macos_app_store: cd ../sing-box-for-apple && \ - xcodebuild -exportArchive -archivePath build/SFM.xcarchive -exportOptionsPlist SFI/Upload.plist + xcodebuild -exportArchive -archivePath build/SFM.xcarchive -exportOptionsPlist SFI/Upload.plist -allowProvisioningUpdates release_macos: build_macos upload_macos_app_store @@ -115,7 +115,7 @@ build_macos_independent: notarize_macos_independent: cd ../sing-box-for-apple && \ - xcodebuild -exportArchive -archivePath "build/SFM.System.xcarchive" -exportOptionsPlist SFM.System/Upload.plist + xcodebuild -exportArchive -archivePath "build/SFM.System.xcarchive" -exportOptionsPlist SFM.System/Upload.plist -allowProvisioningUpdates wait_notarize_macos_independent: sleep 60 @@ -141,7 +141,7 @@ build_tvos: upload_tvos_app_store: cd ../sing-box-for-apple && \ - xcodebuild -exportArchive -archivePath "build/SFT.xcarchive" -exportOptionsPlist SFI/Upload.plist + xcodebuild -exportArchive -archivePath "build/SFT.xcarchive" -exportOptionsPlist SFI/Upload.plist -allowProvisioningUpdates release_tvos: build_tvos upload_tvos_app_store From ddf38799e269a4380d05d2f406a892de100fa882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 21 Oct 2023 12:00:00 +0800 Subject: [PATCH 06/87] makefile: Fix release command --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 68e1f17d99..0b1018070d 100644 --- a/Makefile +++ b/Makefile @@ -63,7 +63,7 @@ release: mkdir dist/release mv dist/*.tar.gz dist/*.zip dist/*.deb dist/*.rpm dist/release ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release - rm -r dist + rm -r dist/release release_install: go install -v github.com/goreleaser/goreleaser@latest From b617eb5adf71b7ad6044159678c9cb232e891037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 21 Oct 2023 12:00:00 +0800 Subject: [PATCH 07/87] documentation: Bump version --- docs/changelog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 871eea17d9..d6ad307fa4 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,8 @@ +#### 1.5.4 + +* Fix Clash cache crash on arm32 devices +* Fixes and improvements + #### 1.5.3 * Fix compatibility with Android 14 From d9853ca2be05a2817d808f7aaf7019f60e342cd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 25 Oct 2023 12:00:00 +0800 Subject: [PATCH 08/87] Update dependencies --- go.mod | 18 +++++----- go.sum | 39 +++++++++++----------- test/go.mod | 47 +++++++++++++------------- test/go.sum | 95 +++++++++++++++++++++++++++-------------------------- 4 files changed, 99 insertions(+), 100 deletions(-) diff --git a/go.mod b/go.mod index f8b43aca7a..f99ff706a0 100644 --- a/go.mod +++ b/go.mod @@ -6,14 +6,14 @@ require ( berty.tech/go-libtor v1.0.385 github.com/Dreamacro/clash v1.17.0 github.com/caddyserver/certmagic v0.19.2 - github.com/cloudflare/circl v1.3.3 + github.com/cloudflare/circl v1.3.5 github.com/cretz/bine v0.2.0 - github.com/fsnotify/fsnotify v1.6.0 + github.com/fsnotify/fsnotify v1.7.0 github.com/go-chi/chi/v5 v5.0.10 github.com/go-chi/cors v1.2.1 github.com/go-chi/render v1.0.3 github.com/gofrs/uuid/v5 v5.0.0 - github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a + github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c github.com/libdns/alidns v1.0.3 github.com/libdns/cloudflare v0.1.0 github.com/logrusorgru/aurora v2.0.3+incompatible @@ -28,7 +28,7 @@ require ( github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.2.15-0.20231021083548-570295cd12f5 + github.com/sagernet/sing v0.2.15 github.com/sagernet/sing-dns v0.1.10 github.com/sagernet/sing-mux v0.1.3 github.com/sagernet/sing-quic v0.1.2 @@ -47,11 +47,11 @@ require ( go.uber.org/zap v1.26.0 go4.org/netipx v0.0.0-20230824141953-6213f710f925 golang.org/x/crypto v0.14.0 - golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 + golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/net v0.17.0 golang.org/x/sys v0.13.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 - google.golang.org/grpc v1.58.2 + google.golang.org/grpc v1.59.0 google.golang.org/protobuf v1.31.0 howett.net/plist v1.0.0 ) @@ -88,11 +88,11 @@ require ( github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/zeebo/blake3 v0.2.3 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/mod v0.12.0 // indirect + golang.org/x/mod v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.13.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect + golang.org/x/tools v0.14.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect diff --git a/go.sum b/go.sum index 912c3a358c..efac2b18c8 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/caddyserver/certmagic v0.19.2/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= -github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.5 h1:g+wWynZqVALYAlpSQFAa7TscDnUK8mKYtrxMpw6AUKo= +github.com/cloudflare/circl v1.3.5/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw= github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo= @@ -22,8 +22,8 @@ github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbe github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= @@ -51,8 +51,8 @@ github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbg github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a h1:S33o3djA1nPRd+d/bf7jbbXytXuK/EoXow7+aa76grQ= -github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a/go.mod h1:zmdm3sTSDP3vOOX3CEWRkkRHtKr1DxBx+J1OQFoDQQs= +github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c h1:PgxFEySCI41sH0mB7/2XswdXbUykQsRUGod8Rn+NubM= +github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= @@ -116,8 +116,8 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.15-0.20231021083548-570295cd12f5 h1:yab4g52MbW5MVzUkZwlh0632xwqO9dBWBT4jlr8hTZ0= -github.com/sagernet/sing v0.2.15-0.20231021083548-570295cd12f5/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= +github.com/sagernet/sing v0.2.15 h1:PFwyiMzkyJkq+YGOVznJUsRVOT6EoVxRGIsllLuvHXA= +github.com/sagernet/sing v0.2.15/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlTZCI= github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= @@ -177,15 +177,15 @@ golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaE golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 h1:9k5exFQKQglLo+RoP+4zMjOFE14P6+vyR0baDAi0Rcs= -golang.org/x/exp v0.0.0-20231005195138-3e424a577f31/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -193,7 +193,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= @@ -207,15 +206,15 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= -google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= diff --git a/test/go.mod b/test/go.mod index db19ff20f2..b4336c697d 100644 --- a/test/go.mod +++ b/test/go.mod @@ -6,36 +6,35 @@ require github.com/sagernet/sing-box v0.0.0 replace github.com/sagernet/sing-box => ../ -replace github.com/sagernet/sing-quic => ../../sing-quic - require ( github.com/docker/docker v24.0.6+incompatible github.com/docker/go-connections v0.4.0 github.com/gofrs/uuid/v5 v5.0.0 - github.com/sagernet/sing v0.2.12 - github.com/sagernet/sing-quic v0.1.1 + github.com/sagernet/sing v0.2.15 + github.com/sagernet/sing-quic v0.1.2 github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 github.com/spyzhov/ajson v0.9.0 github.com/stretchr/testify v1.8.4 - go.uber.org/goleak v1.2.1 - golang.org/x/net v0.15.0 + go.uber.org/goleak v1.3.0 + golang.org/x/net v0.17.0 ) require ( berty.tech/go-libtor v1.0.385 // indirect github.com/Dreamacro/clash v1.17.0 // indirect github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158 // indirect - github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.5 // indirect github.com/caddyserver/certmagic v0.19.2 // indirect - github.com/cloudflare/circl v1.3.3 // indirect + github.com/cloudflare/circl v1.3.5 // indirect github.com/cretz/bine v0.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/docker/distribution v2.8.1+incompatible // indirect - github.com/docker/go-units v0.4.0 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/distribution/reference v0.5.0 // indirect + github.com/docker/distribution v2.8.3+incompatible // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-chi/chi/v5 v5.0.10 // indirect github.com/go-chi/cors v1.2.1 // indirect github.com/go-chi/render v1.0.3 // indirect @@ -46,7 +45,7 @@ require ( github.com/google/btree v1.1.2 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/hashicorp/yamux v0.1.1 // indirect - github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a // indirect + github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c // indirect github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect @@ -56,7 +55,7 @@ require ( github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/mholt/acmez v1.2.0 // indirect github.com/miekg/dns v1.1.56 // indirect - github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect + github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/ooni/go-libtor v1.1.8 // indirect @@ -69,16 +68,17 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.3.4 // indirect + github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect - github.com/sagernet/quic-go v0.0.0-20231001051131-0fc736a289bb // indirect + github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect github.com/sagernet/sing-dns v0.1.10 // indirect github.com/sagernet/sing-mux v0.1.3 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect - github.com/sagernet/sing-tun v0.1.14 // indirect + github.com/sagernet/sing-tun v0.1.15 // indirect github.com/sagernet/sing-vmess v0.1.8 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 // indirect @@ -89,21 +89,20 @@ require ( github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/zeebo/blake3 v0.2.3 // indirect - go.etcd.io/bbolt v1.3.7 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect - golang.org/x/crypto v0.13.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/sys v0.12.0 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect + golang.org/x/mod v0.13.0 // indirect + golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.13.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/grpc v1.58.2 // indirect + golang.org/x/tools v0.14.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - gotest.tools/v3 v3.4.0 // indirect + gotest.tools/v3 v3.5.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/test/go.sum b/test/go.sum index c65df9e59f..9d2a8ca154 100644 --- a/test/go.sum +++ b/test/go.sum @@ -5,8 +5,8 @@ github.com/Dreamacro/clash v1.17.0 h1:LWtp6KcnrCiujY58ufI8pylI+hbCBgSCsLI90EWhpi github.com/Dreamacro/clash v1.17.0/go.mod h1:PtcAft7sdsK325BD6uwm8wvhOkMV3TCeED6dfZ/lnfE= github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158 h1:JFnwKplz9hj8ubqYjm8HkgZS1Rvz9yW+u/XCNNTxr0k= github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158/go.mod h1:QvmEZ/h6KXszPOr2wUFl7Zn3hfFNYdfbXwPVDTyZs6k= -github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= -github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= @@ -16,24 +16,26 @@ github.com/caddyserver/certmagic v0.19.2/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= -github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.5 h1:g+wWynZqVALYAlpSQFAa7TscDnUK8mKYtrxMpw6AUKo= +github.com/cloudflare/circl v1.3.5/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw= github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo= github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= -github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= +github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= +github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE= github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= @@ -61,8 +63,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a h1:S33o3djA1nPRd+d/bf7jbbXytXuK/EoXow7+aa76grQ= -github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a/go.mod h1:zmdm3sTSDP3vOOX3CEWRkkRHtKr1DxBx+J1OQFoDQQs= +github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c h1:PgxFEySCI41sH0mB7/2XswdXbUykQsRUGod8Rn+NubM= +github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -87,8 +89,8 @@ github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= @@ -115,6 +117,8 @@ github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= +github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a h1:wZHruBxZCsQLXHAozWpnJBL3wJ/XufDpz0qKtgpSnA4= github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a/go.mod h1:dNV1ZP9y3qx5ltULeKaQZTZWTLHflgW5DES+Ses7cMI= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= @@ -123,26 +127,28 @@ github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 h1:dnkKrzapqtAwjTS github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2/go.mod h1:1JUiV7nGuf++YFm9eWZ8q2lrwHmhcUGzptMl/vL1+LA= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/quic-go v0.0.0-20231001051131-0fc736a289bb h1:jlrVCepGBoob4QsPChIbe1j0d/lZSJkyVj2ukX3D4PE= -github.com/sagernet/quic-go v0.0.0-20231001051131-0fc736a289bb/go.mod h1:uJGpmJCOcMQqMlHKc3P1Vz6uygmpz4bPeVIoOhdVQnM= +github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee h1:ykuhl9jCS638N+jw1vC9AvT9bbQn6xRNScP2FWPV9dM= +github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee/go.mod h1:0CfhWwZAeXGYM9+Nkkw1zcQtFHQC8KWjbpeDv7pu8iw= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.12 h1:wwdLm3c4qvU4hW8tNtadh60V5z2FGlDZSYYGRzHhD74= -github.com/sagernet/sing v0.2.12/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= +github.com/sagernet/sing v0.2.15 h1:PFwyiMzkyJkq+YGOVznJUsRVOT6EoVxRGIsllLuvHXA= +github.com/sagernet/sing v0.2.15/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlTZCI= github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0= +github.com/sagernet/sing-quic v0.1.2 h1:+u9CRf0KHi5HgXmJ3eB0CtqpWXtF0lx2QlWq+ZFZ+XY= +github.com/sagernet/sing-quic v0.1.2/go.mod h1:H1TX0/y9UUM43wyaLQ+qjg2+o901ibYtwWX2rWG+a3o= github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY= github.com/sagernet/sing-shadowsocks v0.2.5/go.mod h1:MGWGkcU2xW2G2mfArT9/QqpVLOGU+dBaahZCtPHdt7A= github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+MUhpQnAux728= github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.14 h1:Vsval4r78kngCsZsz0FExT6p6akiUeRuiVXjfgnN3Ok= -github.com/sagernet/sing-tun v0.1.14/go.mod h1:Z2WibDUoQh/3wwFCfkIzIG0n/NlAlPuEbLTq3rD1aQY= +github.com/sagernet/sing-tun v0.1.15 h1:XfHQD/dhCCQeespPojB4gRhADI1A/4mSLLJCnh5qUnQ= +github.com/sagernet/sing-tun v0.1.15/go.mod h1:zgRoBAtOM24QXx0IKYFEnuTtXPq1Z4rDYRWkP8kJm+g= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= @@ -177,10 +183,8 @@ github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= @@ -192,26 +196,26 @@ golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaE 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.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= 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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -219,17 +223,15 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= 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= @@ -241,17 +243,16 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm 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.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= -google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= @@ -261,7 +262,7 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8X gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= -gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= From 2686e8afea903b85bf862f5bcc3c83b3f73f8a97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 25 Oct 2023 12:00:00 +0800 Subject: [PATCH 09/87] Fix TUIC server TLS config not started --- inbound/tuic.go | 1 + 1 file changed, 1 insertion(+) diff --git a/inbound/tuic.go b/inbound/tuic.go index 19b4b3d71f..bdef1c5deb 100644 --- a/inbound/tuic.go +++ b/inbound/tuic.go @@ -49,6 +49,7 @@ func NewTUIC(ctx context.Context, router adapter.Router, logger log.ContextLogge tag: tag, listenOptions: options.ListenOptions, }, + tlsConfig: tlsConfig, } service, err := tuic.NewService[int](tuic.ServiceOptions{ Context: ctx, From de0b5cc1c2912890f4e4ec13b15c08f0c927e84c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 25 Oct 2023 12:00:00 +0800 Subject: [PATCH 10/87] Fix Linux IPv6 auto route rules --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f99ff706a0..30b1915b02 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 github.com/sagernet/sing-shadowtls v0.1.4 - github.com/sagernet/sing-tun v0.1.15 + github.com/sagernet/sing-tun v0.1.16 github.com/sagernet/sing-vmess v0.1.8 github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 diff --git a/go.sum b/go.sum index efac2b18c8..055af99c1a 100644 --- a/go.sum +++ b/go.sum @@ -130,8 +130,8 @@ github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+M github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.15 h1:XfHQD/dhCCQeespPojB4gRhADI1A/4mSLLJCnh5qUnQ= -github.com/sagernet/sing-tun v0.1.15/go.mod h1:zgRoBAtOM24QXx0IKYFEnuTtXPq1Z4rDYRWkP8kJm+g= +github.com/sagernet/sing-tun v0.1.16 h1:RHXYIVg6uacvdfbYMiPEz9VX5uu6mNrvP7u9yAH3oNc= +github.com/sagernet/sing-tun v0.1.16/go.mod h1:S3q8GCjeyRniK+KLmo4XqKY0bS3x2UdKkKbqxT/Agl8= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= From edf7d046eb49f0cade4efdec537646c625fce310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 25 Oct 2023 12:00:00 +0800 Subject: [PATCH 11/87] Fix outbound not found message --- box_outbound.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/box_outbound.go b/box_outbound.go index ed96cd84d5..676ae7af72 100644 --- a/box_outbound.go +++ b/box_outbound.go @@ -69,7 +69,7 @@ func (s *Box) startOutbounds() error { } problemOutbound := outbounds[problemOutboundTag] if problemOutbound == nil { - return E.New("dependency[", problemOutbound, "] not found for outbound[", outboundTags[oCurrent], "]") + return E.New("dependency[", problemOutboundTag, "] not found for outbound[", outboundTags[oCurrent], "]") } return lintOutbound(append(oTree, problemOutboundTag), problemOutbound) } From 23aa8a0543de5b81ad19b28a264756e61b99fb11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 25 Oct 2023 12:00:00 +0800 Subject: [PATCH 12/87] Add legacy builds for old Windows and macOS versions --- .goreleaser.yaml | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 8e434d9372..c0703ee1b7 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -36,6 +36,35 @@ builds: - darwin_amd64_v3 - darwin_arm64 mod_timestamp: '{{ .CommitTimestamp }}' + - id: legacy + main: ./cmd/sing-box + flags: + - -v + - -trimpath + asmflags: + - all=-trimpath={{.Env.GOPATH}} + gcflags: + - all=-trimpath={{.Env.GOPATH}} + ldflags: + - -X github.com/sagernet/sing-box/constant.Version={{ .Version }} -s -w -buildid= + tags: + - with_gvisor + - with_quic + - with_dhcp + - with_wireguard + - with_ech + - with_utls + - with_reality_server + - with_clash_api + env: + - CGO_ENABLED=0 + - GOROOT=/nix/store/5h8gjl89zx8qxgc572wa3k81zplv8v4z-go-1.20.10/share/go + gobinary: /nix/store/5h8gjl89zx8qxgc572wa3k81zplv8v4z-go-1.20.10/bin/go + targets: + - windows_amd64_v1 + - windows_386 + - darwin_amd64_v1 + mod_timestamp: '{{ .CommitTimestamp }}' - id: android main: ./cmd/sing-box flags: @@ -90,6 +119,9 @@ snapshot: name_template: "{{ .Version }}.{{ .ShortCommit }}" archives: - id: archive + builds: + - main + - android format: tar.gz format_overrides: - goos: windows @@ -98,6 +130,17 @@ archives: files: - LICENSE name_template: '{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}' + - id: archive-legacy + builds: + - legacy + format: tar.gz + format_overrides: + - goos: windows + format: zip + wrap_in_directory: true + files: + - LICENSE + name_template: '{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}-legacy' nfpms: - id: package package_name: sing-box From cb2e15f8a7cf804f70fe21263306afea6dc83d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 25 Oct 2023 12:00:00 +0800 Subject: [PATCH 13/87] Fix UDP domain NAT --- adapter/inbound.go | 8 ++++ common/dialer/resolve.go | 4 +- outbound/default.go | 11 ++++- outbound/direct.go | 2 +- route/router.go | 2 +- test/box_test.go | 27 ++++++++++++ test/domain_inbound_test.go | 83 +++++++++++++++++++++++++++++++++++++ test/go.mod | 6 +-- test/go.sum | 4 +- test/hysteria2_test.go | 2 +- test/wireguard_test.go | 2 +- 11 files changed, 138 insertions(+), 13 deletions(-) create mode 100644 test/domain_inbound_test.go diff --git a/adapter/inbound.go b/adapter/inbound.go index 6a566dc292..2d24083c4a 100644 --- a/adapter/inbound.go +++ b/adapter/inbound.go @@ -75,3 +75,11 @@ func AppendContext(ctx context.Context) (context.Context, *InboundContext) { metadata = new(InboundContext) return WithContext(ctx, metadata), metadata } + +func ExtendContext(ctx context.Context) (context.Context, *InboundContext) { + var newMetadata InboundContext + if metadata := ContextFrom(ctx); metadata != nil { + newMetadata = *metadata + } + return WithContext(ctx, &newMetadata), &newMetadata +} diff --git a/common/dialer/resolve.go b/common/dialer/resolve.go index 9e20c81d61..f2ee50db5a 100644 --- a/common/dialer/resolve.go +++ b/common/dialer/resolve.go @@ -36,7 +36,7 @@ func (d *ResolveDialer) DialContext(ctx context.Context, network string, destina if !destination.IsFqdn() { return d.dialer.DialContext(ctx, network, destination) } - ctx, metadata := adapter.AppendContext(ctx) + ctx, metadata := adapter.ExtendContext(ctx) ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug) metadata.Destination = destination metadata.Domain = "" @@ -61,7 +61,7 @@ func (d *ResolveDialer) ListenPacket(ctx context.Context, destination M.Socksadd if !destination.IsFqdn() { return d.dialer.ListenPacket(ctx, destination) } - ctx, metadata := adapter.AppendContext(ctx) + ctx, metadata := adapter.ExtendContext(ctx) ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug) metadata.Destination = destination metadata.Domain = "" diff --git a/outbound/default.go b/outbound/default.go index 0382825fc8..79ed7b33b0 100644 --- a/outbound/default.go +++ b/outbound/default.go @@ -17,6 +17,7 @@ import ( "github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/canceler" E "github.com/sagernet/sing/common/exceptions" + M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" ) @@ -119,7 +120,10 @@ func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn, return err } if destinationAddress.IsValid() { - if natConn, loaded := common.Cast[bufio.NATPacketConn](conn); loaded { + if metadata.Destination.IsFqdn() { + outConn = bufio.NewNATPacketConn(bufio.NewPacketConn(outConn), M.SocksaddrFrom(destinationAddress, metadata.Destination.Port), metadata.Destination) + } + if natConn, loaded := common.Cast[*bufio.NATPacketConn](conn); loaded { natConn.UpdateDestination(destinationAddress) } } @@ -159,7 +163,10 @@ func NewDirectPacketConnection(ctx context.Context, router adapter.Router, this return err } if destinationAddress.IsValid() { - if natConn, loaded := common.Cast[bufio.NATPacketConn](conn); loaded { + if metadata.Destination.IsFqdn() { + outConn = bufio.NewNATPacketConn(bufio.NewPacketConn(outConn), M.SocksaddrFrom(destinationAddress, metadata.Destination.Port), metadata.Destination) + } + if natConn, loaded := common.Cast[*bufio.NATPacketConn](conn); loaded { natConn.UpdateDestination(destinationAddress) } } diff --git a/outbound/direct.go b/outbound/direct.go index ed1268305a..d5a835c58e 100644 --- a/outbound/direct.go +++ b/outbound/direct.go @@ -164,7 +164,7 @@ func (h *Direct) DialParallel(ctx context.Context, network string, destination M } func (h *Direct) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - ctx, metadata := adapter.AppendContext(ctx) + ctx, metadata := adapter.ExtendContext(ctx) metadata.Outbound = h.tag metadata.Destination = destination switch h.overrideOption { diff --git a/route/router.go b/route/router.go index e02e9b3961..e7658c1866 100644 --- a/route/router.go +++ b/route/router.go @@ -835,7 +835,7 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m } } if metadata.FakeIP { - conn = fakeip.NewNATPacketConn(conn, metadata.OriginDestination, metadata.Destination) + conn = bufio.NewNATPacketConn(bufio.NewNetPacketConn(conn), metadata.OriginDestination, metadata.Destination) } return detour.NewPacketConnection(ctx, conn, metadata) } diff --git a/test/box_test.go b/test/box_test.go index 4092979ff2..5009cc63a7 100644 --- a/test/box_test.go +++ b/test/box_test.go @@ -2,10 +2,15 @@ package main import ( "context" + "crypto/tls" + "io" "net" + "net/http" "testing" "time" + "github.com/sagernet/quic-go" + "github.com/sagernet/quic-go/http3" "github.com/sagernet/sing-box" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" @@ -74,6 +79,28 @@ func testSuit(t *testing.T, clientPort uint16, testPort uint16) { // require.NoError(t, testPacketConnTimeout(t, dialUDP)) } +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{ + Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) { + destination := M.ParseSocksaddr(addr) + udpConn, err := dialer.DialContext(ctx, N.NetworkUDP, destination) + if err != nil { + return nil, err + } + return quic.DialEarly(ctx, udpConn.(net.PacketConn), destination, tlsCfg, cfg) + }, + }, + } + response, err := client.Get("https://cloudflare.com/cdn-cgi/trace") + require.NoError(t, err) + require.Equal(t, http.StatusOK, response.StatusCode) + content, err := io.ReadAll(response.Body) + require.NoError(t, err) + println(string(content)) +} + func testSuitLargeUDP(t *testing.T, clientPort uint16, testPort uint16) { dialer := socks.NewClient(N.SystemDialer, M.ParseSocksaddrHostPort("127.0.0.1", clientPort), socks.Version5, "", "") dialTCP := func() (net.Conn, error) { diff --git a/test/domain_inbound_test.go b/test/domain_inbound_test.go new file mode 100644 index 0000000000..bf43aa98f2 --- /dev/null +++ b/test/domain_inbound_test.go @@ -0,0 +1,83 @@ +package main + +import ( + "net/netip" + "testing" + + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/option" + dns "github.com/sagernet/sing-dns" + + "github.com/gofrs/uuid/v5" +) + +func TestTUICDomainUDP(t *testing.T) { + _, certPem, keyPem := createSelfSignedCertificate(t, "example.org") + startInstance(t, option.Options{ + Inbounds: []option.Inbound{ + { + Type: C.TypeMixed, + Tag: "mixed-in", + MixedOptions: option.HTTPMixedInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.NewListenAddress(netip.IPv4Unspecified()), + ListenPort: clientPort, + }, + }, + }, + { + Type: C.TypeTUIC, + TUICOptions: option.TUICInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.NewListenAddress(netip.IPv4Unspecified()), + ListenPort: serverPort, + InboundOptions: option.InboundOptions{ + DomainStrategy: option.DomainStrategy(dns.DomainStrategyUseIPv6), + }, + }, + Users: []option.TUICUser{{ + UUID: uuid.Nil.String(), + }}, + TLS: &option.InboundTLSOptions{ + Enabled: true, + ServerName: "example.org", + CertificatePath: certPem, + KeyPath: keyPem, + }, + }, + }, + }, + Outbounds: []option.Outbound{ + { + Type: C.TypeDirect, + }, + { + Type: C.TypeTUIC, + Tag: "tuic-out", + TUICOptions: option.TUICOutboundOptions{ + ServerOptions: option.ServerOptions{ + Server: "127.0.0.1", + ServerPort: serverPort, + }, + UUID: uuid.Nil.String(), + TLS: &option.OutboundTLSOptions{ + Enabled: true, + ServerName: "example.org", + CertificatePath: certPem, + }, + }, + }, + }, + Route: &option.RouteOptions{ + Rules: []option.Rule{ + { + DefaultOptions: option.DefaultRule{ + Inbound: []string{"mixed-in"}, + Outbound: "tuic-out", + }, + }, + }, + }, + }) + testQUIC(t, clientPort) +} diff --git a/test/go.mod b/test/go.mod index b4336c697d..85cda49616 100644 --- a/test/go.mod +++ b/test/go.mod @@ -10,7 +10,9 @@ require ( github.com/docker/docker v24.0.6+incompatible github.com/docker/go-connections v0.4.0 github.com/gofrs/uuid/v5 v5.0.0 + github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee github.com/sagernet/sing v0.2.15 + github.com/sagernet/sing-dns v0.1.10 github.com/sagernet/sing-quic v0.1.2 github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 @@ -73,12 +75,10 @@ require ( github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect - github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect - github.com/sagernet/sing-dns v0.1.10 // indirect github.com/sagernet/sing-mux v0.1.3 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect - github.com/sagernet/sing-tun v0.1.15 // indirect + github.com/sagernet/sing-tun v0.1.16 // indirect github.com/sagernet/sing-vmess v0.1.8 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 // indirect diff --git a/test/go.sum b/test/go.sum index 9d2a8ca154..9e371949ec 100644 --- a/test/go.sum +++ b/test/go.sum @@ -147,8 +147,8 @@ github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+M github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.15 h1:XfHQD/dhCCQeespPojB4gRhADI1A/4mSLLJCnh5qUnQ= -github.com/sagernet/sing-tun v0.1.15/go.mod h1:zgRoBAtOM24QXx0IKYFEnuTtXPq1Z4rDYRWkP8kJm+g= +github.com/sagernet/sing-tun v0.1.16 h1:RHXYIVg6uacvdfbYMiPEz9VX5uu6mNrvP7u9yAH3oNc= +github.com/sagernet/sing-tun v0.1.16/go.mod h1:S3q8GCjeyRniK+KLmo4XqKY0bS3x2UdKkKbqxT/Agl8= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= diff --git a/test/hysteria2_test.go b/test/hysteria2_test.go index 695e598bb4..04735eeb77 100644 --- a/test/hysteria2_test.go +++ b/test/hysteria2_test.go @@ -97,7 +97,7 @@ func testHysteria2Self(t *testing.T, salamanderPassword string) { }, }, }) - testSuit(t, clientPort, testPort) + testSuitLargeUDP(t, clientPort, testPort) } func TestHysteria2Inbound(t *testing.T) { diff --git a/test/wireguard_test.go b/test/wireguard_test.go index 1889a3a60e..50e87ee04d 100644 --- a/test/wireguard_test.go +++ b/test/wireguard_test.go @@ -40,7 +40,7 @@ func _TestWireGuard(t *testing.T) { Server: "127.0.0.1", ServerPort: serverPort, }, - LocalAddress: []option.ListenPrefix{option.ListenPrefix(netip.MustParsePrefix("10.0.0.2/32"))}, + LocalAddress: []netip.Prefix{netip.MustParsePrefix("10.0.0.2/32")}, PrivateKey: "qGnwlkZljMxeECW8fbwAWdvgntnbK7B8UmMFl3zM0mk=", PeerPublicKey: "QsdcBm+oJw2oNv0cIFXLIq1E850lgTBonup4qnKEQBg=", }, From a7710c3845fc1b70c5b390fb5b303d6a776435e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 25 Oct 2023 12:00:00 +0800 Subject: [PATCH 14/87] documentation: Bump version --- docs/changelog.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index d6ad307fa4..d905e5cd0b 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,17 @@ +#### 1.5.5 + +* Fix IPv6 `auto_route` for Linux **1** +* Add legacy builds for old Windows and macOS systems **2** +* Fixes and improvements + +**1**: + +When `auto_route` is enabled and `strict_route` is disabled, the device can now be reached from external IPv6 addresses. + +**2**: + +Built using Go 1.20, the last version that will run on Windows 7, 8, Server 2008, Server 2012 and macOS 10.13 High Sierra, 10.14 Mojave. + #### 1.5.4 * Fix Clash cache crash on arm32 devices From a8112ff8244c20869947dfa7c7b55b2e38daac0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 30 Oct 2023 12:36:03 +0800 Subject: [PATCH 15/87] Update workflows --- .github/workflows/debug.yml | 2 ++ .github/workflows/lint.yml | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml index fab33d3486..20dd4ca68f 100644 --- a/.github/workflows/debug.yml +++ b/.github/workflows/debug.yml @@ -3,6 +3,7 @@ name: Debug build on: push: branches: + - stable-next - main-next - dev-next paths-ignore: @@ -11,6 +12,7 @@ on: - '!.github/workflows/debug.yml' pull_request: branches: + - stable-next - main-next - dev-next diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c81f4a64e8..05b36a1e14 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -3,6 +3,7 @@ name: Lint on: push: branches: + - stable-next - main-next - dev-next paths-ignore: @@ -11,6 +12,7 @@ on: - '!.github/workflows/lint.yml' pull_request: branches: + - stable-next - main-next - dev-next @@ -34,4 +36,6 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: - version: latest \ No newline at end of file + version: latest + args: --timeout=30m + install-mode: binary \ No newline at end of file From aa05a4d05095ac64ef6da3c57e6cff41f5db9dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 25 Oct 2023 12:00:00 +0800 Subject: [PATCH 16/87] Remove deprecated features --- common/proxyproto/dialer.go | 50 --- common/proxyproto/listener.go | 62 --- go.mod | 3 - go.sum | 6 - inbound/default_tcp.go | 6 +- outbound/direct.go | 52 +-- outbound/shadowsocksr.go | 185 +------- outbound/shadowsocksr_stub.go | 2 +- test/clash_test.go | 2 - test/go.mod | 3 - test/go.sum | 6 - test/shadowsocksr_test.go | 48 --- transport/clashssr/obfs/base.go | 9 - transport/clashssr/obfs/http_post.go | 9 - transport/clashssr/obfs/http_simple.go | 405 ------------------ transport/clashssr/obfs/obfs.go | 42 -- transport/clashssr/obfs/plain.go | 15 - transport/clashssr/obfs/random_head.go | 71 --- transport/clashssr/obfs/tls1.2_ticket_auth.go | 226 ---------- .../clashssr/protocol/auth_aes128_md5.go | 18 - .../clashssr/protocol/auth_aes128_sha1.go | 277 ------------ transport/clashssr/protocol/auth_chain_a.go | 306 ------------- transport/clashssr/protocol/auth_chain_b.go | 97 ----- transport/clashssr/protocol/auth_sha1_v4.go | 182 -------- transport/clashssr/protocol/base.go | 75 ---- transport/clashssr/protocol/origin.go | 33 -- transport/clashssr/protocol/packet.go | 36 -- transport/clashssr/protocol/protocol.go | 76 ---- transport/clashssr/protocol/stream.go | 50 --- 29 files changed, 11 insertions(+), 2341 deletions(-) delete mode 100644 common/proxyproto/dialer.go delete mode 100644 common/proxyproto/listener.go delete mode 100644 test/shadowsocksr_test.go delete mode 100644 transport/clashssr/obfs/base.go delete mode 100644 transport/clashssr/obfs/http_post.go delete mode 100644 transport/clashssr/obfs/http_simple.go delete mode 100644 transport/clashssr/obfs/obfs.go delete mode 100644 transport/clashssr/obfs/plain.go delete mode 100644 transport/clashssr/obfs/random_head.go delete mode 100644 transport/clashssr/obfs/tls1.2_ticket_auth.go delete mode 100644 transport/clashssr/protocol/auth_aes128_md5.go delete mode 100644 transport/clashssr/protocol/auth_aes128_sha1.go delete mode 100644 transport/clashssr/protocol/auth_chain_a.go delete mode 100644 transport/clashssr/protocol/auth_chain_b.go delete mode 100644 transport/clashssr/protocol/auth_sha1_v4.go delete mode 100644 transport/clashssr/protocol/base.go delete mode 100644 transport/clashssr/protocol/origin.go delete mode 100644 transport/clashssr/protocol/packet.go delete mode 100644 transport/clashssr/protocol/protocol.go delete mode 100644 transport/clashssr/protocol/stream.go diff --git a/common/proxyproto/dialer.go b/common/proxyproto/dialer.go deleted file mode 100644 index f3fba6f4da..0000000000 --- a/common/proxyproto/dialer.go +++ /dev/null @@ -1,50 +0,0 @@ -package proxyproto - -import ( - "context" - "net" - "net/netip" - - "github.com/sagernet/sing-box/adapter" - E "github.com/sagernet/sing/common/exceptions" - M "github.com/sagernet/sing/common/metadata" - N "github.com/sagernet/sing/common/network" - - "github.com/pires/go-proxyproto" -) - -var _ N.Dialer = (*Dialer)(nil) - -type Dialer struct { - N.Dialer -} - -func (d *Dialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - switch N.NetworkName(network) { - case N.NetworkTCP: - conn, err := d.Dialer.DialContext(ctx, network, destination) - if err != nil { - return nil, err - } - var source M.Socksaddr - metadata := adapter.ContextFrom(ctx) - if metadata != nil { - source = metadata.Source - } - if !source.IsValid() { - source = M.SocksaddrFromNet(conn.LocalAddr()) - } - if destination.Addr.Is6() { - source = M.SocksaddrFrom(netip.AddrFrom16(source.Addr.As16()), source.Port) - } - h := proxyproto.HeaderProxyFromAddrs(1, source.TCPAddr(), destination.TCPAddr()) - _, err = h.WriteTo(conn) - if err != nil { - conn.Close() - return nil, E.Cause(err, "write proxy protocol header") - } - return conn, nil - default: - return d.Dialer.DialContext(ctx, network, destination) - } -} diff --git a/common/proxyproto/listener.go b/common/proxyproto/listener.go deleted file mode 100644 index ff98796740..0000000000 --- a/common/proxyproto/listener.go +++ /dev/null @@ -1,62 +0,0 @@ -package proxyproto - -import ( - std_bufio "bufio" - "net" - - "github.com/sagernet/sing/common/buf" - "github.com/sagernet/sing/common/bufio" - M "github.com/sagernet/sing/common/metadata" - - "github.com/pires/go-proxyproto" -) - -type Listener struct { - net.Listener - AcceptNoHeader bool -} - -func (l *Listener) Accept() (net.Conn, error) { - conn, err := l.Listener.Accept() - if err != nil { - return nil, err - } - bufReader := std_bufio.NewReader(conn) - header, err := proxyproto.Read(bufReader) - if err != nil && !(l.AcceptNoHeader && err == proxyproto.ErrNoProxyProtocol) { - return nil, &Error{err} - } - if bufReader.Buffered() > 0 { - cache := buf.NewSize(bufReader.Buffered()) - _, err = cache.ReadFullFrom(bufReader, cache.FreeLen()) - if err != nil { - return nil, &Error{err} - } - conn = bufio.NewCachedConn(conn, cache) - } - if header != nil { - return &bufio.AddrConn{Conn: conn, Metadata: M.Metadata{ - Source: M.SocksaddrFromNet(header.SourceAddr).Unwrap(), - Destination: M.SocksaddrFromNet(header.DestinationAddr).Unwrap(), - }}, nil - } - return conn, nil -} - -var _ net.Error = (*Error)(nil) - -type Error struct { - error -} - -func (e *Error) Unwrap() error { - return e.error -} - -func (e *Error) Timeout() bool { - return false -} - -func (e *Error) Temporary() bool { - return true -} diff --git a/go.mod b/go.mod index 30b1915b02..5e48872e1f 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.20 require ( berty.tech/go-libtor v1.0.385 - github.com/Dreamacro/clash v1.17.0 github.com/caddyserver/certmagic v0.19.2 github.com/cloudflare/circl v1.3.5 github.com/cretz/bine v0.2.0 @@ -21,7 +20,6 @@ require ( github.com/miekg/dns v1.1.56 github.com/ooni/go-libtor v1.1.8 github.com/oschwald/maxminddb-golang v1.12.0 - github.com/pires/go-proxyproto v0.7.0 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950 @@ -59,7 +57,6 @@ require ( //replace github.com/sagernet/sing => ../sing require ( - github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158 // indirect github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/go.sum b/go.sum index 055af99c1a..fa41839610 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,5 @@ berty.tech/go-libtor v1.0.385 h1:RWK94C3hZj6Z2GdvePpHJLnWYobFr3bY/OdUJ5aoEXw= berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+fJEw= -github.com/Dreamacro/clash v1.17.0 h1:LWtp6KcnrCiujY58ufI8pylI+hbCBgSCsLI90EWhpi4= -github.com/Dreamacro/clash v1.17.0/go.mod h1:PtcAft7sdsK325BD6uwm8wvhOkMV3TCeED6dfZ/lnfE= -github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158 h1:JFnwKplz9hj8ubqYjm8HkgZS1Rvz9yW+u/XCNNTxr0k= -github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158/go.mod h1:QvmEZ/h6KXszPOr2wUFl7Zn3hfFNYdfbXwPVDTyZs6k= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= @@ -89,8 +85,6 @@ github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq5 github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs= -github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= diff --git a/inbound/default_tcp.go b/inbound/default_tcp.go index 4e408f5c15..698801834a 100644 --- a/inbound/default_tcp.go +++ b/inbound/default_tcp.go @@ -5,7 +5,6 @@ import ( "net" "github.com/sagernet/sing-box/adapter" - "github.com/sagernet/sing-box/common/proxyproto" "github.com/sagernet/sing-box/log" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" @@ -34,9 +33,8 @@ func (a *myInboundAdapter) ListenTCP() (net.Listener, error) { if err == nil { a.logger.Info("tcp server started at ", tcpListener.Addr()) } - if a.listenOptions.ProxyProtocol { - a.logger.Warn("Proxy Protocol is deprecated, see https://sing-box.sagernet.org/deprecated") - tcpListener = &proxyproto.Listener{Listener: tcpListener, AcceptNoHeader: a.listenOptions.ProxyProtocolAcceptNoHeader} + if a.listenOptions.ProxyProtocol || a.listenOptions.ProxyProtocolAcceptNoHeader { + return nil, E.New("Proxy Protocol is deprecated and removed in sing-box 1.6.0") } a.tcpListener = tcpListener return tcpListener, err diff --git a/outbound/direct.go b/outbound/direct.go index d5a835c58e..3bf80494b9 100644 --- a/outbound/direct.go +++ b/outbound/direct.go @@ -17,8 +17,6 @@ import ( E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" - - "github.com/pires/go-proxyproto" ) var ( @@ -33,7 +31,6 @@ type Direct struct { fallbackDelay time.Duration overrideOption int overrideDestination M.Socksaddr - proxyProto uint8 } func NewDirect(router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) (*Direct, error) { @@ -54,10 +51,9 @@ func NewDirect(router adapter.Router, logger log.ContextLogger, tag string, opti domainStrategy: dns.DomainStrategy(options.DomainStrategy), fallbackDelay: time.Duration(options.FallbackDelay), dialer: outboundDialer, - proxyProto: options.ProxyProtocol, } - if options.ProxyProtocol > 2 { - return nil, E.New("invalid proxy protocol option: ", options.ProxyProtocol) + if options.ProxyProtocol != 0 { + return nil, E.New("Proxy Protocol is deprecated and removed in sing-box 1.6.0") } if options.OverrideAddress != "" && options.OverridePort != 0 { outbound.overrideOption = 1 @@ -74,7 +70,6 @@ func NewDirect(router adapter.Router, logger log.ContextLogger, tag string, opti func (h *Direct) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { ctx, metadata := adapter.AppendContext(ctx) - originDestination := metadata.Destination metadata.Outbound = h.tag metadata.Destination = destination switch h.overrideOption { @@ -94,31 +89,11 @@ func (h *Direct) DialContext(ctx context.Context, network string, destination M. case N.NetworkUDP: h.logger.InfoContext(ctx, "outbound packet connection to ", destination) } - conn, err := h.dialer.DialContext(ctx, network, destination) - if err != nil { - return nil, err - } - if h.proxyProto > 0 { - source := metadata.Source - if !source.IsValid() { - source = M.SocksaddrFromNet(conn.LocalAddr()) - } - if originDestination.Addr.Is6() { - source = M.SocksaddrFrom(netip.AddrFrom16(source.Addr.As16()), source.Port) - } - header := proxyproto.HeaderProxyFromAddrs(h.proxyProto, source.TCPAddr(), originDestination.TCPAddr()) - _, err = header.WriteTo(conn) - if err != nil { - conn.Close() - return nil, E.Cause(err, "write proxy protocol header") - } - } - return conn, nil + return h.dialer.DialContext(ctx, network, destination) } func (h *Direct) DialParallel(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr) (net.Conn, error) { ctx, metadata := adapter.AppendContext(ctx) - originDestination := metadata.Destination metadata.Outbound = h.tag metadata.Destination = destination switch h.overrideOption { @@ -141,26 +116,7 @@ func (h *Direct) DialParallel(ctx context.Context, network string, destination M } else { domainStrategy = dns.DomainStrategy(metadata.InboundOptions.DomainStrategy) } - conn, err := N.DialParallel(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == dns.DomainStrategyPreferIPv6, h.fallbackDelay) - if err != nil { - return nil, err - } - if h.proxyProto > 0 { - source := metadata.Source - if !source.IsValid() { - source = M.SocksaddrFromNet(conn.LocalAddr()) - } - if originDestination.Addr.Is6() { - source = M.SocksaddrFrom(netip.AddrFrom16(source.Addr.As16()), source.Port) - } - header := proxyproto.HeaderProxyFromAddrs(h.proxyProto, source.TCPAddr(), originDestination.TCPAddr()) - _, err = header.WriteTo(conn) - if err != nil { - conn.Close() - return nil, E.Cause(err, "write proxy protocol header") - } - } - return conn, nil + return N.DialParallel(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == dns.DomainStrategyPreferIPv6, h.fallbackDelay) } func (h *Direct) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { diff --git a/outbound/shadowsocksr.go b/outbound/shadowsocksr.go index 099db32acf..615a71e4e4 100644 --- a/outbound/shadowsocksr.go +++ b/outbound/shadowsocksr.go @@ -4,192 +4,15 @@ package outbound import ( "context" - "errors" - "fmt" - "net" + "os" "github.com/sagernet/sing-box/adapter" - "github.com/sagernet/sing-box/common/dialer" - C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing-box/transport/clashssr/obfs" - "github.com/sagernet/sing-box/transport/clashssr/protocol" - "github.com/sagernet/sing/common/bufio" - E "github.com/sagernet/sing/common/exceptions" - M "github.com/sagernet/sing/common/metadata" - N "github.com/sagernet/sing/common/network" - - "github.com/Dreamacro/clash/transport/shadowsocks/core" - "github.com/Dreamacro/clash/transport/shadowsocks/shadowstream" - "github.com/Dreamacro/clash/transport/socks5" ) -var _ adapter.Outbound = (*ShadowsocksR)(nil) - -type ShadowsocksR struct { - myOutboundAdapter - dialer N.Dialer - serverAddr M.Socksaddr - cipher core.Cipher - obfs obfs.Obfs - protocol protocol.Protocol -} - -func NewShadowsocksR(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksROutboundOptions) (*ShadowsocksR, error) { - logger.Warn("ShadowsocksR is deprecated, see https://sing-box.sagernet.org/deprecated") - outboundDialer, err := dialer.New(router, options.DialerOptions) - if err != nil { - return nil, err - } - outbound := &ShadowsocksR{ - myOutboundAdapter: myOutboundAdapter{ - protocol: C.TypeShadowsocksR, - network: options.Network.Build(), - router: router, - logger: logger, - tag: tag, - dependencies: withDialerDependency(options.DialerOptions), - }, - dialer: outboundDialer, - serverAddr: options.ServerOptions.Build(), - } - var cipher string - switch options.Method { - case "none": - cipher = "dummy" - default: - cipher = options.Method - } - outbound.cipher, err = core.PickCipher(cipher, nil, options.Password) - if err != nil { - return nil, err - } - var ( - ivSize int - key []byte - ) - if cipher == "dummy" { - ivSize = 0 - key = core.Kdf(options.Password, 16) - } else { - streamCipher, ok := outbound.cipher.(*core.StreamCipher) - if !ok { - return nil, fmt.Errorf("%s is not none or a supported stream cipher in ssr", cipher) - } - ivSize = streamCipher.IVSize() - key = streamCipher.Key - } - obfs, obfsOverhead, err := obfs.PickObfs(options.Obfs, &obfs.Base{ - Host: options.Server, - Port: int(options.ServerPort), - Key: key, - IVSize: ivSize, - Param: options.ObfsParam, - }) - if err != nil { - return nil, E.Cause(err, "initialize obfs") - } - protocol, err := protocol.PickProtocol(options.Protocol, &protocol.Base{ - Key: key, - Overhead: obfsOverhead, - Param: options.ProtocolParam, - }) - if err != nil { - return nil, E.Cause(err, "initialize protocol") - } - outbound.obfs = obfs - outbound.protocol = protocol - return outbound, nil -} - -func (h *ShadowsocksR) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - ctx, metadata := adapter.AppendContext(ctx) - metadata.Outbound = h.tag - metadata.Destination = destination - switch network { - case N.NetworkTCP: - h.logger.InfoContext(ctx, "outbound connection to ", destination) - conn, err := h.dialer.DialContext(ctx, network, h.serverAddr) - if err != nil { - return nil, err - } - conn = h.cipher.StreamConn(h.obfs.StreamConn(conn)) - writeIv, err := conn.(*shadowstream.Conn).ObtainWriteIV() - if err != nil { - conn.Close() - return nil, err - } - conn = h.protocol.StreamConn(conn, writeIv) - err = M.SocksaddrSerializer.WriteAddrPort(conn, destination) - if err != nil { - conn.Close() - return nil, E.Cause(err, "write request") - } - return conn, nil - case N.NetworkUDP: - conn, err := h.ListenPacket(ctx, destination) - if err != nil { - return nil, err - } - return bufio.NewBindPacketConn(conn, destination), nil - default: - return nil, E.Extend(N.ErrUnknownNetwork, network) - } -} - -func (h *ShadowsocksR) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - ctx, metadata := adapter.AppendContext(ctx) - metadata.Outbound = h.tag - metadata.Destination = destination - h.logger.InfoContext(ctx, "outbound packet connection to ", destination) - outConn, err := h.dialer.DialContext(ctx, N.NetworkUDP, h.serverAddr) - if err != nil { - return nil, err - } - packetConn := h.cipher.PacketConn(bufio.NewUnbindPacketConn(outConn)) - packetConn = h.protocol.PacketConn(packetConn) - packetConn = &ssPacketConn{packetConn, outConn.RemoteAddr()} - return packetConn, nil -} - -func (h *ShadowsocksR) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { - return NewConnection(ctx, h, conn, metadata) -} - -func (h *ShadowsocksR) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { - return NewPacketConnection(ctx, h, conn, metadata) -} - -type ssPacketConn struct { - net.PacketConn - rAddr net.Addr -} - -func (spc *ssPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { - packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b) - if err != nil { - return - } - return spc.PacketConn.WriteTo(packet[3:], spc.rAddr) -} - -func (spc *ssPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { - n, _, e := spc.PacketConn.ReadFrom(b) - if e != nil { - return 0, nil, e - } - - addr := socks5.SplitAddr(b[:n]) - if addr == nil { - return 0, nil, errors.New("parse addr error") - } - - udpAddr := addr.UDPAddr() - if udpAddr == nil { - return 0, nil, errors.New("parse addr error") - } +var _ int = "ShadowsocksR is deprecated and removed in sing-box 1.6.0" - copy(b, b[len(addr):]) - return n - len(addr), udpAddr, e +func NewShadowsocksR(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksROutboundOptions) (adapter.Outbound, error) { + return nil, os.ErrInvalid } diff --git a/outbound/shadowsocksr_stub.go b/outbound/shadowsocksr_stub.go index d362587614..94971da0bc 100644 --- a/outbound/shadowsocksr_stub.go +++ b/outbound/shadowsocksr_stub.go @@ -12,5 +12,5 @@ import ( ) func NewShadowsocksR(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksROutboundOptions) (adapter.Outbound, error) { - return nil, E.New(`ShadowsocksR is not included in this build, rebuild with -tags with_shadowsocksr`) + return nil, E.New("ShadowsocksR is deprecated and removed in sing-box 1.6.0") } diff --git a/test/clash_test.go b/test/clash_test.go index 1f627dc432..ffd3e10c78 100644 --- a/test/clash_test.go +++ b/test/clash_test.go @@ -36,7 +36,6 @@ const ( ImageHysteria2 = "tobyxdd/hysteria:v2" ImageNginx = "nginx:stable" ImageShadowTLS = "ghcr.io/ihciah/shadow-tls:latest" - ImageShadowsocksR = "teddysun/shadowsocks-r:latest" ImageXRayCore = "teddysun/xray:latest" ImageShadowsocksLegacy = "mritd/shadowsocks:latest" ImageTUICServer = "kilvn/tuic-server:latest" @@ -54,7 +53,6 @@ var allImages = []string{ ImageHysteria2, ImageNginx, ImageShadowTLS, - ImageShadowsocksR, ImageXRayCore, ImageShadowsocksLegacy, ImageTUICServer, diff --git a/test/go.mod b/test/go.mod index 85cda49616..fed2124ab7 100644 --- a/test/go.mod +++ b/test/go.mod @@ -24,8 +24,6 @@ require ( require ( berty.tech/go-libtor v1.0.385 // indirect - github.com/Dreamacro/clash v1.17.0 // indirect - github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.5 // indirect @@ -65,7 +63,6 @@ require ( github.com/opencontainers/image-spec v1.0.2 // indirect github.com/oschwald/maxminddb-golang v1.12.0 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect - github.com/pires/go-proxyproto v0.7.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect diff --git a/test/go.sum b/test/go.sum index 9e371949ec..d13690ad71 100644 --- a/test/go.sum +++ b/test/go.sum @@ -1,10 +1,6 @@ berty.tech/go-libtor v1.0.385 h1:RWK94C3hZj6Z2GdvePpHJLnWYobFr3bY/OdUJ5aoEXw= berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+fJEw= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Dreamacro/clash v1.17.0 h1:LWtp6KcnrCiujY58ufI8pylI+hbCBgSCsLI90EWhpi4= -github.com/Dreamacro/clash v1.17.0/go.mod h1:PtcAft7sdsK325BD6uwm8wvhOkMV3TCeED6dfZ/lnfE= -github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158 h1:JFnwKplz9hj8ubqYjm8HkgZS1Rvz9yW+u/XCNNTxr0k= -github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158/go.mod h1:QvmEZ/h6KXszPOr2wUFl7Zn3hfFNYdfbXwPVDTyZs6k= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= @@ -107,8 +103,6 @@ github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq5 github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs= -github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/test/shadowsocksr_test.go b/test/shadowsocksr_test.go deleted file mode 100644 index fa034b56bf..0000000000 --- a/test/shadowsocksr_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import ( - "net/netip" - "testing" - - C "github.com/sagernet/sing-box/constant" - "github.com/sagernet/sing-box/option" -) - -func TestShadowsocksR(t *testing.T) { - startDockerContainer(t, DockerOptions{ - Image: ImageShadowsocksR, - Ports: []uint16{serverPort, testPort}, - Bind: map[string]string{ - "shadowsocksr.json": "/etc/shadowsocks-r/config.json", - }, - }) - startInstance(t, option.Options{ - Inbounds: []option.Inbound{ - { - Type: C.TypeMixed, - MixedOptions: option.HTTPMixedInboundOptions{ - ListenOptions: option.ListenOptions{ - Listen: option.NewListenAddress(netip.IPv4Unspecified()), - ListenPort: clientPort, - }, - }, - }, - }, - Outbounds: []option.Outbound{ - { - Type: C.TypeShadowsocksR, - ShadowsocksROptions: option.ShadowsocksROutboundOptions{ - ServerOptions: option.ServerOptions{ - Server: "127.0.0.1", - ServerPort: serverPort, - }, - Method: "aes-256-cfb", - Password: "password0", - Obfs: "plain", - Protocol: "origin", - }, - }, - }, - }) - testSuit(t, clientPort, testPort) -} diff --git a/transport/clashssr/obfs/base.go b/transport/clashssr/obfs/base.go deleted file mode 100644 index 7fd1b84cf7..0000000000 --- a/transport/clashssr/obfs/base.go +++ /dev/null @@ -1,9 +0,0 @@ -package obfs - -type Base struct { - Host string - Port int - Key []byte - IVSize int - Param string -} diff --git a/transport/clashssr/obfs/http_post.go b/transport/clashssr/obfs/http_post.go deleted file mode 100644 index 4be6cbe8b1..0000000000 --- a/transport/clashssr/obfs/http_post.go +++ /dev/null @@ -1,9 +0,0 @@ -package obfs - -func init() { - register("http_post", newHTTPPost, 0) -} - -func newHTTPPost(b *Base) Obfs { - return &httpObfs{Base: b, post: true} -} diff --git a/transport/clashssr/obfs/http_simple.go b/transport/clashssr/obfs/http_simple.go deleted file mode 100644 index c1ea76738f..0000000000 --- a/transport/clashssr/obfs/http_simple.go +++ /dev/null @@ -1,405 +0,0 @@ -package obfs - -import ( - "bytes" - "encoding/hex" - "io" - "math/rand" - "net" - "strconv" - "strings" - - "github.com/Dreamacro/clash/common/pool" -) - -func init() { - register("http_simple", newHTTPSimple, 0) -} - -type httpObfs struct { - *Base - post bool -} - -func newHTTPSimple(b *Base) Obfs { - return &httpObfs{Base: b} -} - -type httpConn struct { - net.Conn - *httpObfs - hasSentHeader bool - hasRecvHeader bool - buf []byte -} - -func (h *httpObfs) StreamConn(c net.Conn) net.Conn { - return &httpConn{Conn: c, httpObfs: h} -} - -func (c *httpConn) Read(b []byte) (int, error) { - if c.buf != nil { - n := copy(b, c.buf) - if n == len(c.buf) { - c.buf = nil - } else { - c.buf = c.buf[n:] - } - return n, nil - } - - if c.hasRecvHeader { - return c.Conn.Read(b) - } - - buf := pool.Get(pool.RelayBufferSize) - defer pool.Put(buf) - n, err := c.Conn.Read(buf) - if err != nil { - return 0, err - } - pos := bytes.Index(buf[:n], []byte("\r\n\r\n")) - if pos == -1 { - return 0, io.EOF - } - c.hasRecvHeader = true - dataLength := n - pos - 4 - n = copy(b, buf[4+pos:n]) - if dataLength > n { - c.buf = append(c.buf, buf[4+pos+n:4+pos+dataLength]...) - } - return n, nil -} - -func (c *httpConn) Write(b []byte) (int, error) { - if c.hasSentHeader { - return c.Conn.Write(b) - } - // 30: head length - headLength := c.IVSize + 30 - - bLength := len(b) - headDataLength := bLength - if bLength-headLength > 64 { - headDataLength = headLength + rand.Intn(65) - } - headData := b[:headDataLength] - b = b[headDataLength:] - - var body string - host := c.Host - if len(c.Param) > 0 { - pos := strings.Index(c.Param, "#") - if pos != -1 { - body = strings.ReplaceAll(c.Param[pos+1:], "\n", "\r\n") - body = strings.ReplaceAll(body, "\\n", "\r\n") - host = c.Param[:pos] - } else { - host = c.Param - } - } - hosts := strings.Split(host, ",") - host = hosts[rand.Intn(len(hosts))] - - buf := pool.GetBuffer() - defer pool.PutBuffer(buf) - if c.post { - buf.WriteString("POST /") - } else { - buf.WriteString("GET /") - } - packURLEncodedHeadData(buf, headData) - buf.WriteString(" HTTP/1.1\r\nHost: " + host) - if c.Port != 80 { - buf.WriteString(":" + strconv.Itoa(c.Port)) - } - buf.WriteString("\r\n") - if len(body) > 0 { - buf.WriteString(body + "\r\n\r\n") - } else { - buf.WriteString("User-Agent: ") - buf.WriteString(userAgent[rand.Intn(len(userAgent))]) - buf.WriteString("\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-US,en;q=0.8\r\nAccept-Encoding: gzip, deflate\r\n") - if c.post { - packBoundary(buf) - } - buf.WriteString("DNT: 1\r\nConnection: keep-alive\r\n\r\n") - } - buf.Write(b) - _, err := c.Conn.Write(buf.Bytes()) - if err != nil { - return 0, nil - } - c.hasSentHeader = true - return bLength, nil -} - -func packURLEncodedHeadData(buf *bytes.Buffer, data []byte) { - dataLength := len(data) - for i := 0; i < dataLength; i++ { - buf.WriteRune('%') - buf.WriteString(hex.EncodeToString(data[i : i+1])) - } -} - -func packBoundary(buf *bytes.Buffer) { - buf.WriteString("Content-Type: multipart/form-data; boundary=") - set := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - for i := 0; i < 32; i++ { - buf.WriteByte(set[rand.Intn(62)]) - } - buf.WriteString("\r\n") -} - -var userAgent = []string{ - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto C Build/NRD90M.059) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M Build/MMB29T; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J120M Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Moto G (5) Build/NPPS25.137-93-14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G570M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; CAM-L03 Build/HUAWEICAM-L03) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.63 Safari/534.3", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36", - "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.63 Safari/534.3", - "Mozilla/5.0 (Linux; Android 8.0.0; FIG-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.1 Safari/533.2", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36", - "Mozilla/5.0 (X11; Datanyze; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; SM-J111M Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J700M Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Slackware/Chrome/12.0.742.100 Safari/534.30", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; WAS-LX3 Build/HUAWEIWAS-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.1805 Safari/537.36 MVisionPlayer/1.0.0.0", - "Mozilla/5.0 (Linux; Android 7.0; TRT-LX3 Build/HUAWEITRT-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.89 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; vivo 1610 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; de-de; SAMSUNG GT-I9195 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.5 Chrome/28.0.1500.94 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX3 Build/HUAWEIANE-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (X11; U; Linux i586; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.1 Safari/533.2", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.65 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G610M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-J500M Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.104 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; vivo 1606 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G610M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1; vivo 1716 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G570M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; MYA-L22 Build/HUAWEIMYA-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A1601 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; TRT-LX2 Build/HUAWEITRT-LX2; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.125 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/10.0.649.0 Safari/534.17", - "Mozilla/5.0 (Linux; Android 6.0; CAM-L21 Build/HUAWEICAM-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.3 Safari/534.24", - "Mozilla/5.0 (Linux; Android 7.1.2; Redmi 4X Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Linux; Android 4.4.2; SM-G7102 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; HUAWEI CUN-L22 Build/HUAWEICUN-L22; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1.1; A37fw Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J730GM Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-G610F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.2; Redmi Note 5A Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; Redmi Note 4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36", - "Mozilla/5.0 (Unknown; Linux) AppleWebKit/538.1 (KHTML, like Gecko) Chrome/v1.0.0 Safari/538.1", - "Mozilla/5.0 (Linux; Android 7.0; BLL-L22 Build/HUAWEIBLL-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.0; SM-J710F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1.1; CPH1723 Build/N6F26Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Linux; Android 8.0.0; FIG-LX3 Build/HUAWEIFIG-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Windows; U; Windows NT 6.1; de-DE) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/10.0.649.0 Safari/534.17", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.65 Safari/537.36", - "Mozilla/5.0 (Linux; Android 7.1; Mi A1 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36 MVisionPlayer/1.0.0.0", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Linux; Android 5.1; A37f Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.93 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; CPH1607 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; vivo 1603 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; Redmi 4A Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.116 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36", - "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0.1; SM-G532G Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36", - "Mozilla/5.0 (Linux; Android 6.0; vivo 1713 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", -} diff --git a/transport/clashssr/obfs/obfs.go b/transport/clashssr/obfs/obfs.go deleted file mode 100644 index c56acc8adb..0000000000 --- a/transport/clashssr/obfs/obfs.go +++ /dev/null @@ -1,42 +0,0 @@ -package obfs - -import ( - "errors" - "fmt" - "net" -) - -var ( - errTLS12TicketAuthIncorrectMagicNumber = errors.New("tls1.2_ticket_auth incorrect magic number") - errTLS12TicketAuthTooShortData = errors.New("tls1.2_ticket_auth too short data") - errTLS12TicketAuthHMACError = errors.New("tls1.2_ticket_auth hmac verifying failed") -) - -type authData struct { - clientID [32]byte -} - -type Obfs interface { - StreamConn(net.Conn) net.Conn -} - -type obfsCreator func(b *Base) Obfs - -var obfsList = make(map[string]struct { - overhead int - new obfsCreator -}) - -func register(name string, c obfsCreator, o int) { - obfsList[name] = struct { - overhead int - new obfsCreator - }{overhead: o, new: c} -} - -func PickObfs(name string, b *Base) (Obfs, int, error) { - if choice, ok := obfsList[name]; ok { - return choice.new(b), choice.overhead, nil - } - return nil, 0, fmt.Errorf("Obfs %s not supported", name) -} diff --git a/transport/clashssr/obfs/plain.go b/transport/clashssr/obfs/plain.go deleted file mode 100644 index eb998a47b4..0000000000 --- a/transport/clashssr/obfs/plain.go +++ /dev/null @@ -1,15 +0,0 @@ -package obfs - -import "net" - -type plain struct{} - -func init() { - register("plain", newPlain, 0) -} - -func newPlain(b *Base) Obfs { - return &plain{} -} - -func (p *plain) StreamConn(c net.Conn) net.Conn { return c } diff --git a/transport/clashssr/obfs/random_head.go b/transport/clashssr/obfs/random_head.go deleted file mode 100644 index b10b01c56b..0000000000 --- a/transport/clashssr/obfs/random_head.go +++ /dev/null @@ -1,71 +0,0 @@ -package obfs - -import ( - "encoding/binary" - "hash/crc32" - "math/rand" - "net" - - "github.com/Dreamacro/clash/common/pool" -) - -func init() { - register("random_head", newRandomHead, 0) -} - -type randomHead struct { - *Base -} - -func newRandomHead(b *Base) Obfs { - return &randomHead{Base: b} -} - -type randomHeadConn struct { - net.Conn - *randomHead - hasSentHeader bool - rawTransSent bool - rawTransRecv bool - buf []byte -} - -func (r *randomHead) StreamConn(c net.Conn) net.Conn { - return &randomHeadConn{Conn: c, randomHead: r} -} - -func (c *randomHeadConn) Read(b []byte) (int, error) { - if c.rawTransRecv { - return c.Conn.Read(b) - } - buf := pool.Get(pool.RelayBufferSize) - defer pool.Put(buf) - c.Conn.Read(buf) - c.rawTransRecv = true - c.Write(nil) - return 0, nil -} - -func (c *randomHeadConn) Write(b []byte) (int, error) { - if c.rawTransSent { - return c.Conn.Write(b) - } - c.buf = append(c.buf, b...) - if !c.hasSentHeader { - c.hasSentHeader = true - dataLength := rand.Intn(96) + 4 - buf := pool.Get(dataLength + 4) - defer pool.Put(buf) - rand.Read(buf[:dataLength]) - binary.LittleEndian.PutUint32(buf[dataLength:], 0xffffffff-crc32.ChecksumIEEE(buf[:dataLength])) - _, err := c.Conn.Write(buf) - return len(b), err - } - if c.rawTransRecv { - _, err := c.Conn.Write(c.buf) - c.buf = nil - c.rawTransSent = true - return len(b), err - } - return len(b), nil -} diff --git a/transport/clashssr/obfs/tls1.2_ticket_auth.go b/transport/clashssr/obfs/tls1.2_ticket_auth.go deleted file mode 100644 index 10f2786add..0000000000 --- a/transport/clashssr/obfs/tls1.2_ticket_auth.go +++ /dev/null @@ -1,226 +0,0 @@ -package obfs - -import ( - "bytes" - "crypto/hmac" - "encoding/binary" - "math/rand" - "net" - "strings" - "time" - - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/transport/ssr/tools" -) - -func init() { - register("tls1.2_ticket_auth", newTLS12Ticket, 5) - register("tls1.2_ticket_fastauth", newTLS12Ticket, 5) -} - -type tls12Ticket struct { - *Base - *authData -} - -func newTLS12Ticket(b *Base) Obfs { - r := &tls12Ticket{Base: b, authData: &authData{}} - rand.Read(r.clientID[:]) - return r -} - -type tls12TicketConn struct { - net.Conn - *tls12Ticket - handshakeStatus int - decoded bytes.Buffer - underDecoded bytes.Buffer - sendBuf bytes.Buffer -} - -func (t *tls12Ticket) StreamConn(c net.Conn) net.Conn { - return &tls12TicketConn{Conn: c, tls12Ticket: t} -} - -func (c *tls12TicketConn) Read(b []byte) (int, error) { - if c.decoded.Len() > 0 { - return c.decoded.Read(b) - } - - buf := pool.Get(pool.RelayBufferSize) - defer pool.Put(buf) - n, err := c.Conn.Read(buf) - if err != nil { - return 0, err - } - - if c.handshakeStatus == 8 { - c.underDecoded.Write(buf[:n]) - for c.underDecoded.Len() > 5 { - if !bytes.Equal(c.underDecoded.Bytes()[:3], []byte{0x17, 3, 3}) { - c.underDecoded.Reset() - return 0, errTLS12TicketAuthIncorrectMagicNumber - } - size := int(binary.BigEndian.Uint16(c.underDecoded.Bytes()[3:5])) - if c.underDecoded.Len() < 5+size { - break - } - c.underDecoded.Next(5) - c.decoded.Write(c.underDecoded.Next(size)) - } - n, _ = c.decoded.Read(b) - return n, nil - } - - if n < 11+32+1+32 { - return 0, errTLS12TicketAuthTooShortData - } - - if !hmac.Equal(buf[33:43], c.hmacSHA1(buf[11:33])[:10]) || !hmac.Equal(buf[n-10:n], c.hmacSHA1(buf[:n-10])[:10]) { - return 0, errTLS12TicketAuthHMACError - } - - c.Write(nil) - return 0, nil -} - -func (c *tls12TicketConn) Write(b []byte) (int, error) { - length := len(b) - if c.handshakeStatus == 8 { - buf := pool.GetBuffer() - defer pool.PutBuffer(buf) - for len(b) > 2048 { - size := rand.Intn(4096) + 100 - if len(b) < size { - size = len(b) - } - packData(buf, b[:size]) - b = b[size:] - } - if len(b) > 0 { - packData(buf, b) - } - _, err := c.Conn.Write(buf.Bytes()) - if err != nil { - return 0, err - } - return length, nil - } - - if len(b) > 0 { - packData(&c.sendBuf, b) - } - - if c.handshakeStatus == 0 { - c.handshakeStatus = 1 - - data := pool.GetBuffer() - defer pool.PutBuffer(data) - - data.Write([]byte{3, 3}) - c.packAuthData(data) - data.WriteByte(0x20) - data.Write(c.clientID[:]) - data.Write([]byte{0x00, 0x1c, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0x14, 0xcc, 0x13, 0xc0, 0x0a, 0xc0, 0x14, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x9c, 0x00, 0x35, 0x00, 0x2f, 0x00, 0x0a}) - data.Write([]byte{0x1, 0x0}) - - ext := pool.GetBuffer() - defer pool.PutBuffer(ext) - - host := c.getHost() - ext.Write([]byte{0xff, 0x01, 0x00, 0x01, 0x00}) - packSNIData(ext, host) - ext.Write([]byte{0, 0x17, 0, 0}) - c.packTicketBuf(ext, host) - ext.Write([]byte{0x00, 0x0d, 0x00, 0x16, 0x00, 0x14, 0x06, 0x01, 0x06, 0x03, 0x05, 0x01, 0x05, 0x03, 0x04, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x03, 0x02, 0x01, 0x02, 0x03}) - ext.Write([]byte{0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00}) - ext.Write([]byte{0x00, 0x12, 0x00, 0x00}) - ext.Write([]byte{0x75, 0x50, 0x00, 0x00}) - ext.Write([]byte{0x00, 0x0b, 0x00, 0x02, 0x01, 0x00}) - ext.Write([]byte{0x00, 0x0a, 0x00, 0x06, 0x00, 0x04, 0x00, 0x17, 0x00, 0x18}) - - binary.Write(data, binary.BigEndian, uint16(ext.Len())) - data.ReadFrom(ext) - - ret := pool.GetBuffer() - defer pool.PutBuffer(ret) - - ret.Write([]byte{0x16, 3, 1}) - binary.Write(ret, binary.BigEndian, uint16(data.Len()+4)) - ret.Write([]byte{1, 0}) - binary.Write(ret, binary.BigEndian, uint16(data.Len())) - ret.ReadFrom(data) - - _, err := c.Conn.Write(ret.Bytes()) - if err != nil { - return 0, err - } - return length, nil - } else if c.handshakeStatus == 1 && len(b) == 0 { - buf := pool.GetBuffer() - defer pool.PutBuffer(buf) - - buf.Write([]byte{0x14, 3, 3, 0, 1, 1, 0x16, 3, 3, 0, 0x20}) - tools.AppendRandBytes(buf, 22) - buf.Write(c.hmacSHA1(buf.Bytes())[:10]) - buf.ReadFrom(&c.sendBuf) - - c.handshakeStatus = 8 - - _, err := c.Conn.Write(buf.Bytes()) - return 0, err - } - return length, nil -} - -func packData(buf *bytes.Buffer, data []byte) { - buf.Write([]byte{0x17, 3, 3}) - binary.Write(buf, binary.BigEndian, uint16(len(data))) - buf.Write(data) -} - -func (t *tls12Ticket) packAuthData(buf *bytes.Buffer) { - binary.Write(buf, binary.BigEndian, uint32(time.Now().Unix())) - tools.AppendRandBytes(buf, 18) - buf.Write(t.hmacSHA1(buf.Bytes()[buf.Len()-22:])[:10]) -} - -func packSNIData(buf *bytes.Buffer, u string) { - len := uint16(len(u)) - buf.Write([]byte{0, 0}) - binary.Write(buf, binary.BigEndian, len+5) - binary.Write(buf, binary.BigEndian, len+3) - buf.WriteByte(0) - binary.Write(buf, binary.BigEndian, len) - buf.WriteString(u) -} - -func (c *tls12TicketConn) packTicketBuf(buf *bytes.Buffer, u string) { - length := 16 * (rand.Intn(17) + 8) - buf.Write([]byte{0, 0x23}) - binary.Write(buf, binary.BigEndian, uint16(length)) - tools.AppendRandBytes(buf, length) -} - -func (t *tls12Ticket) hmacSHA1(data []byte) []byte { - key := pool.Get(len(t.Key) + 32) - defer pool.Put(key) - copy(key, t.Key) - copy(key[len(t.Key):], t.clientID[:]) - - sha1Data := tools.HmacSHA1(key, data) - return sha1Data[:10] -} - -func (t *tls12Ticket) getHost() string { - host := t.Param - if len(host) == 0 { - host = t.Host - } - if len(host) > 0 && host[len(host)-1] >= '0' && host[len(host)-1] <= '9' { - host = "" - } - hosts := strings.Split(host, ",") - host = hosts[rand.Intn(len(hosts))] - return host -} diff --git a/transport/clashssr/protocol/auth_aes128_md5.go b/transport/clashssr/protocol/auth_aes128_md5.go deleted file mode 100644 index d3bc941727..0000000000 --- a/transport/clashssr/protocol/auth_aes128_md5.go +++ /dev/null @@ -1,18 +0,0 @@ -package protocol - -import "github.com/Dreamacro/clash/transport/ssr/tools" - -func init() { - register("auth_aes128_md5", newAuthAES128MD5, 9) -} - -func newAuthAES128MD5(b *Base) Protocol { - a := &authAES128{ - Base: b, - authData: &authData{}, - authAES128Function: &authAES128Function{salt: "auth_aes128_md5", hmac: tools.HmacMD5, hashDigest: tools.MD5Sum}, - userData: &userData{}, - } - a.initUserData() - return a -} diff --git a/transport/clashssr/protocol/auth_aes128_sha1.go b/transport/clashssr/protocol/auth_aes128_sha1.go deleted file mode 100644 index 99c2f6f8b2..0000000000 --- a/transport/clashssr/protocol/auth_aes128_sha1.go +++ /dev/null @@ -1,277 +0,0 @@ -package protocol - -import ( - "bytes" - "encoding/binary" - "math" - "math/rand" - "net" - "strconv" - "strings" - - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/transport/ssr/tools" -) - -type ( - hmacMethod func(key, data []byte) []byte - hashDigestMethod func([]byte) []byte -) - -func init() { - register("auth_aes128_sha1", newAuthAES128SHA1, 9) -} - -type authAES128Function struct { - salt string - hmac hmacMethod - hashDigest hashDigestMethod -} - -type authAES128 struct { - *Base - *authData - *authAES128Function - *userData - iv []byte - hasSentHeader bool - rawTrans bool - packID uint32 - recvID uint32 -} - -func newAuthAES128SHA1(b *Base) Protocol { - a := &authAES128{ - Base: b, - authData: &authData{}, - authAES128Function: &authAES128Function{salt: "auth_aes128_sha1", hmac: tools.HmacSHA1, hashDigest: tools.SHA1Sum}, - userData: &userData{}, - } - a.initUserData() - return a -} - -func (a *authAES128) initUserData() { - params := strings.Split(a.Param, ":") - if len(params) > 1 { - if userID, err := strconv.ParseUint(params[0], 10, 32); err == nil { - binary.LittleEndian.PutUint32(a.userID[:], uint32(userID)) - a.userKey = a.hashDigest([]byte(params[1])) - } - } - if len(a.userKey) == 0 { - a.userKey = a.Key - rand.Read(a.userID[:]) - } -} - -func (a *authAES128) StreamConn(c net.Conn, iv []byte) net.Conn { - p := &authAES128{ - Base: a.Base, - authData: a.next(), - authAES128Function: a.authAES128Function, - userData: a.userData, - packID: 1, - recvID: 1, - } - p.iv = iv - return &Conn{Conn: c, Protocol: p} -} - -func (a *authAES128) PacketConn(c net.PacketConn) net.PacketConn { - p := &authAES128{ - Base: a.Base, - authAES128Function: a.authAES128Function, - userData: a.userData, - } - return &PacketConn{PacketConn: c, Protocol: p} -} - -func (a *authAES128) Decode(dst, src *bytes.Buffer) error { - if a.rawTrans { - dst.ReadFrom(src) - return nil - } - for src.Len() > 4 { - macKey := pool.Get(len(a.userKey) + 4) - defer pool.Put(macKey) - copy(macKey, a.userKey) - binary.LittleEndian.PutUint32(macKey[len(a.userKey):], a.recvID) - if !bytes.Equal(a.hmac(macKey, src.Bytes()[:2])[:2], src.Bytes()[2:4]) { - src.Reset() - return errAuthAES128MACError - } - - length := int(binary.LittleEndian.Uint16(src.Bytes()[:2])) - if length >= 8192 || length < 7 { - a.rawTrans = true - src.Reset() - return errAuthAES128LengthError - } - if length > src.Len() { - break - } - - if !bytes.Equal(a.hmac(macKey, src.Bytes()[:length-4])[:4], src.Bytes()[length-4:length]) { - a.rawTrans = true - src.Reset() - return errAuthAES128ChksumError - } - - a.recvID++ - - pos := int(src.Bytes()[4]) - if pos < 255 { - pos += 4 - } else { - pos = int(binary.LittleEndian.Uint16(src.Bytes()[5:7])) + 4 - } - dst.Write(src.Bytes()[pos : length-4]) - src.Next(length) - } - return nil -} - -func (a *authAES128) Encode(buf *bytes.Buffer, b []byte) error { - fullDataLength := len(b) - if !a.hasSentHeader { - dataLength := getDataLength(b) - a.packAuthData(buf, b[:dataLength]) - b = b[dataLength:] - a.hasSentHeader = true - } - for len(b) > 8100 { - a.packData(buf, b[:8100], fullDataLength) - b = b[8100:] - } - if len(b) > 0 { - a.packData(buf, b, fullDataLength) - } - return nil -} - -func (a *authAES128) DecodePacket(b []byte) ([]byte, error) { - if len(b) < 4 { - return nil, errAuthAES128LengthError - } - if !bytes.Equal(a.hmac(a.Key, b[:len(b)-4])[:4], b[len(b)-4:]) { - return nil, errAuthAES128ChksumError - } - return b[:len(b)-4], nil -} - -func (a *authAES128) EncodePacket(buf *bytes.Buffer, b []byte) error { - buf.Write(b) - buf.Write(a.userID[:]) - buf.Write(a.hmac(a.userKey, buf.Bytes())[:4]) - return nil -} - -func (a *authAES128) packData(poolBuf *bytes.Buffer, data []byte, fullDataLength int) { - dataLength := len(data) - randDataLength := a.getRandDataLengthForPackData(dataLength, fullDataLength) - /* - 2: uint16 LittleEndian packedDataLength - 2: hmac of packedDataLength - 3: maxRandDataLengthPrefix (min:1) - 4: hmac of packedData except the last 4 bytes - */ - packedDataLength := 2 + 2 + 3 + randDataLength + dataLength + 4 - if randDataLength < 128 { - packedDataLength -= 2 - } - - macKey := pool.Get(len(a.userKey) + 4) - defer pool.Put(macKey) - copy(macKey, a.userKey) - binary.LittleEndian.PutUint32(macKey[len(a.userKey):], a.packID) - a.packID++ - - binary.Write(poolBuf, binary.LittleEndian, uint16(packedDataLength)) - poolBuf.Write(a.hmac(macKey, poolBuf.Bytes()[poolBuf.Len()-2:])[:2]) - a.packRandData(poolBuf, randDataLength) - poolBuf.Write(data) - poolBuf.Write(a.hmac(macKey, poolBuf.Bytes()[poolBuf.Len()-packedDataLength+4:])[:4]) -} - -func trapezoidRandom(max int, d float64) int { - base := rand.Float64() - if d-0 > 1e-6 { - a := 1 - d - base = (math.Sqrt(a*a+4*d*base) - a) / (2 * d) - } - return int(base * float64(max)) -} - -func (a *authAES128) getRandDataLengthForPackData(dataLength, fullDataLength int) int { - if fullDataLength >= 32*1024-a.Overhead { - return 0 - } - // 1460: tcp_mss - revLength := 1460 - dataLength - 9 - if revLength == 0 { - return 0 - } - if revLength < 0 { - if revLength > -1460 { - return trapezoidRandom(revLength+1460, -0.3) - } - return rand.Intn(32) - } - if dataLength > 900 { - return rand.Intn(revLength) - } - return trapezoidRandom(revLength, -0.3) -} - -func (a *authAES128) packAuthData(poolBuf *bytes.Buffer, data []byte) { - if len(data) == 0 { - return - } - dataLength := len(data) - randDataLength := a.getRandDataLengthForPackAuthData(dataLength) - /* - 7: checkHead(1) and hmac of checkHead(6) - 4: userID - 16: encrypted data of authdata(12), uint16 BigEndian packedDataLength(2) and uint16 BigEndian randDataLength(2) - 4: hmac of userID and encrypted data - 4: hmac of packedAuthData except the last 4 bytes - */ - packedAuthDataLength := 7 + 4 + 16 + 4 + randDataLength + dataLength + 4 - - macKey := pool.Get(len(a.iv) + len(a.Key)) - defer pool.Put(macKey) - copy(macKey, a.iv) - copy(macKey[len(a.iv):], a.Key) - - poolBuf.WriteByte(byte(rand.Intn(256))) - poolBuf.Write(a.hmac(macKey, poolBuf.Bytes())[:6]) - poolBuf.Write(a.userID[:]) - err := a.authData.putEncryptedData(poolBuf, a.userKey, [2]int{packedAuthDataLength, randDataLength}, a.salt) - if err != nil { - poolBuf.Reset() - return - } - poolBuf.Write(a.hmac(macKey, poolBuf.Bytes()[7:])[:4]) - tools.AppendRandBytes(poolBuf, randDataLength) - poolBuf.Write(data) - poolBuf.Write(a.hmac(a.userKey, poolBuf.Bytes())[:4]) -} - -func (a *authAES128) getRandDataLengthForPackAuthData(size int) int { - if size > 400 { - return rand.Intn(512) - } - return rand.Intn(1024) -} - -func (a *authAES128) packRandData(poolBuf *bytes.Buffer, size int) { - if size < 128 { - poolBuf.WriteByte(byte(size + 1)) - tools.AppendRandBytes(poolBuf, size) - return - } - poolBuf.WriteByte(255) - binary.Write(poolBuf, binary.LittleEndian, uint16(size+3)) - tools.AppendRandBytes(poolBuf, size) -} diff --git a/transport/clashssr/protocol/auth_chain_a.go b/transport/clashssr/protocol/auth_chain_a.go deleted file mode 100644 index 0cbdfd70c2..0000000000 --- a/transport/clashssr/protocol/auth_chain_a.go +++ /dev/null @@ -1,306 +0,0 @@ -package protocol - -import ( - "bytes" - "crypto/cipher" - "crypto/rand" - "crypto/rc4" - "encoding/base64" - "encoding/binary" - "net" - "strconv" - "strings" - - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/transport/shadowsocks/core" - "github.com/Dreamacro/clash/transport/ssr/tools" -) - -func init() { - register("auth_chain_a", newAuthChainA, 4) -} - -type randDataLengthMethod func(int, []byte, *tools.XorShift128Plus) int - -type authChainA struct { - *Base - *authData - *userData - iv []byte - salt string - hasSentHeader bool - rawTrans bool - lastClientHash []byte - lastServerHash []byte - encrypter cipher.Stream - decrypter cipher.Stream - randomClient tools.XorShift128Plus - randomServer tools.XorShift128Plus - randDataLength randDataLengthMethod - packID uint32 - recvID uint32 -} - -func newAuthChainA(b *Base) Protocol { - a := &authChainA{ - Base: b, - authData: &authData{}, - userData: &userData{}, - salt: "auth_chain_a", - } - a.initUserData() - return a -} - -func (a *authChainA) initUserData() { - params := strings.Split(a.Param, ":") - if len(params) > 1 { - if userID, err := strconv.ParseUint(params[0], 10, 32); err == nil { - binary.LittleEndian.PutUint32(a.userID[:], uint32(userID)) - a.userKey = []byte(params[1]) - } - } - if len(a.userKey) == 0 { - a.userKey = a.Key - rand.Read(a.userID[:]) - } -} - -func (a *authChainA) StreamConn(c net.Conn, iv []byte) net.Conn { - p := &authChainA{ - Base: a.Base, - authData: a.next(), - userData: a.userData, - salt: a.salt, - packID: 1, - recvID: 1, - } - p.iv = iv - p.randDataLength = p.getRandLength - return &Conn{Conn: c, Protocol: p} -} - -func (a *authChainA) PacketConn(c net.PacketConn) net.PacketConn { - p := &authChainA{ - Base: a.Base, - salt: a.salt, - userData: a.userData, - } - return &PacketConn{PacketConn: c, Protocol: p} -} - -func (a *authChainA) Decode(dst, src *bytes.Buffer) error { - if a.rawTrans { - dst.ReadFrom(src) - return nil - } - for src.Len() > 4 { - macKey := pool.Get(len(a.userKey) + 4) - defer pool.Put(macKey) - copy(macKey, a.userKey) - binary.LittleEndian.PutUint32(macKey[len(a.userKey):], a.recvID) - - dataLength := int(binary.LittleEndian.Uint16(src.Bytes()[:2]) ^ binary.LittleEndian.Uint16(a.lastServerHash[14:16])) - randDataLength := a.randDataLength(dataLength, a.lastServerHash, &a.randomServer) - length := dataLength + randDataLength - - if length >= 4096 { - a.rawTrans = true - src.Reset() - return errAuthChainLengthError - } - - if 4+length > src.Len() { - break - } - - serverHash := tools.HmacMD5(macKey, src.Bytes()[:length+2]) - if !bytes.Equal(serverHash[:2], src.Bytes()[length+2:length+4]) { - a.rawTrans = true - src.Reset() - return errAuthChainChksumError - } - a.lastServerHash = serverHash - - pos := 2 - if dataLength > 0 && randDataLength > 0 { - pos += getRandStartPos(randDataLength, &a.randomServer) - } - wantedData := src.Bytes()[pos : pos+dataLength] - a.decrypter.XORKeyStream(wantedData, wantedData) - if a.recvID == 1 { - dst.Write(wantedData[2:]) - } else { - dst.Write(wantedData) - } - a.recvID++ - src.Next(length + 4) - } - return nil -} - -func (a *authChainA) Encode(buf *bytes.Buffer, b []byte) error { - if !a.hasSentHeader { - dataLength := getDataLength(b) - a.packAuthData(buf, b[:dataLength]) - b = b[dataLength:] - a.hasSentHeader = true - } - for len(b) > 2800 { - a.packData(buf, b[:2800]) - b = b[2800:] - } - if len(b) > 0 { - a.packData(buf, b) - } - return nil -} - -func (a *authChainA) DecodePacket(b []byte) ([]byte, error) { - if len(b) < 9 { - return nil, errAuthChainLengthError - } - if !bytes.Equal(tools.HmacMD5(a.userKey, b[:len(b)-1])[:1], b[len(b)-1:]) { - return nil, errAuthChainChksumError - } - md5Data := tools.HmacMD5(a.Key, b[len(b)-8:len(b)-1]) - - randDataLength := udpGetRandLength(md5Data, &a.randomServer) - - key := core.Kdf(base64.StdEncoding.EncodeToString(a.userKey)+base64.StdEncoding.EncodeToString(md5Data), 16) - rc4Cipher, err := rc4.NewCipher(key) - if err != nil { - return nil, err - } - wantedData := b[:len(b)-8-randDataLength] - rc4Cipher.XORKeyStream(wantedData, wantedData) - return wantedData, nil -} - -func (a *authChainA) EncodePacket(buf *bytes.Buffer, b []byte) error { - authData := pool.Get(3) - defer pool.Put(authData) - rand.Read(authData) - - md5Data := tools.HmacMD5(a.Key, authData) - - randDataLength := udpGetRandLength(md5Data, &a.randomClient) - - key := core.Kdf(base64.StdEncoding.EncodeToString(a.userKey)+base64.StdEncoding.EncodeToString(md5Data), 16) - rc4Cipher, err := rc4.NewCipher(key) - if err != nil { - return err - } - rc4Cipher.XORKeyStream(b, b) - - buf.Write(b) - tools.AppendRandBytes(buf, randDataLength) - buf.Write(authData) - binary.Write(buf, binary.LittleEndian, binary.LittleEndian.Uint32(a.userID[:])^binary.LittleEndian.Uint32(md5Data[:4])) - buf.Write(tools.HmacMD5(a.userKey, buf.Bytes())[:1]) - return nil -} - -func (a *authChainA) packAuthData(poolBuf *bytes.Buffer, data []byte) { - /* - dataLength := len(data) - 12: checkHead(4) and hmac of checkHead(8) - 4: uint32 LittleEndian uid (uid = userID ^ last client hash) - 16: encrypted data of authdata(12), uint16 LittleEndian overhead(2) and uint16 LittleEndian number zero(2) - 4: last server hash(4) - packedAuthDataLength := 12 + 4 + 16 + 4 + dataLength - */ - - macKey := pool.Get(len(a.iv) + len(a.Key)) - defer pool.Put(macKey) - copy(macKey, a.iv) - copy(macKey[len(a.iv):], a.Key) - - // check head - tools.AppendRandBytes(poolBuf, 4) - a.lastClientHash = tools.HmacMD5(macKey, poolBuf.Bytes()) - a.initRC4Cipher() - poolBuf.Write(a.lastClientHash[:8]) - // uid - binary.Write(poolBuf, binary.LittleEndian, binary.LittleEndian.Uint32(a.userID[:])^binary.LittleEndian.Uint32(a.lastClientHash[8:12])) - // encrypted data - err := a.putEncryptedData(poolBuf, a.userKey, [2]int{a.Overhead, 0}, a.salt) - if err != nil { - poolBuf.Reset() - return - } - // last server hash - a.lastServerHash = tools.HmacMD5(a.userKey, poolBuf.Bytes()[12:]) - poolBuf.Write(a.lastServerHash[:4]) - // packed data - a.packData(poolBuf, data) -} - -func (a *authChainA) packData(poolBuf *bytes.Buffer, data []byte) { - a.encrypter.XORKeyStream(data, data) - - macKey := pool.Get(len(a.userKey) + 4) - defer pool.Put(macKey) - copy(macKey, a.userKey) - binary.LittleEndian.PutUint32(macKey[len(a.userKey):], a.packID) - a.packID++ - - length := uint16(len(data)) ^ binary.LittleEndian.Uint16(a.lastClientHash[14:16]) - - originalLength := poolBuf.Len() - binary.Write(poolBuf, binary.LittleEndian, length) - a.putMixedRandDataAndData(poolBuf, data) - a.lastClientHash = tools.HmacMD5(macKey, poolBuf.Bytes()[originalLength:]) - poolBuf.Write(a.lastClientHash[:2]) -} - -func (a *authChainA) putMixedRandDataAndData(poolBuf *bytes.Buffer, data []byte) { - randDataLength := a.randDataLength(len(data), a.lastClientHash, &a.randomClient) - if len(data) == 0 { - tools.AppendRandBytes(poolBuf, randDataLength) - return - } - if randDataLength > 0 { - startPos := getRandStartPos(randDataLength, &a.randomClient) - tools.AppendRandBytes(poolBuf, startPos) - poolBuf.Write(data) - tools.AppendRandBytes(poolBuf, randDataLength-startPos) - return - } - poolBuf.Write(data) -} - -func getRandStartPos(length int, random *tools.XorShift128Plus) int { - if length == 0 { - return 0 - } - return int(int64(random.Next()%8589934609) % int64(length)) -} - -func (a *authChainA) getRandLength(length int, lastHash []byte, random *tools.XorShift128Plus) int { - if length > 1440 { - return 0 - } - random.InitFromBinAndLength(lastHash, length) - if length > 1300 { - return int(random.Next() % 31) - } - if length > 900 { - return int(random.Next() % 127) - } - if length > 400 { - return int(random.Next() % 521) - } - return int(random.Next() % 1021) -} - -func (a *authChainA) initRC4Cipher() { - key := core.Kdf(base64.StdEncoding.EncodeToString(a.userKey)+base64.StdEncoding.EncodeToString(a.lastClientHash), 16) - a.encrypter, _ = rc4.NewCipher(key) - a.decrypter, _ = rc4.NewCipher(key) -} - -func udpGetRandLength(lastHash []byte, random *tools.XorShift128Plus) int { - random.InitFromBin(lastHash) - return int(random.Next() % 127) -} diff --git a/transport/clashssr/protocol/auth_chain_b.go b/transport/clashssr/protocol/auth_chain_b.go deleted file mode 100644 index 857b2a3aa1..0000000000 --- a/transport/clashssr/protocol/auth_chain_b.go +++ /dev/null @@ -1,97 +0,0 @@ -package protocol - -import ( - "net" - "sort" - - "github.com/Dreamacro/clash/transport/ssr/tools" -) - -func init() { - register("auth_chain_b", newAuthChainB, 4) -} - -type authChainB struct { - *authChainA - dataSizeList []int - dataSizeList2 []int -} - -func newAuthChainB(b *Base) Protocol { - a := &authChainB{ - authChainA: &authChainA{ - Base: b, - authData: &authData{}, - userData: &userData{}, - salt: "auth_chain_b", - }, - } - a.initUserData() - return a -} - -func (a *authChainB) StreamConn(c net.Conn, iv []byte) net.Conn { - p := &authChainB{ - authChainA: &authChainA{ - Base: a.Base, - authData: a.next(), - userData: a.userData, - salt: a.salt, - packID: 1, - recvID: 1, - }, - } - p.iv = iv - p.randDataLength = p.getRandLength - p.initDataSize() - return &Conn{Conn: c, Protocol: p} -} - -func (a *authChainB) initDataSize() { - a.dataSizeList = a.dataSizeList[:0] - a.dataSizeList2 = a.dataSizeList2[:0] - - a.randomServer.InitFromBin(a.Key) - length := a.randomServer.Next()%8 + 4 - for ; length > 0; length-- { - a.dataSizeList = append(a.dataSizeList, int(a.randomServer.Next()%2340%2040%1440)) - } - sort.Ints(a.dataSizeList) - - length = a.randomServer.Next()%16 + 8 - for ; length > 0; length-- { - a.dataSizeList2 = append(a.dataSizeList2, int(a.randomServer.Next()%2340%2040%1440)) - } - sort.Ints(a.dataSizeList2) -} - -func (a *authChainB) getRandLength(length int, lashHash []byte, random *tools.XorShift128Plus) int { - if length >= 1440 { - return 0 - } - random.InitFromBinAndLength(lashHash, length) - pos := sort.Search(len(a.dataSizeList), func(i int) bool { return a.dataSizeList[i] >= length+a.Overhead }) - finalPos := pos + int(random.Next()%uint64(len(a.dataSizeList))) - if finalPos < len(a.dataSizeList) { - return a.dataSizeList[finalPos] - length - a.Overhead - } - - pos = sort.Search(len(a.dataSizeList2), func(i int) bool { return a.dataSizeList2[i] >= length+a.Overhead }) - finalPos = pos + int(random.Next()%uint64(len(a.dataSizeList2))) - if finalPos < len(a.dataSizeList2) { - return a.dataSizeList2[finalPos] - length - a.Overhead - } - if finalPos < pos+len(a.dataSizeList2)-1 { - return 0 - } - if length > 1300 { - return int(random.Next() % 31) - } - if length > 900 { - return int(random.Next() % 127) - } - if length > 400 { - return int(random.Next() % 521) - } - return int(random.Next() % 1021) -} diff --git a/transport/clashssr/protocol/auth_sha1_v4.go b/transport/clashssr/protocol/auth_sha1_v4.go deleted file mode 100644 index 30392c9e77..0000000000 --- a/transport/clashssr/protocol/auth_sha1_v4.go +++ /dev/null @@ -1,182 +0,0 @@ -package protocol - -import ( - "bytes" - "encoding/binary" - "hash/adler32" - "hash/crc32" - "math/rand" - "net" - - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/transport/ssr/tools" -) - -func init() { - register("auth_sha1_v4", newAuthSHA1V4, 7) -} - -type authSHA1V4 struct { - *Base - *authData - iv []byte - hasSentHeader bool - rawTrans bool -} - -func newAuthSHA1V4(b *Base) Protocol { - return &authSHA1V4{Base: b, authData: &authData{}} -} - -func (a *authSHA1V4) StreamConn(c net.Conn, iv []byte) net.Conn { - p := &authSHA1V4{Base: a.Base, authData: a.next()} - p.iv = iv - return &Conn{Conn: c, Protocol: p} -} - -func (a *authSHA1V4) PacketConn(c net.PacketConn) net.PacketConn { - return c -} - -func (a *authSHA1V4) Decode(dst, src *bytes.Buffer) error { - if a.rawTrans { - dst.ReadFrom(src) - return nil - } - for src.Len() > 4 { - if uint16(crc32.ChecksumIEEE(src.Bytes()[:2])&0xffff) != binary.LittleEndian.Uint16(src.Bytes()[2:4]) { - src.Reset() - return errAuthSHA1V4CRC32Error - } - - length := int(binary.BigEndian.Uint16(src.Bytes()[:2])) - if length >= 8192 || length < 7 { - a.rawTrans = true - src.Reset() - return errAuthSHA1V4LengthError - } - if length > src.Len() { - break - } - - if adler32.Checksum(src.Bytes()[:length-4]) != binary.LittleEndian.Uint32(src.Bytes()[length-4:length]) { - a.rawTrans = true - src.Reset() - return errAuthSHA1V4Adler32Error - } - - pos := int(src.Bytes()[4]) - if pos < 255 { - pos += 4 - } else { - pos = int(binary.BigEndian.Uint16(src.Bytes()[5:7])) + 4 - } - dst.Write(src.Bytes()[pos : length-4]) - src.Next(length) - } - return nil -} - -func (a *authSHA1V4) Encode(buf *bytes.Buffer, b []byte) error { - if !a.hasSentHeader { - dataLength := getDataLength(b) - - a.packAuthData(buf, b[:dataLength]) - b = b[dataLength:] - - a.hasSentHeader = true - } - for len(b) > 8100 { - a.packData(buf, b[:8100]) - b = b[8100:] - } - if len(b) > 0 { - a.packData(buf, b) - } - - return nil -} - -func (a *authSHA1V4) DecodePacket(b []byte) ([]byte, error) { return b, nil } - -func (a *authSHA1V4) EncodePacket(buf *bytes.Buffer, b []byte) error { - buf.Write(b) - return nil -} - -func (a *authSHA1V4) packData(poolBuf *bytes.Buffer, data []byte) { - dataLength := len(data) - randDataLength := a.getRandDataLength(dataLength) - /* - 2: uint16 BigEndian packedDataLength - 2: uint16 LittleEndian crc32Data & 0xffff - 3: maxRandDataLengthPrefix (min:1) - 4: adler32Data - */ - packedDataLength := 2 + 2 + 3 + randDataLength + dataLength + 4 - if randDataLength < 128 { - packedDataLength -= 2 - } - - binary.Write(poolBuf, binary.BigEndian, uint16(packedDataLength)) - binary.Write(poolBuf, binary.LittleEndian, uint16(crc32.ChecksumIEEE(poolBuf.Bytes()[poolBuf.Len()-2:])&0xffff)) - a.packRandData(poolBuf, randDataLength) - poolBuf.Write(data) - binary.Write(poolBuf, binary.LittleEndian, adler32.Checksum(poolBuf.Bytes()[poolBuf.Len()-packedDataLength+4:])) -} - -func (a *authSHA1V4) packAuthData(poolBuf *bytes.Buffer, data []byte) { - dataLength := len(data) - randDataLength := a.getRandDataLength(12 + dataLength) - /* - 2: uint16 BigEndian packedAuthDataLength - 4: uint32 LittleEndian crc32Data - 3: maxRandDataLengthPrefix (min: 1) - 12: authDataLength - 10: hmacSHA1DataLength - */ - packedAuthDataLength := 2 + 4 + 3 + randDataLength + 12 + dataLength + 10 - if randDataLength < 128 { - packedAuthDataLength -= 2 - } - - salt := []byte("auth_sha1_v4") - crcData := pool.Get(len(salt) + len(a.Key) + 2) - defer pool.Put(crcData) - binary.BigEndian.PutUint16(crcData, uint16(packedAuthDataLength)) - copy(crcData[2:], salt) - copy(crcData[2+len(salt):], a.Key) - - key := pool.Get(len(a.iv) + len(a.Key)) - defer pool.Put(key) - copy(key, a.iv) - copy(key[len(a.iv):], a.Key) - - poolBuf.Write(crcData[:2]) - binary.Write(poolBuf, binary.LittleEndian, crc32.ChecksumIEEE(crcData)) - a.packRandData(poolBuf, randDataLength) - a.putAuthData(poolBuf) - poolBuf.Write(data) - poolBuf.Write(tools.HmacSHA1(key, poolBuf.Bytes()[poolBuf.Len()-packedAuthDataLength+10:])[:10]) -} - -func (a *authSHA1V4) packRandData(poolBuf *bytes.Buffer, size int) { - if size < 128 { - poolBuf.WriteByte(byte(size + 1)) - tools.AppendRandBytes(poolBuf, size) - return - } - poolBuf.WriteByte(255) - binary.Write(poolBuf, binary.BigEndian, uint16(size+3)) - tools.AppendRandBytes(poolBuf, size) -} - -func (a *authSHA1V4) getRandDataLength(size int) int { - if size > 1200 { - return 0 - } - if size > 400 { - return rand.Intn(256) - } - return rand.Intn(512) -} diff --git a/transport/clashssr/protocol/base.go b/transport/clashssr/protocol/base.go deleted file mode 100644 index e187fcb7fa..0000000000 --- a/transport/clashssr/protocol/base.go +++ /dev/null @@ -1,75 +0,0 @@ -package protocol - -import ( - "bytes" - "crypto/aes" - "crypto/cipher" - "encoding/base64" - "encoding/binary" - "math/rand" - "sync" - "time" - - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/transport/shadowsocks/core" -) - -type Base struct { - Key []byte - Overhead int - Param string -} - -type userData struct { - userKey []byte - userID [4]byte -} - -type authData struct { - clientID [4]byte - connectionID uint32 - mutex sync.Mutex -} - -func (a *authData) next() *authData { - r := &authData{} - a.mutex.Lock() - defer a.mutex.Unlock() - if a.connectionID > 0xff000000 || a.connectionID == 0 { - rand.Read(a.clientID[:]) - a.connectionID = rand.Uint32() & 0xffffff - } - a.connectionID++ - copy(r.clientID[:], a.clientID[:]) - r.connectionID = a.connectionID - return r -} - -func (a *authData) putAuthData(buf *bytes.Buffer) { - binary.Write(buf, binary.LittleEndian, uint32(time.Now().Unix())) - buf.Write(a.clientID[:]) - binary.Write(buf, binary.LittleEndian, a.connectionID) -} - -func (a *authData) putEncryptedData(b *bytes.Buffer, userKey []byte, paddings [2]int, salt string) error { - encrypt := pool.Get(16) - defer pool.Put(encrypt) - binary.LittleEndian.PutUint32(encrypt, uint32(time.Now().Unix())) - copy(encrypt[4:], a.clientID[:]) - binary.LittleEndian.PutUint32(encrypt[8:], a.connectionID) - binary.LittleEndian.PutUint16(encrypt[12:], uint16(paddings[0])) - binary.LittleEndian.PutUint16(encrypt[14:], uint16(paddings[1])) - - cipherKey := core.Kdf(base64.StdEncoding.EncodeToString(userKey)+salt, 16) - block, err := aes.NewCipher(cipherKey) - if err != nil { - return err - } - iv := bytes.Repeat([]byte{0}, 16) - cbcCipher := cipher.NewCBCEncrypter(block, iv) - - cbcCipher.CryptBlocks(encrypt, encrypt) - - b.Write(encrypt) - return nil -} diff --git a/transport/clashssr/protocol/origin.go b/transport/clashssr/protocol/origin.go deleted file mode 100644 index 80fdfa9a1b..0000000000 --- a/transport/clashssr/protocol/origin.go +++ /dev/null @@ -1,33 +0,0 @@ -package protocol - -import ( - "bytes" - "net" -) - -type origin struct{} - -func init() { register("origin", newOrigin, 0) } - -func newOrigin(b *Base) Protocol { return &origin{} } - -func (o *origin) StreamConn(c net.Conn, iv []byte) net.Conn { return c } - -func (o *origin) PacketConn(c net.PacketConn) net.PacketConn { return c } - -func (o *origin) Decode(dst, src *bytes.Buffer) error { - dst.ReadFrom(src) - return nil -} - -func (o *origin) Encode(buf *bytes.Buffer, b []byte) error { - buf.Write(b) - return nil -} - -func (o *origin) DecodePacket(b []byte) ([]byte, error) { return b, nil } - -func (o *origin) EncodePacket(buf *bytes.Buffer, b []byte) error { - buf.Write(b) - return nil -} diff --git a/transport/clashssr/protocol/packet.go b/transport/clashssr/protocol/packet.go deleted file mode 100644 index 249db70a26..0000000000 --- a/transport/clashssr/protocol/packet.go +++ /dev/null @@ -1,36 +0,0 @@ -package protocol - -import ( - "net" - - "github.com/Dreamacro/clash/common/pool" -) - -type PacketConn struct { - net.PacketConn - Protocol -} - -func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { - buf := pool.GetBuffer() - defer pool.PutBuffer(buf) - err := c.EncodePacket(buf, b) - if err != nil { - return 0, err - } - _, err = c.PacketConn.WriteTo(buf.Bytes(), addr) - return len(b), err -} - -func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { - n, addr, err := c.PacketConn.ReadFrom(b) - if err != nil { - return n, addr, err - } - decoded, err := c.DecodePacket(b[:n]) - if err != nil { - return n, addr, err - } - copy(b, decoded) - return len(decoded), addr, nil -} diff --git a/transport/clashssr/protocol/protocol.go b/transport/clashssr/protocol/protocol.go deleted file mode 100644 index 41bd984c8b..0000000000 --- a/transport/clashssr/protocol/protocol.go +++ /dev/null @@ -1,76 +0,0 @@ -package protocol - -import ( - "bytes" - "errors" - "fmt" - "math/rand" - "net" -) - -var ( - errAuthSHA1V4CRC32Error = errors.New("auth_sha1_v4 decode data wrong crc32") - errAuthSHA1V4LengthError = errors.New("auth_sha1_v4 decode data wrong length") - errAuthSHA1V4Adler32Error = errors.New("auth_sha1_v4 decode data wrong adler32") - errAuthAES128MACError = errors.New("auth_aes128 decode data wrong mac") - errAuthAES128LengthError = errors.New("auth_aes128 decode data wrong length") - errAuthAES128ChksumError = errors.New("auth_aes128 decode data wrong checksum") - errAuthChainLengthError = errors.New("auth_chain decode data wrong length") - errAuthChainChksumError = errors.New("auth_chain decode data wrong checksum") -) - -type Protocol interface { - StreamConn(net.Conn, []byte) net.Conn - PacketConn(net.PacketConn) net.PacketConn - Decode(dst, src *bytes.Buffer) error - Encode(buf *bytes.Buffer, b []byte) error - DecodePacket([]byte) ([]byte, error) - EncodePacket(buf *bytes.Buffer, b []byte) error -} - -type protocolCreator func(b *Base) Protocol - -var protocolList = make(map[string]struct { - overhead int - new protocolCreator -}) - -func register(name string, c protocolCreator, o int) { - protocolList[name] = struct { - overhead int - new protocolCreator - }{overhead: o, new: c} -} - -func PickProtocol(name string, b *Base) (Protocol, error) { - if choice, ok := protocolList[name]; ok { - b.Overhead += choice.overhead - return choice.new(b), nil - } - return nil, fmt.Errorf("protocol %s not supported", name) -} - -func getHeadSize(b []byte, defaultValue int) int { - if len(b) < 2 { - return defaultValue - } - headType := b[0] & 7 - switch headType { - case 1: - return 7 - case 4: - return 19 - case 3: - return 4 + int(b[1]) - } - return defaultValue -} - -func getDataLength(b []byte) int { - bLength := len(b) - dataLength := getHeadSize(b, 30) + rand.Intn(32) - if bLength < dataLength { - return bLength - } - return dataLength -} diff --git a/transport/clashssr/protocol/stream.go b/transport/clashssr/protocol/stream.go deleted file mode 100644 index 3c846157a7..0000000000 --- a/transport/clashssr/protocol/stream.go +++ /dev/null @@ -1,50 +0,0 @@ -package protocol - -import ( - "bytes" - "net" - - "github.com/Dreamacro/clash/common/pool" -) - -type Conn struct { - net.Conn - Protocol - decoded bytes.Buffer - underDecoded bytes.Buffer -} - -func (c *Conn) Read(b []byte) (int, error) { - if c.decoded.Len() > 0 { - return c.decoded.Read(b) - } - - buf := pool.Get(pool.RelayBufferSize) - defer pool.Put(buf) - n, err := c.Conn.Read(buf) - if err != nil { - return 0, err - } - c.underDecoded.Write(buf[:n]) - err = c.Decode(&c.decoded, &c.underDecoded) - if err != nil { - return 0, err - } - n, _ = c.decoded.Read(b) - return n, nil -} - -func (c *Conn) Write(b []byte) (int, error) { - bLength := len(b) - buf := pool.GetBuffer() - defer pool.PutBuffer(buf) - err := c.Encode(buf, b) - if err != nil { - return 0, err - } - _, err = c.Conn.Write(buf.Bytes()) - if err != nil { - return 0, err - } - return bLength, nil -} From bea177a4cd46174f0f260430e264afab6df086ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 25 Oct 2023 12:00:00 +0800 Subject: [PATCH 17/87] Improve linux bind interface --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5e48872e1f..f6c732fce6 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.2.15 + github.com/sagernet/sing v0.2.16-0.20231021090846-8002db54c028 github.com/sagernet/sing-dns v0.1.10 github.com/sagernet/sing-mux v0.1.3 github.com/sagernet/sing-quic v0.1.2 diff --git a/go.sum b/go.sum index fa41839610..a74cb62906 100644 --- a/go.sum +++ b/go.sum @@ -110,8 +110,8 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.15 h1:PFwyiMzkyJkq+YGOVznJUsRVOT6EoVxRGIsllLuvHXA= -github.com/sagernet/sing v0.2.15/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= +github.com/sagernet/sing v0.2.16-0.20231021090846-8002db54c028 h1:6GbQt7SC9y5Imrq5jDMbXDSaNiMhJ8KBjhjtQRuqQvE= +github.com/sagernet/sing v0.2.16-0.20231021090846-8002db54c028/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlTZCI= github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= From e143fc510d0640cd100b1208e3e2c1244b8b406d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 21 Oct 2023 12:00:00 +0800 Subject: [PATCH 18/87] Update gVisor to 20230814.0 --- experimental/libbox/monitor.go | 11 +++++++++++ go.mod | 4 ++-- go.sum | 8 ++++---- route/router.go | 5 ++--- transport/wireguard/device_stack.go | 4 ++++ 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/experimental/libbox/monitor.go b/experimental/libbox/monitor.go index 1cd2913970..575466c942 100644 --- a/experimental/libbox/monitor.go +++ b/experimental/libbox/monitor.go @@ -65,6 +65,17 @@ func (m *platformDefaultInterfaceMonitor) DefaultInterfaceIndex(destination neti return m.defaultInterfaceIndex } +func (m *platformDefaultInterfaceMonitor) DefaultInterface(destination netip.Addr) (string, int) { + for _, address := range m.networkAddresses { + for _, prefix := range address.addresses { + if prefix.Contains(destination) { + return address.interfaceName, address.interfaceIndex + } + } + } + return m.defaultInterfaceName, m.defaultInterfaceIndex +} + func (m *platformDefaultInterfaceMonitor) OverrideAndroidVPN() bool { return false } diff --git a/go.mod b/go.mod index f6c732fce6..f0c48932c1 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950 - github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 + github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/sing v0.2.16-0.20231021090846-8002db54c028 @@ -33,7 +33,7 @@ require ( github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 github.com/sagernet/sing-shadowtls v0.1.4 - github.com/sagernet/sing-tun v0.1.16 + github.com/sagernet/sing-tun v0.1.17-0.20231026060825-efd9884154a6 github.com/sagernet/sing-vmess v0.1.8 github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 diff --git a/go.sum b/go.sum index a74cb62906..dfc88fd0f0 100644 --- a/go.sum +++ b/go.sum @@ -100,8 +100,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950 h1:hUz/2mJLgi7l2H36JGpDY+jou9FmI6kAm0ZkU+xPpgE= github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950/go.mod h1:5YE39YkJkCcMsfq1jMKkjsrM2GfBoF9JVWnvU89hmvU= -github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 h1:dnkKrzapqtAwjTSWt6hdPrARORfoYvuUczynvRLrueo= -github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2/go.mod h1:1JUiV7nGuf++YFm9eWZ8q2lrwHmhcUGzptMl/vL1+LA= +github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab h1:u+xQoi/Yc6bNUvTfrDD6HhGRybn2lzrhf5vmS+wb4Ho= +github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab/go.mod h1:3akUhSHSVtLuJaYcW5JPepUraBOW06Ibz2HKwaK5rOk= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee h1:ykuhl9jCS638N+jw1vC9AvT9bbQn6xRNScP2FWPV9dM= @@ -124,8 +124,8 @@ github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+M github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.16 h1:RHXYIVg6uacvdfbYMiPEz9VX5uu6mNrvP7u9yAH3oNc= -github.com/sagernet/sing-tun v0.1.16/go.mod h1:S3q8GCjeyRniK+KLmo4XqKY0bS3x2UdKkKbqxT/Agl8= +github.com/sagernet/sing-tun v0.1.17-0.20231026060825-efd9884154a6 h1:4yEXBqQoUgXj7qPSLD6lr+z9/KfsvixO9JUA2i5xnM8= +github.com/sagernet/sing-tun v0.1.17-0.20231026060825-efd9884154a6/go.mod h1:w2+S+uWE94E/pQWSDdDdMIjwAEb645kuGPunr6ZllUg= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= diff --git a/route/router.go b/route/router.go index e7658c1866..6506f05ff2 100644 --- a/route/router.go +++ b/route/router.go @@ -930,9 +930,8 @@ func (r *Router) AutoDetectInterfaceFunc() control.Func { return control.BindToInterfaceFunc(r.InterfaceFinder(), func(network string, address string) (interfaceName string, interfaceIndex int, err error) { remoteAddr := M.ParseSocksaddr(address).Addr if C.IsLinux { - interfaceName = r.InterfaceMonitor().DefaultInterfaceName(remoteAddr) - interfaceIndex = -1 - if interfaceName == "" { + interfaceName, interfaceIndex = r.InterfaceMonitor().DefaultInterface(remoteAddr) + if interfaceIndex == -1 { err = tun.ErrNoRoute } } else { diff --git a/transport/wireguard/device_stack.go b/transport/wireguard/device_stack.go index 215993056b..4ddaffe1f2 100644 --- a/transport/wireguard/device_stack.go +++ b/transport/wireguard/device_stack.go @@ -286,6 +286,10 @@ func (ep *wireEndpoint) ARPHardwareType() header.ARPHardwareType { func (ep *wireEndpoint) AddHeader(buffer stack.PacketBufferPtr) { } +func (ep *wireEndpoint) ParseHeader(ptr stack.PacketBufferPtr) bool { + return true +} + func (ep *wireEndpoint) WritePackets(list stack.PacketBufferList) (int, tcpip.Error) { for _, packetBuffer := range list.AsSlice() { packetBuffer.IncRef() From ac930cf1aa6c39233183bea8d25b84b7df2acdf4 Mon Sep 17 00:00:00 2001 From: septs Date: Sat, 21 Oct 2023 12:00:00 +0800 Subject: [PATCH 19/87] Improve naive auth logical --- inbound/naive.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/inbound/naive.go b/inbound/naive.go index 7542ae0c11..0ea2bbb5df 100644 --- a/inbound/naive.go +++ b/inbound/naive.go @@ -2,7 +2,6 @@ package inbound import ( "context" - "encoding/base64" "encoding/binary" "io" "math/rand" @@ -139,14 +138,9 @@ func (n *Naive) ServeHTTP(writer http.ResponseWriter, request *http.Request) { n.badRequest(ctx, request, E.New("missing naive padding")) return } - var authOk bool - var userName string - authorization := request.Header.Get("Proxy-Authorization") - if strings.HasPrefix(authorization, "BASIC ") || strings.HasPrefix(authorization, "Basic ") { - userPassword, _ := base64.URLEncoding.DecodeString(authorization[6:]) - userPswdArr := strings.SplitN(string(userPassword), ":", 2) - userName = userPswdArr[0] - authOk = n.authenticator.Verify(userPswdArr[0], userPswdArr[1]) + userName, password, authOk := sHttp.ParseBasicAuth(request.Header.Get("Proxy-Authorization")) + if authOk { + authOk = n.authenticator.Verify(userName, password) } if !authOk { rejectHTTP(writer, http.StatusProxyAuthRequired) From 41fd1778a72ecf9c22561d7690873d413eb2123a Mon Sep 17 00:00:00 2001 From: septs Date: Sat, 21 Oct 2023 12:00:00 +0800 Subject: [PATCH 20/87] Improve HTTP headers option --- option/simple.go | 10 +++++----- option/types.go | 13 +++++++++++++ option/v2ray_transport.go | 20 ++++++++++---------- outbound/http.go | 10 +--------- transport/v2rayhttp/client.go | 5 +---- transport/v2rayhttp/server.go | 5 +---- 6 files changed, 31 insertions(+), 32 deletions(-) diff --git a/option/simple.go b/option/simple.go index dec1e0e0c1..55bfe93005 100644 --- a/option/simple.go +++ b/option/simple.go @@ -27,9 +27,9 @@ type SocksOutboundOptions struct { type HTTPOutboundOptions struct { DialerOptions ServerOptions - Username string `json:"username,omitempty"` - Password string `json:"password,omitempty"` - TLS *OutboundTLSOptions `json:"tls,omitempty"` - Path string `json:"path,omitempty"` - Headers map[string]Listable[string] `json:"headers,omitempty"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + TLS *OutboundTLSOptions `json:"tls,omitempty"` + Path string `json:"path,omitempty"` + Headers HTTPHeader `json:"headers,omitempty"` } diff --git a/option/types.go b/option/types.go index 8a5e6cfc52..a357387f2c 100644 --- a/option/types.go +++ b/option/types.go @@ -1,6 +1,7 @@ package option import ( + "net/http" "net/netip" "strings" "time" @@ -235,3 +236,15 @@ func DNSQueryTypeToString(queryType uint16) string { } return F.ToString(queryType) } + +type HTTPHeader map[string]Listable[string] + +func (h HTTPHeader) Build() http.Header { + header := make(http.Header) + for name, values := range h { + for _, value := range values { + header.Add(name, value) + } + } + return header +} diff --git a/option/v2ray_transport.go b/option/v2ray_transport.go index b01cafa700..54b0de7913 100644 --- a/option/v2ray_transport.go +++ b/option/v2ray_transport.go @@ -61,19 +61,19 @@ func (o *V2RayTransportOptions) UnmarshalJSON(bytes []byte) error { } type V2RayHTTPOptions struct { - Host Listable[string] `json:"host,omitempty"` - Path string `json:"path,omitempty"` - Method string `json:"method,omitempty"` - Headers map[string]Listable[string] `json:"headers,omitempty"` - IdleTimeout Duration `json:"idle_timeout,omitempty"` - PingTimeout Duration `json:"ping_timeout,omitempty"` + Host Listable[string] `json:"host,omitempty"` + Path string `json:"path,omitempty"` + Method string `json:"method,omitempty"` + Headers HTTPHeader `json:"headers,omitempty"` + IdleTimeout Duration `json:"idle_timeout,omitempty"` + PingTimeout Duration `json:"ping_timeout,omitempty"` } type V2RayWebsocketOptions struct { - Path string `json:"path,omitempty"` - Headers map[string]Listable[string] `json:"headers,omitempty"` - MaxEarlyData uint32 `json:"max_early_data,omitempty"` - EarlyDataHeaderName string `json:"early_data_header_name,omitempty"` + Path string `json:"path,omitempty"` + Headers HTTPHeader `json:"headers,omitempty"` + MaxEarlyData uint32 `json:"max_early_data,omitempty"` + EarlyDataHeaderName string `json:"early_data_header_name,omitempty"` } type V2RayQUICOptions struct{} diff --git a/outbound/http.go b/outbound/http.go index cd9dc9593e..cfc03216fa 100644 --- a/outbound/http.go +++ b/outbound/http.go @@ -3,7 +3,6 @@ package outbound import ( "context" "net" - "net/http" "os" "github.com/sagernet/sing-box/adapter" @@ -34,13 +33,6 @@ func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogge if err != nil { return nil, err } - var headers http.Header - if options.Headers != nil { - headers = make(http.Header) - for key, values := range options.Headers { - headers[key] = values - } - } return &HTTP{ myOutboundAdapter{ protocol: C.TypeHTTP, @@ -56,7 +48,7 @@ func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogge Username: options.Username, Password: options.Password, Path: options.Path, - Headers: headers, + Headers: options.Headers.Build(), }), }, nil } diff --git a/transport/v2rayhttp/client.go b/transport/v2rayhttp/client.go index 4d660fef9f..d5e8a1f670 100644 --- a/transport/v2rayhttp/client.go +++ b/transport/v2rayhttp/client.go @@ -64,7 +64,7 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt serverAddr: serverAddr, host: options.Host, method: options.Method, - headers: make(http.Header), + headers: options.Headers.Build(), transport: transport, http2: tlsConfig != nil, } @@ -83,9 +83,6 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt if err != nil { return nil, E.New("failed to set path: " + err.Error()) } - for key, valueList := range options.Headers { - client.headers[key] = valueList - } client.url = &uri return client, nil } diff --git a/transport/v2rayhttp/server.go b/transport/v2rayhttp/server.go index a635e8f361..dcfb07a6e5 100644 --- a/transport/v2rayhttp/server.go +++ b/transport/v2rayhttp/server.go @@ -55,7 +55,7 @@ func NewServer(ctx context.Context, options option.V2RayHTTPOptions, tlsConfig t host: options.Host, path: options.Path, method: options.Method, - headers: make(http.Header), + headers: options.Headers.Build(), } if server.method == "" { server.method = "PUT" @@ -63,9 +63,6 @@ func NewServer(ctx context.Context, options option.V2RayHTTPOptions, tlsConfig t if !strings.HasPrefix(server.path, "/") { server.path = "/" + server.path } - for key, value := range options.Headers { - server.headers[key] = value - } server.httpServer = &http.Server{ Handler: server, ReadHeaderTimeout: C.TCPTimeout, From 3b161ab30c933d3f2448a9c24a5be6151654b76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 21 Oct 2023 12:00:00 +0800 Subject: [PATCH 21/87] Fix netip.Prefix usage --- inbound/tun.go | 8 ++++---- option/dns.go | 6 ++++-- option/tun.go | 10 ++++++---- option/types.go | 28 ---------------------------- option/wireguard.go | 4 +++- outbound/wireguard.go | 10 ++++------ route/router.go | 4 ++-- 7 files changed, 23 insertions(+), 47 deletions(-) diff --git a/inbound/tun.go b/inbound/tun.go index 9156d20361..0b57482d39 100644 --- a/inbound/tun.go +++ b/inbound/tun.go @@ -73,14 +73,14 @@ func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger tunOptions: tun.Options{ Name: options.InterfaceName, MTU: tunMTU, - Inet4Address: common.Map(options.Inet4Address, option.ListenPrefix.Build), - Inet6Address: common.Map(options.Inet6Address, option.ListenPrefix.Build), + Inet4Address: options.Inet4Address, + Inet6Address: options.Inet6Address, AutoRoute: options.AutoRoute, StrictRoute: options.StrictRoute, IncludeInterface: options.IncludeInterface, ExcludeInterface: options.ExcludeInterface, - Inet4RouteAddress: common.Map(options.Inet4RouteAddress, option.ListenPrefix.Build), - Inet6RouteAddress: common.Map(options.Inet6RouteAddress, option.ListenPrefix.Build), + Inet4RouteAddress: options.Inet4RouteAddress, + Inet6RouteAddress: options.Inet6RouteAddress, IncludeUID: includeUID, ExcludeUID: excludeUID, IncludeAndroidUser: options.IncludeAndroidUser, diff --git a/option/dns.go b/option/dns.go index 1e73fb5fe8..e0d237b7d3 100644 --- a/option/dns.go +++ b/option/dns.go @@ -1,5 +1,7 @@ package option +import "net/netip" + type DNSOptions struct { Servers []DNSServerOptions `json:"servers,omitempty"` Rules []DNSRule `json:"rules,omitempty"` @@ -28,6 +30,6 @@ type DNSClientOptions struct { type DNSFakeIPOptions struct { Enabled bool `json:"enabled,omitempty"` - Inet4Range *ListenPrefix `json:"inet4_range,omitempty"` - Inet6Range *ListenPrefix `json:"inet6_range,omitempty"` + Inet4Range *netip.Prefix `json:"inet4_range,omitempty"` + Inet6Range *netip.Prefix `json:"inet6_range,omitempty"` } diff --git a/option/tun.go b/option/tun.go index f566f0983f..4cf778041b 100644 --- a/option/tun.go +++ b/option/tun.go @@ -1,14 +1,16 @@ package option +import "net/netip" + type TunInboundOptions struct { InterfaceName string `json:"interface_name,omitempty"` MTU uint32 `json:"mtu,omitempty"` - Inet4Address Listable[ListenPrefix] `json:"inet4_address,omitempty"` - Inet6Address Listable[ListenPrefix] `json:"inet6_address,omitempty"` + Inet4Address Listable[netip.Prefix] `json:"inet4_address,omitempty"` + Inet6Address Listable[netip.Prefix] `json:"inet6_address,omitempty"` AutoRoute bool `json:"auto_route,omitempty"` StrictRoute bool `json:"strict_route,omitempty"` - Inet4RouteAddress Listable[ListenPrefix] `json:"inet4_route_address,omitempty"` - Inet6RouteAddress Listable[ListenPrefix] `json:"inet6_route_address,omitempty"` + Inet4RouteAddress Listable[netip.Prefix] `json:"inet4_route_address,omitempty"` + Inet6RouteAddress Listable[netip.Prefix] `json:"inet6_route_address,omitempty"` IncludeInterface Listable[string] `json:"include_interface,omitempty"` ExcludeInterface Listable[string] `json:"exclude_interface,omitempty"` IncludeUID Listable[uint32] `json:"include_uid,omitempty"` diff --git a/option/types.go b/option/types.go index a357387f2c..f2fed66309 100644 --- a/option/types.go +++ b/option/types.go @@ -172,34 +172,6 @@ func (d *Duration) UnmarshalJSON(bytes []byte) error { return nil } -type ListenPrefix netip.Prefix - -func (p ListenPrefix) MarshalJSON() ([]byte, error) { - prefix := netip.Prefix(p) - if !prefix.IsValid() { - return json.Marshal(nil) - } - return json.Marshal(prefix.String()) -} - -func (p *ListenPrefix) UnmarshalJSON(bytes []byte) error { - var value string - err := json.Unmarshal(bytes, &value) - if err != nil { - return err - } - prefix, err := netip.ParsePrefix(value) - if err != nil { - return err - } - *p = ListenPrefix(prefix) - return nil -} - -func (p ListenPrefix) Build() netip.Prefix { - return netip.Prefix(p) -} - type DNSQueryType uint16 func (t DNSQueryType) MarshalJSON() ([]byte, error) { diff --git a/option/wireguard.go b/option/wireguard.go index 21b6715b34..5ede7a61d6 100644 --- a/option/wireguard.go +++ b/option/wireguard.go @@ -1,10 +1,12 @@ package option +import "net/netip" + type WireGuardOutboundOptions struct { DialerOptions SystemInterface bool `json:"system_interface,omitempty"` InterfaceName string `json:"interface_name,omitempty"` - LocalAddress Listable[ListenPrefix] `json:"local_address"` + LocalAddress Listable[netip.Prefix] `json:"local_address"` PrivateKey string `json:"private_key"` Peers []WireGuardPeer `json:"peers,omitempty"` ServerOptions diff --git a/outbound/wireguard.go b/outbound/wireguard.go index ad9145baeb..e645f056c6 100644 --- a/outbound/wireguard.go +++ b/outbound/wireguard.go @@ -18,7 +18,6 @@ import ( "github.com/sagernet/sing-box/transport/wireguard" "github.com/sagernet/sing-dns" "github.com/sagernet/sing-tun" - "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/debug" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" @@ -71,8 +70,7 @@ func NewWireGuard(ctx context.Context, router adapter.Router, logger log.Context return nil, err } outbound.bind = wireguard.NewClientBind(ctx, outbound, outboundDialer, isConnect, connectAddr, reserved) - localPrefixes := common.Map(options.LocalAddress, option.ListenPrefix.Build) - if len(localPrefixes) == 0 { + if len(options.LocalAddress) == 0 { return nil, E.New("missing local address") } var privateKey string @@ -143,7 +141,7 @@ func NewWireGuard(ctx context.Context, router adapter.Router, logger log.Context ipcConf += "\npreshared_key=" + preSharedKey } var has4, has6 bool - for _, address := range localPrefixes { + for _, address := range options.LocalAddress { if address.Addr().Is4() { has4 = true } else { @@ -163,9 +161,9 @@ func NewWireGuard(ctx context.Context, router adapter.Router, logger log.Context } var wireTunDevice wireguard.Device if !options.SystemInterface && tun.WithGVisor { - wireTunDevice, err = wireguard.NewStackDevice(localPrefixes, mtu) + wireTunDevice, err = wireguard.NewStackDevice(options.LocalAddress, mtu) } else { - wireTunDevice, err = wireguard.NewSystemDevice(router, options.InterfaceName, localPrefixes, mtu) + wireTunDevice, err = wireguard.NewSystemDevice(router, options.InterfaceName, options.LocalAddress, mtu) } if err != nil { return nil, E.Cause(err, "create WireGuard device") diff --git a/route/router.go b/route/router.go index 6506f05ff2..676ebd7b20 100644 --- a/route/router.go +++ b/route/router.go @@ -253,10 +253,10 @@ func NewRouter( var inet4Range netip.Prefix var inet6Range netip.Prefix if fakeIPOptions.Inet4Range != nil { - inet4Range = fakeIPOptions.Inet4Range.Build() + inet4Range = *fakeIPOptions.Inet4Range } if fakeIPOptions.Inet6Range != nil { - inet6Range = fakeIPOptions.Inet6Range.Build() + inet6Range = *fakeIPOptions.Inet6Range } router.fakeIPStore = fakeip.NewStore(router, router.logger, inet4Range, inet6Range) } From 31c294d998081318b752bc8b884751cf22a2238d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 21 Oct 2023 12:00:00 +0800 Subject: [PATCH 22/87] Update BBR and Hysteria congestion control & Migrate legacy Hysteria protocol to library --- go.mod | 6 +- go.sum | 8 +- inbound/hysteria.go | 352 ++++++--------------- inbound/hysteria2.go | 3 +- outbound/hysteria.go | 324 ++++---------------- outbound/hysteria2.go | 2 +- test/go.mod | 10 +- test/go.sum | 20 +- test/hysteria_test.go | 4 +- transport/hysteria/frag.go | 65 ---- transport/hysteria/protocol.go | 539 --------------------------------- transport/hysteria/speed.go | 36 --- transport/hysteria/wrap.go | 68 ----- transport/hysteria/xplus.go | 118 -------- transport/v2rayquic/client.go | 3 +- transport/v2rayquic/server.go | 3 +- transport/v2rayquic/stream.go | 41 +++ 17 files changed, 207 insertions(+), 1395 deletions(-) delete mode 100644 transport/hysteria/frag.go delete mode 100644 transport/hysteria/protocol.go delete mode 100644 transport/hysteria/speed.go delete mode 100644 transport/hysteria/wrap.go delete mode 100644 transport/hysteria/xplus.go create mode 100644 transport/v2rayquic/stream.go diff --git a/go.mod b/go.mod index f0c48932c1..3152bfb51b 100644 --- a/go.mod +++ b/go.mod @@ -24,12 +24,12 @@ require ( github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950 github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab - github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee + github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/sing v0.2.16-0.20231021090846-8002db54c028 github.com/sagernet/sing-dns v0.1.10 github.com/sagernet/sing-mux v0.1.3 - github.com/sagernet/sing-quic v0.1.2 + github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6 github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 github.com/sagernet/sing-shadowtls v0.1.4 @@ -45,7 +45,6 @@ require ( go.uber.org/zap v1.26.0 go4.org/netipx v0.0.0-20230824141953-6213f710f925 golang.org/x/crypto v0.14.0 - golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/net v0.17.0 golang.org/x/sys v0.13.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 @@ -85,6 +84,7 @@ require ( github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/zeebo/blake3 v0.2.3 // indirect go.uber.org/multierr v1.11.0 // indirect + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/mod v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect diff --git a/go.sum b/go.sum index dfc88fd0f0..8fa62347f3 100644 --- a/go.sum +++ b/go.sum @@ -104,8 +104,8 @@ github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab h1:u+xQoi/Yc6bNUvT github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab/go.mod h1:3akUhSHSVtLuJaYcW5JPepUraBOW06Ibz2HKwaK5rOk= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee h1:ykuhl9jCS638N+jw1vC9AvT9bbQn6xRNScP2FWPV9dM= -github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee/go.mod h1:0CfhWwZAeXGYM9+Nkkw1zcQtFHQC8KWjbpeDv7pu8iw= +github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 h1:dAe4OIJAtE0nHOzTHhAReQteh3+sa63rvXbuIpbeOTY= +github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460/go.mod h1:uJGpmJCOcMQqMlHKc3P1Vz6uygmpz4bPeVIoOhdVQnM= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= @@ -116,8 +116,8 @@ github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlT github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0= -github.com/sagernet/sing-quic v0.1.2 h1:+u9CRf0KHi5HgXmJ3eB0CtqpWXtF0lx2QlWq+ZFZ+XY= -github.com/sagernet/sing-quic v0.1.2/go.mod h1:H1TX0/y9UUM43wyaLQ+qjg2+o901ibYtwWX2rWG+a3o= +github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6 h1:w+TUbIZKZFSdf/AUa/y33kY9xaLeNGz/tBNcNhqpqfg= +github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6/go.mod h1:1M7xP4802K9Kz6BQ7LlA7UeCapWvWlH1Htmk2bAqkWc= github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY= github.com/sagernet/sing-shadowsocks v0.2.5/go.mod h1:MGWGkcU2xW2G2mfArT9/QqpVLOGU+dBaahZCtPHdt7A= github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+MUhpQnAux728= diff --git a/inbound/hysteria.go b/inbound/hysteria.go index b96327c1af..29707f650a 100644 --- a/inbound/hysteria.go +++ b/inbound/hysteria.go @@ -4,104 +4,38 @@ package inbound import ( "context" - "sync" + "net" - "github.com/sagernet/quic-go" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/humanize" "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing-box/transport/hysteria" - "github.com/sagernet/sing-quic" - hyCC "github.com/sagernet/sing-quic/hysteria2/congestion" + "github.com/sagernet/sing-quic/hysteria" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/auth" E "github.com/sagernet/sing/common/exceptions" - F "github.com/sagernet/sing/common/format" - M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" - - "golang.org/x/exp/slices" ) var _ adapter.Inbound = (*Hysteria)(nil) type Hysteria struct { myInboundAdapter - quicConfig *quic.Config tlsConfig tls.ServerConfig - authKey []string - authUser []string - xplusKey []byte - sendBPS uint64 - recvBPS uint64 - listener qtls.Listener - udpAccess sync.RWMutex - udpSessionId uint32 - udpSessions map[uint32]chan *hysteria.UDPMessage - udpDefragger hysteria.Defragger + service *hysteria.Service[int] + userNameList []string } func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HysteriaInboundOptions) (*Hysteria, error) { options.UDPFragmentDefault = true - quicConfig := &quic.Config{ - InitialStreamReceiveWindow: options.ReceiveWindowConn, - MaxStreamReceiveWindow: options.ReceiveWindowConn, - InitialConnectionReceiveWindow: options.ReceiveWindowClient, - MaxConnectionReceiveWindow: options.ReceiveWindowClient, - MaxIncomingStreams: int64(options.MaxConnClient), - KeepAlivePeriod: hysteria.KeepAlivePeriod, - DisablePathMTUDiscovery: options.DisableMTUDiscovery || !(C.IsLinux || C.IsWindows), - EnableDatagrams: true, - } - if options.ReceiveWindowConn == 0 { - quicConfig.InitialStreamReceiveWindow = hysteria.DefaultStreamReceiveWindow - quicConfig.MaxStreamReceiveWindow = hysteria.DefaultStreamReceiveWindow - } - if options.ReceiveWindowClient == 0 { - quicConfig.InitialConnectionReceiveWindow = hysteria.DefaultConnectionReceiveWindow - quicConfig.MaxConnectionReceiveWindow = hysteria.DefaultConnectionReceiveWindow - } - if quicConfig.MaxIncomingStreams == 0 { - quicConfig.MaxIncomingStreams = hysteria.DefaultMaxIncomingStreams - } - authKey := common.Map(options.Users, func(it option.HysteriaUser) string { - if len(it.Auth) > 0 { - return string(it.Auth) - } else { - return it.AuthString - } - }) - authUser := common.Map(options.Users, func(it option.HysteriaUser) string { - return it.Name - }) - var xplus []byte - if options.Obfs != "" { - xplus = []byte(options.Obfs) - } - var up, down uint64 - if len(options.Up) > 0 { - up = hysteria.StringToBps(options.Up) - if up == 0 { - return nil, E.New("invalid up speed format: ", options.Up) - } - } else { - up = uint64(options.UpMbps) * hysteria.MbpsToBps - } - if len(options.Down) > 0 { - down = hysteria.StringToBps(options.Down) - if down == 0 { - return nil, E.New("invalid down speed format: ", options.Down) - } - } else { - down = uint64(options.DownMbps) * hysteria.MbpsToBps - } - if up < hysteria.MinSpeedBPS { - return nil, E.New("invalid up speed") + if options.TLS == nil || !options.TLS.Enabled { + return nil, C.ErrTLSRequired } - if down < hysteria.MinSpeedBPS { - return nil, E.New("invalid down speed") + tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) + if err != nil { + return nil, err } inbound := &Hysteria{ myInboundAdapter: myInboundAdapter{ @@ -113,224 +47,108 @@ func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextL tag: tag, listenOptions: options.ListenOptions, }, - quicConfig: quicConfig, - authKey: authKey, - authUser: authUser, - xplusKey: xplus, - sendBPS: up, - recvBPS: down, - udpSessions: make(map[uint32]chan *hysteria.UDPMessage), - } - if options.TLS == nil || !options.TLS.Enabled { - return nil, C.ErrTLSRequired - } - if len(options.TLS.ALPN) == 0 { - options.TLS.ALPN = []string{hysteria.DefaultALPN} - } - tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) - if err != nil { - return nil, err + tlsConfig: tlsConfig, } - inbound.tlsConfig = tlsConfig - return inbound, nil -} - -func (h *Hysteria) Start() error { - packetConn, err := h.myInboundAdapter.ListenUDP() - if err != nil { - return err - } - if len(h.xplusKey) > 0 { - packetConn = hysteria.NewXPlusPacketConn(packetConn, h.xplusKey) - packetConn = &hysteria.PacketConnWrapper{PacketConn: packetConn} - } - err = h.tlsConfig.Start() - if err != nil { - return err - } - listener, err := qtls.Listen(packetConn, h.tlsConfig, h.quicConfig) - if err != nil { - return err - } - h.listener = listener - h.logger.Info("udp server started at ", listener.Addr()) - go h.acceptLoop() - return nil -} - -func (h *Hysteria) acceptLoop() { - for { - ctx := log.ContextWithNewID(h.ctx) - conn, err := h.listener.Accept(ctx) + var sendBps, receiveBps uint64 + if len(options.Up) > 0 { + sendBps, err = humanize.ParseBytes(options.Up) if err != nil { - return + return nil, E.Cause(err, "invalid up speed format: ", options.Up) } - go func() { - hErr := h.accept(ctx, conn) - if hErr != nil { - conn.CloseWithError(0, "") - NewError(h.logger, ctx, E.Cause(hErr, "process connection from ", conn.RemoteAddr())) - } - }() - } -} - -func (h *Hysteria) accept(ctx context.Context, conn quic.Connection) error { - controlStream, err := conn.AcceptStream(ctx) - if err != nil { - return err - } - clientHello, err := hysteria.ReadClientHello(controlStream) - if err != nil { - return err + } else { + sendBps = uint64(options.UpMbps) * hysteria.MbpsToBps } - if len(h.authKey) > 0 { - userIndex := slices.Index(h.authKey, string(clientHello.Auth)) - if userIndex == -1 { - err = hysteria.WriteServerHello(controlStream, hysteria.ServerHello{ - Message: "wrong password", - }) - return E.Errors(E.New("wrong password: ", string(clientHello.Auth)), err) - } - user := h.authUser[userIndex] - if user == "" { - user = F.ToString(userIndex) - } else { - ctx = auth.ContextWithUser(ctx, user) + if len(options.Down) > 0 { + receiveBps, err = humanize.ParseBytes(options.Down) + if receiveBps == 0 { + return nil, E.New("invalid down speed format: ", options.Down) } - h.logger.InfoContext(ctx, "[", user, "] inbound connection from ", conn.RemoteAddr()) } else { - h.logger.InfoContext(ctx, "inbound connection from ", conn.RemoteAddr()) - } - h.logger.DebugContext(ctx, "peer send speed: ", clientHello.SendBPS/1024/1024, " MBps, peer recv speed: ", clientHello.RecvBPS/1024/1024, " MBps") - if clientHello.SendBPS == 0 || clientHello.RecvBPS == 0 { - return E.New("invalid rate from client") - } - serverSendBPS, serverRecvBPS := clientHello.RecvBPS, clientHello.SendBPS - if h.sendBPS > 0 && serverSendBPS > h.sendBPS { - serverSendBPS = h.sendBPS - } - if h.recvBPS > 0 && serverRecvBPS > h.recvBPS { - serverRecvBPS = h.recvBPS - } - err = hysteria.WriteServerHello(controlStream, hysteria.ServerHello{ - OK: true, - SendBPS: serverSendBPS, - RecvBPS: serverRecvBPS, + receiveBps = uint64(options.DownMbps) * hysteria.MbpsToBps + } + service, err := hysteria.NewService[int](hysteria.ServiceOptions{ + Context: ctx, + Logger: logger, + SendBPS: sendBps, + ReceiveBPS: receiveBps, + XPlusPassword: options.Obfs, + TLSConfig: tlsConfig, + Handler: adapter.NewUpstreamHandler(adapter.InboundContext{}, inbound.newConnection, inbound.newPacketConnection, nil), + + // Legacy options + + ConnReceiveWindow: options.ReceiveWindowConn, + StreamReceiveWindow: options.ReceiveWindowClient, + MaxIncomingStreams: int64(options.MaxConnClient), + DisableMTUDiscovery: options.DisableMTUDiscovery, }) if err != nil { - return err + return nil, err } - conn.SetCongestionControl(hyCC.NewBrutalSender(serverSendBPS)) - go h.udpRecvLoop(conn) - for { - var stream quic.Stream - stream, err = conn.AcceptStream(ctx) - if err != nil { - return err + userList := make([]int, 0, len(options.Users)) + userNameList := make([]string, 0, len(options.Users)) + userPasswordList := make([]string, 0, len(options.Users)) + for index, user := range options.Users { + userList = append(userList, index) + userNameList = append(userNameList, user.Name) + var password string + if user.AuthString != "" { + password = user.AuthString + } else { + password = string(user.Auth) } - go func() { - hErr := h.acceptStream(ctx, conn /*&hysteria.StreamWrapper{Stream: stream}*/, stream) - if hErr != nil { - stream.Close() - NewError(h.logger, ctx, E.Cause(hErr, "process stream from ", conn.RemoteAddr())) - } - }() + userPasswordList = append(userPasswordList, password) } + service.UpdateUsers(userList, userPasswordList) + inbound.service = service + inbound.userNameList = userNameList + return inbound, nil } -func (h *Hysteria) udpRecvLoop(conn quic.Connection) { - for { - packet, err := conn.ReceiveMessage(h.ctx) - if err != nil { - return - } - message, err := hysteria.ParseUDPMessage(packet) - if err != nil { - h.logger.Error("parse udp message: ", err) - continue - } - dfMsg := h.udpDefragger.Feed(message) - if dfMsg == nil { - continue - } - h.udpAccess.RLock() - ch, ok := h.udpSessions[dfMsg.SessionID] - if ok { - select { - case ch <- dfMsg: - // OK - default: - // Silently drop the message when the channel is full - } - } - h.udpAccess.RUnlock() +func (h *Hysteria) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { + ctx = log.ContextWithNewID(ctx) + metadata = h.createMetadata(conn, metadata) + userID, _ := auth.UserFromContext[int](ctx) + if userName := h.userNameList[userID]; userName != "" { + metadata.User = userName + h.logger.InfoContext(ctx, "[", userName, "] inbound connection to ", metadata.Destination) + } else { + h.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination) } + return h.router.RouteConnection(ctx, conn, metadata) } -func (h *Hysteria) acceptStream(ctx context.Context, conn quic.Connection, stream quic.Stream) error { - request, err := hysteria.ReadClientRequest(stream) - if err != nil { - return err - } - var metadata adapter.InboundContext - metadata.Inbound = h.tag - metadata.InboundType = C.TypeHysteria - metadata.InboundOptions = h.listenOptions.InboundOptions - metadata.Source = M.SocksaddrFromNet(conn.RemoteAddr()).Unwrap() - metadata.OriginDestination = M.SocksaddrFromNet(conn.LocalAddr()).Unwrap() - metadata.Destination = M.ParseSocksaddrHostPort(request.Host, request.Port).Unwrap() - metadata.User, _ = auth.UserFromContext[string](ctx) - - if !request.UDP { - err = hysteria.WriteServerResponse(stream, hysteria.ServerResponse{ - OK: true, - }) - if err != nil { - return err - } - h.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination) - return h.router.RouteConnection(ctx, hysteria.NewConn(stream, metadata.Destination, false), metadata) +func (h *Hysteria) newPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { + ctx = log.ContextWithNewID(ctx) + metadata = h.createPacketMetadata(conn, metadata) + userID, _ := auth.UserFromContext[int](ctx) + if userName := h.userNameList[userID]; userName != "" { + metadata.User = userName + h.logger.InfoContext(ctx, "[", userName, "] inbound packet connection to ", metadata.Destination) } else { h.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination) - var id uint32 - h.udpAccess.Lock() - id = h.udpSessionId - nCh := make(chan *hysteria.UDPMessage, 1024) - h.udpSessions[id] = nCh - h.udpSessionId += 1 - h.udpAccess.Unlock() - err = hysteria.WriteServerResponse(stream, hysteria.ServerResponse{ - OK: true, - UDPSessionID: id, - }) + } + return h.router.RoutePacketConnection(ctx, conn, metadata) +} + +func (h *Hysteria) Start() error { + if h.tlsConfig != nil { + err := h.tlsConfig.Start() if err != nil { return err } - packetConn := hysteria.NewPacketConn(conn, stream, id, metadata.Destination, nCh, common.Closer(func() error { - h.udpAccess.Lock() - if ch, ok := h.udpSessions[id]; ok { - close(ch) - delete(h.udpSessions, id) - } - h.udpAccess.Unlock() - return nil - })) - go packetConn.Hold() - return h.router.RoutePacketConnection(ctx, packetConn, metadata) } + packetConn, err := h.myInboundAdapter.ListenUDP() + if err != nil { + return err + } + return h.service.Start(packetConn) } func (h *Hysteria) Close() error { - h.udpAccess.Lock() - for _, session := range h.udpSessions { - close(session) - } - h.udpSessions = make(map[uint32]chan *hysteria.UDPMessage) - h.udpAccess.Unlock() return common.Close( &h.myInboundAdapter, - h.listener, h.tlsConfig, + common.PtrOrNil(h.service), ) } diff --git a/inbound/hysteria2.go b/inbound/hysteria2.go index fd650ae972..07b45af27d 100644 --- a/inbound/hysteria2.go +++ b/inbound/hysteria2.go @@ -14,7 +14,7 @@ import ( C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing-box/transport/hysteria" + "github.com/sagernet/sing-quic/hysteria" "github.com/sagernet/sing-quic/hysteria2" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/auth" @@ -32,6 +32,7 @@ type Hysteria2 struct { } func NewHysteria2(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.Hysteria2InboundOptions) (*Hysteria2, error) { + options.UDPFragmentDefault = true if options.TLS == nil || !options.TLS.Enabled { return nil, C.ErrTLSRequired } diff --git a/outbound/hysteria.go b/outbound/hysteria.go index ffdf61bb25..8c130e33bb 100644 --- a/outbound/hysteria.go +++ b/outbound/hysteria.go @@ -5,18 +5,16 @@ package outbound import ( "context" "net" - "sync" + "os" - "github.com/sagernet/quic-go" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/dialer" + "github.com/sagernet/sing-box/common/humanize" "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing-box/transport/hysteria" - "github.com/sagernet/sing-quic" - hyCC "github.com/sagernet/sing-quic/hysteria2/congestion" + "github.com/sagernet/sing-quic/hysteria" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/bufio" E "github.com/sagernet/sing/common/exceptions" @@ -25,27 +23,13 @@ import ( ) var ( - _ adapter.Outbound = (*Hysteria)(nil) - _ adapter.InterfaceUpdateListener = (*Hysteria)(nil) + _ adapter.Outbound = (*TUIC)(nil) + _ adapter.InterfaceUpdateListener = (*TUIC)(nil) ) type Hysteria struct { myOutboundAdapter - ctx context.Context - dialer N.Dialer - serverAddr M.Socksaddr - tlsConfig tls.Config - quicConfig *quic.Config - authKey []byte - xplusKey []byte - sendBPS uint64 - recvBPS uint64 - connAccess sync.Mutex - conn quic.Connection - rawConn net.Conn - udpAccess sync.RWMutex - udpSessions map[uint32]chan *hysteria.UDPMessage - udpDefragger hysteria.Defragger + client *hysteria.Client } func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HysteriaOutboundOptions) (*Hysteria, error) { @@ -57,252 +41,77 @@ func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextL if err != nil { return nil, err } - if len(tlsConfig.NextProtos()) == 0 { - tlsConfig.SetNextProtos([]string{hysteria.DefaultALPN}) - } - quicConfig := &quic.Config{ - InitialStreamReceiveWindow: options.ReceiveWindowConn, - MaxStreamReceiveWindow: options.ReceiveWindowConn, - InitialConnectionReceiveWindow: options.ReceiveWindow, - MaxConnectionReceiveWindow: options.ReceiveWindow, - KeepAlivePeriod: hysteria.KeepAlivePeriod, - DisablePathMTUDiscovery: options.DisableMTUDiscovery, - EnableDatagrams: true, - } - if options.ReceiveWindowConn == 0 { - quicConfig.InitialStreamReceiveWindow = hysteria.DefaultStreamReceiveWindow - quicConfig.MaxStreamReceiveWindow = hysteria.DefaultStreamReceiveWindow - } - if options.ReceiveWindow == 0 { - quicConfig.InitialConnectionReceiveWindow = hysteria.DefaultConnectionReceiveWindow - quicConfig.MaxConnectionReceiveWindow = hysteria.DefaultConnectionReceiveWindow - } - if quicConfig.MaxIncomingStreams == 0 { - quicConfig.MaxIncomingStreams = hysteria.DefaultMaxIncomingStreams + outboundDialer, err := dialer.New(router, options.DialerOptions) + if err != nil { + return nil, err } - var auth []byte - if len(options.Auth) > 0 { - auth = options.Auth + networkList := options.Network.Build() + var password string + if options.AuthString != "" { + password = options.AuthString } else { - auth = []byte(options.AuthString) - } - var xplus []byte - if options.Obfs != "" { - xplus = []byte(options.Obfs) + password = string(options.Auth) } - var up, down uint64 + var sendBps, receiveBps uint64 if len(options.Up) > 0 { - up = hysteria.StringToBps(options.Up) - if up == 0 { - return nil, E.New("invalid up speed format: ", options.Up) + sendBps, err = humanize.ParseBytes(options.Up) + if err != nil { + return nil, E.Cause(err, "invalid up speed format: ", options.Up) } } else { - up = uint64(options.UpMbps) * hysteria.MbpsToBps + sendBps = uint64(options.UpMbps) * hysteria.MbpsToBps } if len(options.Down) > 0 { - down = hysteria.StringToBps(options.Down) - if down == 0 { + receiveBps, err = humanize.ParseBytes(options.Down) + if receiveBps == 0 { return nil, E.New("invalid down speed format: ", options.Down) } } else { - down = uint64(options.DownMbps) * hysteria.MbpsToBps - } - if up < hysteria.MinSpeedBPS { - return nil, E.New("invalid up speed") - } - if down < hysteria.MinSpeedBPS { - return nil, E.New("invalid down speed") - } - outboundDialer, err := dialer.New(router, options.DialerOptions) + receiveBps = uint64(options.DownMbps) * hysteria.MbpsToBps + } + client, err := hysteria.NewClient(hysteria.ClientOptions{ + Context: ctx, + Dialer: outboundDialer, + Logger: logger, + ServerAddress: options.ServerOptions.Build(), + SendBPS: sendBps, + ReceiveBPS: receiveBps, + XPlusPassword: options.Obfs, + Password: password, + TLSConfig: tlsConfig, + UDPDisabled: !common.Contains(networkList, N.NetworkUDP), + + ConnReceiveWindow: options.ReceiveWindowConn, + StreamReceiveWindow: options.ReceiveWindow, + DisableMTUDiscovery: options.DisableMTUDiscovery, + }) if err != nil { return nil, err } return &Hysteria{ myOutboundAdapter: myOutboundAdapter{ protocol: C.TypeHysteria, - network: options.Network.Build(), + network: networkList, router: router, logger: logger, tag: tag, dependencies: withDialerDependency(options.DialerOptions), }, - ctx: ctx, - dialer: outboundDialer, - serverAddr: options.ServerOptions.Build(), - tlsConfig: tlsConfig, - quicConfig: quicConfig, - authKey: auth, - xplusKey: xplus, - sendBPS: up, - recvBPS: down, + client: client, }, nil } -func (h *Hysteria) offer(ctx context.Context) (quic.Connection, error) { - conn := h.conn - if conn != nil && !common.Done(conn.Context()) { - return conn, nil - } - h.connAccess.Lock() - defer h.connAccess.Unlock() - h.udpAccess.Lock() - defer h.udpAccess.Unlock() - conn = h.conn - if conn != nil && !common.Done(conn.Context()) { - return conn, nil - } - common.Close(h.rawConn) - conn, err := h.offerNew(ctx) - if err != nil { - return nil, err - } - if common.Contains(h.network, N.NetworkUDP) { - for _, session := range h.udpSessions { - close(session) - } - h.udpSessions = make(map[uint32]chan *hysteria.UDPMessage) - h.udpDefragger = hysteria.Defragger{} - go h.udpRecvLoop(conn) - } - return conn, nil -} - -func (h *Hysteria) offerNew(ctx context.Context) (quic.Connection, error) { - udpConn, err := h.dialer.DialContext(h.ctx, "udp", h.serverAddr) - if err != nil { - return nil, err - } - var packetConn net.PacketConn - packetConn = bufio.NewUnbindPacketConn(udpConn) - if h.xplusKey != nil { - packetConn = hysteria.NewXPlusPacketConn(packetConn, h.xplusKey) - } - packetConn = &hysteria.PacketConnWrapper{PacketConn: packetConn} - quicConn, err := qtls.Dial(h.ctx, packetConn, udpConn.RemoteAddr(), h.tlsConfig, h.quicConfig) - if err != nil { - packetConn.Close() - return nil, err - } - controlStream, err := quicConn.OpenStreamSync(ctx) - if err != nil { - packetConn.Close() - return nil, err - } - err = hysteria.WriteClientHello(controlStream, hysteria.ClientHello{ - SendBPS: h.sendBPS, - RecvBPS: h.recvBPS, - Auth: h.authKey, - }) - if err != nil { - packetConn.Close() - return nil, err - } - serverHello, err := hysteria.ReadServerHello(controlStream) - if err != nil { - packetConn.Close() - return nil, err - } - if !serverHello.OK { - packetConn.Close() - return nil, E.New("remote error: ", serverHello.Message) - } - quicConn.SetCongestionControl(hyCC.NewBrutalSender(serverHello.RecvBPS)) - h.conn = quicConn - h.rawConn = udpConn - return quicConn, nil -} - -func (h *Hysteria) udpRecvLoop(conn quic.Connection) { - for { - packet, err := conn.ReceiveMessage(h.ctx) - if err != nil { - return - } - message, err := hysteria.ParseUDPMessage(packet) - if err != nil { - h.logger.Error("parse udp message: ", err) - continue - } - dfMsg := h.udpDefragger.Feed(message) - if dfMsg == nil { - continue - } - h.udpAccess.RLock() - ch, ok := h.udpSessions[dfMsg.SessionID] - if ok { - select { - case ch <- dfMsg: - // OK - default: - // Silently drop the message when the channel is full - } - } - h.udpAccess.RUnlock() - } -} - -func (h *Hysteria) InterfaceUpdated() { - h.Close() - return -} - -func (h *Hysteria) Close() error { - h.connAccess.Lock() - defer h.connAccess.Unlock() - h.udpAccess.Lock() - defer h.udpAccess.Unlock() - if h.conn != nil { - h.conn.CloseWithError(0, "") - h.rawConn.Close() - } - for _, session := range h.udpSessions { - close(session) - } - h.udpSessions = make(map[uint32]chan *hysteria.UDPMessage) - return nil -} - -func (h *Hysteria) open(ctx context.Context, reconnect bool) (quic.Connection, quic.Stream, error) { - conn, err := h.offer(ctx) - if err != nil { - if nErr, ok := err.(net.Error); ok && !nErr.Temporary() && reconnect { - return h.open(ctx, false) - } - return nil, nil, err - } - stream, err := conn.OpenStream() - if err != nil { - if nErr, ok := err.(net.Error); ok && !nErr.Temporary() && reconnect { - return h.open(ctx, false) - } - return nil, nil, err - } - return conn, &hysteria.StreamWrapper{Stream: stream}, nil -} - func (h *Hysteria) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { switch N.NetworkName(network) { case N.NetworkTCP: h.logger.InfoContext(ctx, "outbound connection to ", destination) - _, stream, err := h.open(ctx, true) - if err != nil { - return nil, err - } - err = hysteria.WriteClientRequest(stream, hysteria.ClientRequest{ - Host: destination.AddrString(), - Port: destination.Port, - }) - if err != nil { - stream.Close() - return nil, err - } - return hysteria.NewConn(stream, destination, true), nil + return h.client.DialConn(ctx, destination) case N.NetworkUDP: conn, err := h.ListenPacket(ctx, destination) if err != nil { return nil, err } - return conn.(*hysteria.PacketConn), nil + return bufio.NewBindPacketConn(conn, destination), nil default: return nil, E.New("unsupported network: ", network) } @@ -310,44 +119,7 @@ func (h *Hysteria) DialContext(ctx context.Context, network string, destination func (h *Hysteria) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { h.logger.InfoContext(ctx, "outbound packet connection to ", destination) - conn, stream, err := h.open(ctx, true) - if err != nil { - return nil, err - } - err = hysteria.WriteClientRequest(stream, hysteria.ClientRequest{ - UDP: true, - Host: destination.AddrString(), - Port: destination.Port, - }) - if err != nil { - stream.Close() - return nil, err - } - var response *hysteria.ServerResponse - response, err = hysteria.ReadServerResponse(stream) - if err != nil { - stream.Close() - return nil, err - } - if !response.OK { - stream.Close() - return nil, E.New("remote error: ", response.Message) - } - h.udpAccess.Lock() - nCh := make(chan *hysteria.UDPMessage, 1024) - h.udpSessions[response.UDPSessionID] = nCh - h.udpAccess.Unlock() - packetConn := hysteria.NewPacketConn(conn, stream, response.UDPSessionID, destination, nCh, common.Closer(func() error { - h.udpAccess.Lock() - if ch, ok := h.udpSessions[response.UDPSessionID]; ok { - close(ch) - delete(h.udpSessions, response.UDPSessionID) - } - h.udpAccess.Unlock() - return nil - })) - go packetConn.Hold() - return packetConn, nil + return h.client.ListenPacket(ctx, destination) } func (h *Hysteria) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { @@ -357,3 +129,11 @@ func (h *Hysteria) NewConnection(ctx context.Context, conn net.Conn, metadata ad func (h *Hysteria) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { return NewPacketConnection(ctx, h, conn, metadata) } + +func (h *Hysteria) InterfaceUpdated() error { + return h.client.CloseWithError(E.New("network changed")) +} + +func (h *Hysteria) Close() error { + return h.client.CloseWithError(os.ErrClosed) +} diff --git a/outbound/hysteria2.go b/outbound/hysteria2.go index 120865a9f2..2998f9484d 100644 --- a/outbound/hysteria2.go +++ b/outbound/hysteria2.go @@ -13,7 +13,7 @@ import ( C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing-box/transport/hysteria" + "github.com/sagernet/sing-quic/hysteria" "github.com/sagernet/sing-quic/hysteria2" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/bufio" diff --git a/test/go.mod b/test/go.mod index fed2124ab7..50759f68e5 100644 --- a/test/go.mod +++ b/test/go.mod @@ -10,10 +10,10 @@ require ( github.com/docker/docker v24.0.6+incompatible github.com/docker/go-connections v0.4.0 github.com/gofrs/uuid/v5 v5.0.0 - github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee - github.com/sagernet/sing v0.2.15 + github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 + github.com/sagernet/sing v0.2.16-0.20231021090846-8002db54c028 github.com/sagernet/sing-dns v0.1.10 - github.com/sagernet/sing-quic v0.1.2 + github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6 github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 github.com/spyzhov/ajson v0.9.0 @@ -70,12 +70,12 @@ require ( github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect - github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 // indirect + github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect github.com/sagernet/sing-mux v0.1.3 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect - github.com/sagernet/sing-tun v0.1.16 // indirect + github.com/sagernet/sing-tun v0.1.17-0.20231026060825-efd9884154a6 // indirect github.com/sagernet/sing-vmess v0.1.8 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 // indirect diff --git a/test/go.sum b/test/go.sum index d13690ad71..597f559480 100644 --- a/test/go.sum +++ b/test/go.sum @@ -117,32 +117,32 @@ github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a h1:wZHruBx github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a/go.mod h1:dNV1ZP9y3qx5ltULeKaQZTZWTLHflgW5DES+Ses7cMI= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= -github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 h1:dnkKrzapqtAwjTSWt6hdPrARORfoYvuUczynvRLrueo= -github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2/go.mod h1:1JUiV7nGuf++YFm9eWZ8q2lrwHmhcUGzptMl/vL1+LA= +github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab h1:u+xQoi/Yc6bNUvTfrDD6HhGRybn2lzrhf5vmS+wb4Ho= +github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab/go.mod h1:3akUhSHSVtLuJaYcW5JPepUraBOW06Ibz2HKwaK5rOk= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee h1:ykuhl9jCS638N+jw1vC9AvT9bbQn6xRNScP2FWPV9dM= -github.com/sagernet/quic-go v0.0.0-20230919101909-0cc6c5dcecee/go.mod h1:0CfhWwZAeXGYM9+Nkkw1zcQtFHQC8KWjbpeDv7pu8iw= +github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 h1:dAe4OIJAtE0nHOzTHhAReQteh3+sa63rvXbuIpbeOTY= +github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460/go.mod h1:uJGpmJCOcMQqMlHKc3P1Vz6uygmpz4bPeVIoOhdVQnM= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.15 h1:PFwyiMzkyJkq+YGOVznJUsRVOT6EoVxRGIsllLuvHXA= -github.com/sagernet/sing v0.2.15/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= +github.com/sagernet/sing v0.2.16-0.20231021090846-8002db54c028 h1:6GbQt7SC9y5Imrq5jDMbXDSaNiMhJ8KBjhjtQRuqQvE= +github.com/sagernet/sing v0.2.16-0.20231021090846-8002db54c028/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlTZCI= github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0= -github.com/sagernet/sing-quic v0.1.2 h1:+u9CRf0KHi5HgXmJ3eB0CtqpWXtF0lx2QlWq+ZFZ+XY= -github.com/sagernet/sing-quic v0.1.2/go.mod h1:H1TX0/y9UUM43wyaLQ+qjg2+o901ibYtwWX2rWG+a3o= +github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6 h1:w+TUbIZKZFSdf/AUa/y33kY9xaLeNGz/tBNcNhqpqfg= +github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6/go.mod h1:1M7xP4802K9Kz6BQ7LlA7UeCapWvWlH1Htmk2bAqkWc= github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY= github.com/sagernet/sing-shadowsocks v0.2.5/go.mod h1:MGWGkcU2xW2G2mfArT9/QqpVLOGU+dBaahZCtPHdt7A= github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+MUhpQnAux728= github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.16 h1:RHXYIVg6uacvdfbYMiPEz9VX5uu6mNrvP7u9yAH3oNc= -github.com/sagernet/sing-tun v0.1.16/go.mod h1:S3q8GCjeyRniK+KLmo4XqKY0bS3x2UdKkKbqxT/Agl8= +github.com/sagernet/sing-tun v0.1.17-0.20231026060825-efd9884154a6 h1:4yEXBqQoUgXj7qPSLD6lr+z9/KfsvixO9JUA2i5xnM8= +github.com/sagernet/sing-tun v0.1.17-0.20231026060825-efd9884154a6/go.mod h1:w2+S+uWE94E/pQWSDdDdMIjwAEb645kuGPunr6ZllUg= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= diff --git a/test/hysteria_test.go b/test/hysteria_test.go index df0ae3a29e..664e5a7c04 100644 --- a/test/hysteria_test.go +++ b/test/hysteria_test.go @@ -79,7 +79,7 @@ func TestHysteriaSelf(t *testing.T) { }, }, }) - testSuitSimple1(t, clientPort, testPort) + testSuit(t, clientPort, testPort) } func TestHysteriaInbound(t *testing.T) { @@ -118,7 +118,7 @@ func TestHysteriaInbound(t *testing.T) { caPem: "/etc/hysteria/ca.pem", }, }) - testSuitSimple1(t, clientPort, testPort) + testSuit(t, clientPort, testPort) } func TestHysteriaOutbound(t *testing.T) { diff --git a/transport/hysteria/frag.go b/transport/hysteria/frag.go deleted file mode 100644 index 721341f1c4..0000000000 --- a/transport/hysteria/frag.go +++ /dev/null @@ -1,65 +0,0 @@ -package hysteria - -func FragUDPMessage(m UDPMessage, maxSize int) []UDPMessage { - if m.Size() <= maxSize { - return []UDPMessage{m} - } - fullPayload := m.Data - maxPayloadSize := maxSize - m.HeaderSize() - off := 0 - fragID := uint8(0) - fragCount := uint8((len(fullPayload) + maxPayloadSize - 1) / maxPayloadSize) // round up - var frags []UDPMessage - for off < len(fullPayload) { - payloadSize := len(fullPayload) - off - if payloadSize > maxPayloadSize { - payloadSize = maxPayloadSize - } - frag := m - frag.FragID = fragID - frag.FragCount = fragCount - frag.Data = fullPayload[off : off+payloadSize] - frags = append(frags, frag) - off += payloadSize - fragID++ - } - return frags -} - -type Defragger struct { - msgID uint16 - frags []*UDPMessage - count uint8 -} - -func (d *Defragger) Feed(m UDPMessage) *UDPMessage { - if m.FragCount <= 1 { - return &m - } - if m.FragID >= m.FragCount { - // wtf is this? - return nil - } - if m.MsgID != d.msgID { - // new message, clear previous state - d.msgID = m.MsgID - d.frags = make([]*UDPMessage, m.FragCount) - d.count = 1 - d.frags[m.FragID] = &m - } else if d.frags[m.FragID] == nil { - d.frags[m.FragID] = &m - d.count++ - if int(d.count) == len(d.frags) { - // all fragments received, assemble - var data []byte - for _, frag := range d.frags { - data = append(data, frag.Data...) - } - m.Data = data - m.FragID = 0 - m.FragCount = 1 - return &m - } - } - return nil -} diff --git a/transport/hysteria/protocol.go b/transport/hysteria/protocol.go deleted file mode 100644 index a338988f6a..0000000000 --- a/transport/hysteria/protocol.go +++ /dev/null @@ -1,539 +0,0 @@ -package hysteria - -import ( - "bytes" - "encoding/binary" - "io" - "math/rand" - "net" - "os" - "time" - - "github.com/sagernet/quic-go" - "github.com/sagernet/sing/common" - "github.com/sagernet/sing/common/buf" - E "github.com/sagernet/sing/common/exceptions" - M "github.com/sagernet/sing/common/metadata" -) - -const ( - MbpsToBps = 125000 - MinSpeedBPS = 16384 - DefaultStreamReceiveWindow = 15728640 // 15 MB/s - DefaultConnectionReceiveWindow = 67108864 // 64 MB/s - DefaultMaxIncomingStreams = 1024 - DefaultALPN = "hysteria" - KeepAlivePeriod = 10 * time.Second -) - -const Version = 3 - -type ClientHello struct { - SendBPS uint64 - RecvBPS uint64 - Auth []byte -} - -func WriteClientHello(stream io.Writer, hello ClientHello) error { - var requestLen int - requestLen += 1 // version - requestLen += 8 // sendBPS - requestLen += 8 // recvBPS - requestLen += 2 // auth len - requestLen += len(hello.Auth) - request := buf.NewSize(requestLen) - defer request.Release() - common.Must( - request.WriteByte(Version), - binary.Write(request, binary.BigEndian, hello.SendBPS), - binary.Write(request, binary.BigEndian, hello.RecvBPS), - binary.Write(request, binary.BigEndian, uint16(len(hello.Auth))), - common.Error(request.Write(hello.Auth)), - ) - return common.Error(stream.Write(request.Bytes())) -} - -func ReadClientHello(reader io.Reader) (*ClientHello, error) { - var version uint8 - err := binary.Read(reader, binary.BigEndian, &version) - if err != nil { - return nil, err - } - if version != Version { - return nil, E.New("unsupported client version: ", version) - } - var clientHello ClientHello - err = binary.Read(reader, binary.BigEndian, &clientHello.SendBPS) - if err != nil { - return nil, err - } - err = binary.Read(reader, binary.BigEndian, &clientHello.RecvBPS) - if err != nil { - return nil, err - } - var authLen uint16 - err = binary.Read(reader, binary.BigEndian, &authLen) - if err != nil { - return nil, err - } - clientHello.Auth = make([]byte, authLen) - _, err = io.ReadFull(reader, clientHello.Auth) - if err != nil { - return nil, err - } - return &clientHello, nil -} - -type ServerHello struct { - OK bool - SendBPS uint64 - RecvBPS uint64 - Message string -} - -func ReadServerHello(stream io.Reader) (*ServerHello, error) { - var responseLen int - responseLen += 1 // ok - responseLen += 8 // sendBPS - responseLen += 8 // recvBPS - responseLen += 2 // message len - response := buf.NewSize(responseLen) - defer response.Release() - _, err := response.ReadFullFrom(stream, responseLen) - if err != nil { - return nil, err - } - var serverHello ServerHello - serverHello.OK = response.Byte(0) == 1 - serverHello.SendBPS = binary.BigEndian.Uint64(response.Range(1, 9)) - serverHello.RecvBPS = binary.BigEndian.Uint64(response.Range(9, 17)) - messageLen := binary.BigEndian.Uint16(response.Range(17, 19)) - if messageLen == 0 { - return &serverHello, nil - } - message := make([]byte, messageLen) - _, err = io.ReadFull(stream, message) - if err != nil { - return nil, err - } - serverHello.Message = string(message) - return &serverHello, nil -} - -func WriteServerHello(stream io.Writer, hello ServerHello) error { - var responseLen int - responseLen += 1 // ok - responseLen += 8 // sendBPS - responseLen += 8 // recvBPS - responseLen += 2 // message len - responseLen += len(hello.Message) - response := buf.NewSize(responseLen) - defer response.Release() - if hello.OK { - common.Must(response.WriteByte(1)) - } else { - common.Must(response.WriteByte(0)) - } - common.Must( - binary.Write(response, binary.BigEndian, hello.SendBPS), - binary.Write(response, binary.BigEndian, hello.RecvBPS), - binary.Write(response, binary.BigEndian, uint16(len(hello.Message))), - common.Error(response.WriteString(hello.Message)), - ) - return common.Error(stream.Write(response.Bytes())) -} - -type ClientRequest struct { - UDP bool - Host string - Port uint16 -} - -func ReadClientRequest(stream io.Reader) (*ClientRequest, error) { - var clientRequest ClientRequest - err := binary.Read(stream, binary.BigEndian, &clientRequest.UDP) - if err != nil { - return nil, err - } - var hostLen uint16 - err = binary.Read(stream, binary.BigEndian, &hostLen) - if err != nil { - return nil, err - } - host := make([]byte, hostLen) - _, err = io.ReadFull(stream, host) - if err != nil { - return nil, err - } - clientRequest.Host = string(host) - err = binary.Read(stream, binary.BigEndian, &clientRequest.Port) - if err != nil { - return nil, err - } - return &clientRequest, nil -} - -func WriteClientRequest(stream io.Writer, request ClientRequest) error { - var requestLen int - requestLen += 1 // udp - requestLen += 2 // host len - requestLen += len(request.Host) - requestLen += 2 // port - buffer := buf.NewSize(requestLen) - defer buffer.Release() - if request.UDP { - common.Must(buffer.WriteByte(1)) - } else { - common.Must(buffer.WriteByte(0)) - } - common.Must( - binary.Write(buffer, binary.BigEndian, uint16(len(request.Host))), - common.Error(buffer.WriteString(request.Host)), - binary.Write(buffer, binary.BigEndian, request.Port), - ) - return common.Error(stream.Write(buffer.Bytes())) -} - -type ServerResponse struct { - OK bool - UDPSessionID uint32 - Message string -} - -func ReadServerResponse(stream io.Reader) (*ServerResponse, error) { - var responseLen int - responseLen += 1 // ok - responseLen += 4 // udp session id - responseLen += 2 // message len - response := buf.NewSize(responseLen) - defer response.Release() - _, err := response.ReadFullFrom(stream, responseLen) - if err != nil { - return nil, err - } - var serverResponse ServerResponse - serverResponse.OK = response.Byte(0) == 1 - serverResponse.UDPSessionID = binary.BigEndian.Uint32(response.Range(1, 5)) - messageLen := binary.BigEndian.Uint16(response.Range(5, 7)) - if messageLen == 0 { - return &serverResponse, nil - } - message := make([]byte, messageLen) - _, err = io.ReadFull(stream, message) - if err != nil { - return nil, err - } - serverResponse.Message = string(message) - return &serverResponse, nil -} - -func WriteServerResponse(stream io.Writer, response ServerResponse) error { - var responseLen int - responseLen += 1 // ok - responseLen += 4 // udp session id - responseLen += 2 // message len - responseLen += len(response.Message) - buffer := buf.NewSize(responseLen) - defer buffer.Release() - if response.OK { - common.Must(buffer.WriteByte(1)) - } else { - common.Must(buffer.WriteByte(0)) - } - common.Must( - binary.Write(buffer, binary.BigEndian, response.UDPSessionID), - binary.Write(buffer, binary.BigEndian, uint16(len(response.Message))), - common.Error(buffer.WriteString(response.Message)), - ) - return common.Error(stream.Write(buffer.Bytes())) -} - -type UDPMessage struct { - SessionID uint32 - Host string - Port uint16 - MsgID uint16 // doesn't matter when not fragmented, but must not be 0 when fragmented - FragID uint8 // doesn't matter when not fragmented, starts at 0 when fragmented - FragCount uint8 // must be 1 when not fragmented - Data []byte -} - -func (m UDPMessage) HeaderSize() int { - return 4 + 2 + len(m.Host) + 2 + 2 + 1 + 1 + 2 -} - -func (m UDPMessage) Size() int { - return m.HeaderSize() + len(m.Data) -} - -func ParseUDPMessage(packet []byte) (message UDPMessage, err error) { - reader := bytes.NewReader(packet) - err = binary.Read(reader, binary.BigEndian, &message.SessionID) - if err != nil { - return - } - var hostLen uint16 - err = binary.Read(reader, binary.BigEndian, &hostLen) - if err != nil { - return - } - _, err = reader.Seek(int64(hostLen), io.SeekCurrent) - if err != nil { - return - } - if 6+int(hostLen) > len(packet) { - err = E.New("invalid host length") - return - } - message.Host = string(packet[6 : 6+hostLen]) - err = binary.Read(reader, binary.BigEndian, &message.Port) - if err != nil { - return - } - err = binary.Read(reader, binary.BigEndian, &message.MsgID) - if err != nil { - return - } - err = binary.Read(reader, binary.BigEndian, &message.FragID) - if err != nil { - return - } - err = binary.Read(reader, binary.BigEndian, &message.FragCount) - if err != nil { - return - } - var dataLen uint16 - err = binary.Read(reader, binary.BigEndian, &dataLen) - if err != nil { - return - } - if reader.Len() != int(dataLen) { - err = E.New("invalid data length") - } - dataOffset := int(reader.Size()) - reader.Len() - message.Data = packet[dataOffset:] - return -} - -func WriteUDPMessage(conn quic.Connection, message UDPMessage) error { - var messageLen int - messageLen += 4 // session id - messageLen += 2 // host len - messageLen += len(message.Host) - messageLen += 2 // port - messageLen += 2 // msg id - messageLen += 1 // frag id - messageLen += 1 // frag count - messageLen += 2 // data len - messageLen += len(message.Data) - buffer := buf.NewSize(messageLen) - defer buffer.Release() - err := writeUDPMessage(conn, message, buffer) - if errSize, ok := err.(quic.ErrMessageTooLarge); ok { - // need to frag - message.MsgID = uint16(rand.Intn(0xFFFF)) + 1 // msgID must be > 0 when fragCount > 1 - fragMsgs := FragUDPMessage(message, int(errSize)) - for _, fragMsg := range fragMsgs { - buffer.FullReset() - err = writeUDPMessage(conn, fragMsg, buffer) - if err != nil { - return err - } - } - return nil - } - return err -} - -func writeUDPMessage(conn quic.Connection, message UDPMessage, buffer *buf.Buffer) error { - common.Must( - binary.Write(buffer, binary.BigEndian, message.SessionID), - binary.Write(buffer, binary.BigEndian, uint16(len(message.Host))), - common.Error(buffer.WriteString(message.Host)), - binary.Write(buffer, binary.BigEndian, message.Port), - binary.Write(buffer, binary.BigEndian, message.MsgID), - binary.Write(buffer, binary.BigEndian, message.FragID), - binary.Write(buffer, binary.BigEndian, message.FragCount), - binary.Write(buffer, binary.BigEndian, uint16(len(message.Data))), - common.Error(buffer.Write(message.Data)), - ) - return conn.SendMessage(buffer.Bytes()) -} - -var _ net.Conn = (*Conn)(nil) - -type Conn struct { - quic.Stream - destination M.Socksaddr - needReadResponse bool -} - -func NewConn(stream quic.Stream, destination M.Socksaddr, isClient bool) *Conn { - return &Conn{ - Stream: stream, - destination: destination, - needReadResponse: isClient, - } -} - -func (c *Conn) Read(p []byte) (n int, err error) { - if c.needReadResponse { - var response *ServerResponse - response, err = ReadServerResponse(c.Stream) - if err != nil { - c.Close() - return - } - if !response.OK { - c.Close() - return 0, E.New("remote error: ", response.Message) - } - c.needReadResponse = false - } - return c.Stream.Read(p) -} - -func (c *Conn) LocalAddr() net.Addr { - return M.Socksaddr{} -} - -func (c *Conn) RemoteAddr() net.Addr { - return c.destination.TCPAddr() -} - -func (c *Conn) ReaderReplaceable() bool { - return !c.needReadResponse -} - -func (c *Conn) WriterReplaceable() bool { - return true -} - -func (c *Conn) Upstream() any { - return c.Stream -} - -type PacketConn struct { - session quic.Connection - stream quic.Stream - sessionId uint32 - destination M.Socksaddr - msgCh <-chan *UDPMessage - closer io.Closer -} - -func NewPacketConn(session quic.Connection, stream quic.Stream, sessionId uint32, destination M.Socksaddr, msgCh <-chan *UDPMessage, closer io.Closer) *PacketConn { - return &PacketConn{ - session: session, - stream: stream, - sessionId: sessionId, - destination: destination, - msgCh: msgCh, - closer: closer, - } -} - -func (c *PacketConn) Hold() { - // Hold the stream until it's closed - buf := make([]byte, 1024) - for { - _, err := c.stream.Read(buf) - if err != nil { - break - } - } - _ = c.Close() -} - -func (c *PacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { - msg := <-c.msgCh - if msg == nil { - err = net.ErrClosed - return - } - err = common.Error(buffer.Write(msg.Data)) - destination = M.ParseSocksaddrHostPort(msg.Host, msg.Port).Unwrap() - return -} - -func (c *PacketConn) ReadPacketThreadSafe() (buffer *buf.Buffer, destination M.Socksaddr, err error) { - msg := <-c.msgCh - if msg == nil { - err = net.ErrClosed - return - } - buffer = buf.As(msg.Data) - destination = M.ParseSocksaddrHostPort(msg.Host, msg.Port).Unwrap() - return -} - -func (c *PacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { - return WriteUDPMessage(c.session, UDPMessage{ - SessionID: c.sessionId, - Host: destination.AddrString(), - Port: destination.Port, - FragCount: 1, - Data: buffer.Bytes(), - }) -} - -func (c *PacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { - msg := <-c.msgCh - if msg == nil { - err = net.ErrClosed - return - } - n = copy(p, msg.Data) - destination := M.ParseSocksaddrHostPort(msg.Host, msg.Port) - if destination.IsFqdn() { - addr = destination - } else { - addr = destination.UDPAddr() - } - return -} - -func (c *PacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { - err = c.WritePacket(buf.As(p), M.SocksaddrFromNet(addr)) - if err == nil { - n = len(p) - } - return -} - -func (c *PacketConn) LocalAddr() net.Addr { - return M.Socksaddr{} -} - -func (c *PacketConn) RemoteAddr() net.Addr { - return c.destination.UDPAddr() -} - -func (c *PacketConn) SetDeadline(t time.Time) error { - return os.ErrInvalid -} - -func (c *PacketConn) SetReadDeadline(t time.Time) error { - return os.ErrInvalid -} - -func (c *PacketConn) SetWriteDeadline(t time.Time) error { - return os.ErrInvalid -} - -func (c *PacketConn) NeedAdditionalReadDeadline() bool { - return true -} - -func (c *PacketConn) Read(b []byte) (n int, err error) { - n, _, err = c.ReadFrom(b) - return -} - -func (c *PacketConn) Write(b []byte) (n int, err error) { - return c.WriteTo(b, c.destination) -} - -func (c *PacketConn) Close() error { - return common.Close(c.stream, c.closer) -} diff --git a/transport/hysteria/speed.go b/transport/hysteria/speed.go deleted file mode 100644 index 161e0d5881..0000000000 --- a/transport/hysteria/speed.go +++ /dev/null @@ -1,36 +0,0 @@ -package hysteria - -import ( - "regexp" - "strconv" -) - -func StringToBps(s string) uint64 { - if s == "" { - return 0 - } - m := regexp.MustCompile(`^(\d+)\s*([KMGT]?)([Bb])ps$`).FindStringSubmatch(s) - if m == nil { - return 0 - } - var n uint64 - switch m[2] { - case "K": - n = 1 << 10 - case "M": - n = 1 << 20 - case "G": - n = 1 << 30 - case "T": - n = 1 << 40 - default: - n = 1 - } - v, _ := strconv.ParseUint(m[1], 10, 64) - n = v * n - if m[3] == "b" { - // Bits, need to convert to bytes - n = n >> 3 - } - return n -} diff --git a/transport/hysteria/wrap.go b/transport/hysteria/wrap.go deleted file mode 100644 index e89ac95e07..0000000000 --- a/transport/hysteria/wrap.go +++ /dev/null @@ -1,68 +0,0 @@ -package hysteria - -import ( - "net" - "os" - "syscall" - - "github.com/sagernet/quic-go" - "github.com/sagernet/sing/common" - "github.com/sagernet/sing/common/baderror" -) - -type PacketConnWrapper struct { - net.PacketConn -} - -func (c *PacketConnWrapper) SetReadBuffer(bytes int) error { - return common.MustCast[*net.UDPConn](c.PacketConn).SetReadBuffer(bytes) -} - -func (c *PacketConnWrapper) SetWriteBuffer(bytes int) error { - return common.MustCast[*net.UDPConn](c.PacketConn).SetWriteBuffer(bytes) -} - -func (c *PacketConnWrapper) SyscallConn() (syscall.RawConn, error) { - return common.MustCast[*net.UDPConn](c.PacketConn).SyscallConn() -} - -func (c *PacketConnWrapper) File() (f *os.File, err error) { - return common.MustCast[*net.UDPConn](c.PacketConn).File() -} - -func (c *PacketConnWrapper) Upstream() any { - return c.PacketConn -} - -type StreamWrapper struct { - Conn quic.Connection - quic.Stream -} - -func (s *StreamWrapper) Read(p []byte) (n int, err error) { - n, err = s.Stream.Read(p) - return n, baderror.WrapQUIC(err) -} - -func (s *StreamWrapper) Write(p []byte) (n int, err error) { - n, err = s.Stream.Write(p) - return n, baderror.WrapQUIC(err) -} - -func (s *StreamWrapper) LocalAddr() net.Addr { - return s.Conn.LocalAddr() -} - -func (s *StreamWrapper) RemoteAddr() net.Addr { - return s.Conn.RemoteAddr() -} - -func (s *StreamWrapper) Upstream() any { - return s.Stream -} - -func (s *StreamWrapper) Close() error { - s.CancelRead(0) - s.Stream.Close() - return nil -} diff --git a/transport/hysteria/xplus.go b/transport/hysteria/xplus.go deleted file mode 100644 index 14e0eaa8da..0000000000 --- a/transport/hysteria/xplus.go +++ /dev/null @@ -1,118 +0,0 @@ -package hysteria - -import ( - "crypto/sha256" - "math/rand" - "net" - "sync" - "time" - - "github.com/sagernet/sing/common" - "github.com/sagernet/sing/common/buf" - "github.com/sagernet/sing/common/bufio" - M "github.com/sagernet/sing/common/metadata" - N "github.com/sagernet/sing/common/network" -) - -const xplusSaltLen = 16 - -func NewXPlusPacketConn(conn net.PacketConn, key []byte) net.PacketConn { - vectorisedWriter, isVectorised := bufio.CreateVectorisedPacketWriter(conn) - if isVectorised { - return &VectorisedXPlusConn{ - XPlusPacketConn: XPlusPacketConn{ - PacketConn: conn, - key: key, - rand: rand.New(rand.NewSource(time.Now().UnixNano())), - }, - writer: vectorisedWriter, - } - } else { - return &XPlusPacketConn{ - PacketConn: conn, - key: key, - rand: rand.New(rand.NewSource(time.Now().UnixNano())), - } - } -} - -type XPlusPacketConn struct { - net.PacketConn - key []byte - randAccess sync.Mutex - rand *rand.Rand -} - -func (c *XPlusPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { - n, addr, err = c.PacketConn.ReadFrom(p) - if err != nil { - return - } else if n < xplusSaltLen { - n = 0 - return - } - key := sha256.Sum256(append(c.key, p[:xplusSaltLen]...)) - for i := range p[xplusSaltLen:] { - p[i] = p[xplusSaltLen+i] ^ key[i%sha256.Size] - } - n -= xplusSaltLen - return -} - -func (c *XPlusPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { - // can't use unsafe buffer on WriteTo - buffer := buf.NewSize(len(p) + xplusSaltLen) - defer buffer.Release() - salt := buffer.Extend(xplusSaltLen) - c.randAccess.Lock() - _, _ = c.rand.Read(salt) - c.randAccess.Unlock() - key := sha256.Sum256(append(c.key, salt...)) - for i := range p { - common.Must(buffer.WriteByte(p[i] ^ key[i%sha256.Size])) - } - return c.PacketConn.WriteTo(buffer.Bytes(), addr) -} - -func (c *XPlusPacketConn) Upstream() any { - return c.PacketConn -} - -type VectorisedXPlusConn struct { - XPlusPacketConn - writer N.VectorisedPacketWriter -} - -func (c *VectorisedXPlusConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { - header := buf.NewSize(xplusSaltLen) - defer header.Release() - salt := header.Extend(xplusSaltLen) - c.randAccess.Lock() - _, _ = c.rand.Read(salt) - c.randAccess.Unlock() - key := sha256.Sum256(append(c.key, salt...)) - for i := range p { - p[i] ^= key[i%sha256.Size] - } - return bufio.WriteVectorisedPacket(c.writer, [][]byte{header.Bytes(), p}, M.SocksaddrFromNet(addr)) -} - -func (c *VectorisedXPlusConn) WriteVectorisedPacket(buffers []*buf.Buffer, destination M.Socksaddr) error { - header := buf.NewSize(xplusSaltLen) - defer header.Release() - salt := header.Extend(xplusSaltLen) - c.randAccess.Lock() - _, _ = c.rand.Read(salt) - c.randAccess.Unlock() - key := sha256.Sum256(append(c.key, salt...)) - var index int - for _, buffer := range buffers { - data := buffer.Bytes() - for i := range data { - data[i] ^= key[index%sha256.Size] - index++ - } - } - buffers = append([]*buf.Buffer{header}, buffers...) - return c.writer.WriteVectorisedPacket(buffers, destination) -} diff --git a/transport/v2rayquic/client.go b/transport/v2rayquic/client.go index c3345780c1..f51846159f 100644 --- a/transport/v2rayquic/client.go +++ b/transport/v2rayquic/client.go @@ -12,7 +12,6 @@ import ( "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/transport/hysteria" "github.com/sagernet/sing-quic" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/bufio" @@ -93,7 +92,7 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) { if err != nil { return nil, err } - return &hysteria.StreamWrapper{Conn: conn, Stream: stream}, nil + return &StreamWrapper{Conn: conn, Stream: stream}, nil } func (c *Client) Close() error { diff --git a/transport/v2rayquic/server.go b/transport/v2rayquic/server.go index 71960e589b..0ef8d2a13f 100644 --- a/transport/v2rayquic/server.go +++ b/transport/v2rayquic/server.go @@ -12,7 +12,6 @@ import ( "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/transport/hysteria" "github.com/sagernet/sing-quic" "github.com/sagernet/sing/common" M "github.com/sagernet/sing/common/metadata" @@ -86,7 +85,7 @@ func (s *Server) streamAcceptLoop(conn quic.Connection) error { if err != nil { return err } - go s.handler.NewConnection(conn.Context(), &hysteria.StreamWrapper{Conn: conn, Stream: stream}, M.Metadata{}) + go s.handler.NewConnection(conn.Context(), &StreamWrapper{Conn: conn, Stream: stream}, M.Metadata{}) } } diff --git a/transport/v2rayquic/stream.go b/transport/v2rayquic/stream.go new file mode 100644 index 0000000000..d9c3bebacc --- /dev/null +++ b/transport/v2rayquic/stream.go @@ -0,0 +1,41 @@ +package v2rayquic + +import ( + "net" + + "github.com/sagernet/quic-go" + "github.com/sagernet/sing/common/baderror" +) + +type StreamWrapper struct { + Conn quic.Connection + quic.Stream +} + +func (s *StreamWrapper) Read(p []byte) (n int, err error) { + n, err = s.Stream.Read(p) + return n, baderror.WrapQUIC(err) +} + +func (s *StreamWrapper) Write(p []byte) (n int, err error) { + n, err = s.Stream.Write(p) + return n, baderror.WrapQUIC(err) +} + +func (s *StreamWrapper) LocalAddr() net.Addr { + return s.Conn.LocalAddr() +} + +func (s *StreamWrapper) RemoteAddr() net.Addr { + return s.Conn.RemoteAddr() +} + +func (s *StreamWrapper) Upstream() any { + return s.Stream +} + +func (s *StreamWrapper) Close() error { + s.CancelRead(0) + s.Stream.Close() + return nil +} From 343e24969d680a5dbfbff87c3b4561f824c94da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 21 Oct 2023 12:00:00 +0800 Subject: [PATCH 23/87] Add brutal debug option for Hysteria2 --- docs/configuration/inbound/hysteria2.md | 15 ++++++++++----- docs/configuration/inbound/hysteria2.zh.md | 15 ++++++++++----- docs/configuration/outbound/hysteria2.md | 5 +++++ docs/configuration/outbound/hysteria2.zh.md | 4 ++++ inbound/hysteria2.go | 1 + option/hysteria2.go | 14 ++++++++------ outbound/hysteria2.go | 2 ++ 7 files changed, 40 insertions(+), 16 deletions(-) diff --git a/docs/configuration/inbound/hysteria2.md b/docs/configuration/inbound/hysteria2.md index b65304e249..ab6f2e4dd1 100644 --- a/docs/configuration/inbound/hysteria2.md +++ b/docs/configuration/inbound/hysteria2.md @@ -20,8 +20,9 @@ } ], "ignore_client_bandwidth": false, + "tls": {}, "masquerade": "", - "tls": {} + "brutal_debug": false } ``` @@ -67,6 +68,12 @@ Commands the client to use the BBR flow control algorithm instead of Hysteria CC Conflict with `up_mbps` and `down_mbps`. +#### tls + +==Required== + +TLS configuration, see [TLS](/configuration/shared/tls/#inbound). + #### masquerade HTTP3 server behavior when authentication fails. @@ -78,8 +85,6 @@ HTTP3 server behavior when authentication fails. A 404 page will be returned if empty. -#### tls - -==Required== +#### brutal_debug -TLS configuration, see [TLS](/configuration/shared/tls/#inbound). \ No newline at end of file +Enable debug information logging for Hysteria Brutal CC. diff --git a/docs/configuration/inbound/hysteria2.zh.md b/docs/configuration/inbound/hysteria2.zh.md index 49d2258a37..d21a13d09e 100644 --- a/docs/configuration/inbound/hysteria2.zh.md +++ b/docs/configuration/inbound/hysteria2.zh.md @@ -20,8 +20,9 @@ } ], "ignore_client_bandwidth": false, + "tls": {}, "masquerade": "", - "tls": {} + "brutal_debug": false } ``` @@ -65,6 +66,12 @@ Hysteria 用户 与 `up_mbps` 和 `down_mbps` 冲突。 +#### tls + +==必填== + +TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。 + #### masquerade HTTP3 服务器认证失败时的行为。 @@ -76,8 +83,6 @@ HTTP3 服务器认证失败时的行为。 如果为空,则返回 404 页。 -#### tls - -==必填== +#### brutal_debug -TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。 \ No newline at end of file +启用 Hysteria Brutal CC 的调试信息日志记录。 diff --git a/docs/configuration/outbound/hysteria2.md b/docs/configuration/outbound/hysteria2.md index 115c1f2515..9861e332ac 100644 --- a/docs/configuration/outbound/hysteria2.md +++ b/docs/configuration/outbound/hysteria2.md @@ -16,6 +16,7 @@ "password": "goofy_ahh_password", "network": "tcp", "tls": {}, + "brutal_debug": false, ... // Dial Fields } @@ -73,6 +74,10 @@ Both is enabled by default. TLS configuration, see [TLS](/configuration/shared/tls/#outbound). +#### brutal_debug + +Enable debug information logging for Hysteria Brutal CC. + ### Dial Fields See [Dial Fields](/configuration/shared/dial) for details. diff --git a/docs/configuration/outbound/hysteria2.zh.md b/docs/configuration/outbound/hysteria2.zh.md index ba699b5840..e9d1cb2d30 100644 --- a/docs/configuration/outbound/hysteria2.zh.md +++ b/docs/configuration/outbound/hysteria2.zh.md @@ -16,6 +16,7 @@ "password": "goofy_ahh_password", "network": "tcp", "tls": {}, + "brutal_debug": false, ... // 拨号字段 } @@ -73,6 +74,9 @@ QUIC 流量混淆器密码. TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#outbound)。 +#### brutal_debug + +启用 Hysteria Brutal CC 的调试信息日志记录。 ### 拨号字段 diff --git a/inbound/hysteria2.go b/inbound/hysteria2.go index 07b45af27d..5db881c3d4 100644 --- a/inbound/hysteria2.go +++ b/inbound/hysteria2.go @@ -90,6 +90,7 @@ func NewHysteria2(ctx context.Context, router adapter.Router, logger log.Context service, err := hysteria2.NewService[int](hysteria2.ServiceOptions{ Context: ctx, Logger: logger, + BrutalDebug: options.BrutalDebug, SendBPS: uint64(options.UpMbps * hysteria.MbpsToBps), ReceiveBPS: uint64(options.DownMbps * hysteria.MbpsToBps), SalamanderPassword: salamanderPassword, diff --git a/option/hysteria2.go b/option/hysteria2.go index 48396ca1aa..feab475b3a 100644 --- a/option/hysteria2.go +++ b/option/hysteria2.go @@ -9,6 +9,7 @@ type Hysteria2InboundOptions struct { IgnoreClientBandwidth bool `json:"ignore_client_bandwidth,omitempty"` TLS *InboundTLSOptions `json:"tls,omitempty"` Masquerade string `json:"masquerade,omitempty"` + BrutalDebug bool `json:"brutal_debug,omitempty"` } type Hysteria2Obfs struct { @@ -24,10 +25,11 @@ type Hysteria2User struct { type Hysteria2OutboundOptions struct { DialerOptions ServerOptions - UpMbps int `json:"up_mbps,omitempty"` - DownMbps int `json:"down_mbps,omitempty"` - Obfs *Hysteria2Obfs `json:"obfs,omitempty"` - Password string `json:"password,omitempty"` - Network NetworkList `json:"network,omitempty"` - TLS *OutboundTLSOptions `json:"tls,omitempty"` + UpMbps int `json:"up_mbps,omitempty"` + DownMbps int `json:"down_mbps,omitempty"` + Obfs *Hysteria2Obfs `json:"obfs,omitempty"` + Password string `json:"password,omitempty"` + Network NetworkList `json:"network,omitempty"` + TLS *OutboundTLSOptions `json:"tls,omitempty"` + BrutalDebug bool `json:"brutal_debug,omitempty"` } diff --git a/outbound/hysteria2.go b/outbound/hysteria2.go index 2998f9484d..f2ffe2fd1b 100644 --- a/outbound/hysteria2.go +++ b/outbound/hysteria2.go @@ -61,6 +61,8 @@ func NewHysteria2(ctx context.Context, router adapter.Router, logger log.Context client, err := hysteria2.NewClient(hysteria2.ClientOptions{ Context: ctx, Dialer: outboundDialer, + Logger: logger, + BrutalDebug: options.BrutalDebug, ServerAddress: options.ServerOptions.Build(), SendBPS: uint64(options.UpMbps * hysteria.MbpsToBps), ReceiveBPS: uint64(options.DownMbps * hysteria.MbpsToBps), From 97286eea1e53ea7dff0fe1feb386abc6557f8d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 21 Oct 2023 12:00:00 +0800 Subject: [PATCH 24/87] Add TLS self sign generate command --- cmd/sing-box/cmd_generate.go | 49 +-------------------- cmd/sing-box/cmd_generate_tls.go | 40 +++++++++++++++++ cmd/sing-box/cmd_generate_vapid.go | 40 +++++++++++++++++ cmd/sing-box/cmd_generate_wireguard.go | 61 ++++++++++++++++++++++++++ common/tls/mkcert.go | 34 ++++++++------ common/tls/std_server.go | 2 +- 6 files changed, 164 insertions(+), 62 deletions(-) create mode 100644 cmd/sing-box/cmd_generate_tls.go create mode 100644 cmd/sing-box/cmd_generate_vapid.go create mode 100644 cmd/sing-box/cmd_generate_wireguard.go diff --git a/cmd/sing-box/cmd_generate.go b/cmd/sing-box/cmd_generate.go index cf00d58a44..74d64c559e 100644 --- a/cmd/sing-box/cmd_generate.go +++ b/cmd/sing-box/cmd_generate.go @@ -11,7 +11,6 @@ import ( "github.com/gofrs/uuid/v5" "github.com/spf13/cobra" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) var commandGenerate = &cobra.Command{ @@ -22,8 +21,7 @@ var commandGenerate = &cobra.Command{ func init() { commandGenerate.AddCommand(commandGenerateUUID) commandGenerate.AddCommand(commandGenerateRandom) - commandGenerate.AddCommand(commandGenerateWireGuardKeyPair) - commandGenerate.AddCommand(commandGenerateRealityKeyPair) + mainCommand.AddCommand(commandGenerate) } @@ -92,48 +90,3 @@ func generateUUID() error { _, err = os.Stdout.WriteString(newUUID.String() + "\n") return err } - -var commandGenerateWireGuardKeyPair = &cobra.Command{ - Use: "wg-keypair", - Short: "Generate WireGuard key pair", - Args: cobra.NoArgs, - Run: func(cmd *cobra.Command, args []string) { - err := generateWireGuardKey() - if err != nil { - log.Fatal(err) - } - }, -} - -func generateWireGuardKey() error { - privateKey, err := wgtypes.GeneratePrivateKey() - if err != nil { - return err - } - os.Stdout.WriteString("PrivateKey: " + privateKey.String() + "\n") - os.Stdout.WriteString("PublicKey: " + privateKey.PublicKey().String() + "\n") - return nil -} - -var commandGenerateRealityKeyPair = &cobra.Command{ - Use: "reality-keypair", - Short: "Generate reality key pair", - Args: cobra.NoArgs, - Run: func(cmd *cobra.Command, args []string) { - err := generateRealityKey() - if err != nil { - log.Fatal(err) - } - }, -} - -func generateRealityKey() error { - privateKey, err := wgtypes.GeneratePrivateKey() - if err != nil { - return err - } - publicKey := privateKey.PublicKey() - os.Stdout.WriteString("PrivateKey: " + base64.RawURLEncoding.EncodeToString(privateKey[:]) + "\n") - os.Stdout.WriteString("PublicKey: " + base64.RawURLEncoding.EncodeToString(publicKey[:]) + "\n") - return nil -} diff --git a/cmd/sing-box/cmd_generate_tls.go b/cmd/sing-box/cmd_generate_tls.go new file mode 100644 index 0000000000..d871566fac --- /dev/null +++ b/cmd/sing-box/cmd_generate_tls.go @@ -0,0 +1,40 @@ +package main + +import ( + "os" + "time" + + "github.com/sagernet/sing-box/common/tls" + "github.com/sagernet/sing-box/log" + + "github.com/spf13/cobra" +) + +var flagGenerateTLSKeyPairMonths int + +var commandGenerateTLSKeyPair = &cobra.Command{ + Use: "tls-keypair ", + Short: "Generate TLS self sign key pair", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + err := generateTLSKeyPair(args[0]) + if err != nil { + log.Fatal(err) + } + }, +} + +func init() { + commandGenerateTLSKeyPair.Flags().IntVarP(&flagGenerateTLSKeyPairMonths, "months", "m", 1, "Valid months") + commandGenerate.AddCommand(commandGenerateTLSKeyPair) +} + +func generateTLSKeyPair(serverName string) error { + privateKeyPem, publicKeyPem, err := tls.GenerateKeyPair(time.Now, serverName, time.Now().AddDate(0, flagGenerateTLSKeyPairMonths, 0)) + if err != nil { + return err + } + os.Stdout.WriteString(string(privateKeyPem) + "\n") + os.Stdout.WriteString(string(publicKeyPem) + "\n") + return nil +} diff --git a/cmd/sing-box/cmd_generate_vapid.go b/cmd/sing-box/cmd_generate_vapid.go new file mode 100644 index 0000000000..e83e6d8054 --- /dev/null +++ b/cmd/sing-box/cmd_generate_vapid.go @@ -0,0 +1,40 @@ +//go:build go1.20 + +package main + +import ( + "crypto/ecdh" + "crypto/rand" + "encoding/base64" + "os" + + "github.com/sagernet/sing-box/log" + + "github.com/spf13/cobra" +) + +var commandGenerateVAPIDKeyPair = &cobra.Command{ + Use: "vapid-keypair", + Short: "Generate VAPID key pair", + Run: func(cmd *cobra.Command, args []string) { + err := generateVAPIDKeyPair() + if err != nil { + log.Fatal(err) + } + }, +} + +func init() { + commandGenerate.AddCommand(commandGenerateVAPIDKeyPair) +} + +func generateVAPIDKeyPair() error { + privateKey, err := ecdh.P256().GenerateKey(rand.Reader) + if err != nil { + return err + } + publicKey := privateKey.PublicKey() + os.Stdout.WriteString("PrivateKey: " + base64.RawURLEncoding.EncodeToString(privateKey.Bytes()) + "\n") + os.Stdout.WriteString("PublicKey: " + base64.RawURLEncoding.EncodeToString(publicKey.Bytes()) + "\n") + return nil +} diff --git a/cmd/sing-box/cmd_generate_wireguard.go b/cmd/sing-box/cmd_generate_wireguard.go new file mode 100644 index 0000000000..087e74b271 --- /dev/null +++ b/cmd/sing-box/cmd_generate_wireguard.go @@ -0,0 +1,61 @@ +package main + +import ( + "encoding/base64" + "os" + + "github.com/sagernet/sing-box/log" + + "github.com/spf13/cobra" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +func init() { + commandGenerate.AddCommand(commandGenerateWireGuardKeyPair) + commandGenerate.AddCommand(commandGenerateRealityKeyPair) +} + +var commandGenerateWireGuardKeyPair = &cobra.Command{ + Use: "wg-keypair", + Short: "Generate WireGuard key pair", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + err := generateWireGuardKey() + if err != nil { + log.Fatal(err) + } + }, +} + +func generateWireGuardKey() error { + privateKey, err := wgtypes.GeneratePrivateKey() + if err != nil { + return err + } + os.Stdout.WriteString("PrivateKey: " + privateKey.String() + "\n") + os.Stdout.WriteString("PublicKey: " + privateKey.PublicKey().String() + "\n") + return nil +} + +var commandGenerateRealityKeyPair = &cobra.Command{ + Use: "reality-keypair", + Short: "Generate reality key pair", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + err := generateRealityKey() + if err != nil { + log.Fatal(err) + } + }, +} + +func generateRealityKey() error { + privateKey, err := wgtypes.GeneratePrivateKey() + if err != nil { + return err + } + publicKey := privateKey.PublicKey() + os.Stdout.WriteString("PrivateKey: " + base64.RawURLEncoding.EncodeToString(privateKey[:]) + "\n") + os.Stdout.WriteString("PublicKey: " + base64.RawURLEncoding.EncodeToString(publicKey[:]) + "\n") + return nil +} diff --git a/common/tls/mkcert.go b/common/tls/mkcert.go index 9598cffa5a..1e71a76315 100644 --- a/common/tls/mkcert.go +++ b/common/tls/mkcert.go @@ -11,22 +11,34 @@ import ( "time" ) -func GenerateKeyPair(timeFunc func() time.Time, serverName string) (*tls.Certificate, error) { +func GenerateCertificate(timeFunc func() time.Time, serverName string) (*tls.Certificate, error) { + privateKeyPem, publicKeyPem, err := GenerateKeyPair(timeFunc, serverName, timeFunc().Add(time.Hour)) + if err != nil { + return nil, err + } + certificate, err := tls.X509KeyPair(publicKeyPem, privateKeyPem) + if err != nil { + return nil, err + } + return &certificate, err +} + +func GenerateKeyPair(timeFunc func() time.Time, serverName string, expire time.Time) (privateKeyPem []byte, publicKeyPem []byte, err error) { if timeFunc == nil { timeFunc = time.Now } key, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { - return nil, err + return } serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) if err != nil { - return nil, err + return } template := &x509.Certificate{ SerialNumber: serialNumber, NotBefore: timeFunc().Add(time.Hour * -1), - NotAfter: timeFunc().Add(time.Hour), + NotAfter: expire, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, @@ -37,17 +49,13 @@ func GenerateKeyPair(timeFunc func() time.Time, serverName string) (*tls.Certifi } publicDer, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key) if err != nil { - return nil, err + return } privateDer, err := x509.MarshalPKCS8PrivateKey(key) if err != nil { - return nil, err - } - publicPem := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: publicDer}) - privPem := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privateDer}) - keyPair, err := tls.X509KeyPair(publicPem, privPem) - if err != nil { - return nil, err + return } - return &keyPair, err + publicKeyPem = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: publicDer}) + privateKeyPem = pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privateDer}) + return } diff --git a/common/tls/std_server.go b/common/tls/std_server.go index 36ce67b67a..28a94cf15f 100644 --- a/common/tls/std_server.go +++ b/common/tls/std_server.go @@ -233,7 +233,7 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound } if certificate == nil && key == nil && options.Insecure { tlsConfig.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { - return GenerateKeyPair(ntp.TimeFuncFromContext(ctx), info.ServerName) + return GenerateCertificate(ntp.TimeFuncFromContext(ctx), info.ServerName) } } else { if certificate == nil { From 53b123241f4366c01098a61ab28d783ecfa7c3ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 25 Oct 2023 12:00:00 +0800 Subject: [PATCH 25/87] android: Add build info tools for debug --- experimental/libbox/build_info.go | 234 ++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 experimental/libbox/build_info.go diff --git a/experimental/libbox/build_info.go b/experimental/libbox/build_info.go new file mode 100644 index 0000000000..5a02593c3d --- /dev/null +++ b/experimental/libbox/build_info.go @@ -0,0 +1,234 @@ +//go:build android + +package libbox + +import ( + "archive/zip" + "bytes" + "debug/buildinfo" + "io" + "runtime/debug" + "strings" + + "github.com/sagernet/sing/common" +) + +const ( + androidVPNCoreTypeOpenVPN = "OpenVPN" + androidVPNCoreTypeShadowsocks = "Shadowsocks" + androidVPNCoreTypeClash = "Clash" + androidVPNCoreTypeV2Ray = "V2Ray" + androidVPNCoreTypeWireGuard = "WireGuard" + androidVPNCoreTypeSingBox = "sing-box" + androidVPNCoreTypeUnknown = "Unknown" +) + +type AndroidVPNType struct { + CoreType string + CorePath string + GoVersion string +} + +func ReadAndroidVPNType(publicSourceDirList StringIterator) (*AndroidVPNType, error) { + apkPathList := iteratorToArray[string](publicSourceDirList) + var lastError error + for _, apkPath := range apkPathList { + androidVPNType, err := readAndroidVPNType(apkPath) + if androidVPNType == nil { + if err != nil { + lastError = err + } + continue + } + return androidVPNType, nil + } + return nil, lastError +} + +func readAndroidVPNType(publicSourceDir string) (*AndroidVPNType, error) { + reader, err := zip.OpenReader(publicSourceDir) + if err != nil { + return nil, err + } + defer reader.Close() + var lastError error + for _, file := range reader.File { + if !strings.HasPrefix(file.Name, "lib/") { + continue + } + vpnType, err := readAndroidVPNTypeEntry(file) + if err != nil { + lastError = err + continue + } + return vpnType, nil + } + for _, file := range reader.File { + if !strings.HasPrefix(file.Name, "lib/") { + continue + } + if strings.Contains(file.Name, androidVPNCoreTypeOpenVPN) || strings.Contains(file.Name, "ovpn") { + return &AndroidVPNType{CoreType: androidVPNCoreTypeOpenVPN}, nil + } + if strings.Contains(file.Name, androidVPNCoreTypeShadowsocks) { + return &AndroidVPNType{CoreType: androidVPNCoreTypeShadowsocks}, nil + } + } + return nil, lastError +} + +func readAndroidVPNTypeEntry(zipFile *zip.File) (*AndroidVPNType, error) { + readCloser, err := zipFile.Open() + if err != nil { + return nil, err + } + libContent := make([]byte, zipFile.UncompressedSize64) + _, err = io.ReadFull(readCloser, libContent) + readCloser.Close() + if err != nil { + return nil, err + } + buildInfo, err := buildinfo.Read(bytes.NewReader(libContent)) + if err != nil { + return nil, err + } + var vpnType AndroidVPNType + vpnType.GoVersion = buildInfo.GoVersion + if !strings.HasPrefix(vpnType.GoVersion, "go") { + vpnType.GoVersion = "obfuscated" + } else { + vpnType.GoVersion = vpnType.GoVersion[2:] + } + vpnType.CoreType = androidVPNCoreTypeUnknown + if len(buildInfo.Deps) == 0 { + vpnType.CoreType = "obfuscated" + return &vpnType, nil + } + + dependencies := make(map[string]bool) + dependencies[buildInfo.Path] = true + for _, module := range buildInfo.Deps { + dependencies[module.Path] = true + if module.Replace != nil { + dependencies[module.Replace.Path] = true + } + } + for dependency := range dependencies { + pkgType, loaded := determinePkgType(dependency) + if loaded { + vpnType.CoreType = pkgType + } + } + if vpnType.CoreType == androidVPNCoreTypeUnknown { + for dependency := range dependencies { + pkgType, loaded := determinePkgTypeSecondary(dependency) + if loaded { + vpnType.CoreType = pkgType + return &vpnType, nil + } + } + } + if vpnType.CoreType != androidVPNCoreTypeUnknown { + vpnType.CorePath, _ = determineCorePath(buildInfo, vpnType.CoreType) + return &vpnType, nil + } + if dependencies["github.com/golang/protobuf"] && dependencies["github.com/v2fly/ss-bloomring"] { + vpnType.CoreType = androidVPNCoreTypeV2Ray + return &vpnType, nil + } + return &vpnType, nil +} + +func determinePkgType(pkgName string) (string, bool) { + pkgNameLower := strings.ToLower(pkgName) + if strings.Contains(pkgNameLower, "clash") { + return androidVPNCoreTypeClash, true + } + if strings.Contains(pkgNameLower, "v2ray") || strings.Contains(pkgNameLower, "xray") { + return androidVPNCoreTypeV2Ray, true + } + + if strings.Contains(pkgNameLower, "sing-box") { + return androidVPNCoreTypeSingBox, true + } + return "", false +} + +func determinePkgTypeSecondary(pkgName string) (string, bool) { + pkgNameLower := strings.ToLower(pkgName) + if strings.Contains(pkgNameLower, "wireguard") { + return androidVPNCoreTypeWireGuard, true + } + return "", false +} + +func determineCorePath(pkgInfo *buildinfo.BuildInfo, pkgType string) (string, bool) { + switch pkgType { + case androidVPNCoreTypeClash: + return determineCorePathForPkgs(pkgInfo, []string{"github.com/Dreamacro/clash"}, []string{"clash"}) + case androidVPNCoreTypeV2Ray: + if v2rayVersion, loaded := determineCorePathForPkgs(pkgInfo, []string{ + "github.com/v2fly/v2ray-core", + "github.com/v2fly/v2ray-core/v4", + "github.com/v2fly/v2ray-core/v5", + }, []string{ + "v2ray", + }); loaded { + return v2rayVersion, true + } + if xrayVersion, loaded := determineCorePathForPkgs(pkgInfo, []string{ + "github.com/xtls/xray-core", + }, []string{ + "xray", + }); loaded { + return xrayVersion, true + } + return "", false + case androidVPNCoreTypeSingBox: + return determineCorePathForPkgs(pkgInfo, []string{"github.com/sagernet/sing-box"}, []string{"sing-box"}) + case androidVPNCoreTypeWireGuard: + return determineCorePathForPkgs(pkgInfo, []string{"golang.zx2c4.com/wireguard"}, []string{"wireguard"}) + default: + return "", false + } +} + +func determineCorePathForPkgs(pkgInfo *buildinfo.BuildInfo, pkgs []string, names []string) (string, bool) { + for _, pkg := range pkgs { + if pkgInfo.Path == pkg { + return pkg, true + } + strictDependency := common.Find(pkgInfo.Deps, func(module *debug.Module) bool { + return module.Path == pkg + }) + if strictDependency != nil { + if isValidVersion(strictDependency.Version) { + return strictDependency.Path + " " + strictDependency.Version, true + } else { + return strictDependency.Path, true + } + } + } + for _, name := range names { + if strings.Contains(pkgInfo.Path, name) { + return pkgInfo.Path, true + } + looseDependency := common.Find(pkgInfo.Deps, func(module *debug.Module) bool { + return strings.Contains(module.Path, name) || (module.Replace != nil && strings.Contains(module.Replace.Path, name)) + }) + if looseDependency != nil { + return looseDependency.Path, true + } + } + return "", false +} + +func isValidVersion(version string) bool { + if version == "(devel)" { + return false + } + if strings.Contains(version, "v0.0.0") { + return false + } + return true +} From 9350f3983b014470101ccb9d8704e25e575aa6b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 30 Oct 2023 13:55:59 +0800 Subject: [PATCH 26/87] docs: Remove obsolete fields --- docs/configuration/inbound/shadowsocks.md | 46 ----------------------- 1 file changed, 46 deletions(-) diff --git a/docs/configuration/inbound/shadowsocks.md b/docs/configuration/inbound/shadowsocks.md index e69c9cb9d1..0349d01c72 100644 --- a/docs/configuration/inbound/shadowsocks.md +++ b/docs/configuration/inbound/shadowsocks.md @@ -82,49 +82,3 @@ Both if empty. | none | / | | 2022 methods | `sing-box generate rand --base64 ` | | other methods | any string | - -### Listen Fields - -#### listen - -==Required== - -Listen address. - -#### listen_port - -==Required== - -Listen port. - -#### tcp_fast_open - -Enable tcp fast open for listener. - -#### sniff - -Enable sniffing. - -See [Protocol Sniff](/configuration/route/sniff/) for details. - -#### sniff_override_destination - -Override the connection destination address with the sniffed domain. - -If the domain name is invalid (like tor), this will not work. - -#### domain_strategy - -One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`. - -If set, the requested domain name will be resolved to IP before routing. - -If `sniff_override_destination` is in effect, its value will be taken as a fallback. - -#### udp_timeout - -UDP NAT expiration time in seconds, default is 300 (5 minutes). - -#### proxy_protocol - -Parse [Proxy Protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) in the connection header. \ No newline at end of file From e82dab027df19a3c1fbfb6d47d4acc1a9cccd9c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 25 Oct 2023 12:00:00 +0800 Subject: [PATCH 27/87] documentation: Bump version --- docs/changelog.md | 108 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index d905e5cd0b..b92ad87335 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,28 @@ +#### 1.6.0 + +* Fixes and improvements + +Important changes since 1.5: + +* Our [Apple tvOS client](/installation/clients/sft) is now available in the App Store 🍎 +* Update BBR congestion control for TUIC and Hysteria2 **1** +* Update brutal congestion control for Hysteria2 +* Add `brutal_debug` option for Hysteria2 +* Update legacy Hysteria protocol **2** +* Add TLS self sign key pair generate command +* Remove [Deprecated Features](/deprecated) by agreement + +**1**: + +None of the existing Golang BBR congestion control implementations have been reviewed or unit tested. +This update is intended to address the multi-send defects of the old implementation and may introduce new issues. + +**2** + +Based on discussions with the original author, the brutal CC and QUIC protocol parameters of +the old protocol (Hysteria 1) have been updated to be consistent with Hysteria 2 + + #### 1.5.5 * Fix IPv6 `auto_route` for Linux **1** @@ -12,25 +37,108 @@ When `auto_route` is enabled and `strict_route` is disabled, the device can now Built using Go 1.20, the last version that will run on Windows 7, 8, Server 2008, Server 2012 and macOS 10.13 High Sierra, 10.14 Mojave. + +#### 1.6.0-rc.4 + +* Fixes and improvements + +#### 1.6.0-rc.1 + +* Add legacy builds for old Windows and macOS systems **1** +* Fixes and improvements + +**1**: + +Built using Go 1.20, the last version that will run on Windows 7, 8, Server 2008, Server 2012 and macOS 10.13 High Sierra, 10.14 Mojave. + +#### 1.6.0-beta.4 + +* Fix IPv6 `auto_route` for Linux **1** +* Fixes and improvements + +**1**: + +When `auto_route` is enabled and `strict_route` is disabled, the device can now be reached from external IPv6 addresses. + #### 1.5.4 * Fix Clash cache crash on arm32 devices * Fixes and improvements +#### 1.6.0-beta.3 + +* Update the legacy Hysteria protocol **1** +* Fixes and improvements + +**1** + +Based on discussions with the original author, the brutal CC and QUIC protocol parameters of +the old protocol (Hysteria 1) have been updated to be consistent with Hysteria 2 + +#### 1.6.0-beta.2 + +* Add TLS self sign key pair generate command +* Update brutal congestion control for Hysteria2 +* Fix Clash cache crash on arm32 devices +* Update golang.org/x/net to v0.17.0 +* Fixes and improvements + #### 1.5.3 * Fix compatibility with Android 14 * Fixes and improvements +#### 1.6.0-beta.1 + +* Fixes and improvements + +#### 1.6.0-alpha.5 + +* Fix compatibility with Android 14 +* Update BBR congestion control for TUIC and Hysteria2 **1** +* Fixes and improvements + +**1**: + +None of the existing Golang BBR congestion control implementations have been reviewed or unit tested. +This update is intended to fix a memory leak flaw in the new implementation introduced in 1.6.0-alpha.1 and may +introduce new issues. + +#### 1.6.0-alpha.4 + +* Add `brutal_debug` option for Hysteria2 +* Fixes and improvements + #### 1.5.2 * Our [Apple tvOS client](/installation/clients/sft) is now available in the App Store 🍎 * Fixes and improvements +#### 1.6.0-alpha.3 + +* Fixes and improvements + +#### 1.6.0-alpha.2 + +* Fixes and improvements + #### 1.5.1 * Fixes and improvements +#### 1.6.0-alpha.1 + +* Update BBR congestion control for TUIC and Hysteria2 **1** +* Update quic-go to v0.39.0 +* Update gVisor to 20230814.0 +* Remove [Deprecated Features](/deprecated) by agreement +* Fixes and improvements + +**1**: + +None of the existing Golang BBR congestion control implementations have been reviewed or unit tested. +This update is intended to address the multi-send defects of the old implementation and may introduce new issues. + #### 1.5.0 * Fixes and improvements From d57b35ec3075e67904c38f0cd584b12a942075da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 31 Oct 2023 17:32:03 +0800 Subject: [PATCH 28/87] documentation: Add privacy policy for android --- docs/installation/clients/sfa.md | 5 +++++ docs/installation/clients/sfa.zh.md | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/docs/installation/clients/sfa.md b/docs/installation/clients/sfa.md index 2ec79ec1c6..e2709af53c 100644 --- a/docs/installation/clients/sfa.md +++ b/docs/installation/clients/sfa.md @@ -16,3 +16,8 @@ Experimental Android client for sing-box. * User Agent in remote profile request is `SFA/$version ($version_code; sing-box $sing_box_version)` * The working directory is located at `/sdcard/Android/data/io.nekohasekai.sfa/files` (External files directory) * Crash logs is located in `$working_directory/stderr.log` + +#### Privacy policy + +* SFA did not collect or share personal data. +* The data generated by the software is always on your device. diff --git a/docs/installation/clients/sfa.zh.md b/docs/installation/clients/sfa.zh.md index fa005f11cf..7dfe63352e 100644 --- a/docs/installation/clients/sfa.zh.md +++ b/docs/installation/clients/sfa.zh.md @@ -16,3 +16,8 @@ * 远程配置文件请求中的 User Agent 为 `SFA/$version ($version_code; sing-box $sing_box_version)` * 工作目录位于 `/sdcard/Android/data/io.nekohasekai.sfa/files` (外部文件目录) * 崩溃日志位于 `$working_directory/stderr.log` + +#### 隐私政策 + +* SFA 不收集或共享个人数据。 +* 软件生成的数据始终在您的设备上。 From 3efccaa8f5022c0531be15ba513e1cdd3200978e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 31 Oct 2023 18:24:58 +0800 Subject: [PATCH 29/87] Update dependencies --- go.mod | 2 +- go.sum | 4 ++-- test/go.mod | 4 ++-- test/go.sum | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 3152bfb51b..c92c419bee 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( berty.tech/go-libtor v1.0.385 github.com/caddyserver/certmagic v0.19.2 - github.com/cloudflare/circl v1.3.5 + github.com/cloudflare/circl v1.3.6 github.com/cretz/bine v0.2.0 github.com/fsnotify/fsnotify v1.7.0 github.com/go-chi/chi/v5 v5.0.10 diff --git a/go.sum b/go.sum index 8fa62347f3..94d23a9d0c 100644 --- a/go.sum +++ b/go.sum @@ -9,8 +9,8 @@ github.com/caddyserver/certmagic v0.19.2/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cloudflare/circl v1.3.5 h1:g+wWynZqVALYAlpSQFAa7TscDnUK8mKYtrxMpw6AUKo= -github.com/cloudflare/circl v1.3.5/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg= +github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw= github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo= diff --git a/test/go.mod b/test/go.mod index 50759f68e5..856f10f157 100644 --- a/test/go.mod +++ b/test/go.mod @@ -7,7 +7,7 @@ require github.com/sagernet/sing-box v0.0.0 replace github.com/sagernet/sing-box => ../ require ( - github.com/docker/docker v24.0.6+incompatible + github.com/docker/docker v24.0.7+incompatible github.com/docker/go-connections v0.4.0 github.com/gofrs/uuid/v5 v5.0.0 github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 @@ -28,7 +28,7 @@ require ( github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.5 // indirect github.com/caddyserver/certmagic v0.19.2 // indirect - github.com/cloudflare/circl v1.3.5 // indirect + github.com/cloudflare/circl v1.3.6 // indirect github.com/cretz/bine v0.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/distribution/reference v0.5.0 // indirect diff --git a/test/go.sum b/test/go.sum index 597f559480..bd89d8b67e 100644 --- a/test/go.sum +++ b/test/go.sum @@ -12,8 +12,8 @@ github.com/caddyserver/certmagic v0.19.2/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cloudflare/circl v1.3.5 h1:g+wWynZqVALYAlpSQFAa7TscDnUK8mKYtrxMpw6AUKo= -github.com/cloudflare/circl v1.3.5/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg= +github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw= github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo= github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI= @@ -24,8 +24,8 @@ github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE= -github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= +github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= From 998cc7bd224b78bbc007aa929ff56a8d628893d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 3 Nov 2023 07:12:55 +0800 Subject: [PATCH 30/87] Add multicast filter for tun --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c92c419bee..7b778365e3 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 github.com/sagernet/sing-shadowtls v0.1.4 - github.com/sagernet/sing-tun v0.1.17-0.20231026060825-efd9884154a6 + github.com/sagernet/sing-tun v0.1.17-0.20231104000141-150b1162316c github.com/sagernet/sing-vmess v0.1.8 github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 diff --git a/go.sum b/go.sum index 94d23a9d0c..ad8fe76700 100644 --- a/go.sum +++ b/go.sum @@ -124,8 +124,8 @@ github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+M github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.17-0.20231026060825-efd9884154a6 h1:4yEXBqQoUgXj7qPSLD6lr+z9/KfsvixO9JUA2i5xnM8= -github.com/sagernet/sing-tun v0.1.17-0.20231026060825-efd9884154a6/go.mod h1:w2+S+uWE94E/pQWSDdDdMIjwAEb645kuGPunr6ZllUg= +github.com/sagernet/sing-tun v0.1.17-0.20231104000141-150b1162316c h1:ImeHV8svNieQhubImBFMpr0TvCt4+MEnDq0Ca/PKznc= +github.com/sagernet/sing-tun v0.1.17-0.20231104000141-150b1162316c/go.mod h1:w2+S+uWE94E/pQWSDdDdMIjwAEb645kuGPunr6ZllUg= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= From 126f825241ff164a9536916fe32269979c7a64cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 5 Nov 2023 16:02:10 +0800 Subject: [PATCH 31/87] Update dependencies --- go.mod | 8 ++++---- go.sum | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 7b778365e3..0d5a73286c 100644 --- a/go.mod +++ b/go.mod @@ -26,27 +26,27 @@ require ( github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.2.16-0.20231021090846-8002db54c028 + github.com/sagernet/sing v0.2.16 github.com/sagernet/sing-dns v0.1.10 github.com/sagernet/sing-mux v0.1.3 github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6 github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 github.com/sagernet/sing-shadowtls v0.1.4 - github.com/sagernet/sing-tun v0.1.17-0.20231104000141-150b1162316c + github.com/sagernet/sing-tun v0.1.17 github.com/sagernet/sing-vmess v0.1.8 github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f - github.com/spf13/cobra v1.7.0 + github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 go.uber.org/zap v1.26.0 go4.org/netipx v0.0.0-20230824141953-6213f710f925 golang.org/x/crypto v0.14.0 golang.org/x/net v0.17.0 - golang.org/x/sys v0.13.0 + golang.org/x/sys v0.14.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 google.golang.org/grpc v1.59.0 google.golang.org/protobuf v1.31.0 diff --git a/go.sum b/go.sum index ad8fe76700..46fcc76e22 100644 --- a/go.sum +++ b/go.sum @@ -11,7 +11,7 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg= github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw= github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo= github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI= @@ -110,8 +110,8 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.16-0.20231021090846-8002db54c028 h1:6GbQt7SC9y5Imrq5jDMbXDSaNiMhJ8KBjhjtQRuqQvE= -github.com/sagernet/sing v0.2.16-0.20231021090846-8002db54c028/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= +github.com/sagernet/sing v0.2.16 h1:InsjvUFKbgvqpWbHkvLHwplWJs1mu+FIn6yEVQrP9ZE= +github.com/sagernet/sing v0.2.16/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlTZCI= github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= @@ -124,8 +124,8 @@ github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+M github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.17-0.20231104000141-150b1162316c h1:ImeHV8svNieQhubImBFMpr0TvCt4+MEnDq0Ca/PKznc= -github.com/sagernet/sing-tun v0.1.17-0.20231104000141-150b1162316c/go.mod h1:w2+S+uWE94E/pQWSDdDdMIjwAEb645kuGPunr6ZllUg= +github.com/sagernet/sing-tun v0.1.17 h1:czy6lyXdH+ZqsOmMJufHwooPlOckMLamDIVGKbcEDTY= +github.com/sagernet/sing-tun v0.1.17/go.mod h1:dEhn+gztt87EJsJRzGKw6uWpu2DihQwJN/6F7WV6Z3M= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= @@ -140,8 +140,8 @@ github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f h1:Kvo8w8Y9l github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f/go.mod h1:mySs0abhpc/gLlvhoq7HP1RzOaRmIXVeZGCh++zoApk= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -189,8 +189,8 @@ golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= From 11629a931bd38d7ad97ff2b24d1878bf09854b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 3 Nov 2023 02:20:35 +0800 Subject: [PATCH 32/87] Update release script --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 0b1018070d..a2ecf2166a 100644 --- a/Makefile +++ b/Makefile @@ -84,6 +84,9 @@ upload_android: release_android: lib_android update_android_version build_android upload_android publish_android: + cd ../sing-box-for-android && ./gradlew :app:publishReleaseBundle + +publish_android_appcenter: cd ../sing-box-for-android && ./gradlew :app:appCenterAssembleAndUploadRelease build_ios: From 9f01d5c5b43d95e210eb442cba63b3a20ddacfe6 Mon Sep 17 00:00:00 2001 From: johnthecoderpro <149151524+johnthecoderpro@users.noreply.github.com> Date: Sun, 5 Nov 2023 15:31:42 +0800 Subject: [PATCH 33/87] Fix download geo resources --- route/router_geo_resources.go | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/route/router_geo_resources.go b/route/router_geo_resources.go index 7abc5db5ed..523833dcff 100644 --- a/route/router_geo_resources.go +++ b/route/router_geo_resources.go @@ -157,12 +157,6 @@ func (r *Router) downloadGeoIPDatabase(savePath string) error { filemanager.MkdirAll(r.ctx, parentDir, 0o755) } - saveFile, err := filemanager.Create(r.ctx, savePath) - if err != nil { - return E.Cause(err, "open output file: ", downloadURL) - } - defer saveFile.Close() - httpClient := &http.Client{ Transport: &http.Transport{ ForceAttemptHTTP2: true, @@ -182,7 +176,16 @@ func (r *Router) downloadGeoIPDatabase(savePath string) error { return err } defer response.Body.Close() + + saveFile, err := filemanager.Create(r.ctx, savePath) + if err != nil { + return E.Cause(err, "open output file: ", downloadURL) + } _, err = io.Copy(saveFile, response.Body) + saveFile.Close() + if err != nil { + filemanager.Remove(r.ctx, savePath) + } return err } @@ -209,12 +212,6 @@ func (r *Router) downloadGeositeDatabase(savePath string) error { filemanager.MkdirAll(r.ctx, parentDir, 0o755) } - saveFile, err := filemanager.Create(r.ctx, savePath) - if err != nil { - return E.Cause(err, "open output file: ", downloadURL) - } - defer saveFile.Close() - httpClient := &http.Client{ Transport: &http.Transport{ ForceAttemptHTTP2: true, @@ -234,7 +231,16 @@ func (r *Router) downloadGeositeDatabase(savePath string) error { return err } defer response.Body.Close() + + saveFile, err := filemanager.Create(r.ctx, savePath) + if err != nil { + return E.Cause(err, "open output file: ", downloadURL) + } _, err = io.Copy(saveFile, response.Body) + saveFile.Close() + if err != nil { + filemanager.Remove(r.ctx, savePath) + } return err } From bb928f096ad15eba7e8df812587d64281b9703ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 5 Nov 2023 23:11:29 +0800 Subject: [PATCH 34/87] Fix missing default next proto in hysteria2 --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 0d5a73286c..53ef0f1655 100644 --- a/go.mod +++ b/go.mod @@ -26,10 +26,10 @@ require ( github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.2.16 + github.com/sagernet/sing v0.2.17 github.com/sagernet/sing-dns v0.1.10 github.com/sagernet/sing-mux v0.1.3 - github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6 + github.com/sagernet/sing-quic v0.1.3 github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 github.com/sagernet/sing-shadowtls v0.1.4 diff --git a/go.sum b/go.sum index 46fcc76e22..c5d7cfc236 100644 --- a/go.sum +++ b/go.sum @@ -110,14 +110,14 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.16 h1:InsjvUFKbgvqpWbHkvLHwplWJs1mu+FIn6yEVQrP9ZE= -github.com/sagernet/sing v0.2.16/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= +github.com/sagernet/sing v0.2.17 h1:vMPKb3MV0Aa5ws4dCJkRI8XEjrsUcDn810czd0FwmzI= +github.com/sagernet/sing v0.2.17/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlTZCI= github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0= -github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6 h1:w+TUbIZKZFSdf/AUa/y33kY9xaLeNGz/tBNcNhqpqfg= -github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6/go.mod h1:1M7xP4802K9Kz6BQ7LlA7UeCapWvWlH1Htmk2bAqkWc= +github.com/sagernet/sing-quic v0.1.3 h1:YfSPGQdlE6YspjPSlQJaVH333leFiYQM8JX7TumsWQs= +github.com/sagernet/sing-quic v0.1.3/go.mod h1:wvGU7MYih+cpJV2VrrpSGyjZIFSmUyqzawzmDyqeWJA= github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY= github.com/sagernet/sing-shadowsocks v0.2.5/go.mod h1:MGWGkcU2xW2G2mfArT9/QqpVLOGU+dBaahZCtPHdt7A= github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+MUhpQnAux728= From aaa67028637f8cd1055ac8ccc56b44d08dc4c546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 5 Nov 2023 23:23:49 +0800 Subject: [PATCH 35/87] Fix Host ignored in v2ray websocket transport --- transport/v2ray/transport.go | 2 +- transport/v2rayhttp/client.go | 2 +- transport/v2raywebsocket/client.go | 12 +++++++++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/transport/v2ray/transport.go b/transport/v2ray/transport.go index 3481c852c6..9dfee28119 100644 --- a/transport/v2ray/transport.go +++ b/transport/v2ray/transport.go @@ -50,7 +50,7 @@ func NewClientTransport(ctx context.Context, dialer N.Dialer, serverAddr M.Socks case C.V2RayTransportTypeGRPC: return NewGRPCClient(ctx, dialer, serverAddr, options.GRPCOptions, tlsConfig) case C.V2RayTransportTypeWebsocket: - return v2raywebsocket.NewClient(ctx, dialer, serverAddr, options.WebsocketOptions, tlsConfig), nil + return v2raywebsocket.NewClient(ctx, dialer, serverAddr, options.WebsocketOptions, tlsConfig) case C.V2RayTransportTypeQUIC: if tlsConfig == nil { return nil, C.ErrTLSRequired diff --git a/transport/v2rayhttp/client.go b/transport/v2rayhttp/client.go index d5e8a1f670..f280eeef55 100644 --- a/transport/v2rayhttp/client.go +++ b/transport/v2rayhttp/client.go @@ -81,7 +81,7 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt uri.Path = options.Path err := sHTTP.URLSetPath(&uri, options.Path) if err != nil { - return nil, E.New("failed to set path: " + err.Error()) + return nil, E.Cause(err, "parse path") } client.url = &uri return client, nil diff --git a/transport/v2raywebsocket/client.go b/transport/v2raywebsocket/client.go index 9f14f676e6..e7e857cae1 100644 --- a/transport/v2raywebsocket/client.go +++ b/transport/v2raywebsocket/client.go @@ -28,7 +28,7 @@ type Client struct { earlyDataHeaderName string } -func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayWebsocketOptions, tlsConfig tls.Config) adapter.V2RayClientTransport { +func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayWebsocketOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) { wsDialer := &websocket.Dialer{ ReadBufferSize: 4 * 1024, WriteBufferSize: 4 * 1024, @@ -68,11 +68,17 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt requestURL.Path = options.Path err := sHTTP.URLSetPath(&requestURL, options.Path) if err != nil { - return nil + return nil, E.Cause(err, "parse path") } headers := make(http.Header) for key, value := range options.Headers { headers[key] = value + if key == "Host" { + if len(value) > 1 { + return nil, E.New("multiple Host headers") + } + requestURL.Host = value[0] + } } return &Client{ wsDialer, @@ -81,7 +87,7 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt headers, options.MaxEarlyData, options.EarlyDataHeaderName, - } + }, nil } func (c *Client) DialContext(ctx context.Context) (net.Conn, error) { From d29f7475d200672c90b0118d612a8b04614329a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 5 Nov 2023 16:03:39 +0800 Subject: [PATCH 36/87] documentation: Bump version --- docs/changelog.md | 5 +++++ docs/installation/clients/sfa.md | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/changelog.md b/docs/changelog.md index b92ad87335..417ba4e8f7 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,8 @@ +#### 1.6.1 + +* Our [Android client](/installation/clients/sfa) is now available in the Google Play Store ▶️ +* Fixes and improvements + #### 1.6.0 * Fixes and improvements diff --git a/docs/installation/clients/sfa.md b/docs/installation/clients/sfa.md index e2709af53c..54b4f3e553 100644 --- a/docs/installation/clients/sfa.md +++ b/docs/installation/clients/sfa.md @@ -8,7 +8,7 @@ Experimental Android client for sing-box. #### Download -* [AppCenter](https://install.appcenter.ms/users/nekohasekai/apps/sfa/distribution_groups/publictest) +* [Play Store](https://play.google.com/store/apps/details?id=io.nekohasekai.sfa) * [Github Releases](https://github.com/SagerNet/sing-box/releases) #### Note From a20a0cb4557ae4dbdb0da6c6335ad44d5917772d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 30 Oct 2023 12:00:00 +0800 Subject: [PATCH 37/87] Add broadcast filter --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 53ef0f1655..52736c8df6 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 github.com/sagernet/sing-shadowtls v0.1.4 - github.com/sagernet/sing-tun v0.1.17 + github.com/sagernet/sing-tun v0.1.19 github.com/sagernet/sing-vmess v0.1.8 github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 diff --git a/go.sum b/go.sum index c5d7cfc236..bfc060d486 100644 --- a/go.sum +++ b/go.sum @@ -124,8 +124,8 @@ github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+M github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.17 h1:czy6lyXdH+ZqsOmMJufHwooPlOckMLamDIVGKbcEDTY= -github.com/sagernet/sing-tun v0.1.17/go.mod h1:dEhn+gztt87EJsJRzGKw6uWpu2DihQwJN/6F7WV6Z3M= +github.com/sagernet/sing-tun v0.1.19 h1:Xp69PWltr0Ga8GFhVusQEV4rx7XUMlqSV/FZnJcWF/k= +github.com/sagernet/sing-tun v0.1.19/go.mod h1:YA4MqRgYbO+igD07xt5WyRLjmwcXD5oRFy2itQbUVK0= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= From e05bf6308e823bf44823cbfe3b5f7a46147deb72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 6 Nov 2023 20:20:18 +0800 Subject: [PATCH 38/87] Fix build script --- Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Makefile b/Makefile index a2ecf2166a..e6a4913db4 100644 --- a/Makefile +++ b/Makefile @@ -152,10 +152,8 @@ update_apple_version: go run ./cmd/internal/update_apple_version release_apple: lib_ios update_apple_version release_ios release_macos release_tvos release_macos_independent - rm -rf dist release_apple_beta: update_apple_version release_ios release_macos release_tvos - rm -rf dist test: @go test -v ./... && \ From 8de0fad9f5ec914ea7c35e005b25e7333f4cc3c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 6 Nov 2023 20:02:00 +0800 Subject: [PATCH 39/87] documentation: Bump version --- docs/changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 417ba4e8f7..24273be53d 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,7 @@ +#### 1.6.2 + +* Fixes and improvements + #### 1.6.1 * Our [Android client](/installation/clients/sfa) is now available in the Google Play Store ▶️ From 0a06ccae50d66b6fda9a272d85773cc629a7fb51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 7 Nov 2023 22:14:15 +0800 Subject: [PATCH 40/87] platform: Fix legacy code --- experimental/libbox/http.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/experimental/libbox/http.go b/experimental/libbox/http.go index 982962a628..8dda751d5a 100644 --- a/experimental/libbox/http.go +++ b/experimental/libbox/http.go @@ -151,6 +151,9 @@ type httpRequest struct { func (r *httpRequest) SetURL(link string) (err error) { r.request.URL, err = url.Parse(link) + if err != nil { + return + } if r.request.URL.User != nil { user := r.request.URL.User.Username() password, _ := r.request.URL.User.Password() From 267d9617b7d1eab97400684bfed99bce3ba1caa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 7 Nov 2023 22:27:37 +0800 Subject: [PATCH 41/87] build: Fix tag calculate --- cmd/internal/build_shared/tag.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmd/internal/build_shared/tag.go b/cmd/internal/build_shared/tag.go index 8a5840ac2e..608b5877db 100644 --- a/cmd/internal/build_shared/tag.go +++ b/cmd/internal/build_shared/tag.go @@ -17,9 +17,6 @@ func ReadTag() (string, error) { } shortCommit, _ := shell.Exec("git", "rev-parse", "--short", "HEAD").ReadOutput() version := badversion.Parse(currentTagRev[1:]) - if version.PreReleaseIdentifier == "" { - version.Patch++ - } return version.String() + "-" + shortCommit, nil } From 6ae86eda9826b7c93521c520beeccb190e75a8ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 9 Nov 2023 14:34:19 +0800 Subject: [PATCH 42/87] build: Update gradle command --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index e6a4913db4..73b2d4acdb 100644 --- a/Makefile +++ b/Makefile @@ -73,21 +73,21 @@ update_android_version: go run ./cmd/internal/update_android_version build_android: - cd ../sing-box-for-android && ./gradlew :app:assembleRelease && ./gradlew --stop + cd ../sing-box-for-android && ./gradlew :app:assemblePlayRelease && ./gradlew --stop upload_android: mkdir -p dist/release_android - cp ../sing-box-for-android/app/build/outputs/apk/release/*.apk dist/release_android + cp ../sing-box-for-android/app/build/outputs/apk/play/release/*.apk dist/release_android ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release_android rm -rf dist/release_android release_android: lib_android update_android_version build_android upload_android publish_android: - cd ../sing-box-for-android && ./gradlew :app:publishReleaseBundle + cd ../sing-box-for-android && ./gradlew :app:publishPlayReleaseBundle publish_android_appcenter: - cd ../sing-box-for-android && ./gradlew :app:appCenterAssembleAndUploadRelease + cd ../sing-box-for-android && ./gradlew :app:appCenterAssembleAndUploadPlayRelease build_ios: cd ../sing-box-for-apple && \ From 63b8e8ed23a71275f331f24d6f6524115580b095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 9 Nov 2023 15:07:06 +0800 Subject: [PATCH 43/87] platform: Increase HTTP timeout to 15s --- experimental/libbox/http.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/experimental/libbox/http.go b/experimental/libbox/http.go index 8dda751d5a..87c5bed626 100644 --- a/experimental/libbox/http.go +++ b/experimental/libbox/http.go @@ -17,8 +17,8 @@ import ( "os" "strconv" "sync" + "time" - C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/bufio" E "github.com/sagernet/sing/common/exceptions" @@ -69,7 +69,7 @@ type httpClient struct { func NewHTTPClient() HTTPClient { client := new(httpClient) - client.client.Timeout = C.TCPTimeout + client.client.Timeout = 15 * time.Second client.client.Transport = &client.transport client.transport.TLSClientConfig = &client.tls client.transport.DisableKeepAlives = true From f6fee5367695778c8fb3cd4c522b9a415f425c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 9 Nov 2023 15:53:19 +0800 Subject: [PATCH 44/87] Fix mux client close --- go.mod | 8 ++++---- go.sum | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 52736c8df6..c588e2a6e2 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/sing v0.2.17 github.com/sagernet/sing-dns v0.1.10 - github.com/sagernet/sing-mux v0.1.3 + github.com/sagernet/sing-mux v0.1.4 github.com/sagernet/sing-quic v0.1.3 github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 @@ -44,8 +44,8 @@ require ( github.com/stretchr/testify v1.8.4 go.uber.org/zap v1.26.0 go4.org/netipx v0.0.0-20230824141953-6213f710f925 - golang.org/x/crypto v0.14.0 - golang.org/x/net v0.17.0 + golang.org/x/crypto v0.15.0 + golang.org/x/net v0.18.0 golang.org/x/sys v0.14.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 google.golang.org/grpc v1.59.0 @@ -86,7 +86,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/mod v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect diff --git a/go.sum b/go.sum index bfc060d486..35fc3d068f 100644 --- a/go.sum +++ b/go.sum @@ -114,8 +114,8 @@ github.com/sagernet/sing v0.2.17 h1:vMPKb3MV0Aa5ws4dCJkRI8XEjrsUcDn810czd0FwmzI= github.com/sagernet/sing v0.2.17/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlTZCI= github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= -github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= -github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0= +github.com/sagernet/sing-mux v0.1.4 h1:BPNPOQr6HkXG3iY/BrfvUKUl+A7gYsGKVSxvoR3PO50= +github.com/sagernet/sing-mux v0.1.4/go.mod h1:dKvcu/sb3fZ88uGv9vzAqUej6J4W+pHu5GqjRuFwAWs= github.com/sagernet/sing-quic v0.1.3 h1:YfSPGQdlE6YspjPSlQJaVH333leFiYQM8JX7TumsWQs= github.com/sagernet/sing-quic v0.1.3/go.mod h1:wvGU7MYih+cpJV2VrrpSGyjZIFSmUyqzawzmDyqeWJA= github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY= @@ -169,16 +169,16 @@ go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0Eq go4.org/netipx v0.0.0-20230824141953-6213f710f925/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -192,11 +192,11 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= 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.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From c2c3f7284f430154599f03220cd381181e0fc126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 9 Nov 2023 15:58:23 +0800 Subject: [PATCH 45/87] Revert "Fix Host ignored in v2ray websocket transport" This reverts commit aaa67028637f8cd1055ac8ccc56b44d08dc4c546. --- transport/v2ray/transport.go | 2 +- transport/v2rayhttp/client.go | 2 +- transport/v2raywebsocket/client.go | 12 +++--------- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/transport/v2ray/transport.go b/transport/v2ray/transport.go index 9dfee28119..3481c852c6 100644 --- a/transport/v2ray/transport.go +++ b/transport/v2ray/transport.go @@ -50,7 +50,7 @@ func NewClientTransport(ctx context.Context, dialer N.Dialer, serverAddr M.Socks case C.V2RayTransportTypeGRPC: return NewGRPCClient(ctx, dialer, serverAddr, options.GRPCOptions, tlsConfig) case C.V2RayTransportTypeWebsocket: - return v2raywebsocket.NewClient(ctx, dialer, serverAddr, options.WebsocketOptions, tlsConfig) + return v2raywebsocket.NewClient(ctx, dialer, serverAddr, options.WebsocketOptions, tlsConfig), nil case C.V2RayTransportTypeQUIC: if tlsConfig == nil { return nil, C.ErrTLSRequired diff --git a/transport/v2rayhttp/client.go b/transport/v2rayhttp/client.go index f280eeef55..d5e8a1f670 100644 --- a/transport/v2rayhttp/client.go +++ b/transport/v2rayhttp/client.go @@ -81,7 +81,7 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt uri.Path = options.Path err := sHTTP.URLSetPath(&uri, options.Path) if err != nil { - return nil, E.Cause(err, "parse path") + return nil, E.New("failed to set path: " + err.Error()) } client.url = &uri return client, nil diff --git a/transport/v2raywebsocket/client.go b/transport/v2raywebsocket/client.go index e7e857cae1..9f14f676e6 100644 --- a/transport/v2raywebsocket/client.go +++ b/transport/v2raywebsocket/client.go @@ -28,7 +28,7 @@ type Client struct { earlyDataHeaderName string } -func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayWebsocketOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) { +func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayWebsocketOptions, tlsConfig tls.Config) adapter.V2RayClientTransport { wsDialer := &websocket.Dialer{ ReadBufferSize: 4 * 1024, WriteBufferSize: 4 * 1024, @@ -68,17 +68,11 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt requestURL.Path = options.Path err := sHTTP.URLSetPath(&requestURL, options.Path) if err != nil { - return nil, E.Cause(err, "parse path") + return nil } headers := make(http.Header) for key, value := range options.Headers { headers[key] = value - if key == "Host" { - if len(value) > 1 { - return nil, E.New("multiple Host headers") - } - requestURL.Host = value[0] - } } return &Client{ wsDialer, @@ -87,7 +81,7 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt headers, options.MaxEarlyData, options.EarlyDataHeaderName, - }, nil + } } func (c *Client) DialContext(ctx context.Context) (net.Conn, error) { From 50036924e8078abb8d4840148c1e08b81a161084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 9 Nov 2023 15:56:45 +0800 Subject: [PATCH 46/87] documentation: Bump version --- docs/changelog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 24273be53d..2cd394b2d1 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,8 @@ +#### 1.6.3 + +* iOS/Android: Fix profile auto update +* Fixes and improvements + #### 1.6.2 * Fixes and improvements From bb7d03d1db68ddd73cf4669abdba2394b8fc0d7a Mon Sep 17 00:00:00 2001 From: Kumiko as a Service Date: Thu, 9 Nov 2023 21:36:32 -0500 Subject: [PATCH 47/87] Use golang's cross-compilation capabilities --- Dockerfile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8957450248..5b80ff6170 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,13 @@ -FROM golang:1.21-alpine AS builder +FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS builder LABEL maintainer="nekohasekai " COPY . /go/src/github.com/sagernet/sing-box WORKDIR /go/src/github.com/sagernet/sing-box +ARG TARGETOS TARGETARCH ARG GOPROXY="" ENV GOPROXY ${GOPROXY} ENV CGO_ENABLED=0 +ENV GOOS=$TARGETOS +ENV GOARCH=$TARGETARCH RUN set -ex \ && apk add git build-base \ && export COMMIT=$(git rev-parse --short HEAD) \ @@ -13,11 +16,11 @@ RUN set -ex \ -o /go/bin/sing-box \ -ldflags "-X \"github.com/sagernet/sing-box/constant.Version=$VERSION\" -s -w -buildid=" \ ./cmd/sing-box -FROM alpine AS dist +FROM --platform=$TARGETPLATFORM alpine AS dist LABEL maintainer="nekohasekai " RUN set -ex \ && apk upgrade \ && apk add bash tzdata ca-certificates \ && rm -rf /var/cache/apk/* COPY --from=builder /go/bin/sing-box /usr/local/bin/sing-box -ENTRYPOINT ["sing-box"] \ No newline at end of file +ENTRYPOINT ["sing-box"] From 2224c68959302d194838b518e53b90f2e1bc5cbd Mon Sep 17 00:00:00 2001 From: SakuraWald Date: Wed, 8 Nov 2023 17:26:50 +0800 Subject: [PATCH 48/87] Fix issue template --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 ++ .github/ISSUE_TEMPLATE/bug_report_zh.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 6133e7657e..ce6e37a279 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -46,6 +46,7 @@ body: description: If you are using the original command line program, please provide the output of the `sing-box version` command. value: |-
+ ```console # Replace this line with the output ``` @@ -71,6 +72,7 @@ body: For the Android client, please check the `/sdcard/Android/data/io.nekohasekai.sfa/files/stderr.log` file for crash logs. value: |-
+ ```console # Replace this line with logs ``` diff --git a/.github/ISSUE_TEMPLATE/bug_report_zh.yml b/.github/ISSUE_TEMPLATE/bug_report_zh.yml index 7c6c7c22bc..08f3a533f8 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_zh.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_zh.yml @@ -46,6 +46,7 @@ body: description: 如果您使用原始命令行程序,请提供 `sing-box version` 命令的输出。 value: |-
+ ```console # 使用输出内容覆盖此行 ``` @@ -71,6 +72,7 @@ body: 对于 Android 图形客户端程序,请检查 `/sdcard/Android/data/io.nekohasekai.sfa/files/stderr.log` 文件以导出崩溃日志。 value: |-
+ ```console # 使用日志内容覆盖此行 ``` From 3ef9b1b343883d97ef51bbfb8ebfea538eda4ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 10 Nov 2023 10:56:25 +0800 Subject: [PATCH 49/87] Update protobuf generated binary --- experimental/v2rayapi/stats_grpc.pb.go | 18 ++++++++++++------ transport/v2raygrpc/stream_grpc.pb.go | 6 +++++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/experimental/v2rayapi/stats_grpc.pb.go b/experimental/v2rayapi/stats_grpc.pb.go index de89f88e8c..ee95028747 100644 --- a/experimental/v2rayapi/stats_grpc.pb.go +++ b/experimental/v2rayapi/stats_grpc.pb.go @@ -13,6 +13,12 @@ import ( // Requires gRPC-Go v1.32.0 or later. const _ = grpc.SupportPackageIsVersion7 +const ( + StatsService_GetStats_FullMethodName = "/experimental.v2rayapi.StatsService/GetStats" + StatsService_QueryStats_FullMethodName = "/experimental.v2rayapi.StatsService/QueryStats" + StatsService_GetSysStats_FullMethodName = "/experimental.v2rayapi.StatsService/GetSysStats" +) + // StatsServiceClient is the client API for StatsService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. @@ -32,7 +38,7 @@ func NewStatsServiceClient(cc grpc.ClientConnInterface) StatsServiceClient { func (c *statsServiceClient) GetStats(ctx context.Context, in *GetStatsRequest, opts ...grpc.CallOption) (*GetStatsResponse, error) { out := new(GetStatsResponse) - err := c.cc.Invoke(ctx, "/experimental.v2rayapi.StatsService/GetStats", in, out, opts...) + err := c.cc.Invoke(ctx, StatsService_GetStats_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -41,7 +47,7 @@ func (c *statsServiceClient) GetStats(ctx context.Context, in *GetStatsRequest, func (c *statsServiceClient) QueryStats(ctx context.Context, in *QueryStatsRequest, opts ...grpc.CallOption) (*QueryStatsResponse, error) { out := new(QueryStatsResponse) - err := c.cc.Invoke(ctx, "/experimental.v2rayapi.StatsService/QueryStats", in, out, opts...) + err := c.cc.Invoke(ctx, StatsService_QueryStats_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -50,7 +56,7 @@ func (c *statsServiceClient) QueryStats(ctx context.Context, in *QueryStatsReque func (c *statsServiceClient) GetSysStats(ctx context.Context, in *SysStatsRequest, opts ...grpc.CallOption) (*SysStatsResponse, error) { out := new(SysStatsResponse) - err := c.cc.Invoke(ctx, "/experimental.v2rayapi.StatsService/GetSysStats", in, out, opts...) + err := c.cc.Invoke(ctx, StatsService_GetSysStats_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -104,7 +110,7 @@ func _StatsService_GetStats_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/experimental.v2rayapi.StatsService/GetStats", + FullMethod: StatsService_GetStats_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(StatsServiceServer).GetStats(ctx, req.(*GetStatsRequest)) @@ -122,7 +128,7 @@ func _StatsService_QueryStats_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/experimental.v2rayapi.StatsService/QueryStats", + FullMethod: StatsService_QueryStats_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(StatsServiceServer).QueryStats(ctx, req.(*QueryStatsRequest)) @@ -140,7 +146,7 @@ func _StatsService_GetSysStats_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/experimental.v2rayapi.StatsService/GetSysStats", + FullMethod: StatsService_GetSysStats_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(StatsServiceServer).GetSysStats(ctx, req.(*SysStatsRequest)) diff --git a/transport/v2raygrpc/stream_grpc.pb.go b/transport/v2raygrpc/stream_grpc.pb.go index 4403ca8d26..ea634849d4 100644 --- a/transport/v2raygrpc/stream_grpc.pb.go +++ b/transport/v2raygrpc/stream_grpc.pb.go @@ -13,6 +13,10 @@ import ( // Requires gRPC-Go v1.32.0 or later. const _ = grpc.SupportPackageIsVersion7 +const ( + GunService_Tun_FullMethodName = "/transport.v2raygrpc.GunService/Tun" +) + // GunServiceClient is the client API for GunService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. @@ -29,7 +33,7 @@ func NewGunServiceClient(cc grpc.ClientConnInterface) GunServiceClient { } func (c *gunServiceClient) Tun(ctx context.Context, opts ...grpc.CallOption) (GunService_TunClient, error) { - stream, err := c.cc.NewStream(ctx, &GunService_ServiceDesc.Streams[0], "/transport.v2raygrpc.GunService/Tun", opts...) + stream, err := c.cc.NewStream(ctx, &GunService_ServiceDesc.Streams[0], GunService_Tun_FullMethodName, opts...) if err != nil { return nil, err } From f7c2eb6e7646bf4741f98d995a428843baf78291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 13 Nov 2023 13:27:59 +0800 Subject: [PATCH 50/87] Fix v2ray ws crash --- transport/v2raywebsocket/conn.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/transport/v2raywebsocket/conn.go b/transport/v2raywebsocket/conn.go index 1faeaa36a7..6400b118d9 100644 --- a/transport/v2raywebsocket/conn.go +++ b/transport/v2raywebsocket/conn.go @@ -153,6 +153,9 @@ func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) { } c.access.Lock() defer c.access.Unlock() + if c.err != nil { + return 0, c.err + } if c.conn != nil { return c.conn.Write(b) } @@ -174,6 +177,9 @@ func (c *EarlyWebsocketConn) WriteBuffer(buffer *buf.Buffer) error { if c.conn != nil { return c.conn.WriteBuffer(buffer) } + if c.err != nil { + return c.err + } err := c.writeRequest(buffer.Bytes()) c.err = err close(c.create) From b013acd89d5949145d58826c18706a6799d0fd6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 13 Nov 2023 13:35:10 +0800 Subject: [PATCH 51/87] tun: Fix broadcast filter not applied to mixed stack --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c588e2a6e2..c2ab9be03b 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 github.com/sagernet/sing-shadowtls v0.1.4 - github.com/sagernet/sing-tun v0.1.19 + github.com/sagernet/sing-tun v0.1.20-0.20231113053348-91024284375c github.com/sagernet/sing-vmess v0.1.8 github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 diff --git a/go.sum b/go.sum index 35fc3d068f..5d70b8e8f8 100644 --- a/go.sum +++ b/go.sum @@ -124,8 +124,8 @@ github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+M github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.19 h1:Xp69PWltr0Ga8GFhVusQEV4rx7XUMlqSV/FZnJcWF/k= -github.com/sagernet/sing-tun v0.1.19/go.mod h1:YA4MqRgYbO+igD07xt5WyRLjmwcXD5oRFy2itQbUVK0= +github.com/sagernet/sing-tun v0.1.20-0.20231113053348-91024284375c h1:gb5/0Kb1Ha+LUkOVW/3dAqa0zmQBCkz8XREzMiGCCq0= +github.com/sagernet/sing-tun v0.1.20-0.20231113053348-91024284375c/go.mod h1:YA4MqRgYbO+igD07xt5WyRLjmwcXD5oRFy2itQbUVK0= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= From 6815f9418020322e8cd030399449929273cfda33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 13 Nov 2023 13:46:59 +0800 Subject: [PATCH 52/87] build: Update Go to 1.20.11 for legacy builds --- .goreleaser.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index c0703ee1b7..82eafe4559 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -58,8 +58,8 @@ builds: - with_clash_api env: - CGO_ENABLED=0 - - GOROOT=/nix/store/5h8gjl89zx8qxgc572wa3k81zplv8v4z-go-1.20.10/share/go - gobinary: /nix/store/5h8gjl89zx8qxgc572wa3k81zplv8v4z-go-1.20.10/bin/go + - GOROOT=/nix/store/kg6i737jjqs923jcijnm003h68c1dghj-go-1.20.11/share/go + gobinary: /nix/store/kg6i737jjqs923jcijnm003h68c1dghj-go-1.20.11/bin/go targets: - windows_amd64_v1 - windows_386 From e777b4c6dc3862625b1ea09814fa4f637d0e5358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 13 Nov 2023 13:53:52 +0800 Subject: [PATCH 53/87] Fix not closing outConn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mahdi-zarei Co-authored-by: 世界 --- outbound/default.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/outbound/default.go b/outbound/default.go index 79ed7b33b0..8067b6db5d 100644 --- a/outbound/default.go +++ b/outbound/default.go @@ -71,6 +71,7 @@ func NewConnection(ctx context.Context, this N.Dialer, conn net.Conn, metadata a } err = N.ReportHandshakeSuccess(conn) if err != nil { + outConn.Close() return err } return CopyEarlyConn(ctx, conn, outConn) @@ -97,6 +98,7 @@ func NewDirectConnection(ctx context.Context, router adapter.Router, this N.Dial } err = N.ReportHandshakeSuccess(conn) if err != nil { + outConn.Close() return err } return CopyEarlyConn(ctx, conn, outConn) @@ -117,6 +119,7 @@ func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn, } err = N.ReportHandshakeSuccess(conn) if err != nil { + outConn.Close() return err } if destinationAddress.IsValid() { @@ -160,6 +163,7 @@ func NewDirectPacketConnection(ctx context.Context, router adapter.Router, this } err = N.ReportHandshakeSuccess(conn) if err != nil { + outConn.Close() return err } if destinationAddress.IsValid() { @@ -188,6 +192,7 @@ func CopyEarlyConn(ctx context.Context, conn net.Conn, serverConn net.Conn) erro _, err := serverConn.Write(payload.Bytes()) payload.Release() if err != nil { + serverConn.Close() return err } return bufio.CopyConn(ctx, conn, serverConn) @@ -199,22 +204,26 @@ func CopyEarlyConn(ctx context.Context, conn net.Conn, serverConn net.Conn) erro if err != os.ErrInvalid { if err != nil { payload.Release() + serverConn.Close() return err } _, err = payload.ReadOnceFrom(conn) if err != nil && !E.IsTimeout(err) { payload.Release() + serverConn.Close() return E.Cause(err, "read payload") } err = conn.SetReadDeadline(time.Time{}) if err != nil { payload.Release() + serverConn.Close() return err } } _, err = serverConn.Write(payload.Bytes()) payload.Release() if err != nil { + serverConn.Close() return N.ReportHandshakeFailure(conn, err) } } From 71218ef0d30820d3220fde2f7e4528661f57a736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 13 Nov 2023 14:12:22 +0800 Subject: [PATCH 54/87] build: Unify build tags --- .goreleaser.yaml | 4 ++++ Dockerfile | 3 ++- Makefile | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 82eafe4559..d425db9136 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -19,6 +19,7 @@ builds: - with_ech - with_utls - with_reality_server + - with_acme - with_clash_api env: - CGO_ENABLED=0 @@ -55,6 +56,7 @@ builds: - with_ech - with_utls - with_reality_server + - with_acme - with_clash_api env: - CGO_ENABLED=0 @@ -83,6 +85,8 @@ builds: - with_wireguard - with_ech - with_utls + - with_reality_server + - with_acme - with_clash_api env: - CGO_ENABLED=1 diff --git a/Dockerfile b/Dockerfile index 5b80ff6170..52adff513c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,8 @@ RUN set -ex \ && apk add git build-base \ && export COMMIT=$(git rev-parse --short HEAD) \ && export VERSION=$(go run ./cmd/internal/read_tag) \ - && go build -v -trimpath -tags with_gvisor,with_quic,with_dhcp,with_wireguard,with_ech,with_utls,with_reality_server,with_clash_api,with_acme \ + && go build -v -trimpath -tags \ + "with_gvisor,with_quic,with_dhcp,with_wireguard,with_ech,with_utls,with_reality_server,with_acme,with_clash_api" \ -o /go/bin/sing-box \ -ldflags "-X \"github.com/sagernet/sing-box/constant.Version=$VERSION\" -s -w -buildid=" \ ./cmd/sing-box diff --git a/Makefile b/Makefile index 73b2d4acdb..f8efc9cc2d 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ COMMIT = $(shell git rev-parse --short HEAD) TAGS_GO118 = with_gvisor,with_dhcp,with_wireguard,with_utls,with_reality_server,with_clash_api TAGS_GO120 = with_quic,with_ech TAGS ?= $(TAGS_GO118),$(TAGS_GO120) -TAGS_TEST ?= with_gvisor,with_quic,with_wireguard,with_grpc,with_ech,with_utls,with_reality_server,with_shadowsocksr +TAGS_TEST ?= with_gvisor,with_quic,with_wireguard,with_grpc,with_ech,with_utls,with_reality_server GOHOSTOS = $(shell go env GOHOSTOS) GOHOSTARCH = $(shell go env GOHOSTARCH) From a3ef7a7d88cf11ef96149fe89c0c57e945becee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 13 Nov 2023 13:58:20 +0800 Subject: [PATCH 55/87] Fix trojan-go mux context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: maskedeken Co-authored-by: 世界 --- transport/trojan/mux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transport/trojan/mux.go b/transport/trojan/mux.go index 745cde569a..773240008d 100644 --- a/transport/trojan/mux.go +++ b/transport/trojan/mux.go @@ -17,7 +17,7 @@ func HandleMuxConnection(ctx context.Context, conn net.Conn, metadata M.Metadata return err } var group task.Group - group.Append0(func(ctx context.Context) error { + group.Append0(func(_ context.Context) error { var stream net.Conn for { stream, err = session.AcceptStream() From ce164724eacf3c4a3a1f650eefb2fd0d2da96d18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 13 Nov 2023 15:24:13 +0800 Subject: [PATCH 56/87] build: Add apk and archlinux package builds --- .goreleaser.yaml | 2 ++ Makefile | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index d425db9136..ffa3c4717e 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -157,6 +157,8 @@ nfpms: formats: - deb - rpm + - apk + - archlinux priority: extra contents: - src: release/config/config.json diff --git a/Makefile b/Makefile index f8efc9cc2d..ed41143df5 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ proto_install: release: go run ./cmd/internal/build goreleaser release --clean --skip-publish || exit 1 mkdir dist/release - mv dist/*.tar.gz dist/*.zip dist/*.deb dist/*.rpm dist/release + mv dist/*.tar.gz dist/*.zip dist/*.deb dist/*.rpm dist/*.apk dist/*.pkg.tar.zst dist/release ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release rm -r dist/release From 6635dd9abc519dde8117b0df55e338a07bdeec98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 13 Nov 2023 13:39:30 +0800 Subject: [PATCH 57/87] documentation: Bump version --- docs/changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 2cd394b2d1..f6eb21d97c 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,7 @@ +#### 1.6.4 + +* Fixes and improvements + #### 1.6.3 * iOS/Android: Fix profile auto update From 7a679bc328e16b12dbe0b6c731fb5acdc89b002f Mon Sep 17 00:00:00 2001 From: 0x7d274284 <112329548+0x7d274284@users.noreply.github.com> Date: Tue, 14 Nov 2023 10:34:38 +0800 Subject: [PATCH 58/87] Fix Dockerfile Keep the .git folder at compile time to get the correct version Signed-off-by: 0x7d274284 <112329548+0x7d274284@users.noreply.github.com> --- .github/workflows/docker.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 52046a497b..2d5eedbb51 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -39,6 +39,8 @@ jobs: with: platforms: linux/386,linux/amd64,linux/arm64,linux/s390x target: dist + build-args: | + BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 tags: | ${{ steps.tag.outputs.latest }} ${{ steps.tag.outputs.versioned }} From e21f84932cd9b83f18aab9b93693e5e413bfd880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 13 Nov 2023 22:58:53 +0800 Subject: [PATCH 59/87] build: Fix missing linux/386 --- .goreleaser.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index ffa3c4717e..0fb7f09045 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -24,6 +24,7 @@ builds: env: - CGO_ENABLED=0 targets: + - linux_386 - linux_amd64_v1 - linux_amd64_v3 - linux_arm64 From cbef1b1e593a68ec0f3443840c67ab77e1a385c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 14 Nov 2023 17:19:29 +0800 Subject: [PATCH 60/87] Remove apk build due to missing openrc configuration --- .goreleaser.yaml | 1 - Makefile | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 0fb7f09045..2fe2e27704 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -158,7 +158,6 @@ nfpms: formats: - deb - rpm - - apk - archlinux priority: extra contents: diff --git a/Makefile b/Makefile index ed41143df5..ed62162a28 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ proto_install: release: go run ./cmd/internal/build goreleaser release --clean --skip-publish || exit 1 mkdir dist/release - mv dist/*.tar.gz dist/*.zip dist/*.deb dist/*.rpm dist/*.apk dist/*.pkg.tar.zst dist/release + mv dist/*.tar.gz dist/*.zip dist/*.deb dist/*.rpm dist/*.pkg.tar.zst dist/release ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release rm -r dist/release From fe866b123ad7969f00fd8ab3483551a0b0dee2a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 14 Nov 2023 17:18:24 +0800 Subject: [PATCH 61/87] Fix sing-tun version --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c2ab9be03b..2acc40066a 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 github.com/sagernet/sing-shadowtls v0.1.4 - github.com/sagernet/sing-tun v0.1.20-0.20231113053348-91024284375c + github.com/sagernet/sing-tun v0.1.20-0.20231114091624-78e0dfa18fab github.com/sagernet/sing-vmess v0.1.8 github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 diff --git a/go.sum b/go.sum index 5d70b8e8f8..852e5fc94d 100644 --- a/go.sum +++ b/go.sum @@ -124,8 +124,8 @@ github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+M github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.20-0.20231113053348-91024284375c h1:gb5/0Kb1Ha+LUkOVW/3dAqa0zmQBCkz8XREzMiGCCq0= -github.com/sagernet/sing-tun v0.1.20-0.20231113053348-91024284375c/go.mod h1:YA4MqRgYbO+igD07xt5WyRLjmwcXD5oRFy2itQbUVK0= +github.com/sagernet/sing-tun v0.1.20-0.20231114091624-78e0dfa18fab h1:WTM++II47WUmMgOXMCTUo3E5083I4oII4wd8/Gnsbds= +github.com/sagernet/sing-tun v0.1.20-0.20231114091624-78e0dfa18fab/go.mod h1:YA4MqRgYbO+igD07xt5WyRLjmwcXD5oRFy2itQbUVK0= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= From 2c6967d7f9e2ecf85ea3ed6ea024fe1e81293ee0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Nov 2023 19:16:02 +0800 Subject: [PATCH 62/87] dependencies: Update actions/checkout digest to b4ffde6 Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/debug.yml | 8 ++++---- .github/workflows/docker.yml | 2 +- .github/workflows/lint.yml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml index 20dd4ca68f..def969a360 100644 --- a/.github/workflows/debug.yml +++ b/.github/workflows/debug.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 with: fetch-depth: 0 - name: Get latest go version @@ -50,7 +50,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 with: fetch-depth: 0 - name: Setup Go @@ -70,7 +70,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 with: fetch-depth: 0 - name: Setup Go @@ -201,7 +201,7 @@ jobs: TAGS: with_clash_api,with_quic steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 with: fetch-depth: 0 - name: Get latest go version diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 2d5eedbb51..a106e593a5 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 - name: Setup Docker Buildx uses: docker/setup-buildx-action@v3 - name: Setup QEMU for Docker Buildx diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 05b36a1e14..2ab5b5e569 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 with: fetch-depth: 0 - name: Get latest go version From 3cadc9037577aa78724f53ec4916485c3feb52b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 14 Nov 2023 20:13:01 +0800 Subject: [PATCH 63/87] Fix TUIC authentication failed error message --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2acc40066a..709d012401 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/sagernet/sing v0.2.17 github.com/sagernet/sing-dns v0.1.10 github.com/sagernet/sing-mux v0.1.4 - github.com/sagernet/sing-quic v0.1.3 + github.com/sagernet/sing-quic v0.1.4-0.20231111111624-370e6abf6769 github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 github.com/sagernet/sing-shadowtls v0.1.4 diff --git a/go.sum b/go.sum index 852e5fc94d..0906f9fc2d 100644 --- a/go.sum +++ b/go.sum @@ -116,8 +116,8 @@ github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlT github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= github.com/sagernet/sing-mux v0.1.4 h1:BPNPOQr6HkXG3iY/BrfvUKUl+A7gYsGKVSxvoR3PO50= github.com/sagernet/sing-mux v0.1.4/go.mod h1:dKvcu/sb3fZ88uGv9vzAqUej6J4W+pHu5GqjRuFwAWs= -github.com/sagernet/sing-quic v0.1.3 h1:YfSPGQdlE6YspjPSlQJaVH333leFiYQM8JX7TumsWQs= -github.com/sagernet/sing-quic v0.1.3/go.mod h1:wvGU7MYih+cpJV2VrrpSGyjZIFSmUyqzawzmDyqeWJA= +github.com/sagernet/sing-quic v0.1.4-0.20231111111624-370e6abf6769 h1:V84NPJKirL/oDkvUh9Dor2gMZ+TTNHK3jcedqRkgcQA= +github.com/sagernet/sing-quic v0.1.4-0.20231111111624-370e6abf6769/go.mod h1:iggBfFE2ojS2yYQU8Hnrkm029RsHPdYYIKWqeCI64HE= github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY= github.com/sagernet/sing-shadowsocks v0.2.5/go.mod h1:MGWGkcU2xW2G2mfArT9/QqpVLOGU+dBaahZCtPHdt7A= github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+MUhpQnAux728= From 1825869124b4822eee2a029b7409d0a87d7c5a27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 15 Nov 2023 13:05:33 +0800 Subject: [PATCH 64/87] platform: Refactor log interface --- box.go | 3 ++- experimental/libbox/platform/interface.go | 2 -- experimental/libbox/service.go | 24 ++++++++++++++++------- log/default.go | 6 +++--- log/log.go | 2 +- log/observable.go | 11 ++++++----- log/platform.go | 6 ++++++ 7 files changed, 35 insertions(+), 19 deletions(-) create mode 100644 log/platform.go diff --git a/box.go b/box.go index 0a66c88c3a..b8a0fad160 100644 --- a/box.go +++ b/box.go @@ -41,6 +41,7 @@ type Options struct { option.Options Context context.Context PlatformInterface platform.Interface + PlatformLogWriter log.PlatformWriter } func New(options Options) (*Box, error) { @@ -71,7 +72,7 @@ func New(options Options) (*Box, error) { Observable: needClashAPI, DefaultWriter: defaultLogWriter, BaseTime: createdAt, - PlatformWriter: options.PlatformInterface, + PlatformWriter: options.PlatformLogWriter, }) if err != nil { return nil, E.Cause(err, "create log factory") diff --git a/experimental/libbox/platform/interface.go b/experimental/libbox/platform/interface.go index 77afa17b53..8c47197186 100644 --- a/experimental/libbox/platform/interface.go +++ b/experimental/libbox/platform/interface.go @@ -2,7 +2,6 @@ package platform import ( "context" - "io" "net/netip" "github.com/sagernet/sing-box/adapter" @@ -25,7 +24,6 @@ type Interface interface { UnderNetworkExtension() bool ClearDNSCache() process.Searcher - io.Writer } type NetworkInterface struct { diff --git a/experimental/libbox/service.go b/experimental/libbox/service.go index c8fef13e1d..67b57d7da5 100644 --- a/experimental/libbox/service.go +++ b/experimental/libbox/service.go @@ -3,6 +3,7 @@ package libbox import ( "context" "net/netip" + "runtime" runtimeDebug "runtime/debug" "syscall" @@ -12,6 +13,7 @@ import ( "github.com/sagernet/sing-box/common/urltest" "github.com/sagernet/sing-box/experimental/libbox/internal/procfs" "github.com/sagernet/sing-box/experimental/libbox/platform" + "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-tun" "github.com/sagernet/sing/common" @@ -44,10 +46,12 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage) pauseManager := pause.NewDefaultManager(ctx) ctx = pause.ContextWithManager(ctx, pauseManager) + platformWrapper := &platformInterfaceWrapper{iif: platformInterface, useProcFS: platformInterface.UseProcFS()} instance, err := box.New(box.Options{ Context: ctx, Options: options, - PlatformInterface: &platformInterfaceWrapper{iif: platformInterface, useProcFS: platformInterface.UseProcFS()}, + PlatformInterface: platformWrapper, + PlatformLogWriter: platformWrapper, }) if err != nil { cancel() @@ -83,7 +87,10 @@ func (s *BoxService) Wake() { _ = s.instance.Router().ResetNetwork() } -var _ platform.Interface = (*platformInterfaceWrapper)(nil) +var ( + _ platform.Interface = (*platformInterfaceWrapper)(nil) + _ log.PlatformWriter = (*platformInterfaceWrapper)(nil) +) type platformInterfaceWrapper struct { iif PlatformInterface @@ -131,11 +138,6 @@ func (w *platformInterfaceWrapper) OpenTun(options *tun.Options, platformOptions return tun.New(*options) } -func (w *platformInterfaceWrapper) Write(p []byte) (n int, err error) { - w.iif.WriteLog(string(p)) - return len(p), nil -} - func (w *platformInterfaceWrapper) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*process.Info, error) { var uid int32 if w.useProcFS { @@ -203,3 +205,11 @@ func (w *platformInterfaceWrapper) UnderNetworkExtension() bool { func (w *platformInterfaceWrapper) ClearDNSCache() { w.iif.ClearDNSCache() } + +func (w *platformInterfaceWrapper) DisableColors() bool { + return runtime.GOOS != "android" +} + +func (w *platformInterfaceWrapper) WriteMessage(level log.Level, message string) { + w.iif.WriteLog(message) +} diff --git a/log/default.go b/log/default.go index e355464797..c2e1c7452e 100644 --- a/log/default.go +++ b/log/default.go @@ -16,11 +16,11 @@ type simpleFactory struct { formatter Formatter platformFormatter Formatter writer io.Writer - platformWriter io.Writer + platformWriter PlatformWriter level Level } -func NewFactory(formatter Formatter, writer io.Writer, platformWriter io.Writer) Factory { +func NewFactory(formatter Formatter, writer io.Writer, platformWriter PlatformWriter) Factory { return &simpleFactory{ formatter: formatter, platformFormatter: Formatter{ @@ -76,7 +76,7 @@ func (l *simpleLogger) Log(ctx context.Context, level Level, args []any) { os.Exit(1) } if l.platformWriter != nil { - l.platformWriter.Write([]byte(l.platformFormatter.Format(ctx, level, l.tag, F.ToString(args...), nowTime))) + l.platformWriter.WriteMessage(level, l.platformFormatter.Format(ctx, level, l.tag, F.ToString(args...), nowTime)) } } diff --git a/log/log.go b/log/log.go index b6b0805c9d..19dbbbd912 100644 --- a/log/log.go +++ b/log/log.go @@ -42,7 +42,7 @@ type Options struct { Observable bool DefaultWriter io.Writer BaseTime time.Time - PlatformWriter io.Writer + PlatformWriter PlatformWriter } func New(options Options) (Factory, error) { diff --git a/log/observable.go b/log/observable.go index 83d9cf9c62..c12cbbbe24 100644 --- a/log/observable.go +++ b/log/observable.go @@ -6,7 +6,6 @@ import ( "os" "time" - C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing/common" F "github.com/sagernet/sing/common/format" "github.com/sagernet/sing/common/observable" @@ -18,18 +17,17 @@ type observableFactory struct { formatter Formatter platformFormatter Formatter writer io.Writer - platformWriter io.Writer + platformWriter PlatformWriter level Level subscriber *observable.Subscriber[Entry] observer *observable.Observer[Entry] } -func NewObservableFactory(formatter Formatter, writer io.Writer, platformWriter io.Writer) ObservableFactory { +func NewObservableFactory(formatter Formatter, writer io.Writer, platformWriter PlatformWriter) ObservableFactory { factory := &observableFactory{ formatter: formatter, platformFormatter: Formatter{ BaseTime: formatter.BaseTime, - DisableColors: C.IsDarwin || C.IsIos, DisableLineBreak: true, }, writer: writer, @@ -37,6 +35,9 @@ func NewObservableFactory(formatter Formatter, writer io.Writer, platformWriter level: LevelTrace, subscriber: observable.NewSubscriber[Entry](128), } + if platformWriter != nil { + factory.platformFormatter.DisableColors = platformWriter.DisableColors() + } factory.observer = observable.NewObserver[Entry](factory.subscriber, 64) return factory } @@ -94,7 +95,7 @@ func (l *observableLogger) Log(ctx context.Context, level Level, args []any) { } l.subscriber.Emit(Entry{level, messageSimple}) if l.platformWriter != nil { - l.platformWriter.Write([]byte(l.platformFormatter.Format(ctx, level, l.tag, F.ToString(args...), nowTime))) + l.platformWriter.WriteMessage(level, l.platformFormatter.Format(ctx, level, l.tag, F.ToString(args...), nowTime)) } } diff --git a/log/platform.go b/log/platform.go new file mode 100644 index 0000000000..c6a9e525a1 --- /dev/null +++ b/log/platform.go @@ -0,0 +1,6 @@ +package log + +type PlatformWriter interface { + DisableColors() bool + WriteMessage(level Level, message string) +} From 36dff630d683ca78f59efcf8bc24ccfbe2df4e85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 14 Nov 2023 20:14:01 +0800 Subject: [PATCH 65/87] documentation: Bump version --- docs/changelog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index f6eb21d97c..cb2316f9f2 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,8 @@ +#### 1.6.5 + +* Fix crash if TUIC inbound authentication failed +* Fixes and improvements + #### 1.6.4 * Fixes and improvements From 005d6cf4cf32b7821800237dce107a8d61fc0af6 Mon Sep 17 00:00:00 2001 From: guangwu Date: Thu, 16 Nov 2023 01:10:52 +0800 Subject: [PATCH 66/87] chore: unnecessary use of fmt.Sprintf --- experimental/clashapi/proxies.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/experimental/clashapi/proxies.go b/experimental/clashapi/proxies.go index f312481c49..050efd8d17 100644 --- a/experimental/clashapi/proxies.go +++ b/experimental/clashapi/proxies.go @@ -2,7 +2,6 @@ package clashapi import ( "context" - "fmt" "net/http" "sort" "strconv" @@ -176,7 +175,7 @@ func updateProxy(w http.ResponseWriter, r *http.Request) { if !selector.SelectOutbound(req.Name) { render.Status(r, http.StatusBadRequest) - render.JSON(w, r, newError(fmt.Sprintf("Selector update error: not found"))) + render.JSON(w, r, newError("Selector update error: not found")) return } From 3a2808cff6fd672bd9d308ff5374176715afe360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AB=A6=E6=82=85?= Date: Thu, 16 Nov 2023 01:11:28 +0800 Subject: [PATCH 67/87] documentation: Fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The old meaning is wrong. Correct the meaning according to the English documentation and the actual effect of the option. Signed-off-by: 嫦悅 --- docs/configuration/route/index.zh.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/configuration/route/index.zh.md b/docs/configuration/route/index.zh.md index c05bb2e14a..c3ef2e54cf 100644 --- a/docs/configuration/route/index.zh.md +++ b/docs/configuration/route/index.zh.md @@ -28,7 +28,7 @@ #### final -默认出站标签。如果未空,将使用第一个可用于对应协议的出站。 +默认出站标签。如果为空,将使用第一个可用于对应协议的出站。 #### auto_detect_interface @@ -66,4 +66,4 @@ 默认为出站连接设置路由标记。 -如果设置了 `outbound.routing_mark` 设置,则不生效。 \ No newline at end of file +如果设置了 `outbound.routing_mark` 设置,则不生效。 From 7c49196792e2000146c9b97885e669e43fbb300c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 15 Nov 2023 13:05:33 +0800 Subject: [PATCH 68/87] build: Fix bad environment key --- cmd/internal/build/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/internal/build/main.go b/cmd/internal/build/main.go index c7a64bb80d..cae67ba41c 100644 --- a/cmd/internal/build/main.go +++ b/cmd/internal/build/main.go @@ -12,7 +12,7 @@ import ( func main() { build_shared.FindSDK() - if os.Getenv("build.Default.GOPATH") == "" { + if os.Getenv("GOPATH") == "" { os.Setenv("GOPATH", build.Default.GOPATH) } From 240abe204c145b1c3313b4a7c132ea75fefc8576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 16 Nov 2023 18:13:34 +0800 Subject: [PATCH 69/87] Fix zero TTL was incorrectly reset --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 709d012401..998aa98642 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/sing v0.2.17 - github.com/sagernet/sing-dns v0.1.10 + github.com/sagernet/sing-dns v0.1.11-0.20231116102430-5a2133f5d358 github.com/sagernet/sing-mux v0.1.4 github.com/sagernet/sing-quic v0.1.4-0.20231111111624-370e6abf6769 github.com/sagernet/sing-shadowsocks v0.2.5 diff --git a/go.sum b/go.sum index 0906f9fc2d..68981503c8 100644 --- a/go.sum +++ b/go.sum @@ -112,8 +112,8 @@ github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2 github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= github.com/sagernet/sing v0.2.17 h1:vMPKb3MV0Aa5ws4dCJkRI8XEjrsUcDn810czd0FwmzI= github.com/sagernet/sing v0.2.17/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= -github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlTZCI= -github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= +github.com/sagernet/sing-dns v0.1.11-0.20231116102430-5a2133f5d358 h1:psJQg/KXVQTupFFR1liaCAucW+NwCDhe1oYfkmz8EJ8= +github.com/sagernet/sing-dns v0.1.11-0.20231116102430-5a2133f5d358/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= github.com/sagernet/sing-mux v0.1.4 h1:BPNPOQr6HkXG3iY/BrfvUKUl+A7gYsGKVSxvoR3PO50= github.com/sagernet/sing-mux v0.1.4/go.mod h1:dKvcu/sb3fZ88uGv9vzAqUej6J4W+pHu5GqjRuFwAWs= github.com/sagernet/sing-quic v0.1.4-0.20231111111624-370e6abf6769 h1:V84NPJKirL/oDkvUh9Dor2gMZ+TTNHK3jcedqRkgcQA= From 72a81afb761622729f1faa299bbc2f7cf9499063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 16 Nov 2023 18:21:55 +0800 Subject: [PATCH 70/87] Fix "Fix Linux IPv6 auto route rules" --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 998aa98642..dd5000ece4 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 github.com/sagernet/sing-shadowtls v0.1.4 - github.com/sagernet/sing-tun v0.1.20-0.20231114091624-78e0dfa18fab + github.com/sagernet/sing-tun v0.1.20-0.20231116102114-958d6a25a41d github.com/sagernet/sing-vmess v0.1.8 github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 diff --git a/go.sum b/go.sum index 68981503c8..d973e70b0e 100644 --- a/go.sum +++ b/go.sum @@ -124,8 +124,8 @@ github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+M github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.20-0.20231114091624-78e0dfa18fab h1:WTM++II47WUmMgOXMCTUo3E5083I4oII4wd8/Gnsbds= -github.com/sagernet/sing-tun v0.1.20-0.20231114091624-78e0dfa18fab/go.mod h1:YA4MqRgYbO+igD07xt5WyRLjmwcXD5oRFy2itQbUVK0= +github.com/sagernet/sing-tun v0.1.20-0.20231116102114-958d6a25a41d h1:c0M01hMieuYwOMk+xzgudn0jNjPLUR15I/QnXk0eLkc= +github.com/sagernet/sing-tun v0.1.20-0.20231116102114-958d6a25a41d/go.mod h1:6kkPL/u9tWcLFfu55VbwMDnO++17cUihSmImkZjdZro= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= From 6a2bfd26d0826a5a1dbfb4a1f0e5f39cff36547a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 16 Nov 2023 22:47:20 +0800 Subject: [PATCH 71/87] Fix QUIC sniffer --- common/sniff/quic.go | 67 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/common/sniff/quic.go b/common/sniff/quic.go index c18e09a0e1..55dc1c0023 100644 --- a/common/sniff/quic.go +++ b/common/sniff/quic.go @@ -182,11 +182,52 @@ func QUICClientHello(ctx context.Context, packet []byte) (*adapter.InboundContex break } switch frameType { - case 0x0: + case 0x00: // PADDING continue - case 0x1: + case 0x01: // PING continue - case 0x6: + case 0x02, 0x03: // ACK + _, err = qtls.ReadUvarint(decryptedReader) // Largest Acknowledged + if err != nil { + return nil, err + } + _, err = qtls.ReadUvarint(decryptedReader) // ACK Delay + if err != nil { + return nil, err + } + ackRangeCount, err := qtls.ReadUvarint(decryptedReader) // ACK Range Count + if err != nil { + return nil, err + } + _, err = qtls.ReadUvarint(decryptedReader) // First ACK Range + if err != nil { + return nil, err + } + for i := 0; i < int(ackRangeCount); i++ { + _, err = qtls.ReadUvarint(decryptedReader) // Gap + if err != nil { + return nil, err + } + _, err = qtls.ReadUvarint(decryptedReader) // ACK Range Length + if err != nil { + return nil, err + } + } + if frameType == 0x03 { + _, err = qtls.ReadUvarint(decryptedReader) // ECT0 Count + if err != nil { + return nil, err + } + _, err = qtls.ReadUvarint(decryptedReader) // ECT1 Count + if err != nil { + return nil, err + } + _, err = qtls.ReadUvarint(decryptedReader) // ECN-CE Count + if err != nil { + return nil, err + } + } + case 0x06: // CRYPTO var offset uint64 offset, err = qtls.ReadUvarint(decryptedReader) if err != nil { @@ -208,8 +249,26 @@ func QUICClientHello(ctx context.Context, packet []byte) (*adapter.InboundContex if err != nil { return nil, err } + case 0x1c: // CONNECTION_CLOSE + _, err = qtls.ReadUvarint(decryptedReader) // Error Code + if err != nil { + return nil, err + } + _, err = qtls.ReadUvarint(decryptedReader) // Frame Type + if err != nil { + return nil, err + } + var length uint64 + length, err = qtls.ReadUvarint(decryptedReader) // Reason Phrase Length + if err != nil { + return nil, err + } + _, err = decryptedReader.Seek(int64(length), io.SeekCurrent) // Reason Phrase + if err != nil { + return nil, err + } default: - // ignore unknown frame type + return nil, os.ErrInvalid } } tlsHdr := make([]byte, 5) From 925214869b9715efb435cb0eac17754551011984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 19 Nov 2023 12:17:06 +0800 Subject: [PATCH 72/87] Add test for ss2022 EIH --- test/shadowsocks_test.go | 78 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/test/shadowsocks_test.go b/test/shadowsocks_test.go index 07b324d214..f3fc61d1e8 100644 --- a/test/shadowsocks_test.go +++ b/test/shadowsocks_test.go @@ -74,6 +74,23 @@ func TestShadowsocks2022(t *testing.T) { } } +func TestShadowsocks2022EIH(t *testing.T) { + for _, method16 := range []string{ + "2022-blake3-aes-128-gcm", + } { + t.Run(method16, func(t *testing.T) { + testShadowsocks2022EIH(t, method16, mkBase64(t, 16)) + }) + } + for _, method32 := range []string{ + "2022-blake3-aes-256-gcm", + } { + t.Run(method32, func(t *testing.T) { + testShadowsocks2022EIH(t, method32, mkBase64(t, 32)) + }) + } +} + func testShadowsocksInboundWithShadowsocksRust(t *testing.T, method string, password string) { startDockerContainer(t, DockerOptions{ Image: ImageShadowsocksRustClient, @@ -252,6 +269,67 @@ func TestShadowsocksUoT(t *testing.T) { testSuit(t, clientPort, testPort) } +func testShadowsocks2022EIH(t *testing.T, method string, password string) { + startInstance(t, option.Options{ + Inbounds: []option.Inbound{ + { + Type: C.TypeMixed, + Tag: "mixed-in", + MixedOptions: option.HTTPMixedInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.NewListenAddress(netip.IPv4Unspecified()), + ListenPort: clientPort, + }, + }, + }, + { + Type: C.TypeShadowsocks, + ShadowsocksOptions: option.ShadowsocksInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.NewListenAddress(netip.IPv4Unspecified()), + ListenPort: serverPort, + }, + Method: method, + Password: password, + Users: []option.ShadowsocksUser{ + { + Password: password, + }, + }, + }, + }, + }, + Outbounds: []option.Outbound{ + { + Type: C.TypeDirect, + }, + { + Type: C.TypeShadowsocks, + Tag: "ss-out", + ShadowsocksOptions: option.ShadowsocksOutboundOptions{ + ServerOptions: option.ServerOptions{ + Server: "127.0.0.1", + ServerPort: serverPort, + }, + Method: method, + Password: password + ":" + password, + }, + }, + }, + Route: &option.RouteOptions{ + Rules: []option.Rule{ + { + DefaultOptions: option.DefaultRule{ + Inbound: []string{"mixed-in"}, + Outbound: "ss-out", + }, + }, + }, + }, + }) + testSuit(t, clientPort, testPort) +} + func mkBase64(t *testing.T, length int) string { psk := make([]byte, length) _, err := rand.Read(psk) From eaccc9759a16b69e14f5e95ed7388f6475ca0970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 20 Nov 2023 23:41:10 +0800 Subject: [PATCH 73/87] Fix platform API check --- box.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/box.go b/box.go index b8a0fad160..c10222ddf7 100644 --- a/box.go +++ b/box.go @@ -56,7 +56,7 @@ func New(options Options) (*Box, error) { applyDebugOptions(common.PtrValueOrDefault(experimentalOptions.Debug)) var needClashAPI bool var needV2RayAPI bool - if experimentalOptions.ClashAPI != nil || options.PlatformInterface != nil { + if experimentalOptions.ClashAPI != nil || options.PlatformLogWriter != nil { needClashAPI = true } if experimentalOptions.V2RayAPI != nil && experimentalOptions.V2RayAPI.Listen != "" { From 50c129056745ee069129c4f8c0da36562867e8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 20 Nov 2023 18:44:00 +0800 Subject: [PATCH 74/87] Update dependencies --- go.mod | 16 +++++++-------- go.sum | 34 ++++++++++++++++---------------- test/go.mod | 26 ++++++++++++------------- test/go.sum | 56 ++++++++++++++++++++++++++--------------------------- 4 files changed, 66 insertions(+), 66 deletions(-) diff --git a/go.mod b/go.mod index dd5000ece4..9b5d4e9d9b 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/libdns/cloudflare v0.1.0 github.com/logrusorgru/aurora v2.0.3+incompatible github.com/mholt/acmez v1.2.0 - github.com/miekg/dns v1.1.56 + github.com/miekg/dns v1.1.57 github.com/ooni/go-libtor v1.1.8 github.com/oschwald/maxminddb-golang v1.12.0 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a @@ -27,13 +27,13 @@ require ( github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/sing v0.2.17 - github.com/sagernet/sing-dns v0.1.11-0.20231116102430-5a2133f5d358 + github.com/sagernet/sing-dns v0.1.11 github.com/sagernet/sing-mux v0.1.4 - github.com/sagernet/sing-quic v0.1.4-0.20231111111624-370e6abf6769 + github.com/sagernet/sing-quic v0.1.4 github.com/sagernet/sing-shadowsocks v0.2.5 - github.com/sagernet/sing-shadowsocks2 v0.1.4 + github.com/sagernet/sing-shadowsocks2 v0.1.5 github.com/sagernet/sing-shadowtls v0.1.4 - github.com/sagernet/sing-tun v0.1.20-0.20231116102114-958d6a25a41d + github.com/sagernet/sing-tun v0.1.20 github.com/sagernet/sing-vmess v0.1.8 github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 @@ -84,11 +84,11 @@ require ( github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/zeebo/blake3 v0.2.3 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/mod v0.13.0 // indirect + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/mod v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.14.0 // indirect + golang.org/x/tools v0.15.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index d973e70b0e..bebf5f1958 100644 --- a/go.sum +++ b/go.sum @@ -72,8 +72,8 @@ github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczG github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= -github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= -github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= +github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= +github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= @@ -112,20 +112,20 @@ github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2 github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= github.com/sagernet/sing v0.2.17 h1:vMPKb3MV0Aa5ws4dCJkRI8XEjrsUcDn810czd0FwmzI= github.com/sagernet/sing v0.2.17/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= -github.com/sagernet/sing-dns v0.1.11-0.20231116102430-5a2133f5d358 h1:psJQg/KXVQTupFFR1liaCAucW+NwCDhe1oYfkmz8EJ8= -github.com/sagernet/sing-dns v0.1.11-0.20231116102430-5a2133f5d358/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= +github.com/sagernet/sing-dns v0.1.11 h1:PPrMCVVrAeR3f5X23I+cmvacXJ+kzuyAsBiWyUKhGSE= +github.com/sagernet/sing-dns v0.1.11/go.mod h1:zJ/YjnYB61SYE+ubMcMqVdpaSvsyQ2iShQGO3vuLvvE= github.com/sagernet/sing-mux v0.1.4 h1:BPNPOQr6HkXG3iY/BrfvUKUl+A7gYsGKVSxvoR3PO50= github.com/sagernet/sing-mux v0.1.4/go.mod h1:dKvcu/sb3fZ88uGv9vzAqUej6J4W+pHu5GqjRuFwAWs= -github.com/sagernet/sing-quic v0.1.4-0.20231111111624-370e6abf6769 h1:V84NPJKirL/oDkvUh9Dor2gMZ+TTNHK3jcedqRkgcQA= -github.com/sagernet/sing-quic v0.1.4-0.20231111111624-370e6abf6769/go.mod h1:iggBfFE2ojS2yYQU8Hnrkm029RsHPdYYIKWqeCI64HE= +github.com/sagernet/sing-quic v0.1.4 h1:F5KRGXMXKQEmP8VrzVollf9HWcRqggcuG9nRCL+5IJ8= +github.com/sagernet/sing-quic v0.1.4/go.mod h1:aXHVP+osF3w5wJzoWZbJSrX3ceJiU9QMd0KPnKV6C/o= github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY= github.com/sagernet/sing-shadowsocks v0.2.5/go.mod h1:MGWGkcU2xW2G2mfArT9/QqpVLOGU+dBaahZCtPHdt7A= -github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+MUhpQnAux728= -github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc= +github.com/sagernet/sing-shadowsocks2 v0.1.5 h1:JDeAJ4ZWlYZ7F6qEVdDKPhQEangxKw/JtmU+i/YfCYE= +github.com/sagernet/sing-shadowsocks2 v0.1.5/go.mod h1:KF65y8lI5PGHyMgRZGYXYsH9ilgRc/yr+NYbSNGuBm4= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.20-0.20231116102114-958d6a25a41d h1:c0M01hMieuYwOMk+xzgudn0jNjPLUR15I/QnXk0eLkc= -github.com/sagernet/sing-tun v0.1.20-0.20231116102114-958d6a25a41d/go.mod h1:6kkPL/u9tWcLFfu55VbwMDnO++17cUihSmImkZjdZro= +github.com/sagernet/sing-tun v0.1.20 h1:vYWo/w6fkKc8I1WP/IB8eBWZVsGIC6eoEoNR6XqEDlY= +github.com/sagernet/sing-tun v0.1.20/go.mod h1:6kkPL/u9tWcLFfu55VbwMDnO++17cUihSmImkZjdZro= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= @@ -171,15 +171,15 @@ golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaE golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -200,8 +200,8 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80= diff --git a/test/go.mod b/test/go.mod index 856f10f157..9aa1bf0315 100644 --- a/test/go.mod +++ b/test/go.mod @@ -11,15 +11,15 @@ require ( github.com/docker/go-connections v0.4.0 github.com/gofrs/uuid/v5 v5.0.0 github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 - github.com/sagernet/sing v0.2.16-0.20231021090846-8002db54c028 - github.com/sagernet/sing-dns v0.1.10 - github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6 + github.com/sagernet/sing v0.2.17 + github.com/sagernet/sing-dns v0.1.11 + github.com/sagernet/sing-quic v0.1.4 github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.4 github.com/spyzhov/ajson v0.9.0 github.com/stretchr/testify v1.8.4 go.uber.org/goleak v1.3.0 - golang.org/x/net v0.17.0 + golang.org/x/net v0.18.0 ) require ( @@ -54,7 +54,7 @@ require ( github.com/libdns/libdns v0.2.1 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/mholt/acmez v1.2.0 // indirect - github.com/miekg/dns v1.1.56 // indirect + github.com/miekg/dns v1.1.57 // indirect github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect @@ -73,9 +73,9 @@ require ( github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect - github.com/sagernet/sing-mux v0.1.3 // indirect + github.com/sagernet/sing-mux v0.1.4 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect - github.com/sagernet/sing-tun v0.1.17-0.20231026060825-efd9884154a6 // indirect + github.com/sagernet/sing-tun v0.1.20 // indirect github.com/sagernet/sing-vmess v0.1.8 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 // indirect @@ -89,13 +89,13 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/mod v0.13.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/crypto v0.15.0 // indirect + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.14.0 // indirect + golang.org/x/tools v0.15.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/test/go.sum b/test/go.sum index bd89d8b67e..3c87ccbfac 100644 --- a/test/go.sum +++ b/test/go.sum @@ -83,8 +83,8 @@ github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczG github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= -github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= -github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= +github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= +github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= @@ -127,22 +127,22 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.16-0.20231021090846-8002db54c028 h1:6GbQt7SC9y5Imrq5jDMbXDSaNiMhJ8KBjhjtQRuqQvE= -github.com/sagernet/sing v0.2.16-0.20231021090846-8002db54c028/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= -github.com/sagernet/sing-dns v0.1.10 h1:iIU7nRBlUYj+fF2TaktGIvRiTFFrHwSMedLQsvlTZCI= -github.com/sagernet/sing-dns v0.1.10/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c= -github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= -github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0= -github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6 h1:w+TUbIZKZFSdf/AUa/y33kY9xaLeNGz/tBNcNhqpqfg= -github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6/go.mod h1:1M7xP4802K9Kz6BQ7LlA7UeCapWvWlH1Htmk2bAqkWc= +github.com/sagernet/sing v0.2.17 h1:vMPKb3MV0Aa5ws4dCJkRI8XEjrsUcDn810czd0FwmzI= +github.com/sagernet/sing v0.2.17/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= +github.com/sagernet/sing-dns v0.1.11 h1:PPrMCVVrAeR3f5X23I+cmvacXJ+kzuyAsBiWyUKhGSE= +github.com/sagernet/sing-dns v0.1.11/go.mod h1:zJ/YjnYB61SYE+ubMcMqVdpaSvsyQ2iShQGO3vuLvvE= +github.com/sagernet/sing-mux v0.1.4 h1:BPNPOQr6HkXG3iY/BrfvUKUl+A7gYsGKVSxvoR3PO50= +github.com/sagernet/sing-mux v0.1.4/go.mod h1:dKvcu/sb3fZ88uGv9vzAqUej6J4W+pHu5GqjRuFwAWs= +github.com/sagernet/sing-quic v0.1.4 h1:F5KRGXMXKQEmP8VrzVollf9HWcRqggcuG9nRCL+5IJ8= +github.com/sagernet/sing-quic v0.1.4/go.mod h1:aXHVP+osF3w5wJzoWZbJSrX3ceJiU9QMd0KPnKV6C/o= github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY= github.com/sagernet/sing-shadowsocks v0.2.5/go.mod h1:MGWGkcU2xW2G2mfArT9/QqpVLOGU+dBaahZCtPHdt7A= github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+MUhpQnAux728= github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.17-0.20231026060825-efd9884154a6 h1:4yEXBqQoUgXj7qPSLD6lr+z9/KfsvixO9JUA2i5xnM8= -github.com/sagernet/sing-tun v0.1.17-0.20231026060825-efd9884154a6/go.mod h1:w2+S+uWE94E/pQWSDdDdMIjwAEb645kuGPunr6ZllUg= +github.com/sagernet/sing-tun v0.1.20 h1:vYWo/w6fkKc8I1WP/IB8eBWZVsGIC6eoEoNR6XqEDlY= +github.com/sagernet/sing-tun v0.1.20/go.mod h1:6kkPL/u9tWcLFfu55VbwMDnO++17cUihSmImkZjdZro= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= @@ -190,26 +190,26 @@ golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaE 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.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= 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.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= 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.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -222,23 +222,23 @@ golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= 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.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.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.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= 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= From 661eadc3bdffb555941208581152a0894370b1c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 20 Nov 2023 18:44:31 +0800 Subject: [PATCH 75/87] documentation: Bump version --- docs/changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index cb2316f9f2..c500a2f262 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,3 +1,7 @@ +#### 1.6.6 + +* Fixes and improvements + #### 1.6.5 * Fix crash if TUIC inbound authentication failed From d3373d7f12a33eabe0544d0f48e62c0a460a01fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 9 Nov 2023 16:59:44 +0800 Subject: [PATCH 76/87] Migrate to gobwas/ws --- common/dialer/detour.go | 10 ++- experimental/clashapi/api_meta.go | 17 ++-- experimental/clashapi/connections.go | 9 +- experimental/clashapi/server.go | 38 ++++----- go.mod | 4 +- go.sum | 9 +- transport/v2ray/transport.go | 2 +- transport/v2rayhttp/client.go | 2 +- transport/v2raywebsocket/client.go | 94 +++++++++++---------- transport/v2raywebsocket/conn.go | 120 +++++++++++++++++---------- transport/v2raywebsocket/mask.go | 6 -- transport/v2raywebsocket/server.go | 13 +-- transport/v2raywebsocket/writer.go | 27 ++---- 13 files changed, 191 insertions(+), 160 deletions(-) delete mode 100644 transport/v2raywebsocket/mask.go diff --git a/common/dialer/detour.go b/common/dialer/detour.go index 81600913d4..ff484da29e 100644 --- a/common/dialer/detour.go +++ b/common/dialer/detour.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing/common/bufio/deadline" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" @@ -44,7 +45,14 @@ func (d *DetourDialer) DialContext(ctx context.Context, network string, destinat if err != nil { return nil, err } - return dialer.DialContext(ctx, network, destination) + conn, err := dialer.DialContext(ctx, network, destination) + if err != nil { + return nil, err + } + if deadline.NeedAdditionalReadDeadline(conn) { + conn = deadline.NewConn(conn) + } + return conn, nil } func (d *DetourDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { diff --git a/experimental/clashapi/api_meta.go b/experimental/clashapi/api_meta.go index bfdee1b85b..876f98695d 100644 --- a/experimental/clashapi/api_meta.go +++ b/experimental/clashapi/api_meta.go @@ -2,12 +2,14 @@ package clashapi import ( "bytes" + "net" "net/http" "time" "github.com/sagernet/sing-box/common/json" "github.com/sagernet/sing-box/experimental/clashapi/trafficontrol" - "github.com/sagernet/websocket" + "github.com/sagernet/ws" + "github.com/sagernet/ws/wsutil" "github.com/go-chi/chi/v5" "github.com/go-chi/render" @@ -27,16 +29,16 @@ type Memory struct { func memory(trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { - var wsConn *websocket.Conn - if websocket.IsWebSocketUpgrade(r) { + var conn net.Conn + if r.Header.Get("Upgrade") == "websocket" { var err error - wsConn, err = upgrader.Upgrade(w, r, nil) + conn, _, _, err = ws.UpgradeHTTP(r, w) if err != nil { return } } - if wsConn == nil { + if conn == nil { w.Header().Set("Content-Type", "application/json") render.Status(r, http.StatusOK) } @@ -63,13 +65,12 @@ func memory(trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r }); err != nil { break } - if wsConn == nil { + if conn == nil { _, err = w.Write(buf.Bytes()) w.(http.Flusher).Flush() } else { - err = wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()) + err = wsutil.WriteServerText(conn, buf.Bytes()) } - if err != nil { break } diff --git a/experimental/clashapi/connections.go b/experimental/clashapi/connections.go index 94cfb9a37a..042bdd3645 100644 --- a/experimental/clashapi/connections.go +++ b/experimental/clashapi/connections.go @@ -9,7 +9,8 @@ import ( "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/json" "github.com/sagernet/sing-box/experimental/clashapi/trafficontrol" - "github.com/sagernet/websocket" + "github.com/sagernet/ws" + "github.com/sagernet/ws/wsutil" "github.com/go-chi/chi/v5" "github.com/go-chi/render" @@ -25,13 +26,13 @@ func connectionRouter(router adapter.Router, trafficManager *trafficontrol.Manag func getConnections(trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { - if !websocket.IsWebSocketUpgrade(r) { + if r.Header.Get("Upgrade") != "websocket" { snapshot := trafficManager.Snapshot() render.JSON(w, r, snapshot) return } - conn, err := upgrader.Upgrade(w, r, nil) + conn, _, _, err := ws.UpgradeHTTP(r, w) if err != nil { return } @@ -56,7 +57,7 @@ func getConnections(trafficManager *trafficontrol.Manager) func(w http.ResponseW if err := json.NewEncoder(buf).Encode(snapshot); err != nil { return err } - return conn.WriteMessage(websocket.TextMessage, buf.Bytes()) + return wsutil.WriteServerText(conn, buf.Bytes()) } if err = sendSnapshot(); err != nil { diff --git a/experimental/clashapi/server.go b/experimental/clashapi/server.go index 9ac06620d9..493d73972b 100644 --- a/experimental/clashapi/server.go +++ b/experimental/clashapi/server.go @@ -25,7 +25,8 @@ import ( N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/service" "github.com/sagernet/sing/service/filemanager" - "github.com/sagernet/websocket" + "github.com/sagernet/ws" + "github.com/sagernet/ws/wsutil" "github.com/go-chi/chi/v5" "github.com/go-chi/cors" @@ -314,7 +315,7 @@ func authentication(serverSecret string) func(next http.Handler) http.Handler { } // Browser websocket not support custom header - if websocket.IsWebSocketUpgrade(r) && r.URL.Query().Get("token") != "" { + if r.Header.Get("Upgrade") == "websocket" && r.URL.Query().Get("token") != "" { token := r.URL.Query().Get("token") if token != serverSecret { render.Status(r, http.StatusUnauthorized) @@ -351,12 +352,6 @@ func hello(redirect bool) func(w http.ResponseWriter, r *http.Request) { } } -var upgrader = websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { - return true - }, -} - type Traffic struct { Up int64 `json:"up"` Down int64 `json:"down"` @@ -364,16 +359,17 @@ type Traffic struct { func traffic(trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { - var wsConn *websocket.Conn - if websocket.IsWebSocketUpgrade(r) { + var conn net.Conn + if r.Header.Get("Upgrade") == "websocket" { var err error - wsConn, err = upgrader.Upgrade(w, r, nil) + conn, _, _, err = ws.UpgradeHTTP(r, w) if err != nil { return } + defer conn.Close() } - if wsConn == nil { + if conn == nil { w.Header().Set("Content-Type", "application/json") render.Status(r, http.StatusOK) } @@ -392,11 +388,11 @@ func traffic(trafficManager *trafficontrol.Manager) func(w http.ResponseWriter, break } - if wsConn == nil { + if conn == nil { _, err = w.Write(buf.Bytes()) w.(http.Flusher).Flush() } else { - err = wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()) + err = wsutil.WriteServerText(conn, buf.Bytes()) } if err != nil { @@ -432,16 +428,16 @@ func getLogs(logFactory log.ObservableFactory) func(w http.ResponseWriter, r *ht } defer logFactory.UnSubscribe(subscription) - var wsConn *websocket.Conn - if websocket.IsWebSocketUpgrade(r) { - var err error - wsConn, err = upgrader.Upgrade(w, r, nil) + var conn net.Conn + if r.Header.Get("Upgrade") == "websocket" { + conn, _, _, err = ws.UpgradeHTTP(r, w) if err != nil { return } + defer conn.Close() } - if wsConn == nil { + if conn == nil { w.Header().Set("Content-Type", "application/json") render.Status(r, http.StatusOK) } @@ -465,11 +461,11 @@ func getLogs(logFactory log.ObservableFactory) func(w http.ResponseWriter, r *ht if err != nil { break } - if wsConn == nil { + if conn == nil { _, err = w.Write(buf.Bytes()) w.(http.Flusher).Flush() } else { - err = wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()) + err = wsutil.WriteServerText(conn, buf.Bytes()) } if err != nil { diff --git a/go.mod b/go.mod index 9b5d4e9d9b..eaa3f37da0 100644 --- a/go.mod +++ b/go.mod @@ -38,8 +38,8 @@ require ( github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 - github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f + github.com/sagernet/ws v0.0.0-20231030053741-7d481eb31bed github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 go.uber.org/zap v1.26.0 @@ -61,6 +61,8 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.1 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect diff --git a/go.sum b/go.sum index bebf5f1958..0a57fb1181 100644 --- a/go.sum +++ b/go.sum @@ -31,6 +31,10 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -134,10 +138,10 @@ github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 h1:Px+hN4Vzgx+iCGV github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6/go.mod h1:zovq6vTvEM6ECiqE3Eeb9rpIylPpamPcmrJ9tv0Bt0M= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= -github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs= -github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY= github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f h1:Kvo8w8Y9lzFGB/7z09MJ3TR99TFtfI/IuY87Ygcycho= github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f/go.mod h1:mySs0abhpc/gLlvhoq7HP1RzOaRmIXVeZGCh++zoApk= +github.com/sagernet/ws v0.0.0-20231030053741-7d481eb31bed h1:90a510OeE9siSJoYsI8nSjPmA+u5ROMDts/ZkdNsuXY= +github.com/sagernet/ws v0.0.0-20231030053741-7d481eb31bed/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= @@ -189,6 +193,7 @@ golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/transport/v2ray/transport.go b/transport/v2ray/transport.go index 3481c852c6..9dfee28119 100644 --- a/transport/v2ray/transport.go +++ b/transport/v2ray/transport.go @@ -50,7 +50,7 @@ func NewClientTransport(ctx context.Context, dialer N.Dialer, serverAddr M.Socks case C.V2RayTransportTypeGRPC: return NewGRPCClient(ctx, dialer, serverAddr, options.GRPCOptions, tlsConfig) case C.V2RayTransportTypeWebsocket: - return v2raywebsocket.NewClient(ctx, dialer, serverAddr, options.WebsocketOptions, tlsConfig), nil + return v2raywebsocket.NewClient(ctx, dialer, serverAddr, options.WebsocketOptions, tlsConfig) case C.V2RayTransportTypeQUIC: if tlsConfig == nil { return nil, C.ErrTLSRequired diff --git a/transport/v2rayhttp/client.go b/transport/v2rayhttp/client.go index d5e8a1f670..f280eeef55 100644 --- a/transport/v2rayhttp/client.go +++ b/transport/v2rayhttp/client.go @@ -81,7 +81,7 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt uri.Path = options.Path err := sHTTP.URLSetPath(&uri, options.Path) if err != nil { - return nil, E.New("failed to set path: " + err.Error()) + return nil, E.Cause(err, "parse path") } client.url = &uri return client, nil diff --git a/transport/v2raywebsocket/client.go b/transport/v2raywebsocket/client.go index 9f14f676e6..54c4df0b6e 100644 --- a/transport/v2raywebsocket/client.go +++ b/transport/v2raywebsocket/client.go @@ -5,58 +5,37 @@ import ( "net" "net/http" "net/url" + "strings" "time" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/tls" + C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" sHTTP "github.com/sagernet/sing/protocol/http" - "github.com/sagernet/websocket" + "github.com/sagernet/ws" ) var _ adapter.V2RayClientTransport = (*Client)(nil) type Client struct { - dialer *websocket.Dialer + dialer N.Dialer + tlsConfig tls.Config + serverAddr M.Socksaddr requestURL url.URL - requestURLString string headers http.Header maxEarlyData uint32 earlyDataHeaderName string } -func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayWebsocketOptions, tlsConfig tls.Config) adapter.V2RayClientTransport { - wsDialer := &websocket.Dialer{ - ReadBufferSize: 4 * 1024, - WriteBufferSize: 4 * 1024, - HandshakeTimeout: time.Second * 8, - } +func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayWebsocketOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) { if tlsConfig != nil { if len(tlsConfig.NextProtos()) == 0 { tlsConfig.SetNextProtos([]string{"http/1.1"}) } - wsDialer.NetDialTLSContext = func(ctx context.Context, network, addr string) (net.Conn, error) { - conn, err := dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) - if err != nil { - return nil, err - } - tlsConn, err := tls.ClientHandshake(ctx, conn, tlsConfig) - if err != nil { - return nil, err - } - return &deadConn{tlsConn}, nil - } - } else { - wsDialer.NetDialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { - conn, err := dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) - if err != nil { - return nil, err - } - return &deadConn{conn}, nil - } } var requestURL url.URL if tlsConfig == nil { @@ -68,37 +47,68 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt requestURL.Path = options.Path err := sHTTP.URLSetPath(&requestURL, options.Path) if err != nil { - return nil + return nil, E.Cause(err, "parse path") + } + if !strings.HasPrefix(requestURL.Path, "/") { + requestURL.Path = "/" + requestURL.Path } headers := make(http.Header) for key, value := range options.Headers { headers[key] = value + if key == "Host" { + if len(value) > 1 { + return nil, E.New("multiple Host headers") + } + requestURL.Host = value[0] + } + } + if headers.Get("User-Agent") == "" { + headers.Set("User-Agent", "Go-http-client/1.1") } return &Client{ - wsDialer, + dialer, + tlsConfig, + serverAddr, requestURL, - requestURL.String(), headers, options.MaxEarlyData, options.EarlyDataHeaderName, + }, nil +} + +func (c *Client) dialContext(ctx context.Context, requestURL *url.URL, headers http.Header) (*WebsocketConn, error) { + conn, err := c.dialer.DialContext(ctx, N.NetworkTCP, c.serverAddr) + if err != nil { + return nil, err + } + if c.tlsConfig != nil { + conn, err = tls.ClientHandshake(ctx, conn, c.tlsConfig) + if err != nil { + return nil, err + } + } + conn.SetDeadline(time.Now().Add(C.TCPTimeout)) + var protocols []string + if protocolHeader := headers.Get("Sec-WebSocket-Protocol"); protocolHeader != "" { + protocols = []string{protocolHeader} + headers.Del("Sec-WebSocket-Protocol") } + reader, _, err := ws.Dialer{Header: ws.HandshakeHeaderHTTP(headers), Protocols: protocols}.Upgrade(conn, requestURL) + conn.SetDeadline(time.Time{}) + if err != nil { + return nil, err + } + return NewConn(conn, reader, nil, ws.StateClientSide), nil } func (c *Client) DialContext(ctx context.Context) (net.Conn, error) { if c.maxEarlyData <= 0 { - conn, response, err := c.dialer.DialContext(ctx, c.requestURLString, c.headers) - if err == nil { - return &WebsocketConn{Conn: conn, Writer: NewWriter(conn, false)}, nil + conn, err := c.dialContext(ctx, &c.requestURL, c.headers) + if err != nil { + return nil, err } - return nil, wrapDialError(response, err) + return conn, nil } else { return &EarlyWebsocketConn{Client: c, ctx: ctx, create: make(chan struct{})}, nil } } - -func wrapDialError(response *http.Response, err error) error { - if response == nil { - return err - } - return E.Extend(err, "HTTP ", response.StatusCode, " ", response.Status) -} diff --git a/transport/v2raywebsocket/conn.go b/transport/v2raywebsocket/conn.go index 6400b118d9..5b51e5c528 100644 --- a/transport/v2raywebsocket/conn.go +++ b/transport/v2raywebsocket/conn.go @@ -1,11 +1,11 @@ package v2raywebsocket import ( + "bufio" "context" "encoding/base64" "io" "net" - "net/http" "os" "sync" "time" @@ -13,50 +13,96 @@ import ( C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/debug" E "github.com/sagernet/sing/common/exceptions" - "github.com/sagernet/websocket" + "github.com/sagernet/ws" + "github.com/sagernet/ws/wsutil" ) type WebsocketConn struct { - *websocket.Conn + net.Conn *Writer - remoteAddr net.Addr - reader io.Reader + state ws.State + reader *wsutil.Reader + controlHandler wsutil.FrameHandlerFunc + remoteAddr net.Addr } -func NewServerConn(wsConn *websocket.Conn, remoteAddr net.Addr) *WebsocketConn { +func NewConn(conn net.Conn, br *bufio.Reader, remoteAddr net.Addr, state ws.State) *WebsocketConn { + controlHandler := wsutil.ControlFrameHandler(conn, state) + var reader io.Reader + if br != nil && br.Buffered() > 0 { + reader = br + } else { + reader = conn + } return &WebsocketConn{ - Conn: wsConn, - remoteAddr: remoteAddr, - Writer: NewWriter(wsConn, true), + Conn: conn, + state: state, + reader: &wsutil.Reader{ + Source: reader, + State: state, + SkipHeaderCheck: !debug.Enabled, + OnIntermediate: controlHandler, + }, + controlHandler: controlHandler, + remoteAddr: remoteAddr, + Writer: NewWriter(conn, state), } } func (c *WebsocketConn) Close() error { - err := c.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add(C.TCPTimeout)) - if err != nil { - return c.Conn.Close() + c.Conn.SetWriteDeadline(time.Now().Add(C.TCPTimeout)) + frame := ws.NewCloseFrame(ws.NewCloseFrameBody( + ws.StatusNormalClosure, "", + )) + if c.state == ws.StateClientSide { + frame = ws.MaskFrameInPlace(frame) } + ws.WriteFrame(c.Conn, frame) + c.Conn.Close() return nil } func (c *WebsocketConn) Read(b []byte) (n int, err error) { + var header ws.Header for { - if c.reader == nil { - _, c.reader, err = c.NextReader() + n, err = c.reader.Read(b) + if n > 0 { + err = nil + return + } + if !E.IsMulti(err, io.EOF, wsutil.ErrNoFrameAdvance) { + return + } + header, err = c.reader.NextFrame() + if err != nil { + return + } + if header.OpCode.IsControl() { + err = c.controlHandler(header, c.reader) if err != nil { - err = wrapError(err) return } + continue } - n, err = c.reader.Read(b) - if E.IsMulti(err, io.EOF) { - c.reader = nil + if header.OpCode&ws.OpBinary == 0 { + err = c.reader.Discard() + if err != nil { + return + } continue } - err = wrapError(err) + } +} + +func (c *WebsocketConn) Write(p []byte) (n int, err error) { + err = wsutil.WriteMessage(c.Conn, c.state, ws.OpBinary, p) + if err != nil { return } + n = len(p) + return } func (c *WebsocketConn) RemoteAddr() net.Addr { @@ -83,11 +129,7 @@ func (c *WebsocketConn) NeedAdditionalReadDeadline() bool { } func (c *WebsocketConn) Upstream() any { - return c.Conn.NetConn() -} - -func (c *WebsocketConn) UpstreamWriter() any { - return c.Writer + return c.Conn } type EarlyWebsocketConn struct { @@ -113,8 +155,7 @@ func (c *EarlyWebsocketConn) writeRequest(content []byte) error { var ( earlyData []byte lateData []byte - conn *websocket.Conn - response *http.Response + conn *WebsocketConn err error ) if len(content) > int(c.maxEarlyData) { @@ -128,23 +169,26 @@ func (c *EarlyWebsocketConn) writeRequest(content []byte) error { if c.earlyDataHeaderName == "" { requestURL := c.requestURL requestURL.Path += earlyDataString - conn, response, err = c.dialer.DialContext(c.ctx, requestURL.String(), c.headers) + conn, err = c.dialContext(c.ctx, &requestURL, c.headers) } else { headers := c.headers.Clone() headers.Set(c.earlyDataHeaderName, earlyDataString) - conn, response, err = c.dialer.DialContext(c.ctx, c.requestURLString, headers) + conn, err = c.dialContext(c.ctx, &c.requestURL, headers) } } else { - conn, response, err = c.dialer.DialContext(c.ctx, c.requestURLString, c.headers) + conn, err = c.dialContext(c.ctx, &c.requestURL, c.headers) } if err != nil { - return wrapDialError(response, err) + return err } - c.conn = &WebsocketConn{Conn: conn, Writer: NewWriter(conn, false)} if len(lateData) > 0 { - _, err = c.conn.Write(lateData) + _, err = conn.Write(lateData) + if err != nil { + return err + } } - return err + c.conn = conn + return nil } func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) { @@ -230,13 +274,3 @@ func (c *EarlyWebsocketConn) Upstream() any { func (c *EarlyWebsocketConn) LazyHeadroom() bool { return c.conn == nil } - -func wrapError(err error) error { - if websocket.IsCloseError(err, websocket.CloseNormalClosure) { - return io.EOF - } - if websocket.IsCloseError(err, websocket.CloseAbnormalClosure) { - return net.ErrClosed - } - return err -} diff --git a/transport/v2raywebsocket/mask.go b/transport/v2raywebsocket/mask.go deleted file mode 100644 index 01ea8437a1..0000000000 --- a/transport/v2raywebsocket/mask.go +++ /dev/null @@ -1,6 +0,0 @@ -package v2raywebsocket - -import _ "unsafe" - -//go:linkname maskBytes github.com/sagernet/websocket.maskBytes -func maskBytes(key [4]byte, pos int, b []byte) int diff --git a/transport/v2raywebsocket/server.go b/transport/v2raywebsocket/server.go index 9d8bc69af7..ae6e15f376 100644 --- a/transport/v2raywebsocket/server.go +++ b/transport/v2raywebsocket/server.go @@ -20,7 +20,7 @@ import ( N "github.com/sagernet/sing/common/network" aTLS "github.com/sagernet/sing/common/tls" sHttp "github.com/sagernet/sing/protocol/http" - "github.com/sagernet/websocket" + "github.com/sagernet/ws" ) var _ adapter.V2RayServerTransport = (*Server)(nil) @@ -58,13 +58,6 @@ func NewServer(ctx context.Context, options option.V2RayWebsocketOptions, tlsCon return server, nil } -var upgrader = websocket.Upgrader{ - HandshakeTimeout: C.TCPTimeout, - CheckOrigin: func(r *http.Request) bool { - return true - }, -} - func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) { if s.maxEarlyData == 0 || s.earlyDataHeaderName != "" { if request.URL.Path != s.path { @@ -95,14 +88,14 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) { s.invalidRequest(writer, request, http.StatusBadRequest, E.Cause(err, "decode early data")) return } - wsConn, err := upgrader.Upgrade(writer, request, nil) + wsConn, reader, _, err := ws.UpgradeHTTP(request, writer) if err != nil { s.invalidRequest(writer, request, 0, E.Cause(err, "upgrade websocket connection")) return } var metadata M.Metadata metadata.Source = sHttp.SourceAddress(request) - conn = NewServerConn(wsConn, metadata.Source.TCPAddr()) + conn = NewConn(wsConn, reader.Reader, metadata.Source.TCPAddr(), ws.StateServerSide) if len(earlyData) > 0 { conn = bufio.NewCachedConn(conn, buf.As(earlyData)) } diff --git a/transport/v2raywebsocket/writer.go b/transport/v2raywebsocket/writer.go index fbb61f0f4d..5bd0d0a14f 100644 --- a/transport/v2raywebsocket/writer.go +++ b/transport/v2raywebsocket/writer.go @@ -2,36 +2,27 @@ package v2raywebsocket import ( "encoding/binary" + "io" "math/rand" "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" N "github.com/sagernet/sing/common/network" - "github.com/sagernet/websocket" + "github.com/sagernet/ws" ) type Writer struct { - *websocket.Conn writer N.ExtendedWriter isServer bool } -func NewWriter(conn *websocket.Conn, isServer bool) *Writer { +func NewWriter(writer io.Writer, state ws.State) *Writer { return &Writer{ - conn, - bufio.NewExtendedWriter(conn.NetConn()), - isServer, + bufio.NewExtendedWriter(writer), + state == ws.StateServerSide, } } -func (w *Writer) Write(p []byte) (n int, err error) { - err = w.Conn.WriteMessage(websocket.BinaryMessage, p) - if err != nil { - return - } - return len(p), nil -} - func (w *Writer) WriteBuffer(buffer *buf.Buffer) error { var payloadBitLength int dataLen := buffer.Len() @@ -52,7 +43,7 @@ func (w *Writer) WriteBuffer(buffer *buf.Buffer) error { } header := buffer.ExtendHeader(headerLen) - header[0] = websocket.BinaryMessage | 1<<7 + header[0] = byte(ws.OpBinary) | 0x80 if w.isServer { header[1] = 0 } else { @@ -72,16 +63,12 @@ func (w *Writer) WriteBuffer(buffer *buf.Buffer) error { if !w.isServer { maskKey := rand.Uint32() binary.BigEndian.PutUint32(header[1+payloadBitLength:], maskKey) - maskBytes(*(*[4]byte)(header[1+payloadBitLength:]), 0, data) + ws.Cipher(data, *(*[4]byte)(header[1+payloadBitLength:]), 0) } return w.writer.WriteBuffer(buffer) } -func (w *Writer) Upstream() any { - return w.Conn.NetConn() -} - func (w *Writer) FrontHeadroom() int { return 14 } From b244c9bbca6e101558b9c68c2cc478c0afaae216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 30 Oct 2023 12:00:00 +0800 Subject: [PATCH 77/87] Add udp_disable_domain_unmapping inbound listen option --- docs/configuration/shared/listen.md | 54 +++++++++++++------------- docs/configuration/shared/listen.zh.md | 38 ++++++++---------- go.mod | 2 +- go.sum | 4 +- option/inbound.go | 9 +++-- outbound/default.go | 10 +++-- 6 files changed, 58 insertions(+), 59 deletions(-) diff --git a/docs/configuration/shared/listen.md b/docs/configuration/shared/listen.md index d4a0e58ee3..c1b1ed3382 100644 --- a/docs/configuration/shared/listen.md +++ b/docs/configuration/shared/listen.md @@ -7,28 +7,26 @@ "tcp_fast_open": false, "tcp_multi_path": false, "udp_fragment": false, + "udp_timeout": 300, + "detour": "another-in", "sniff": false, "sniff_override_destination": false, "sniff_timeout": "300ms", "domain_strategy": "prefer_ipv6", - "udp_timeout": 300, - "proxy_protocol": false, - "proxy_protocol_accept_no_header": false, - "detour": "another-in" + "udp_disable_domain_unmapping": false } ``` ### Fields -| Field | Available Context | -|-----------------------------------|-------------------------------------------------------------------| -| `listen` | Needs to listen on TCP or UDP. | -| `listen_port` | Needs to listen on TCP or UDP. | -| `tcp_fast_open` | Needs to listen on TCP. | -| `tcp_multi_path` | Needs to listen on TCP. | -| `udp_timeout` | Needs to assemble UDP connections, currently Tun and Shadowsocks. | -| `proxy_protocol` | Needs to listen on TCP. | -| `proxy_protocol_accept_no_header` | When `proxy_protocol` enabled | +| Field | Available Context | +|--------------------------------|-------------------------------------------------------------------| +| `listen` | Needs to listen on TCP or UDP. | +| `listen_port` | Needs to listen on TCP or UDP. | +| `tcp_fast_open` | Needs to listen on TCP. | +| `tcp_multi_path` | Needs to listen on TCP. | +| `udp_timeout` | Needs to assemble UDP connections, currently Tun and Shadowsocks. | +| `udp_disable_domain_unmapping` | Needs to listen on UDP and accept domain UDP addresses. | #### listen @@ -56,6 +54,16 @@ Enable TCP Multi Path. Enable UDP fragmentation. +#### udp_timeout + +UDP NAT expiration time in seconds, default is 300 (5 minutes). + +#### detour + +If set, connections will be forwarded to the specified inbound. + +Requires target inbound support, see [Injectable](/configuration/inbound/#fields). + #### sniff Enable sniffing. @@ -82,20 +90,10 @@ If set, the requested domain name will be resolved to IP before routing. If `sniff_override_destination` is in effect, its value will be taken as a fallback. -#### udp_timeout - -UDP NAT expiration time in seconds, default is 300 (5 minutes). - -#### proxy_protocol - -Parse [Proxy Protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) in the connection header. +#### udp_disable_domain_unmapping -#### proxy_protocol_accept_no_header - -Accept connections without Proxy Protocol header. - -#### detour - -If set, connections will be forwarded to the specified inbound. +If enabled, for UDP proxy requests addressed to a domain, +the original packet address will be sent in the response instead of the mapped domain. -Requires target inbound support, see [Injectable](/configuration/inbound/#fields). \ No newline at end of file +This option is used for compatibility with clients that +do not support receiving UDP packets with domain addresses, such as Surge. diff --git a/docs/configuration/shared/listen.zh.md b/docs/configuration/shared/listen.zh.md index b25ce295c0..b7fd74870a 100644 --- a/docs/configuration/shared/listen.zh.md +++ b/docs/configuration/shared/listen.zh.md @@ -7,14 +7,13 @@ "tcp_fast_open": false, "tcp_multi_path": false, "udp_fragment": false, + "udp_timeout": 300, + "detour": "another-in", "sniff": false, "sniff_override_destination": false, "sniff_timeout": "300ms", "domain_strategy": "prefer_ipv6", - "udp_timeout": 300, - "proxy_protocol": false, - "proxy_protocol_accept_no_header": false, - "detour": "another-in" + "udp_disable_domain_unmapping": false } ``` @@ -26,8 +25,7 @@ | `tcp_fast_open` | 需要监听 TCP。 | | `tcp_multi_path` | 需要监听 TCP。 | | `udp_timeout` | 需要组装 UDP 连接, 当前为 Tun 和 Shadowsocks。 | -| `proxy_protocol` | 需要监听 TCP。 | -| `proxy_protocol_accept_no_header` | `proxy_protocol` 启用时 | +| ### 字段 @@ -57,6 +55,16 @@ 启用 UDP 分段。 +#### udp_timeout + +UDP NAT 过期时间,以秒为单位,默认为 300(5 分钟)。 + +#### detour + +如果设置,连接将被转发到指定的入站。 + +需要目标入站支持,参阅 [注入支持](/zh/configuration/inbound/#_3)。 + #### sniff 启用协议探测。 @@ -83,20 +91,8 @@ 如果 `sniff_override_destination` 生效,它的值将作为后备。 -#### udp_timeout - -UDP NAT 过期时间,以秒为单位,默认为 300(5 分钟)。 - -#### proxy_protocol - -解析连接头中的 [代理协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)。 +#### udp_disable_domain_unmapping -#### proxy_protocol_accept_no_header - -接受没有代理协议标头的连接。 - -#### detour - -如果设置,连接将被转发到指定的入站。 +如果启用,对于地址为域的 UDP 代理请求,将在响应中发送原始包地址而不是映射的域。 -需要目标入站支持,参阅 [注入支持](/zh/configuration/inbound/#_3)。 \ No newline at end of file +此选项用于兼容不支持接收带有域地址的 UDP 包的客户端,如 Surge。 diff --git a/go.mod b/go.mod index eaa3f37da0..58d78c2bdd 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.2.17 + github.com/sagernet/sing v0.2.18-0.20231119032432-6a556bfa50cc github.com/sagernet/sing-dns v0.1.11 github.com/sagernet/sing-mux v0.1.4 github.com/sagernet/sing-quic v0.1.4 diff --git a/go.sum b/go.sum index 0a57fb1181..7c1dd96809 100644 --- a/go.sum +++ b/go.sum @@ -114,8 +114,8 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.17 h1:vMPKb3MV0Aa5ws4dCJkRI8XEjrsUcDn810czd0FwmzI= -github.com/sagernet/sing v0.2.17/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= +github.com/sagernet/sing v0.2.18-0.20231119032432-6a556bfa50cc h1:dmU0chO0QrBpARo8sqyOc+mvPLW+qux4ca16kb2WIc8= +github.com/sagernet/sing v0.2.18-0.20231119032432-6a556bfa50cc/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/sagernet/sing-dns v0.1.11 h1:PPrMCVVrAeR3f5X23I+cmvacXJ+kzuyAsBiWyUKhGSE= github.com/sagernet/sing-dns v0.1.11/go.mod h1:zJ/YjnYB61SYE+ubMcMqVdpaSvsyQ2iShQGO3vuLvvE= github.com/sagernet/sing-mux v0.1.4 h1:BPNPOQr6HkXG3iY/BrfvUKUl+A7gYsGKVSxvoR3PO50= diff --git a/option/inbound.go b/option/inbound.go index 06408f58b2..c61428adb5 100644 --- a/option/inbound.go +++ b/option/inbound.go @@ -120,10 +120,11 @@ func (h *Inbound) UnmarshalJSON(bytes []byte) error { } type InboundOptions struct { - SniffEnabled bool `json:"sniff,omitempty"` - SniffOverrideDestination bool `json:"sniff_override_destination,omitempty"` - SniffTimeout Duration `json:"sniff_timeout,omitempty"` - DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"` + SniffEnabled bool `json:"sniff,omitempty"` + SniffOverrideDestination bool `json:"sniff_override_destination,omitempty"` + SniffTimeout Duration `json:"sniff_timeout,omitempty"` + DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"` + UDPDisableDomainUnmapping bool `json:"udp_disable_domain_unmapping,omitempty"` } type ListenOptions struct { diff --git a/outbound/default.go b/outbound/default.go index 8067b6db5d..972aca9479 100644 --- a/outbound/default.go +++ b/outbound/default.go @@ -124,9 +124,13 @@ func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn, } if destinationAddress.IsValid() { if metadata.Destination.IsFqdn() { - outConn = bufio.NewNATPacketConn(bufio.NewPacketConn(outConn), M.SocksaddrFrom(destinationAddress, metadata.Destination.Port), metadata.Destination) + if metadata.InboundOptions.UDPDisableDomainUnmapping { + outConn = bufio.NewUnidirectionalNATPacketConn(bufio.NewPacketConn(outConn), M.SocksaddrFrom(destinationAddress, metadata.Destination.Port), metadata.Destination) + } else { + outConn = bufio.NewNATPacketConn(bufio.NewPacketConn(outConn), M.SocksaddrFrom(destinationAddress, metadata.Destination.Port), metadata.Destination) + } } - if natConn, loaded := common.Cast[*bufio.NATPacketConn](conn); loaded { + if natConn, loaded := common.Cast[bufio.NATPacketConn](conn); loaded { natConn.UpdateDestination(destinationAddress) } } @@ -170,7 +174,7 @@ func NewDirectPacketConnection(ctx context.Context, router adapter.Router, this if metadata.Destination.IsFqdn() { outConn = bufio.NewNATPacketConn(bufio.NewPacketConn(outConn), M.SocksaddrFrom(destinationAddress, metadata.Destination.Port), metadata.Destination) } - if natConn, loaded := common.Cast[*bufio.NATPacketConn](conn); loaded { + if natConn, loaded := common.Cast[bufio.NATPacketConn](conn); loaded { natConn.UpdateDestination(destinationAddress) } } From a3d24ed7d300de3bc5a1ef47fd67022c05154fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 30 Oct 2023 12:00:00 +0800 Subject: [PATCH 78/87] Add exclude route support for tun & Update gVisor to 20231113.0 --- docs/configuration/inbound/tun.md | 14 +++++++++ docs/configuration/inbound/tun.zh.md | 14 +++++++++ experimental/libbox/service.go | 6 +++- experimental/libbox/tun.go | 9 ++++-- go.mod | 6 ++-- go.sum | 12 ++++---- inbound/tun.go | 36 ++++++++++++----------- option/tun.go | 44 +++++++++++++++------------- 8 files changed, 91 insertions(+), 50 deletions(-) diff --git a/docs/configuration/inbound/tun.md b/docs/configuration/inbound/tun.md index 4c9670a27d..e6c52c54c1 100644 --- a/docs/configuration/inbound/tun.md +++ b/docs/configuration/inbound/tun.md @@ -22,6 +22,12 @@ "::/1", "8000::/1" ], + "inet4_route_exclude_address": [ + "192.168.0.0/16" + ], + "inet6_route_exclude_address": [ + "fc00::/7" + ], "endpoint_independent_nat": false, "stack": "system", "include_interface": [ @@ -130,6 +136,14 @@ Use custom routes instead of default when `auto_route` is enabled. Use custom routes instead of default when `auto_route` is enabled. +#### inet4_route_exclude_address + +Exclude custom routes when `auto_route` is enabled. + +#### inet6_route_exclude_address + +Exclude custom routes when `auto_route` is enabled. + #### endpoint_independent_nat !!! info "" diff --git a/docs/configuration/inbound/tun.zh.md b/docs/configuration/inbound/tun.zh.md index fbd10abf7e..8f246c042b 100644 --- a/docs/configuration/inbound/tun.zh.md +++ b/docs/configuration/inbound/tun.zh.md @@ -22,6 +22,12 @@ "::/1", "8000::/1" ], + "inet4_route_exclude_address": [ + "192.168.0.0/16" + ], + "inet6_route_exclude_address": [ + "fc00::/7" + ], "endpoint_independent_nat": false, "stack": "system", "include_interface": [ @@ -131,6 +137,14 @@ tun 接口的 IPv6 前缀。 启用 `auto_route` 时使用自定义路由而不是默认路由。 +#### inet4_route_exclude_address + +启用 `auto_route` 时排除自定义路由。 + +#### inet6_route_exclude_address + +启用 `auto_route` 时排除自定义路由。 + #### endpoint_independent_nat 启用独立于端点的 NAT。 diff --git a/experimental/libbox/service.go b/experimental/libbox/service.go index 67b57d7da5..ce4d6d2aad 100644 --- a/experimental/libbox/service.go +++ b/experimental/libbox/service.go @@ -122,7 +122,11 @@ func (w *platformInterfaceWrapper) OpenTun(options *tun.Options, platformOptions if len(options.IncludeAndroidUser) > 0 { return nil, E.New("android: unsupported android_user option") } - tunFd, err := w.iif.OpenTun(&tunOptions{options, platformOptions}) + routeRanges, err := options.BuildAutoRouteRanges(true) + if err != nil { + return nil, err + } + tunFd, err := w.iif.OpenTun(&tunOptions{options, routeRanges, platformOptions}) if err != nil { return nil, err } diff --git a/experimental/libbox/tun.go b/experimental/libbox/tun.go index e692a5d651..e40ad58b46 100644 --- a/experimental/libbox/tun.go +++ b/experimental/libbox/tun.go @@ -60,6 +60,7 @@ var _ TunOptions = (*tunOptions)(nil) type tunOptions struct { *tun.Options + routeRanges []netip.Prefix option.TunPlatformOptions } @@ -91,11 +92,15 @@ func (o *tunOptions) GetStrictRoute() bool { } func (o *tunOptions) GetInet4RouteAddress() RoutePrefixIterator { - return mapRoutePrefix(o.Inet4RouteAddress) + return mapRoutePrefix(common.Filter(o.routeRanges, func(it netip.Prefix) bool { + return it.Addr().Is4() + })) } func (o *tunOptions) GetInet6RouteAddress() RoutePrefixIterator { - return mapRoutePrefix(o.Inet6RouteAddress) + return mapRoutePrefix(common.Filter(o.routeRanges, func(it netip.Prefix) bool { + return it.Addr().Is6() + })) } func (o *tunOptions) GetIncludePackage() StringIterator { diff --git a/go.mod b/go.mod index 58d78c2bdd..ae3412ab96 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950 - github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab + github.com/sagernet/gvisor v0.0.0-20231119034329-07cfb6aaf930 github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/sing v0.2.18-0.20231119032432-6a556bfa50cc @@ -33,7 +33,7 @@ require ( github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.5 github.com/sagernet/sing-shadowtls v0.1.4 - github.com/sagernet/sing-tun v0.1.20 + github.com/sagernet/sing-tun v0.1.21-0.20231119035513-f6ea97c5af71 github.com/sagernet/sing-vmess v0.1.8 github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 @@ -89,7 +89,7 @@ require ( golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect + golang.org/x/time v0.4.0 // indirect golang.org/x/tools v0.15.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect diff --git a/go.sum b/go.sum index 7c1dd96809..8a97f9f8a2 100644 --- a/go.sum +++ b/go.sum @@ -104,8 +104,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950 h1:hUz/2mJLgi7l2H36JGpDY+jou9FmI6kAm0ZkU+xPpgE= github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950/go.mod h1:5YE39YkJkCcMsfq1jMKkjsrM2GfBoF9JVWnvU89hmvU= -github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab h1:u+xQoi/Yc6bNUvTfrDD6HhGRybn2lzrhf5vmS+wb4Ho= -github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab/go.mod h1:3akUhSHSVtLuJaYcW5JPepUraBOW06Ibz2HKwaK5rOk= +github.com/sagernet/gvisor v0.0.0-20231119034329-07cfb6aaf930 h1:dSPgjIw0CT6ISLeEh8Q20dZMBMFCcEceo23+LncRcNQ= +github.com/sagernet/gvisor v0.0.0-20231119034329-07cfb6aaf930/go.mod h1:JpKHkOYgh4wLwrX2BhH3ZIvCvazCkTnPeEcmigZJfHY= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 h1:dAe4OIJAtE0nHOzTHhAReQteh3+sa63rvXbuIpbeOTY= @@ -128,8 +128,8 @@ github.com/sagernet/sing-shadowsocks2 v0.1.5 h1:JDeAJ4ZWlYZ7F6qEVdDKPhQEangxKw/J github.com/sagernet/sing-shadowsocks2 v0.1.5/go.mod h1:KF65y8lI5PGHyMgRZGYXYsH9ilgRc/yr+NYbSNGuBm4= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.20 h1:vYWo/w6fkKc8I1WP/IB8eBWZVsGIC6eoEoNR6XqEDlY= -github.com/sagernet/sing-tun v0.1.20/go.mod h1:6kkPL/u9tWcLFfu55VbwMDnO++17cUihSmImkZjdZro= +github.com/sagernet/sing-tun v0.1.21-0.20231119035513-f6ea97c5af71 h1:WQi0TwhjbSNFFbxybIgAUSjVvo7uWSsLD28ldoM2avY= +github.com/sagernet/sing-tun v0.1.21-0.20231119035513-f6ea97c5af71/go.mod h1:hyzA4gDWbeg2SXklqPDswBKa//QcjlZqKw9aPcNdQ9A= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= @@ -202,8 +202,8 @@ 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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= diff --git a/inbound/tun.go b/inbound/tun.go index 0b57482d39..7d1f519934 100644 --- a/inbound/tun.go +++ b/inbound/tun.go @@ -71,23 +71,25 @@ func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger logger: logger, inboundOptions: options.InboundOptions, tunOptions: tun.Options{ - Name: options.InterfaceName, - MTU: tunMTU, - Inet4Address: options.Inet4Address, - Inet6Address: options.Inet6Address, - AutoRoute: options.AutoRoute, - StrictRoute: options.StrictRoute, - IncludeInterface: options.IncludeInterface, - ExcludeInterface: options.ExcludeInterface, - Inet4RouteAddress: options.Inet4RouteAddress, - Inet6RouteAddress: options.Inet6RouteAddress, - IncludeUID: includeUID, - ExcludeUID: excludeUID, - IncludeAndroidUser: options.IncludeAndroidUser, - IncludePackage: options.IncludePackage, - ExcludePackage: options.ExcludePackage, - InterfaceMonitor: router.InterfaceMonitor(), - TableIndex: 2022, + Name: options.InterfaceName, + MTU: tunMTU, + Inet4Address: options.Inet4Address, + Inet6Address: options.Inet6Address, + AutoRoute: options.AutoRoute, + StrictRoute: options.StrictRoute, + IncludeInterface: options.IncludeInterface, + ExcludeInterface: options.ExcludeInterface, + Inet4RouteAddress: options.Inet4RouteAddress, + Inet6RouteAddress: options.Inet6RouteAddress, + Inet4RouteExcludeAddress: options.Inet4RouteExcludeAddress, + Inet6RouteExcludeAddress: options.Inet6RouteExcludeAddress, + IncludeUID: includeUID, + ExcludeUID: excludeUID, + IncludeAndroidUser: options.IncludeAndroidUser, + IncludePackage: options.IncludePackage, + ExcludePackage: options.ExcludePackage, + InterfaceMonitor: router.InterfaceMonitor(), + TableIndex: 2022, }, endpointIndependentNat: options.EndpointIndependentNat, udpTimeout: udpTimeout, diff --git a/option/tun.go b/option/tun.go index 4cf778041b..306d45415d 100644 --- a/option/tun.go +++ b/option/tun.go @@ -3,26 +3,28 @@ package option import "net/netip" type TunInboundOptions struct { - InterfaceName string `json:"interface_name,omitempty"` - MTU uint32 `json:"mtu,omitempty"` - Inet4Address Listable[netip.Prefix] `json:"inet4_address,omitempty"` - Inet6Address Listable[netip.Prefix] `json:"inet6_address,omitempty"` - AutoRoute bool `json:"auto_route,omitempty"` - StrictRoute bool `json:"strict_route,omitempty"` - Inet4RouteAddress Listable[netip.Prefix] `json:"inet4_route_address,omitempty"` - Inet6RouteAddress Listable[netip.Prefix] `json:"inet6_route_address,omitempty"` - IncludeInterface Listable[string] `json:"include_interface,omitempty"` - ExcludeInterface Listable[string] `json:"exclude_interface,omitempty"` - IncludeUID Listable[uint32] `json:"include_uid,omitempty"` - IncludeUIDRange Listable[string] `json:"include_uid_range,omitempty"` - ExcludeUID Listable[uint32] `json:"exclude_uid,omitempty"` - ExcludeUIDRange Listable[string] `json:"exclude_uid_range,omitempty"` - IncludeAndroidUser Listable[int] `json:"include_android_user,omitempty"` - IncludePackage Listable[string] `json:"include_package,omitempty"` - ExcludePackage Listable[string] `json:"exclude_package,omitempty"` - EndpointIndependentNat bool `json:"endpoint_independent_nat,omitempty"` - UDPTimeout int64 `json:"udp_timeout,omitempty"` - Stack string `json:"stack,omitempty"` - Platform *TunPlatformOptions `json:"platform,omitempty"` + InterfaceName string `json:"interface_name,omitempty"` + MTU uint32 `json:"mtu,omitempty"` + Inet4Address Listable[netip.Prefix] `json:"inet4_address,omitempty"` + Inet6Address Listable[netip.Prefix] `json:"inet6_address,omitempty"` + AutoRoute bool `json:"auto_route,omitempty"` + StrictRoute bool `json:"strict_route,omitempty"` + Inet4RouteAddress Listable[netip.Prefix] `json:"inet4_route_address,omitempty"` + Inet6RouteAddress Listable[netip.Prefix] `json:"inet6_route_address,omitempty"` + Inet4RouteExcludeAddress Listable[netip.Prefix] `json:"inet4_route_exclude_address,omitempty"` + Inet6RouteExcludeAddress Listable[netip.Prefix] `json:"inet6_route_exclude_address,omitempty"` + IncludeInterface Listable[string] `json:"include_interface,omitempty"` + ExcludeInterface Listable[string] `json:"exclude_interface,omitempty"` + IncludeUID Listable[uint32] `json:"include_uid,omitempty"` + IncludeUIDRange Listable[string] `json:"include_uid_range,omitempty"` + ExcludeUID Listable[uint32] `json:"exclude_uid,omitempty"` + ExcludeUIDRange Listable[string] `json:"exclude_uid_range,omitempty"` + IncludeAndroidUser Listable[int] `json:"include_android_user,omitempty"` + IncludePackage Listable[string] `json:"include_package,omitempty"` + ExcludePackage Listable[string] `json:"exclude_package,omitempty"` + EndpointIndependentNat bool `json:"endpoint_independent_nat,omitempty"` + UDPTimeout int64 `json:"udp_timeout,omitempty"` + Stack string `json:"stack,omitempty"` + Platform *TunPlatformOptions `json:"platform,omitempty"` InboundOptions } From fac552a268b00feecdf6f670dba1b844606dc1c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 3 Nov 2023 01:47:25 +0800 Subject: [PATCH 79/87] Add support for v2ray http upgrade transport --- constant/v2ray.go | 9 +- docs/configuration/shared/v2ray-transport.md | 30 ++++ .../shared/v2ray-transport.zh.md | 30 ++++ option/v2ray_transport.go | 21 ++- test/v2ray_httpupgrade_test.go | 16 ++ transport/v2ray/transport.go | 6 +- transport/v2raygrpclite/client.go | 2 +- transport/v2raygrpclite/server.go | 8 +- transport/v2rayhttp/client.go | 2 +- transport/v2rayhttp/server.go | 8 +- transport/v2rayhttpupgrade/client.go | 118 +++++++++++++++ transport/v2rayhttpupgrade/server.go | 139 ++++++++++++++++++ 12 files changed, 369 insertions(+), 20 deletions(-) create mode 100644 test/v2ray_httpupgrade_test.go create mode 100644 transport/v2rayhttpupgrade/client.go create mode 100644 transport/v2rayhttpupgrade/server.go diff --git a/constant/v2ray.go b/constant/v2ray.go index 2243d736fb..c3089a6cf6 100644 --- a/constant/v2ray.go +++ b/constant/v2ray.go @@ -1,8 +1,9 @@ package constant const ( - V2RayTransportTypeHTTP = "http" - V2RayTransportTypeWebsocket = "ws" - V2RayTransportTypeQUIC = "quic" - V2RayTransportTypeGRPC = "grpc" + V2RayTransportTypeHTTP = "http" + V2RayTransportTypeWebsocket = "ws" + V2RayTransportTypeQUIC = "quic" + V2RayTransportTypeGRPC = "grpc" + V2RayTransportTypeHTTPUpgrade = "httpupgrade" ) diff --git a/docs/configuration/shared/v2ray-transport.md b/docs/configuration/shared/v2ray-transport.md index 4b5b6f6669..418ef28db2 100644 --- a/docs/configuration/shared/v2ray-transport.md +++ b/docs/configuration/shared/v2ray-transport.md @@ -15,6 +15,7 @@ Available transports: * WebSocket * QUIC * gRPC +* HTTPUpgrade !!! warning "Difference from v2ray-core" @@ -184,3 +185,32 @@ In standard gRPC client: If enabled, the client transport sends keepalive pings even with no active connections. If disabled, when there are no active connections, `idle_timeout` and `ping_timeout` will be ignored and no keepalive pings will be sent. Disabled by default. + +### HTTPUpgrade + +```json +{ + "type": "httpupgrade", + "host": "", + "path": "", + "headers": {} +} +``` + +#### host + +Host domain. + +The server will verify if not empty. + +#### path + +Path of HTTP request. + +The server will verify if not empty. + +#### headers + +Extra headers of HTTP request. + +The server will write in response if not empty. diff --git a/docs/configuration/shared/v2ray-transport.zh.md b/docs/configuration/shared/v2ray-transport.zh.md index deab558983..2ea93562d6 100644 --- a/docs/configuration/shared/v2ray-transport.zh.md +++ b/docs/configuration/shared/v2ray-transport.zh.md @@ -14,6 +14,7 @@ V2Ray Transport 是 v2ray 发明的一组私有协议,并污染了其他协议 * WebSocket * QUIC * gRPC +* HTTPUpgrade !!! warning "与 v2ray-core 的区别" @@ -183,3 +184,32 @@ gRPC 服务名称。 如果启用,客户端传输即使没有活动连接也会发送 keepalive ping。如果禁用,则在没有活动连接时,将忽略 `idle_timeout` 和 `ping_timeout`,并且不会发送 keepalive ping。 默认禁用。 + +### HTTPUpgrade + +```json +{ + "type": "httpupgrade", + "host": "", + "path": "", + "headers": {} +} +``` + +#### host + +主机域名。 + +默认服务器将验证。 + +#### path + +HTTP 请求路径 + +默认服务器将验证。 + +#### headers + +HTTP 请求的额外标头。 + +默认服务器将写入响应。 diff --git a/option/v2ray_transport.go b/option/v2ray_transport.go index 54b0de7913..63af28a371 100644 --- a/option/v2ray_transport.go +++ b/option/v2ray_transport.go @@ -7,11 +7,12 @@ import ( ) type _V2RayTransportOptions struct { - Type string `json:"type,omitempty"` - HTTPOptions V2RayHTTPOptions `json:"-"` - WebsocketOptions V2RayWebsocketOptions `json:"-"` - QUICOptions V2RayQUICOptions `json:"-"` - GRPCOptions V2RayGRPCOptions `json:"-"` + Type string `json:"type,omitempty"` + HTTPOptions V2RayHTTPOptions `json:"-"` + WebsocketOptions V2RayWebsocketOptions `json:"-"` + QUICOptions V2RayQUICOptions `json:"-"` + GRPCOptions V2RayGRPCOptions `json:"-"` + HTTPUpgradeOptions V2RayHTTPUpgradeOptions `json:"-"` } type V2RayTransportOptions _V2RayTransportOptions @@ -29,6 +30,8 @@ func (o V2RayTransportOptions) MarshalJSON() ([]byte, error) { v = o.QUICOptions case C.V2RayTransportTypeGRPC: v = o.GRPCOptions + case C.V2RayTransportTypeHTTPUpgrade: + v = o.HTTPUpgradeOptions default: return nil, E.New("unknown transport type: " + o.Type) } @@ -50,6 +53,8 @@ func (o *V2RayTransportOptions) UnmarshalJSON(bytes []byte) error { v = &o.QUICOptions case C.V2RayTransportTypeGRPC: v = &o.GRPCOptions + case C.V2RayTransportTypeHTTPUpgrade: + v = &o.HTTPUpgradeOptions default: return E.New("unknown transport type: " + o.Type) } @@ -85,3 +90,9 @@ type V2RayGRPCOptions struct { PermitWithoutStream bool `json:"permit_without_stream,omitempty"` ForceLite bool `json:"-"` // for test } + +type V2RayHTTPUpgradeOptions struct { + Host string `json:"host,omitempty"` + Path string `json:"path,omitempty"` + Headers HTTPHeader `json:"headers,omitempty"` +} diff --git a/test/v2ray_httpupgrade_test.go b/test/v2ray_httpupgrade_test.go new file mode 100644 index 0000000000..9a79aa3af9 --- /dev/null +++ b/test/v2ray_httpupgrade_test.go @@ -0,0 +1,16 @@ +package main + +import ( + "testing" + + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/option" +) + +func TestV2RayHTTPUpgrade(t *testing.T) { + t.Run("self", func(t *testing.T) { + testV2RayTransportSelf(t, &option.V2RayTransportOptions{ + Type: C.V2RayTransportTypeHTTPUpgrade, + }) + }) +} diff --git a/transport/v2ray/transport.go b/transport/v2ray/transport.go index 9dfee28119..deb8a7f0ee 100644 --- a/transport/v2ray/transport.go +++ b/transport/v2ray/transport.go @@ -8,6 +8,7 @@ import ( C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/transport/v2rayhttp" + "github.com/sagernet/sing-box/transport/v2rayhttpupgrade" "github.com/sagernet/sing-box/transport/v2raywebsocket" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" @@ -35,6 +36,8 @@ func NewServerTransport(ctx context.Context, options option.V2RayTransportOption return NewQUICServer(ctx, options.QUICOptions, tlsConfig, handler) case C.V2RayTransportTypeGRPC: return NewGRPCServer(ctx, options.GRPCOptions, tlsConfig, handler) + case C.V2RayTransportTypeHTTPUpgrade: + return v2rayhttpupgrade.NewServer(ctx, options.HTTPUpgradeOptions, tlsConfig, handler) default: return nil, E.New("unknown transport type: " + options.Type) } @@ -56,7 +59,8 @@ func NewClientTransport(ctx context.Context, dialer N.Dialer, serverAddr M.Socks return nil, C.ErrTLSRequired } return NewQUICClient(ctx, dialer, serverAddr, options.QUICOptions, tlsConfig) - + case C.V2RayTransportTypeHTTPUpgrade: + return v2rayhttpupgrade.NewClient(ctx, dialer, serverAddr, options.HTTPUpgradeOptions, tlsConfig) default: return nil, E.New("unknown transport type: " + options.Type) } diff --git a/transport/v2raygrpclite/client.go b/transport/v2raygrpclite/client.go index 8480ac533b..588a813385 100644 --- a/transport/v2raygrpclite/client.go +++ b/transport/v2raygrpclite/client.go @@ -100,7 +100,7 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) { conn.setup(nil, err) } else if response.StatusCode != 200 { response.Body.Close() - conn.setup(nil, E.New("unexpected status: ", response.StatusCode, " ", response.Status)) + conn.setup(nil, E.New("unexpected status: ", response.Status)) } else { conn.setup(response.Body, nil) } diff --git a/transport/v2raygrpclite/server.go b/transport/v2raygrpclite/server.go index a3025ca6e7..6d3e42ebe5 100644 --- a/transport/v2raygrpclite/server.go +++ b/transport/v2raygrpclite/server.go @@ -35,10 +35,6 @@ type Server struct { path string } -func (s *Server) Network() []string { - return []string{N.NetworkTCP} -} - func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig tls.ServerConfig, handler adapter.V2RayServerTransportHandler) (*Server, error) { server := &Server{ tlsConfig: tlsConfig, @@ -92,6 +88,10 @@ func (s *Server) invalidRequest(writer http.ResponseWriter, request *http.Reques s.handler.NewError(request.Context(), E.Cause(err, "process connection from ", request.RemoteAddr)) } +func (s *Server) Network() []string { + return []string{N.NetworkTCP} +} + func (s *Server) Serve(listener net.Listener) error { if s.tlsConfig != nil { if !common.Contains(s.tlsConfig.NextProtos(), http2.NextProtoTLS) { diff --git a/transport/v2rayhttp/client.go b/transport/v2rayhttp/client.go index f280eeef55..44c135ef6f 100644 --- a/transport/v2rayhttp/client.go +++ b/transport/v2rayhttp/client.go @@ -143,7 +143,7 @@ func (c *Client) dialHTTP2(ctx context.Context) (net.Conn, error) { conn.Setup(nil, err) } else if response.StatusCode != 200 { response.Body.Close() - conn.Setup(nil, E.New("unexpected status: ", response.StatusCode, " ", response.Status)) + conn.Setup(nil, E.New("unexpected status: ", response.Status)) } else { conn.Setup(response.Body, nil) } diff --git a/transport/v2rayhttp/server.go b/transport/v2rayhttp/server.go index dcfb07a6e5..ef5fffcd2d 100644 --- a/transport/v2rayhttp/server.go +++ b/transport/v2rayhttp/server.go @@ -40,10 +40,6 @@ type Server struct { headers http.Header } -func (s *Server) Network() []string { - return []string{N.NetworkTCP} -} - func NewServer(ctx context.Context, options option.V2RayHTTPOptions, tlsConfig tls.ServerConfig, handler adapter.V2RayServerTransportHandler) (*Server, error) { server := &Server{ ctx: ctx, @@ -153,6 +149,10 @@ func (s *Server) invalidRequest(writer http.ResponseWriter, request *http.Reques s.handler.NewError(request.Context(), E.Cause(err, "process connection from ", request.RemoteAddr)) } +func (s *Server) Network() []string { + return []string{N.NetworkTCP} +} + func (s *Server) Serve(listener net.Listener) error { if s.tlsConfig != nil { if len(s.tlsConfig.NextProtos()) == 0 { diff --git a/transport/v2rayhttpupgrade/client.go b/transport/v2rayhttpupgrade/client.go new file mode 100644 index 0000000000..c10e1b8fdc --- /dev/null +++ b/transport/v2rayhttpupgrade/client.go @@ -0,0 +1,118 @@ +package v2rayhttpupgrade + +import ( + std_bufio "bufio" + "context" + "net" + "net/http" + "net/url" + "strings" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" + E "github.com/sagernet/sing/common/exceptions" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + sHTTP "github.com/sagernet/sing/protocol/http" +) + +var _ adapter.V2RayClientTransport = (*Client)(nil) + +type Client struct { + dialer N.Dialer + tlsConfig tls.Config + serverAddr M.Socksaddr + requestURL url.URL + headers http.Header + host string +} + +func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayHTTPUpgradeOptions, tlsConfig tls.Config) (*Client, error) { + if tlsConfig != nil { + if len(tlsConfig.NextProtos()) == 0 { + tlsConfig.SetNextProtos([]string{"http/1.1"}) + } + } + var host string + if options.Host != "" { + host = options.Host + } else if tlsConfig != nil && tlsConfig.ServerName() != "" { + host = tlsConfig.ServerName() + } else { + host = serverAddr.String() + } + var requestURL url.URL + if tlsConfig == nil { + requestURL.Scheme = "http" + } else { + requestURL.Scheme = "https" + } + requestURL.Host = serverAddr.String() + requestURL.Path = options.Path + err := sHTTP.URLSetPath(&requestURL, options.Path) + if err != nil { + return nil, E.Cause(err, "parse path") + } + if !strings.HasPrefix(requestURL.Path, "/") { + requestURL.Path = "/" + requestURL.Path + } + headers := make(http.Header) + for key, value := range options.Headers { + headers[key] = value + } + return &Client{ + dialer: dialer, + tlsConfig: tlsConfig, + serverAddr: serverAddr, + requestURL: requestURL, + headers: headers, + host: host, + }, nil +} + +func (c *Client) DialContext(ctx context.Context) (net.Conn, error) { + conn, err := c.dialer.DialContext(ctx, N.NetworkTCP, c.serverAddr) + if err != nil { + return nil, err + } + if c.tlsConfig != nil { + conn, err = tls.ClientHandshake(ctx, conn, c.tlsConfig) + if err != nil { + return nil, err + } + } + request := &http.Request{ + Method: http.MethodGet, + URL: &c.requestURL, + Header: c.headers.Clone(), + Host: c.host, + } + request.Header.Set("Connection", "Upgrade") + request.Header.Set("Upgrade", "websocket") + err = request.Write(conn) + if err != nil { + return nil, err + } + bufReader := std_bufio.NewReader(conn) + response, err := http.ReadResponse(bufReader, request) + if err != nil { + return nil, err + } + if response.StatusCode != 101 || + !strings.EqualFold(response.Header.Get("Connection"), "upgrade") || + !strings.EqualFold(response.Header.Get("Upgrade"), "websocket") { + return nil, E.New("unexpected status: ", response.Status) + } + if bufReader.Buffered() > 0 { + buffer := buf.NewSize(bufReader.Buffered()) + _, err = buffer.ReadFullFrom(bufReader, buffer.Len()) + if err != nil { + return nil, err + } + conn = bufio.NewCachedConn(conn, buffer) + } + return conn, nil +} diff --git a/transport/v2rayhttpupgrade/server.go b/transport/v2rayhttpupgrade/server.go new file mode 100644 index 0000000000..653778f91d --- /dev/null +++ b/transport/v2rayhttpupgrade/server.go @@ -0,0 +1,139 @@ +package v2rayhttpupgrade + +import ( + "context" + "net" + "net/http" + "os" + "strings" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/tls" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common" + E "github.com/sagernet/sing/common/exceptions" + 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" +) + +var _ adapter.V2RayServerTransport = (*Server)(nil) + +type Server struct { + ctx context.Context + tlsConfig tls.ServerConfig + handler adapter.V2RayServerTransportHandler + httpServer *http.Server + host string + path string + headers http.Header +} + +func NewServer(ctx context.Context, options option.V2RayHTTPUpgradeOptions, tlsConfig tls.ServerConfig, handler adapter.V2RayServerTransportHandler) (*Server, error) { + server := &Server{ + ctx: ctx, + tlsConfig: tlsConfig, + handler: handler, + host: options.Host, + path: options.Path, + headers: options.Headers.Build(), + } + if !strings.HasPrefix(server.path, "/") { + server.path = "/" + server.path + } + server.httpServer = &http.Server{ + Handler: server, + ReadHeaderTimeout: C.TCPTimeout, + MaxHeaderBytes: http.DefaultMaxHeaderBytes, + BaseContext: func(net.Listener) context.Context { + return ctx + }, + TLSNextProto: make(map[string]func(*http.Server, *tls.STDConn, http.Handler)), + } + return server, nil +} + +type httpFlusher interface { + FlushError() error +} + +func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) { + host := request.Host + if len(s.host) > 0 && host != s.host { + s.invalidRequest(writer, request, http.StatusBadRequest, E.New("bad host: ", host)) + return + } + if !strings.HasPrefix(request.URL.Path, s.path) { + s.invalidRequest(writer, request, http.StatusNotFound, E.New("bad path: ", request.URL.Path)) + return + } + if request.Method != http.MethodGet { + s.invalidRequest(writer, request, http.StatusNotFound, E.New("bad method: ", request.Method)) + return + } + if !strings.EqualFold(request.Header.Get("Connection"), "upgrade") { + s.invalidRequest(writer, request, http.StatusNotFound, E.New("not a upgrade request")) + return + } + if !strings.EqualFold(request.Header.Get("Upgrade"), "websocket") { + s.invalidRequest(writer, request, http.StatusNotFound, E.New("not a websocket request")) + return + } + if request.Header.Get("Sec-WebSocket-Key") != "" { + s.invalidRequest(writer, request, http.StatusNotFound, E.New("real websocket request received")) + return + } + writer.Header().Set("Connection", "upgrade") + writer.Header().Set("Upgrade", "websocket") + writer.WriteHeader(http.StatusSwitchingProtocols) + if flusher, isFlusher := writer.(httpFlusher); isFlusher { + err := flusher.FlushError() + if err != nil { + s.invalidRequest(writer, request, http.StatusInternalServerError, E.New("flush response")) + } + } + hijacker, canHijack := writer.(http.Hijacker) + if !canHijack { + s.invalidRequest(writer, request, http.StatusInternalServerError, E.New("invalid connection, maybe HTTP/2")) + return + } + conn, _, err := hijacker.Hijack() + if err != nil { + s.invalidRequest(writer, request, http.StatusInternalServerError, E.Cause(err, "hijack failed")) + return + } + var metadata M.Metadata + metadata.Source = sHttp.SourceAddress(request) + s.handler.NewConnection(request.Context(), conn, metadata) +} + +func (s *Server) invalidRequest(writer http.ResponseWriter, request *http.Request, statusCode int, err error) { + if statusCode > 0 { + writer.WriteHeader(statusCode) + } + s.handler.NewError(request.Context(), E.Cause(err, "process connection from ", request.RemoteAddr)) +} + +func (s *Server) Network() []string { + return []string{N.NetworkTCP} +} + +func (s *Server) Serve(listener net.Listener) error { + if s.tlsConfig != nil { + if len(s.tlsConfig.NextProtos()) == 0 { + s.tlsConfig.SetNextProtos([]string{"http/1.1"}) + } + listener = aTLS.NewListener(listener, s.tlsConfig) + } + return s.httpServer.Serve(listener) +} + +func (s *Server) ServePacket(listener net.PacketConn) error { + return os.ErrInvalid +} + +func (s *Server) Close() error { + return common.Close(common.PtrOrNil(s.httpServer)) +} From d183372e1847c73b5bb5022063f2a979705ce3c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 8 Nov 2023 12:09:22 +0800 Subject: [PATCH 80/87] Migrate multiplex and UoT server to inbound & Add tcp-brutal support for multiplex --- adapter/conn_router.go | 104 ++++++ adapter/router.go | 5 +- common/mux/client.go | 23 +- common/mux/protocol.go | 14 - common/mux/router.go | 65 ++++ common/mux/v2ray_legacy.go | 32 ++ common/uot/router.go | 53 +++ constant/speed.go | 3 + docs/configuration/inbound/hysteria2.zh.md | 2 +- docs/configuration/inbound/shadowsocks.md | 13 +- docs/configuration/inbound/shadowsocks.zh.md | 15 +- docs/configuration/inbound/trojan.md | 5 + docs/configuration/inbound/trojan.zh.md | 5 + docs/configuration/inbound/tuic.zh.md | 2 +- docs/configuration/inbound/vless.md | 5 + docs/configuration/inbound/vless.zh.md | 5 + docs/configuration/inbound/vmess.md | 5 + docs/configuration/inbound/vmess.zh.md | 5 + docs/configuration/outbound/hysteria2.zh.md | 2 +- docs/configuration/outbound/shadowsocks.md | 2 +- docs/configuration/outbound/shadowsocks.zh.md | 2 +- docs/configuration/outbound/trojan.md | 2 +- docs/configuration/outbound/trojan.zh.md | 2 +- docs/configuration/outbound/tuic.zh.md | 2 +- docs/configuration/outbound/vless.md | 5 + docs/configuration/outbound/vless.zh.md | 5 + docs/configuration/outbound/vmess.md | 4 +- docs/configuration/outbound/vmess.zh.md | 2 +- docs/configuration/shared/multiplex.md | 35 +- docs/configuration/shared/multiplex.zh.md | 35 +- docs/configuration/shared/tcp-brutal.md | 28 ++ docs/configuration/shared/tcp-brutal.zh.md | 28 ++ go.mod | 2 +- go.sum | 4 +- inbound/default.go | 2 +- inbound/http.go | 3 +- inbound/mixed.go | 3 +- inbound/naive.go | 3 +- inbound/shadowsocks.go | 12 +- inbound/shadowsocks_multi.go | 14 +- inbound/shadowsocks_relay.go | 9 +- inbound/socks.go | 3 +- inbound/trojan.go | 5 + inbound/tuic.go | 3 +- inbound/vless.go | 10 +- inbound/vmess.go | 11 +- mkdocs.yml | 1 + option/multiplex.go | 23 ++ option/outbound.go | 9 - option/shadowsocks.go | 15 +- option/simple.go | 10 +- option/trojan.go | 11 +- option/vless.go | 21 +- option/vmess.go | 27 +- outbound/shadowsocks.go | 4 +- outbound/socks.go | 2 +- outbound/trojan.go | 2 +- outbound/vless.go | 2 +- outbound/vmess.go | 2 +- route/router.go | 27 +- test/brutal_test.go | 346 ++++++++++++++++++ test/go.mod | 16 +- test/go.sum | 33 +- test/mux_test.go | 21 +- test/shadowsocks_test.go | 2 +- 65 files changed, 997 insertions(+), 176 deletions(-) create mode 100644 adapter/conn_router.go delete mode 100644 common/mux/protocol.go create mode 100644 common/mux/router.go create mode 100644 common/mux/v2ray_legacy.go create mode 100644 common/uot/router.go create mode 100644 constant/speed.go create mode 100644 docs/configuration/shared/tcp-brutal.md create mode 100644 docs/configuration/shared/tcp-brutal.zh.md create mode 100644 option/multiplex.go create mode 100644 test/brutal_test.go diff --git a/adapter/conn_router.go b/adapter/conn_router.go new file mode 100644 index 0000000000..a87c45e8c5 --- /dev/null +++ b/adapter/conn_router.go @@ -0,0 +1,104 @@ +package adapter + +import ( + "context" + "net" + + "github.com/sagernet/sing/common/logger" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" +) + +type ConnectionRouter interface { + RouteConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error + RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error +} + +func NewRouteHandler( + metadata InboundContext, + router ConnectionRouter, + logger logger.ContextLogger, +) UpstreamHandlerAdapter { + return &routeHandlerWrapper{ + metadata: metadata, + router: router, + logger: logger, + } +} + +func NewRouteContextHandler( + router ConnectionRouter, + logger logger.ContextLogger, +) UpstreamHandlerAdapter { + return &routeContextHandlerWrapper{ + router: router, + logger: logger, + } +} + +var _ UpstreamHandlerAdapter = (*routeHandlerWrapper)(nil) + +type routeHandlerWrapper struct { + metadata InboundContext + router ConnectionRouter + logger logger.ContextLogger +} + +func (w *routeHandlerWrapper) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { + myMetadata := w.metadata + if metadata.Source.IsValid() { + myMetadata.Source = metadata.Source + } + if metadata.Destination.IsValid() { + myMetadata.Destination = metadata.Destination + } + return w.router.RouteConnection(ctx, conn, myMetadata) +} + +func (w *routeHandlerWrapper) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error { + myMetadata := w.metadata + if metadata.Source.IsValid() { + myMetadata.Source = metadata.Source + } + if metadata.Destination.IsValid() { + myMetadata.Destination = metadata.Destination + } + return w.router.RoutePacketConnection(ctx, conn, myMetadata) +} + +func (w *routeHandlerWrapper) NewError(ctx context.Context, err error) { + w.logger.ErrorContext(ctx, err) +} + +var _ UpstreamHandlerAdapter = (*routeContextHandlerWrapper)(nil) + +type routeContextHandlerWrapper struct { + router ConnectionRouter + logger logger.ContextLogger +} + +func (w *routeContextHandlerWrapper) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { + myMetadata := ContextFrom(ctx) + if metadata.Source.IsValid() { + myMetadata.Source = metadata.Source + } + if metadata.Destination.IsValid() { + myMetadata.Destination = metadata.Destination + } + return w.router.RouteConnection(ctx, conn, *myMetadata) +} + +func (w *routeContextHandlerWrapper) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error { + myMetadata := ContextFrom(ctx) + if metadata.Source.IsValid() { + myMetadata.Source = metadata.Source + } + if metadata.Destination.IsValid() { + myMetadata.Destination = metadata.Destination + } + return w.router.RoutePacketConnection(ctx, conn, *myMetadata) +} + +func (w *routeContextHandlerWrapper) NewError(ctx context.Context, err error) { + w.logger.ErrorContext(ctx, err) +} diff --git a/adapter/router.go b/adapter/router.go index ec23d9311f..ab2d916c65 100644 --- a/adapter/router.go +++ b/adapter/router.go @@ -2,14 +2,12 @@ package adapter import ( "context" - "net" "net/netip" "github.com/sagernet/sing-box/common/geoip" "github.com/sagernet/sing-dns" "github.com/sagernet/sing-tun" "github.com/sagernet/sing/common/control" - N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/service" mdns "github.com/miekg/dns" @@ -24,8 +22,7 @@ type Router interface { FakeIPStore() FakeIPStore - RouteConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error - RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error + ConnectionRouter GeoIPReader() *geoip.Reader LoadGeosite(code string) (Rule, error) diff --git a/common/mux/client.go b/common/mux/client.go index 36dd31379b..6f201deac4 100644 --- a/common/mux/client.go +++ b/common/mux/client.go @@ -1,21 +1,42 @@ package mux import ( + C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-mux" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" N "github.com/sagernet/sing/common/network" ) -func NewClientWithOptions(dialer N.Dialer, options option.MultiplexOptions) (*Client, error) { +type Client = mux.Client + +func NewClientWithOptions(dialer N.Dialer, logger logger.Logger, options option.OutboundMultiplexOptions) (*Client, error) { if !options.Enabled { return nil, nil } + var brutalOptions mux.BrutalOptions + if options.Brutal != nil && options.Brutal.Enabled { + brutalOptions = mux.BrutalOptions{ + Enabled: true, + SendBPS: uint64(options.Brutal.UpMbps * C.MbpsToBps), + ReceiveBPS: uint64(options.Brutal.DownMbps * C.MbpsToBps), + } + if brutalOptions.SendBPS < mux.BrutalMinSpeedBPS { + return nil, E.New("brutal: invalid upload speed") + } + if brutalOptions.ReceiveBPS < mux.BrutalMinSpeedBPS { + return nil, E.New("brutal: invalid download speed") + } + } return mux.NewClient(mux.Options{ Dialer: dialer, + Logger: logger, Protocol: options.Protocol, MaxConnections: options.MaxConnections, MinStreams: options.MinStreams, MaxStreams: options.MaxStreams, Padding: options.Padding, + Brutal: brutalOptions, }) } diff --git a/common/mux/protocol.go b/common/mux/protocol.go deleted file mode 100644 index abb0e26865..0000000000 --- a/common/mux/protocol.go +++ /dev/null @@ -1,14 +0,0 @@ -package mux - -import ( - "github.com/sagernet/sing-mux" -) - -type ( - Client = mux.Client -) - -var ( - Destination = mux.Destination - HandleConnection = mux.HandleConnection -) diff --git a/common/mux/router.go b/common/mux/router.go new file mode 100644 index 0000000000..8a2296852b --- /dev/null +++ b/common/mux/router.go @@ -0,0 +1,65 @@ +package mux + +import ( + "context" + "net" + + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing-mux" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" + N "github.com/sagernet/sing/common/network" +) + +type Router struct { + router adapter.ConnectionRouter + service *mux.Service +} + +func NewRouterWithOptions(router adapter.ConnectionRouter, logger logger.ContextLogger, options option.InboundMultiplexOptions) (adapter.ConnectionRouter, error) { + if !options.Enabled { + return router, nil + } + var brutalOptions mux.BrutalOptions + if options.Brutal != nil && options.Brutal.Enabled { + brutalOptions = mux.BrutalOptions{ + Enabled: true, + SendBPS: uint64(options.Brutal.UpMbps * C.MbpsToBps), + ReceiveBPS: uint64(options.Brutal.DownMbps * C.MbpsToBps), + } + if brutalOptions.SendBPS < mux.BrutalMinSpeedBPS { + return nil, E.New("brutal: invalid upload speed") + } + if brutalOptions.ReceiveBPS < mux.BrutalMinSpeedBPS { + return nil, E.New("brutal: invalid download speed") + } + } + service, err := mux.NewService(mux.ServiceOptions{ + NewStreamContext: func(ctx context.Context, conn net.Conn) context.Context { + return log.ContextWithNewID(ctx) + }, + Logger: logger, + Handler: adapter.NewRouteContextHandler(router, logger), + Padding: options.Padding, + Brutal: brutalOptions, + }) + if err != nil { + return nil, err + } + return &Router{router, service}, nil +} + +func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { + if metadata.Destination == mux.Destination { + return r.service.NewConnection(adapter.WithContext(ctx, &metadata), conn, adapter.UpstreamMetadata(metadata)) + } else { + return r.router.RouteConnection(ctx, conn, metadata) + } +} + +func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { + return r.router.RoutePacketConnection(ctx, conn, metadata) +} diff --git a/common/mux/v2ray_legacy.go b/common/mux/v2ray_legacy.go new file mode 100644 index 0000000000..f53aff2db4 --- /dev/null +++ b/common/mux/v2ray_legacy.go @@ -0,0 +1,32 @@ +package mux + +import ( + "context" + "net" + + "github.com/sagernet/sing-box/adapter" + vmess "github.com/sagernet/sing-vmess" + "github.com/sagernet/sing/common/logger" + N "github.com/sagernet/sing/common/network" +) + +type V2RayLegacyRouter struct { + router adapter.ConnectionRouter + logger logger.ContextLogger +} + +func NewV2RayLegacyRouter(router adapter.ConnectionRouter, logger logger.ContextLogger) adapter.ConnectionRouter { + return &V2RayLegacyRouter{router, logger} +} + +func (r *V2RayLegacyRouter) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { + if metadata.Destination.Fqdn == vmess.MuxDestination.Fqdn { + r.logger.InfoContext(ctx, "inbound legacy multiplex connection") + return vmess.HandleMuxConnection(ctx, conn, adapter.NewRouteHandler(metadata, r.router, r.logger)) + } + return r.router.RouteConnection(ctx, conn, metadata) +} + +func (r *V2RayLegacyRouter) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { + return r.router.RoutePacketConnection(ctx, conn, metadata) +} diff --git a/common/uot/router.go b/common/uot/router.go new file mode 100644 index 0000000000..fb2d23d557 --- /dev/null +++ b/common/uot/router.go @@ -0,0 +1,53 @@ +package uot + +import ( + "context" + "net" + "net/netip" + + "github.com/sagernet/sing-box/adapter" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/common/uot" +) + +var _ adapter.ConnectionRouter = (*Router)(nil) + +type Router struct { + router adapter.ConnectionRouter + logger logger.ContextLogger +} + +func NewRouter(router adapter.ConnectionRouter, logger logger.ContextLogger) *Router { + return &Router{router, logger} +} + +func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { + switch metadata.Destination.Fqdn { + case uot.MagicAddress: + request, err := uot.ReadRequest(conn) + if err != nil { + return E.Cause(err, "read UoT request") + } + if request.IsConnect { + r.logger.InfoContext(ctx, "inbound UoT connect connection to ", request.Destination) + } else { + r.logger.InfoContext(ctx, "inbound UoT connection to ", request.Destination) + } + metadata.Domain = metadata.Destination.Fqdn + metadata.Destination = request.Destination + return r.router.RoutePacketConnection(ctx, uot.NewConn(conn, *request), metadata) + case uot.LegacyMagicAddress: + r.logger.InfoContext(ctx, "inbound legacy UoT connection") + metadata.Domain = metadata.Destination.Fqdn + metadata.Destination = M.Socksaddr{Addr: netip.IPv4Unspecified()} + return r.RoutePacketConnection(ctx, uot.NewConn(conn, uot.Request{}), metadata) + } + return r.router.RouteConnection(ctx, conn, metadata) +} + +func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { + return r.router.RoutePacketConnection(ctx, conn, metadata) +} diff --git a/constant/speed.go b/constant/speed.go new file mode 100644 index 0000000000..7a2ec130a2 --- /dev/null +++ b/constant/speed.go @@ -0,0 +1,3 @@ +package constant + +const MbpsToBps = 125000 diff --git a/docs/configuration/inbound/hysteria2.zh.md b/docs/configuration/inbound/hysteria2.zh.md index d21a13d09e..f43188c09f 100644 --- a/docs/configuration/inbound/hysteria2.zh.md +++ b/docs/configuration/inbound/hysteria2.zh.md @@ -62,7 +62,7 @@ Hysteria 用户 #### ignore_client_bandwidth -命令客户端使用 BBR 流量控制算法而不是 Hysteria CC。 +命令客户端使用 BBR 拥塞控制算法而不是 Hysteria CC。 与 `up_mbps` 和 `down_mbps` 冲突。 diff --git a/docs/configuration/inbound/shadowsocks.md b/docs/configuration/inbound/shadowsocks.md index 0349d01c72..415a59138e 100644 --- a/docs/configuration/inbound/shadowsocks.md +++ b/docs/configuration/inbound/shadowsocks.md @@ -8,7 +8,8 @@ ... // Listen Fields "method": "2022-blake3-aes-128-gcm", - "password": "8JCsPssfgS8tiRwiMlhARg==" + "password": "8JCsPssfgS8tiRwiMlhARg==", + "multiplex": {} } ``` @@ -23,7 +24,8 @@ "name": "sekai", "password": "PCD2Z4o12bKUoFa3cC97Hw==" } - ] + ], + "multiplex": {} } ``` @@ -41,7 +43,8 @@ "server_port": 8080, "password": "PCD2Z4o12bKUoFa3cC97Hw==" } - ] + ], + "multiplex": {} } ``` @@ -82,3 +85,7 @@ Both if empty. | none | / | | 2022 methods | `sing-box generate rand --base64 ` | | other methods | any string | + +#### multiplex + +See [Multiplex](/configuration/shared/multiplex#inbound) for details. diff --git a/docs/configuration/inbound/shadowsocks.zh.md b/docs/configuration/inbound/shadowsocks.zh.md index 11edd05756..36a292bb0c 100644 --- a/docs/configuration/inbound/shadowsocks.zh.md +++ b/docs/configuration/inbound/shadowsocks.zh.md @@ -8,7 +8,8 @@ ... // 监听字段 "method": "2022-blake3-aes-128-gcm", - "password": "8JCsPssfgS8tiRwiMlhARg==" + "password": "8JCsPssfgS8tiRwiMlhARg==", + "multiplex": {} } ``` @@ -23,7 +24,8 @@ "name": "sekai", "password": "PCD2Z4o12bKUoFa3cC97Hw==" } - ] + ], + "multiplex": {} } ``` @@ -41,7 +43,8 @@ "server_port": 8080, "password": "PCD2Z4o12bKUoFa3cC97Hw==" } - ] + ], + "multiplex": {} } ``` @@ -81,4 +84,8 @@ See [Listen Fields](/configuration/shared/listen) for details. |---------------|------------------------------------------| | none | / | | 2022 methods | `sing-box generate rand --base64 <密钥长度>` | -| other methods | 任意字符串 | \ No newline at end of file +| other methods | 任意字符串 | + +#### multiplex + +参阅 [多路复用](/zh/configuration/shared/multiplex#inbound)。 diff --git a/docs/configuration/inbound/trojan.md b/docs/configuration/inbound/trojan.md index cdaf8f5030..787d2b11bf 100644 --- a/docs/configuration/inbound/trojan.md +++ b/docs/configuration/inbound/trojan.md @@ -24,6 +24,7 @@ "server_port": 8081 } }, + "multiplex": {}, "transport": {} } ``` @@ -58,6 +59,10 @@ Fallback server configuration for specified ALPN. If not empty, TLS fallback requests with ALPN not in this table will be rejected. +#### multiplex + +See [Multiplex](/configuration/shared/multiplex#inbound) for details. + #### transport V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport). diff --git a/docs/configuration/inbound/trojan.zh.md b/docs/configuration/inbound/trojan.zh.md index 6cc8c4756e..f52422af82 100644 --- a/docs/configuration/inbound/trojan.zh.md +++ b/docs/configuration/inbound/trojan.zh.md @@ -24,6 +24,7 @@ "server_port": 8081 } }, + "multiplex": {}, "transport": {} } ``` @@ -60,6 +61,10 @@ TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。 如果不为空,ALPN 不在此列表中的 TLS 回退请求将被拒绝。 +#### multiplex + +参阅 [多路复用](/zh/configuration/shared/multiplex#inbound)。 + #### transport V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。 \ No newline at end of file diff --git a/docs/configuration/inbound/tuic.zh.md b/docs/configuration/inbound/tuic.zh.md index 9a6f395e37..60a7ccf6fd 100644 --- a/docs/configuration/inbound/tuic.zh.md +++ b/docs/configuration/inbound/tuic.zh.md @@ -48,7 +48,7 @@ TUIC 用户密码 #### congestion_control -QUIC 流量控制算法 +QUIC 拥塞控制算法 可选值: `cubic`, `new_reno`, `bbr` diff --git a/docs/configuration/inbound/vless.md b/docs/configuration/inbound/vless.md index a8d0c426da..f78ae01c19 100644 --- a/docs/configuration/inbound/vless.md +++ b/docs/configuration/inbound/vless.md @@ -15,6 +15,7 @@ } ], "tls": {}, + "multiplex": {}, "transport": {} } ``` @@ -49,6 +50,10 @@ Available values: TLS configuration, see [TLS](/configuration/shared/tls/#inbound). +#### multiplex + +See [Multiplex](/configuration/shared/multiplex#inbound) for details. + #### transport V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport). diff --git a/docs/configuration/inbound/vless.zh.md b/docs/configuration/inbound/vless.zh.md index 3ce1261c9a..4beecd6faa 100644 --- a/docs/configuration/inbound/vless.zh.md +++ b/docs/configuration/inbound/vless.zh.md @@ -15,6 +15,7 @@ } ], "tls": {}, + "multiplex": {}, "transport": {} } ``` @@ -49,6 +50,10 @@ VLESS 子协议。 TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。 +#### multiplex + +参阅 [多路复用](/zh/configuration/shared/multiplex#inbound)。 + #### transport V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。 diff --git a/docs/configuration/inbound/vmess.md b/docs/configuration/inbound/vmess.md index 2439d6e148..0e559d1ef6 100644 --- a/docs/configuration/inbound/vmess.md +++ b/docs/configuration/inbound/vmess.md @@ -15,6 +15,7 @@ } ], "tls": {}, + "multiplex": {}, "transport": {} } ``` @@ -44,6 +45,10 @@ VMess users. TLS configuration, see [TLS](/configuration/shared/tls/#inbound). +#### multiplex + +See [Multiplex](/configuration/shared/multiplex#inbound) for details. + #### transport V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport). diff --git a/docs/configuration/inbound/vmess.zh.md b/docs/configuration/inbound/vmess.zh.md index ae90145b1c..9554ab79e0 100644 --- a/docs/configuration/inbound/vmess.zh.md +++ b/docs/configuration/inbound/vmess.zh.md @@ -15,6 +15,7 @@ } ], "tls": {}, + "multiplex": {}, "transport": {} } ``` @@ -44,6 +45,10 @@ VMess 用户。 TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。 +#### multiplex + +参阅 [多路复用](/zh/configuration/shared/multiplex#inbound)。 + #### transport V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。 diff --git a/docs/configuration/outbound/hysteria2.zh.md b/docs/configuration/outbound/hysteria2.zh.md index e9d1cb2d30..1e490a63af 100644 --- a/docs/configuration/outbound/hysteria2.zh.md +++ b/docs/configuration/outbound/hysteria2.zh.md @@ -44,7 +44,7 @@ 最大带宽。 -如果为空,将使用 BBR 流量控制算法而不是 Hysteria CC。 +如果为空,将使用 BBR 拥塞控制算法而不是 Hysteria CC。 #### obfs.type diff --git a/docs/configuration/outbound/shadowsocks.md b/docs/configuration/outbound/shadowsocks.md index e004d77b1a..6fc9348408 100644 --- a/docs/configuration/outbound/shadowsocks.md +++ b/docs/configuration/outbound/shadowsocks.md @@ -95,7 +95,7 @@ Conflict with `multiplex`. #### multiplex -Multiplex configuration, see [Multiplex](/configuration/shared/multiplex). +See [Multiplex](/configuration/shared/multiplex#outbound) for details. ### Dial Fields diff --git a/docs/configuration/outbound/shadowsocks.zh.md b/docs/configuration/outbound/shadowsocks.zh.md index 16c627e325..6d9b7a5c85 100644 --- a/docs/configuration/outbound/shadowsocks.zh.md +++ b/docs/configuration/outbound/shadowsocks.zh.md @@ -95,7 +95,7 @@ UDP over TCP 配置。 #### multiplex -多路复用配置, 参阅 [多路复用](/zh/configuration/shared/multiplex)。 +参阅 [多路复用](/zh/configuration/shared/multiplex#outbound)。 ### 拨号字段 diff --git a/docs/configuration/outbound/trojan.md b/docs/configuration/outbound/trojan.md index cee13401a6..34b16c7d38 100644 --- a/docs/configuration/outbound/trojan.md +++ b/docs/configuration/outbound/trojan.md @@ -51,7 +51,7 @@ TLS configuration, see [TLS](/configuration/shared/tls/#outbound). #### multiplex -Multiplex configuration, see [Multiplex](/configuration/shared/multiplex). +See [Multiplex](/configuration/shared/multiplex#outbound) for details. #### transport diff --git a/docs/configuration/outbound/trojan.zh.md b/docs/configuration/outbound/trojan.zh.md index ac9191873f..55bb970911 100644 --- a/docs/configuration/outbound/trojan.zh.md +++ b/docs/configuration/outbound/trojan.zh.md @@ -51,7 +51,7 @@ TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#outbound)。 #### multiplex -多路复用配置, 参阅 [多路复用](/zh/configuration/shared/multiplex)。 +参阅 [多路复用](/zh/configuration/shared/multiplex#outbound)。 #### transport diff --git a/docs/configuration/outbound/tuic.zh.md b/docs/configuration/outbound/tuic.zh.md index ce5a18999b..11d44448af 100644 --- a/docs/configuration/outbound/tuic.zh.md +++ b/docs/configuration/outbound/tuic.zh.md @@ -51,7 +51,7 @@ TUIC 用户密码 #### congestion_control -QUIC 流量控制算法 +QUIC 拥塞控制算法 可选值: `cubic`, `new_reno`, `bbr` diff --git a/docs/configuration/outbound/vless.md b/docs/configuration/outbound/vless.md index 5fc69bf407..0d2fadc646 100644 --- a/docs/configuration/outbound/vless.md +++ b/docs/configuration/outbound/vless.md @@ -12,6 +12,7 @@ "network": "tcp", "tls": {}, "packet_encoding": "", + "multiplex": {}, "transport": {}, ... // Dial Fields @@ -68,6 +69,10 @@ UDP packet encoding, xudp is used by default. | packetaddr | Supported by v2ray 5+ | | xudp | Supported by xray | +#### multiplex + +See [Multiplex](/configuration/shared/multiplex#outbound) for details. + #### transport V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport). diff --git a/docs/configuration/outbound/vless.zh.md b/docs/configuration/outbound/vless.zh.md index 75713bf514..3d3f24ee65 100644 --- a/docs/configuration/outbound/vless.zh.md +++ b/docs/configuration/outbound/vless.zh.md @@ -12,6 +12,7 @@ "network": "tcp", "tls": {}, "packet_encoding": "", + "multiplex": {}, "transport": {}, ... // 拨号字段 @@ -68,6 +69,10 @@ UDP 包编码,默认使用 xudp。 | packetaddr | 由 v2ray 5+ 支持 | | xudp | 由 xray 支持 | +#### multiplex + +参阅 [多路复用](/zh/configuration/shared/multiplex#outbound)。 + #### transport V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。 diff --git a/docs/configuration/outbound/vmess.md b/docs/configuration/outbound/vmess.md index 4522047724..ac29559e72 100644 --- a/docs/configuration/outbound/vmess.md +++ b/docs/configuration/outbound/vmess.md @@ -15,8 +15,8 @@ "network": "tcp", "tls": {}, "packet_encoding": "", - "multiplex": {}, "transport": {}, + "multiplex": {}, ... // Dial Fields } @@ -96,7 +96,7 @@ UDP packet encoding. #### multiplex -Multiplex configuration, see [Multiplex](/configuration/shared/multiplex). +See [Multiplex](/configuration/shared/multiplex#outbound) for details. #### transport diff --git a/docs/configuration/outbound/vmess.zh.md b/docs/configuration/outbound/vmess.zh.md index 16fcfc7acf..dbf1612e51 100644 --- a/docs/configuration/outbound/vmess.zh.md +++ b/docs/configuration/outbound/vmess.zh.md @@ -96,7 +96,7 @@ UDP 包编码。 #### multiplex -多路复用配置, 参阅 [多路复用](/zh/configuration/shared/multiplex)。 +参阅 [多路复用](/zh/configuration/shared/multiplex#outbound)。 #### transport diff --git a/docs/configuration/shared/multiplex.md b/docs/configuration/shared/multiplex.md index 833efaff3f..eab2116381 100644 --- a/docs/configuration/shared/multiplex.md +++ b/docs/configuration/shared/multiplex.md @@ -1,8 +1,14 @@ -### Server Requirements +### Inbound -`sing-box` :) +```json +{ + "enabled": true, + "padding": false, + "brutal": {} +} +``` -### Structure +### Outbound ```json { @@ -11,11 +17,27 @@ "max_connections": 4, "min_streams": 4, "max_streams": 0, - "padding": false + "padding": false, + "brutal": {} } ``` -### Fields + +### Inbound Fields + +#### enabled + +Enable multiplex support. + +#### padding + +If enabled, non-padded connections will be rejected. + +#### brutal + +See [TCP Brutal](/configuration/shared/tcp-brutal) for details. + +### Outbound Fields #### enabled @@ -59,3 +81,6 @@ Conflict with `max_connections` and `min_streams`. Enable padding. +#### brutal + +See [TCP Brutal](/configuration/shared/tcp-brutal) for details. diff --git a/docs/configuration/shared/multiplex.zh.md b/docs/configuration/shared/multiplex.zh.md index 99a0ba0354..ae1cad64e7 100644 --- a/docs/configuration/shared/multiplex.zh.md +++ b/docs/configuration/shared/multiplex.zh.md @@ -1,8 +1,14 @@ -### 服务器要求 +### 入站 -`sing-box` :) +```json +{ + "enabled": true, + "padding": false, + "brutal": {} +} +``` -### 结构 +### 出站 ```json { @@ -10,11 +16,27 @@ "protocol": "smux", "max_connections": 4, "min_streams": 4, - "max_streams": 0 + "max_streams": 0, + "padding": false, + "brutal": {} } ``` -### 字段 +### 入站字段 + +#### enabled + +启用多路复用支持。 + +#### padding + +如果启用,将拒绝非填充连接。 + +#### brutal + +参阅 [TCP Brutal](/zh/configuration/shared/tcp-brutal)。 + +### 出站字段 #### enabled @@ -58,3 +80,6 @@ 启用填充。 +#### brutal + +参阅 [TCP Brutal](/zh/configuration/shared/tcp-brutal)。 \ No newline at end of file diff --git a/docs/configuration/shared/tcp-brutal.md b/docs/configuration/shared/tcp-brutal.md new file mode 100644 index 0000000000..d248a463f1 --- /dev/null +++ b/docs/configuration/shared/tcp-brutal.md @@ -0,0 +1,28 @@ +### Server Requirements + +* Linux +* `brutal` congestion control algorithm kernel module installed + +See [tcp-brutal](https://github.com/apernet/tcp-brutal) for details. + +### Structure + +```json +{ + "enabled": true, + "up_mbps": 100, + "down_mbps": 100 +} +``` + +### Fields + +#### enabled + +Enable TCP Brutal congestion control algorithm。 + +#### up_mbps, down_mbps + +==Required== + +Upload and download bandwidth, in Mbps. \ No newline at end of file diff --git a/docs/configuration/shared/tcp-brutal.zh.md b/docs/configuration/shared/tcp-brutal.zh.md new file mode 100644 index 0000000000..efb8c51f60 --- /dev/null +++ b/docs/configuration/shared/tcp-brutal.zh.md @@ -0,0 +1,28 @@ +### 服务器要求 + +* Linux +* `brutal` 拥塞控制算法内核模块已安装 + +参阅 [tcp-brutal](https://github.com/apernet/tcp-brutal)。 + +### 结构 + +```json +{ + "enabled": true, + "up_mbps": 100, + "down_mbps": 100 +} +``` + +### 字段 + +#### enabled + +启用 TCP Brutal 拥塞控制算法。 + +#### up_mbps, down_mbps + +==必填== + +上传和下载带宽,以 Mbps 为单位。 diff --git a/go.mod b/go.mod index ae3412ab96..3386fa090a 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/sing v0.2.18-0.20231119032432-6a556bfa50cc github.com/sagernet/sing-dns v0.1.11 - github.com/sagernet/sing-mux v0.1.4 + github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 github.com/sagernet/sing-quic v0.1.4 github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.5 diff --git a/go.sum b/go.sum index 8a97f9f8a2..de645a2a94 100644 --- a/go.sum +++ b/go.sum @@ -118,8 +118,8 @@ github.com/sagernet/sing v0.2.18-0.20231119032432-6a556bfa50cc h1:dmU0chO0QrBpAR github.com/sagernet/sing v0.2.18-0.20231119032432-6a556bfa50cc/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/sagernet/sing-dns v0.1.11 h1:PPrMCVVrAeR3f5X23I+cmvacXJ+kzuyAsBiWyUKhGSE= github.com/sagernet/sing-dns v0.1.11/go.mod h1:zJ/YjnYB61SYE+ubMcMqVdpaSvsyQ2iShQGO3vuLvvE= -github.com/sagernet/sing-mux v0.1.4 h1:BPNPOQr6HkXG3iY/BrfvUKUl+A7gYsGKVSxvoR3PO50= -github.com/sagernet/sing-mux v0.1.4/go.mod h1:dKvcu/sb3fZ88uGv9vzAqUej6J4W+pHu5GqjRuFwAWs= +github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 h1:ncKb5tVOsCQgCsv6UpsA0jinbNb5OQ5GMPJlyQP3EHM= +github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07/go.mod h1:u/MZf32xPG8jEKe3t+xUV67EBnKtDtCaPhsJQOQGUYU= github.com/sagernet/sing-quic v0.1.4 h1:F5KRGXMXKQEmP8VrzVollf9HWcRqggcuG9nRCL+5IJ8= github.com/sagernet/sing-quic v0.1.4/go.mod h1:aXHVP+osF3w5wJzoWZbJSrX3ceJiU9QMd0KPnKV6C/o= github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY= diff --git a/inbound/default.go b/inbound/default.go index de538e1701..44c580deb9 100644 --- a/inbound/default.go +++ b/inbound/default.go @@ -22,7 +22,7 @@ type myInboundAdapter struct { protocol string network []string ctx context.Context - router adapter.Router + router adapter.ConnectionRouter logger log.ContextLogger tag string listenOptions option.ListenOptions diff --git a/inbound/http.go b/inbound/http.go index 14a614b1af..fa6c3d5867 100644 --- a/inbound/http.go +++ b/inbound/http.go @@ -8,6 +8,7 @@ import ( "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/tls" + "github.com/sagernet/sing-box/common/uot" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -35,7 +36,7 @@ func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogge protocol: C.TypeHTTP, network: []string{N.NetworkTCP}, ctx: ctx, - router: router, + router: uot.NewRouter(router, logger), logger: logger, tag: tag, listenOptions: options.ListenOptions, diff --git a/inbound/mixed.go b/inbound/mixed.go index fceefe4d84..8c3bf3b4f9 100644 --- a/inbound/mixed.go +++ b/inbound/mixed.go @@ -7,6 +7,7 @@ import ( "os" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/uot" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -37,7 +38,7 @@ func NewMixed(ctx context.Context, router adapter.Router, logger log.ContextLogg protocol: C.TypeMixed, network: []string{N.NetworkTCP}, ctx: ctx, - router: router, + router: uot.NewRouter(router, logger), logger: logger, tag: tag, listenOptions: options.ListenOptions, diff --git a/inbound/naive.go b/inbound/naive.go index 0ea2bbb5df..1ff159d100 100644 --- a/inbound/naive.go +++ b/inbound/naive.go @@ -13,6 +13,7 @@ import ( "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/tls" + "github.com/sagernet/sing-box/common/uot" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/include" "github.com/sagernet/sing-box/log" @@ -43,7 +44,7 @@ func NewNaive(ctx context.Context, router adapter.Router, logger log.ContextLogg protocol: C.TypeNaive, network: options.Network.Build(), ctx: ctx, - router: router, + router: uot.NewRouter(router, logger), logger: logger, tag: tag, listenOptions: options.ListenOptions, diff --git a/inbound/shadowsocks.go b/inbound/shadowsocks.go index 822a5f57f8..a45b6daf4b 100644 --- a/inbound/shadowsocks.go +++ b/inbound/shadowsocks.go @@ -6,6 +6,8 @@ import ( "os" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/mux" + "github.com/sagernet/sing-box/common/uot" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -48,21 +50,27 @@ func newShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte protocol: C.TypeShadowsocks, network: options.Network.Build(), ctx: ctx, - router: router, + router: uot.NewRouter(router, logger), logger: logger, tag: tag, listenOptions: options.ListenOptions, }, } + inbound.connHandler = inbound inbound.packetHandler = inbound + var err error + inbound.router, err = mux.NewRouterWithOptions(inbound.router, logger, common.PtrValueOrDefault(options.Multiplex)) + if err != nil { + return nil, err + } + var udpTimeout int64 if options.UDPTimeout != 0 { udpTimeout = options.UDPTimeout } else { udpTimeout = int64(C.UDPTimeout.Seconds()) } - var err error switch { case options.Method == shadowsocks.MethodNone: inbound.service = shadowsocks.NewNoneService(options.UDPTimeout, inbound.upstreamContextHandler()) diff --git a/inbound/shadowsocks_multi.go b/inbound/shadowsocks_multi.go index 6a1baac264..c3c7d2abd3 100644 --- a/inbound/shadowsocks_multi.go +++ b/inbound/shadowsocks_multi.go @@ -6,6 +6,8 @@ import ( "os" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/mux" + "github.com/sagernet/sing-box/common/uot" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -38,7 +40,7 @@ func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log. protocol: C.TypeShadowsocks, network: options.Network.Build(), ctx: ctx, - router: router, + router: uot.NewRouter(router, logger), logger: logger, tag: tag, listenOptions: options.ListenOptions, @@ -46,16 +48,18 @@ func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log. } inbound.connHandler = inbound inbound.packetHandler = inbound + var err error + inbound.router, err = mux.NewRouterWithOptions(inbound.router, logger, common.PtrValueOrDefault(options.Multiplex)) + if err != nil { + return nil, err + } var udpTimeout int64 if options.UDPTimeout != 0 { udpTimeout = options.UDPTimeout } else { udpTimeout = int64(C.UDPTimeout.Seconds()) } - var ( - service shadowsocks.MultiService[int] - err error - ) + var service shadowsocks.MultiService[int] if common.Contains(shadowaead_2022.List, options.Method) { service, err = shadowaead_2022.NewMultiServiceWithPassword[int]( options.Method, diff --git a/inbound/shadowsocks_relay.go b/inbound/shadowsocks_relay.go index 2f624447be..44f39c9f6a 100644 --- a/inbound/shadowsocks_relay.go +++ b/inbound/shadowsocks_relay.go @@ -6,6 +6,8 @@ import ( "os" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/mux" + "github.com/sagernet/sing-box/common/uot" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -34,7 +36,7 @@ func newShadowsocksRelay(ctx context.Context, router adapter.Router, logger log. protocol: C.TypeShadowsocks, network: options.Network.Build(), ctx: ctx, - router: router, + router: uot.NewRouter(router, logger), logger: logger, tag: tag, listenOptions: options.ListenOptions, @@ -43,6 +45,11 @@ func newShadowsocksRelay(ctx context.Context, router adapter.Router, logger log. } inbound.connHandler = inbound inbound.packetHandler = inbound + var err error + inbound.router, err = mux.NewRouterWithOptions(inbound.router, logger, common.PtrValueOrDefault(options.Multiplex)) + if err != nil { + return nil, err + } var udpTimeout int64 if options.UDPTimeout != 0 { udpTimeout = options.UDPTimeout diff --git a/inbound/socks.go b/inbound/socks.go index 8cc256efee..65dfb1e651 100644 --- a/inbound/socks.go +++ b/inbound/socks.go @@ -6,6 +6,7 @@ import ( "os" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/uot" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -30,7 +31,7 @@ func NewSocks(ctx context.Context, router adapter.Router, logger log.ContextLogg protocol: C.TypeSOCKS, network: []string{N.NetworkTCP}, ctx: ctx, - router: router, + router: uot.NewRouter(router, logger), logger: logger, tag: tag, listenOptions: options.ListenOptions, diff --git a/inbound/trojan.go b/inbound/trojan.go index 82432131b0..203b6d3927 100644 --- a/inbound/trojan.go +++ b/inbound/trojan.go @@ -6,6 +6,7 @@ import ( "os" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/mux" "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" @@ -94,6 +95,10 @@ func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLog return nil, E.Cause(err, "create server transport: ", options.Transport.Type) } } + inbound.router, err = mux.NewRouterWithOptions(inbound.router, logger, common.PtrValueOrDefault(options.Multiplex)) + if err != nil { + return nil, err + } inbound.service = service inbound.connHandler = inbound return inbound, nil diff --git a/inbound/tuic.go b/inbound/tuic.go index bdef1c5deb..ff9b9ce728 100644 --- a/inbound/tuic.go +++ b/inbound/tuic.go @@ -9,6 +9,7 @@ import ( "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/tls" + "github.com/sagernet/sing-box/common/uot" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -44,7 +45,7 @@ func NewTUIC(ctx context.Context, router adapter.Router, logger log.ContextLogge protocol: C.TypeTUIC, network: []string{N.NetworkUDP}, ctx: ctx, - router: router, + router: uot.NewRouter(router, logger), logger: logger, tag: tag, listenOptions: options.ListenOptions, diff --git a/inbound/vless.go b/inbound/vless.go index 11df86bfed..029fdaf756 100644 --- a/inbound/vless.go +++ b/inbound/vless.go @@ -6,7 +6,9 @@ import ( "os" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/mux" "github.com/sagernet/sing-box/common/tls" + "github.com/sagernet/sing-box/common/uot" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -42,7 +44,7 @@ func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogg protocol: C.TypeVLESS, network: []string{N.NetworkTCP}, ctx: ctx, - router: router, + router: uot.NewRouter(router, logger), logger: logger, tag: tag, listenOptions: options.ListenOptions, @@ -50,6 +52,11 @@ func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogg ctx: ctx, users: options.Users, } + var err error + inbound.router, err = mux.NewRouterWithOptions(inbound.router, logger, common.PtrValueOrDefault(options.Multiplex)) + if err != nil { + return nil, err + } service := vless.NewService[int](logger, adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound)) service.UpdateUsers(common.MapIndexed(inbound.users, func(index int, _ option.VLESSUser) int { return index @@ -59,7 +66,6 @@ func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogg return it.Flow })) inbound.service = service - var err error if options.TLS != nil { inbound.tlsConfig, err = tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) if err != nil { diff --git a/inbound/vmess.go b/inbound/vmess.go index 77a8b28acf..70676bbd8c 100644 --- a/inbound/vmess.go +++ b/inbound/vmess.go @@ -6,7 +6,9 @@ import ( "os" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/mux" "github.com/sagernet/sing-box/common/tls" + "github.com/sagernet/sing-box/common/uot" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" @@ -42,7 +44,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg protocol: C.TypeVMess, network: []string{N.NetworkTCP}, ctx: ctx, - router: router, + router: uot.NewRouter(router, logger), logger: logger, tag: tag, listenOptions: options.ListenOptions, @@ -50,6 +52,11 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg ctx: ctx, users: options.Users, } + var err error + inbound.router, err = mux.NewRouterWithOptions(inbound.router, logger, common.PtrValueOrDefault(options.Multiplex)) + if err != nil { + return nil, err + } var serviceOptions []vmess.ServiceOption if timeFunc := ntp.TimeFuncFromContext(ctx); timeFunc != nil { serviceOptions = append(serviceOptions, vmess.ServiceWithTimeFunc(timeFunc)) @@ -59,7 +66,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg } service := vmess.NewService[int](adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound), serviceOptions...) inbound.service = service - err := service.UpdateUsers(common.MapIndexed(options.Users, func(index int, it option.VMessUser) int { + err = service.UpdateUsers(common.MapIndexed(options.Users, func(index int, it option.VMessUser) int { return index }), common.Map(options.Users, func(it option.VMessUser) string { return it.UUID diff --git a/mkdocs.yml b/mkdocs.yml index 5632affae6..98c46c6fb9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -75,6 +75,7 @@ nav: - Multiplex: configuration/shared/multiplex.md - V2Ray Transport: configuration/shared/v2ray-transport.md - UDP over TCP: configuration/shared/udp-over-tcp.md + - TCP Brutal: configuration/shared/tcp-brutal.md - Inbound: - configuration/inbound/index.md - Direct: configuration/inbound/direct.md diff --git a/option/multiplex.go b/option/multiplex.go new file mode 100644 index 0000000000..309d8bdc39 --- /dev/null +++ b/option/multiplex.go @@ -0,0 +1,23 @@ +package option + +type InboundMultiplexOptions struct { + Enabled bool `json:"enabled,omitempty"` + Padding bool `json:"padding,omitempty"` + Brutal *BrutalOptions `json:"brutal,omitempty"` +} + +type OutboundMultiplexOptions struct { + Enabled bool `json:"enabled,omitempty"` + Protocol string `json:"protocol,omitempty"` + MaxConnections int `json:"max_connections,omitempty"` + MinStreams int `json:"min_streams,omitempty"` + MaxStreams int `json:"max_streams,omitempty"` + Padding bool `json:"padding,omitempty"` + Brutal *BrutalOptions `json:"brutal,omitempty"` +} + +type BrutalOptions struct { + Enabled bool `json:"enabled,omitempty"` + UpMbps int `json:"up_mbps,omitempty"` + DownMbps int `json:"down_mbps,omitempty"` +} diff --git a/option/outbound.go b/option/outbound.go index 3d780ef4ed..2985319ea5 100644 --- a/option/outbound.go +++ b/option/outbound.go @@ -154,12 +154,3 @@ type ServerOptions struct { func (o ServerOptions) Build() M.Socksaddr { return M.ParseSocksaddrHostPort(o.Server, o.ServerPort) } - -type MultiplexOptions struct { - Enabled bool `json:"enabled,omitempty"` - Protocol string `json:"protocol,omitempty"` - MaxConnections int `json:"max_connections,omitempty"` - MinStreams int `json:"min_streams,omitempty"` - MaxStreams int `json:"max_streams,omitempty"` - Padding bool `json:"padding,omitempty"` -} diff --git a/option/shadowsocks.go b/option/shadowsocks.go index 38a18b832e..187b9b633d 100644 --- a/option/shadowsocks.go +++ b/option/shadowsocks.go @@ -7,6 +7,7 @@ type ShadowsocksInboundOptions struct { Password string `json:"password,omitempty"` Users []ShadowsocksUser `json:"users,omitempty"` Destinations []ShadowsocksDestination `json:"destinations,omitempty"` + Multiplex *InboundMultiplexOptions `json:"multiplex,omitempty"` } type ShadowsocksUser struct { @@ -23,11 +24,11 @@ type ShadowsocksDestination struct { type ShadowsocksOutboundOptions struct { DialerOptions ServerOptions - Method string `json:"method"` - Password string `json:"password"` - Plugin string `json:"plugin,omitempty"` - PluginOptions string `json:"plugin_opts,omitempty"` - Network NetworkList `json:"network,omitempty"` - UDPOverTCPOptions *UDPOverTCPOptions `json:"udp_over_tcp,omitempty"` - MultiplexOptions *MultiplexOptions `json:"multiplex,omitempty"` + Method string `json:"method"` + Password string `json:"password"` + Plugin string `json:"plugin,omitempty"` + PluginOptions string `json:"plugin_opts,omitempty"` + Network NetworkList `json:"network,omitempty"` + UDPOverTCP *UDPOverTCPOptions `json:"udp_over_tcp,omitempty"` + Multiplex *OutboundMultiplexOptions `json:"multiplex,omitempty"` } diff --git a/option/simple.go b/option/simple.go index 55bfe93005..b8692e0cf1 100644 --- a/option/simple.go +++ b/option/simple.go @@ -17,11 +17,11 @@ type HTTPMixedInboundOptions struct { type SocksOutboundOptions struct { DialerOptions ServerOptions - Version string `json:"version,omitempty"` - Username string `json:"username,omitempty"` - Password string `json:"password,omitempty"` - Network NetworkList `json:"network,omitempty"` - UDPOverTCPOptions *UDPOverTCPOptions `json:"udp_over_tcp,omitempty"` + Version string `json:"version,omitempty"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + Network NetworkList `json:"network,omitempty"` + UDPOverTCP *UDPOverTCPOptions `json:"udp_over_tcp,omitempty"` } type HTTPOutboundOptions struct { diff --git a/option/trojan.go b/option/trojan.go index 11392cd501..d24ed16aed 100644 --- a/option/trojan.go +++ b/option/trojan.go @@ -6,6 +6,7 @@ type TrojanInboundOptions struct { TLS *InboundTLSOptions `json:"tls,omitempty"` Fallback *ServerOptions `json:"fallback,omitempty"` FallbackForALPN map[string]*ServerOptions `json:"fallback_for_alpn,omitempty"` + Multiplex *InboundMultiplexOptions `json:"multiplex,omitempty"` Transport *V2RayTransportOptions `json:"transport,omitempty"` } @@ -17,9 +18,9 @@ type TrojanUser struct { type TrojanOutboundOptions struct { DialerOptions ServerOptions - Password string `json:"password"` - Network NetworkList `json:"network,omitempty"` - TLS *OutboundTLSOptions `json:"tls,omitempty"` - Multiplex *MultiplexOptions `json:"multiplex,omitempty"` - Transport *V2RayTransportOptions `json:"transport,omitempty"` + Password string `json:"password"` + Network NetworkList `json:"network,omitempty"` + TLS *OutboundTLSOptions `json:"tls,omitempty"` + Multiplex *OutboundMultiplexOptions `json:"multiplex,omitempty"` + Transport *V2RayTransportOptions `json:"transport,omitempty"` } diff --git a/option/vless.go b/option/vless.go index 5547bd88c7..09010922e9 100644 --- a/option/vless.go +++ b/option/vless.go @@ -2,9 +2,10 @@ package option type VLESSInboundOptions struct { ListenOptions - Users []VLESSUser `json:"users,omitempty"` - TLS *InboundTLSOptions `json:"tls,omitempty"` - Transport *V2RayTransportOptions `json:"transport,omitempty"` + Users []VLESSUser `json:"users,omitempty"` + TLS *InboundTLSOptions `json:"tls,omitempty"` + Multiplex *InboundMultiplexOptions `json:"multiplex,omitempty"` + Transport *V2RayTransportOptions `json:"transport,omitempty"` } type VLESSUser struct { @@ -16,11 +17,11 @@ type VLESSUser struct { type VLESSOutboundOptions struct { DialerOptions ServerOptions - UUID string `json:"uuid"` - Flow string `json:"flow,omitempty"` - Network NetworkList `json:"network,omitempty"` - TLS *OutboundTLSOptions `json:"tls,omitempty"` - Multiplex *MultiplexOptions `json:"multiplex,omitempty"` - Transport *V2RayTransportOptions `json:"transport,omitempty"` - PacketEncoding *string `json:"packet_encoding,omitempty"` + UUID string `json:"uuid"` + Flow string `json:"flow,omitempty"` + Network NetworkList `json:"network,omitempty"` + TLS *OutboundTLSOptions `json:"tls,omitempty"` + Multiplex *OutboundMultiplexOptions `json:"multiplex,omitempty"` + Transport *V2RayTransportOptions `json:"transport,omitempty"` + PacketEncoding *string `json:"packet_encoding,omitempty"` } diff --git a/option/vmess.go b/option/vmess.go index a2ba210315..8045e9d6da 100644 --- a/option/vmess.go +++ b/option/vmess.go @@ -2,9 +2,10 @@ package option type VMessInboundOptions struct { ListenOptions - Users []VMessUser `json:"users,omitempty"` - TLS *InboundTLSOptions `json:"tls,omitempty"` - Transport *V2RayTransportOptions `json:"transport,omitempty"` + Users []VMessUser `json:"users,omitempty"` + TLS *InboundTLSOptions `json:"tls,omitempty"` + Multiplex *InboundMultiplexOptions `json:"multiplex,omitempty"` + Transport *V2RayTransportOptions `json:"transport,omitempty"` } type VMessUser struct { @@ -16,14 +17,14 @@ type VMessUser struct { type VMessOutboundOptions struct { DialerOptions ServerOptions - UUID string `json:"uuid"` - Security string `json:"security"` - AlterId int `json:"alter_id,omitempty"` - GlobalPadding bool `json:"global_padding,omitempty"` - AuthenticatedLength bool `json:"authenticated_length,omitempty"` - Network NetworkList `json:"network,omitempty"` - TLS *OutboundTLSOptions `json:"tls,omitempty"` - PacketEncoding string `json:"packet_encoding,omitempty"` - Multiplex *MultiplexOptions `json:"multiplex,omitempty"` - Transport *V2RayTransportOptions `json:"transport,omitempty"` + UUID string `json:"uuid"` + Security string `json:"security"` + AlterId int `json:"alter_id,omitempty"` + GlobalPadding bool `json:"global_padding,omitempty"` + AuthenticatedLength bool `json:"authenticated_length,omitempty"` + Network NetworkList `json:"network,omitempty"` + TLS *OutboundTLSOptions `json:"tls,omitempty"` + PacketEncoding string `json:"packet_encoding,omitempty"` + Multiplex *OutboundMultiplexOptions `json:"multiplex,omitempty"` + Transport *V2RayTransportOptions `json:"transport,omitempty"` } diff --git a/outbound/shadowsocks.go b/outbound/shadowsocks.go index e436e1241d..addb6e576f 100644 --- a/outbound/shadowsocks.go +++ b/outbound/shadowsocks.go @@ -62,9 +62,9 @@ func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte return nil, err } } - uotOptions := common.PtrValueOrDefault(options.UDPOverTCPOptions) + uotOptions := common.PtrValueOrDefault(options.UDPOverTCP) if !uotOptions.Enabled { - outbound.multiplexDialer, err = mux.NewClientWithOptions((*shadowsocksDialer)(outbound), common.PtrValueOrDefault(options.MultiplexOptions)) + outbound.multiplexDialer, err = mux.NewClientWithOptions((*shadowsocksDialer)(outbound), logger, common.PtrValueOrDefault(options.Multiplex)) if err != nil { return nil, err } diff --git a/outbound/socks.go b/outbound/socks.go index bd6b1ada73..063f7b952a 100644 --- a/outbound/socks.go +++ b/outbound/socks.go @@ -54,7 +54,7 @@ func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, optio client: socks.NewClient(outboundDialer, options.ServerOptions.Build(), version, options.Username, options.Password), resolve: version == socks.Version4, } - uotOptions := common.PtrValueOrDefault(options.UDPOverTCPOptions) + uotOptions := common.PtrValueOrDefault(options.UDPOverTCP) if uotOptions.Enabled { outbound.uotClient = &uot.Client{ Dialer: outbound.client, diff --git a/outbound/trojan.go b/outbound/trojan.go index e8ccb6ae9d..1436961394 100644 --- a/outbound/trojan.go +++ b/outbound/trojan.go @@ -62,7 +62,7 @@ func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLog return nil, E.Cause(err, "create client transport: ", options.Transport.Type) } } - outbound.multiplexDialer, err = mux.NewClientWithOptions((*trojanDialer)(outbound), common.PtrValueOrDefault(options.Multiplex)) + outbound.multiplexDialer, err = mux.NewClientWithOptions((*trojanDialer)(outbound), logger, common.PtrValueOrDefault(options.Multiplex)) if err != nil { return nil, err } diff --git a/outbound/vless.go b/outbound/vless.go index a78bddcd2e..506521f700 100644 --- a/outbound/vless.go +++ b/outbound/vless.go @@ -81,7 +81,7 @@ func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogg if err != nil { return nil, err } - outbound.multiplexDialer, err = mux.NewClientWithOptions((*vlessDialer)(outbound), common.PtrValueOrDefault(options.Multiplex)) + outbound.multiplexDialer, err = mux.NewClientWithOptions((*vlessDialer)(outbound), logger, common.PtrValueOrDefault(options.Multiplex)) if err != nil { return nil, err } diff --git a/outbound/vmess.go b/outbound/vmess.go index a981464bbd..6add541481 100644 --- a/outbound/vmess.go +++ b/outbound/vmess.go @@ -64,7 +64,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg return nil, E.Cause(err, "create client transport: ", options.Transport.Type) } } - outbound.multiplexDialer, err = mux.NewClientWithOptions((*vmessDialer)(outbound), common.PtrValueOrDefault(options.Multiplex)) + outbound.multiplexDialer, err = mux.NewClientWithOptions((*vmessDialer)(outbound), logger, common.PtrValueOrDefault(options.Multiplex)) if err != nil { return nil, err } diff --git a/route/router.go b/route/router.go index 676ebd7b20..2d2f2cde57 100644 --- a/route/router.go +++ b/route/router.go @@ -16,7 +16,6 @@ import ( "github.com/sagernet/sing-box/common/dialer" "github.com/sagernet/sing-box/common/geoip" "github.com/sagernet/sing-box/common/geosite" - "github.com/sagernet/sing-box/common/mux" "github.com/sagernet/sing-box/common/process" "github.com/sagernet/sing-box/common/sniff" C "github.com/sagernet/sing-box/constant" @@ -27,6 +26,7 @@ import ( "github.com/sagernet/sing-box/outbound" "github.com/sagernet/sing-box/transport/fakeip" "github.com/sagernet/sing-dns" + mux "github.com/sagernet/sing-mux" "github.com/sagernet/sing-tun" "github.com/sagernet/sing-vmess" "github.com/sagernet/sing/common" @@ -606,30 +606,13 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad metadata.Network = N.NetworkTCP switch metadata.Destination.Fqdn { case mux.Destination.Fqdn: - r.logger.InfoContext(ctx, "inbound multiplex connection") - handler := adapter.NewUpstreamHandler(metadata, r.RouteConnection, r.RoutePacketConnection, r) - return mux.HandleConnection(ctx, handler, r.logger, conn, adapter.UpstreamMetadata(metadata)) + return E.New("global multiplex is deprecated since sing-box v1.7.0, enable multiplex in inbound options instead.") case vmess.MuxDestination.Fqdn: - r.logger.InfoContext(ctx, "inbound legacy multiplex connection") - return vmess.HandleMuxConnection(ctx, conn, adapter.NewUpstreamHandler(metadata, r.RouteConnection, r.RoutePacketConnection, r)) + return E.New("global multiplex (v2ray legacy) not supported since sing-box v1.7.0.") case uot.MagicAddress: - request, err := uot.ReadRequest(conn) - if err != nil { - return E.Cause(err, "read UoT request") - } - if request.IsConnect { - r.logger.InfoContext(ctx, "inbound UoT connect connection to ", request.Destination) - } else { - r.logger.InfoContext(ctx, "inbound UoT connection to ", request.Destination) - } - metadata.Domain = metadata.Destination.Fqdn - metadata.Destination = request.Destination - return r.RoutePacketConnection(ctx, uot.NewConn(conn, *request), metadata) + return E.New("global UoT not supported since sing-box v1.7.0.") case uot.LegacyMagicAddress: - r.logger.InfoContext(ctx, "inbound legacy UoT connection") - metadata.Domain = metadata.Destination.Fqdn - metadata.Destination = M.Socksaddr{Addr: netip.IPv4Unspecified()} - return r.RoutePacketConnection(ctx, uot.NewConn(conn, uot.Request{}), metadata) + return E.New("global UoT (legacy) not supported since sing-box v1.7.0.") } if r.fakeIPStore != nil && r.fakeIPStore.Contains(metadata.Destination.Addr) { diff --git a/test/brutal_test.go b/test/brutal_test.go new file mode 100644 index 0000000000..6bfdfcc1b1 --- /dev/null +++ b/test/brutal_test.go @@ -0,0 +1,346 @@ +package main + +import ( + "net/netip" + "testing" + + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing-shadowsocks/shadowaead_2022" + + "github.com/gofrs/uuid/v5" +) + +func TestBrutalShadowsocks(t *testing.T) { + method := shadowaead_2022.List[0] + password := mkBase64(t, 16) + startInstance(t, option.Options{ + Inbounds: []option.Inbound{ + { + Type: C.TypeMixed, + Tag: "mixed-in", + MixedOptions: option.HTTPMixedInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.NewListenAddress(netip.IPv4Unspecified()), + ListenPort: clientPort, + }, + }, + }, + { + Type: C.TypeShadowsocks, + ShadowsocksOptions: option.ShadowsocksInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.NewListenAddress(netip.IPv4Unspecified()), + ListenPort: serverPort, + }, + Method: method, + Password: password, + Multiplex: &option.InboundMultiplexOptions{ + Enabled: true, + Brutal: &option.BrutalOptions{ + Enabled: true, + UpMbps: 100, + DownMbps: 100, + }, + }, + }, + }, + }, + Outbounds: []option.Outbound{ + { + Type: C.TypeDirect, + }, + { + Type: C.TypeShadowsocks, + Tag: "ss-out", + ShadowsocksOptions: option.ShadowsocksOutboundOptions{ + ServerOptions: option.ServerOptions{ + Server: "127.0.0.1", + ServerPort: serverPort, + }, + Method: method, + Password: password, + Multiplex: &option.OutboundMultiplexOptions{ + Enabled: true, + Protocol: "smux", + Padding: true, + Brutal: &option.BrutalOptions{ + Enabled: true, + UpMbps: 100, + DownMbps: 100, + }, + }, + }, + }, + }, + Route: &option.RouteOptions{ + Rules: []option.Rule{ + { + DefaultOptions: option.DefaultRule{ + Inbound: []string{"mixed-in"}, + Outbound: "ss-out", + }, + }, + }, + }, + }) + testSuit(t, clientPort, testPort) +} + +func TestBrutalTrojan(t *testing.T) { + _, certPem, keyPem := createSelfSignedCertificate(t, "example.org") + password := mkBase64(t, 16) + startInstance(t, option.Options{ + Inbounds: []option.Inbound{ + { + Type: C.TypeMixed, + Tag: "mixed-in", + MixedOptions: option.HTTPMixedInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.NewListenAddress(netip.IPv4Unspecified()), + ListenPort: clientPort, + }, + }, + }, + { + Type: C.TypeTrojan, + TrojanOptions: option.TrojanInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.NewListenAddress(netip.IPv4Unspecified()), + ListenPort: serverPort, + }, + Users: []option.TrojanUser{{Password: password}}, + Multiplex: &option.InboundMultiplexOptions{ + Enabled: true, + Brutal: &option.BrutalOptions{ + Enabled: true, + UpMbps: 100, + DownMbps: 100, + }, + }, + TLS: &option.InboundTLSOptions{ + Enabled: true, + ServerName: "example.org", + CertificatePath: certPem, + KeyPath: keyPem, + }, + }, + }, + }, + Outbounds: []option.Outbound{ + { + Type: C.TypeDirect, + }, + { + Type: C.TypeTrojan, + Tag: "ss-out", + TrojanOptions: option.TrojanOutboundOptions{ + ServerOptions: option.ServerOptions{ + Server: "127.0.0.1", + ServerPort: serverPort, + }, + Password: password, + Multiplex: &option.OutboundMultiplexOptions{ + Enabled: true, + Protocol: "yamux", + Padding: true, + Brutal: &option.BrutalOptions{ + Enabled: true, + UpMbps: 100, + DownMbps: 100, + }, + }, + TLS: &option.OutboundTLSOptions{ + Enabled: true, + ServerName: "example.org", + CertificatePath: certPem, + }, + }, + }, + }, + Route: &option.RouteOptions{ + Rules: []option.Rule{ + { + DefaultOptions: option.DefaultRule{ + Inbound: []string{"mixed-in"}, + Outbound: "ss-out", + }, + }, + }, + }, + }) + testSuit(t, clientPort, testPort) +} + +func TestBrutalVMess(t *testing.T) { + user, _ := uuid.NewV4() + startInstance(t, option.Options{ + Inbounds: []option.Inbound{ + { + Type: C.TypeMixed, + Tag: "mixed-in", + MixedOptions: option.HTTPMixedInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.NewListenAddress(netip.IPv4Unspecified()), + ListenPort: clientPort, + }, + }, + }, + { + Type: C.TypeVMess, + VMessOptions: option.VMessInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.NewListenAddress(netip.IPv4Unspecified()), + ListenPort: serverPort, + }, + Users: []option.VMessUser{{UUID: user.String()}}, + Multiplex: &option.InboundMultiplexOptions{ + Enabled: true, + Brutal: &option.BrutalOptions{ + Enabled: true, + UpMbps: 100, + DownMbps: 100, + }, + }, + }, + }, + }, + Outbounds: []option.Outbound{ + { + Type: C.TypeDirect, + }, + { + Type: C.TypeVMess, + Tag: "ss-out", + VMessOptions: option.VMessOutboundOptions{ + ServerOptions: option.ServerOptions{ + Server: "127.0.0.1", + ServerPort: serverPort, + }, + UUID: user.String(), + Multiplex: &option.OutboundMultiplexOptions{ + Enabled: true, + Protocol: "h2mux", + Padding: true, + Brutal: &option.BrutalOptions{ + Enabled: true, + UpMbps: 100, + DownMbps: 100, + }, + }, + }, + }, + }, + Route: &option.RouteOptions{ + Rules: []option.Rule{ + { + DefaultOptions: option.DefaultRule{ + Inbound: []string{"mixed-in"}, + Outbound: "ss-out", + }, + }, + }, + }, + }) + testSuit(t, clientPort, testPort) +} + +func TestBrutalVLESS(t *testing.T) { + user, _ := uuid.NewV4() + startInstance(t, option.Options{ + Inbounds: []option.Inbound{ + { + Type: C.TypeMixed, + Tag: "mixed-in", + MixedOptions: option.HTTPMixedInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.NewListenAddress(netip.IPv4Unspecified()), + ListenPort: clientPort, + }, + }, + }, + { + Type: C.TypeVLESS, + VLESSOptions: option.VLESSInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.NewListenAddress(netip.IPv4Unspecified()), + ListenPort: serverPort, + }, + Users: []option.VLESSUser{{UUID: user.String()}}, + Multiplex: &option.InboundMultiplexOptions{ + Enabled: true, + Brutal: &option.BrutalOptions{ + Enabled: true, + UpMbps: 100, + DownMbps: 100, + }, + }, + TLS: &option.InboundTLSOptions{ + Enabled: true, + ServerName: "google.com", + Reality: &option.InboundRealityOptions{ + Enabled: true, + Handshake: option.InboundRealityHandshakeOptions{ + ServerOptions: option.ServerOptions{ + Server: "google.com", + ServerPort: 443, + }, + }, + ShortID: []string{"0123456789abcdef"}, + PrivateKey: "UuMBgl7MXTPx9inmQp2UC7Jcnwc6XYbwDNebonM-FCc", + }, + }, + }, + }, + }, + Outbounds: []option.Outbound{ + { + Type: C.TypeDirect, + }, + { + Type: C.TypeVLESS, + Tag: "ss-out", + VLESSOptions: option.VLESSOutboundOptions{ + ServerOptions: option.ServerOptions{ + Server: "127.0.0.1", + ServerPort: serverPort, + }, + UUID: user.String(), + TLS: &option.OutboundTLSOptions{ + Enabled: true, + ServerName: "google.com", + Reality: &option.OutboundRealityOptions{ + Enabled: true, + ShortID: "0123456789abcdef", + PublicKey: "jNXHt1yRo0vDuchQlIP6Z0ZvjT3KtzVI-T4E7RoLJS0", + }, + UTLS: &option.OutboundUTLSOptions{ + Enabled: true, + }, + }, + Multiplex: &option.OutboundMultiplexOptions{ + Enabled: true, + Protocol: "h2mux", + Padding: true, + Brutal: &option.BrutalOptions{ + Enabled: true, + UpMbps: 100, + DownMbps: 100, + }, + }, + }, + }, + }, + Route: &option.RouteOptions{ + Rules: []option.Rule{ + { + DefaultOptions: option.DefaultRule{ + Inbound: []string{"mixed-in"}, + Outbound: "ss-out", + }, + }, + }, + }, + }) + testSuit(t, clientPort, testPort) +} diff --git a/test/go.mod b/test/go.mod index 9aa1bf0315..42c9d087b4 100644 --- a/test/go.mod +++ b/test/go.mod @@ -11,11 +11,11 @@ require ( github.com/docker/go-connections v0.4.0 github.com/gofrs/uuid/v5 v5.0.0 github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 - github.com/sagernet/sing v0.2.17 + github.com/sagernet/sing v0.2.18-0.20231119032432-6a556bfa50cc github.com/sagernet/sing-dns v0.1.11 github.com/sagernet/sing-quic v0.1.4 github.com/sagernet/sing-shadowsocks v0.2.5 - github.com/sagernet/sing-shadowsocks2 v0.1.4 + github.com/sagernet/sing-shadowsocks2 v0.1.5 github.com/spyzhov/ajson v0.9.0 github.com/stretchr/testify v1.8.4 go.uber.org/goleak v1.3.0 @@ -40,6 +40,8 @@ require ( github.com/go-chi/render v1.0.3 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.1.2 // indirect @@ -70,18 +72,18 @@ require ( github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect - github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab // indirect + github.com/sagernet/gvisor v0.0.0-20231119034329-07cfb6aaf930 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect - github.com/sagernet/sing-mux v0.1.4 // indirect + github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect - github.com/sagernet/sing-tun v0.1.20 // indirect + github.com/sagernet/sing-tun v0.1.21-0.20231119035513-f6ea97c5af71 // indirect github.com/sagernet/sing-vmess v0.1.8 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 // indirect github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect - github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f // indirect + github.com/sagernet/ws v0.0.0-20231030053741-7d481eb31bed // indirect github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect @@ -94,7 +96,7 @@ require ( golang.org/x/mod v0.14.0 // indirect golang.org/x/sys v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect + golang.org/x/time v0.4.0 // indirect golang.org/x/tools v0.15.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/grpc v1.59.0 // indirect diff --git a/test/go.sum b/test/go.sum index 3c87ccbfac..c3d155cb45 100644 --- a/test/go.sum +++ b/test/go.sum @@ -43,6 +43,10 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -117,8 +121,8 @@ github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a h1:wZHruBx github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a/go.mod h1:dNV1ZP9y3qx5ltULeKaQZTZWTLHflgW5DES+Ses7cMI= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= -github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab h1:u+xQoi/Yc6bNUvTfrDD6HhGRybn2lzrhf5vmS+wb4Ho= -github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab/go.mod h1:3akUhSHSVtLuJaYcW5JPepUraBOW06Ibz2HKwaK5rOk= +github.com/sagernet/gvisor v0.0.0-20231119034329-07cfb6aaf930 h1:dSPgjIw0CT6ISLeEh8Q20dZMBMFCcEceo23+LncRcNQ= +github.com/sagernet/gvisor v0.0.0-20231119034329-07cfb6aaf930/go.mod h1:JpKHkOYgh4wLwrX2BhH3ZIvCvazCkTnPeEcmigZJfHY= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 h1:dAe4OIJAtE0nHOzTHhAReQteh3+sa63rvXbuIpbeOTY= @@ -127,22 +131,22 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.17 h1:vMPKb3MV0Aa5ws4dCJkRI8XEjrsUcDn810czd0FwmzI= -github.com/sagernet/sing v0.2.17/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= +github.com/sagernet/sing v0.2.18-0.20231119032432-6a556bfa50cc h1:dmU0chO0QrBpARo8sqyOc+mvPLW+qux4ca16kb2WIc8= +github.com/sagernet/sing v0.2.18-0.20231119032432-6a556bfa50cc/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/sagernet/sing-dns v0.1.11 h1:PPrMCVVrAeR3f5X23I+cmvacXJ+kzuyAsBiWyUKhGSE= github.com/sagernet/sing-dns v0.1.11/go.mod h1:zJ/YjnYB61SYE+ubMcMqVdpaSvsyQ2iShQGO3vuLvvE= -github.com/sagernet/sing-mux v0.1.4 h1:BPNPOQr6HkXG3iY/BrfvUKUl+A7gYsGKVSxvoR3PO50= -github.com/sagernet/sing-mux v0.1.4/go.mod h1:dKvcu/sb3fZ88uGv9vzAqUej6J4W+pHu5GqjRuFwAWs= +github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 h1:ncKb5tVOsCQgCsv6UpsA0jinbNb5OQ5GMPJlyQP3EHM= +github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07/go.mod h1:u/MZf32xPG8jEKe3t+xUV67EBnKtDtCaPhsJQOQGUYU= github.com/sagernet/sing-quic v0.1.4 h1:F5KRGXMXKQEmP8VrzVollf9HWcRqggcuG9nRCL+5IJ8= github.com/sagernet/sing-quic v0.1.4/go.mod h1:aXHVP+osF3w5wJzoWZbJSrX3ceJiU9QMd0KPnKV6C/o= github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY= github.com/sagernet/sing-shadowsocks v0.2.5/go.mod h1:MGWGkcU2xW2G2mfArT9/QqpVLOGU+dBaahZCtPHdt7A= -github.com/sagernet/sing-shadowsocks2 v0.1.4 h1:vht2M8t3m5DTgXR2j24KbYOygG5aOp+MUhpQnAux728= -github.com/sagernet/sing-shadowsocks2 v0.1.4/go.mod h1:Mgdee99NxxNd5Zld3ixIs18yVs4x2dI2VTDDE1N14Wc= +github.com/sagernet/sing-shadowsocks2 v0.1.5 h1:JDeAJ4ZWlYZ7F6qEVdDKPhQEangxKw/JtmU+i/YfCYE= +github.com/sagernet/sing-shadowsocks2 v0.1.5/go.mod h1:KF65y8lI5PGHyMgRZGYXYsH9ilgRc/yr+NYbSNGuBm4= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/sing-tun v0.1.20 h1:vYWo/w6fkKc8I1WP/IB8eBWZVsGIC6eoEoNR6XqEDlY= -github.com/sagernet/sing-tun v0.1.20/go.mod h1:6kkPL/u9tWcLFfu55VbwMDnO++17cUihSmImkZjdZro= +github.com/sagernet/sing-tun v0.1.21-0.20231119035513-f6ea97c5af71 h1:WQi0TwhjbSNFFbxybIgAUSjVvo7uWSsLD28ldoM2avY= +github.com/sagernet/sing-tun v0.1.21-0.20231119035513-f6ea97c5af71/go.mod h1:hyzA4gDWbeg2SXklqPDswBKa//QcjlZqKw9aPcNdQ9A= github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= @@ -151,10 +155,10 @@ github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 h1:Px+hN4Vzgx+iCGV github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6/go.mod h1:zovq6vTvEM6ECiqE3Eeb9rpIylPpamPcmrJ9tv0Bt0M= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= -github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs= -github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY= github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f h1:Kvo8w8Y9lzFGB/7z09MJ3TR99TFtfI/IuY87Ygcycho= github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f/go.mod h1:mySs0abhpc/gLlvhoq7HP1RzOaRmIXVeZGCh++zoApk= +github.com/sagernet/ws v0.0.0-20231030053741-7d481eb31bed h1:90a510OeE9siSJoYsI8nSjPmA+u5ROMDts/ZkdNsuXY= +github.com/sagernet/ws v0.0.0-20231030053741-7d481eb31bed/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= github.com/spyzhov/ajson v0.9.0 h1:tF46gJGOenYVj+k9K1U1XpCxVWhmiyY5PsVCAs1+OJ0= @@ -222,6 +226,7 @@ golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -231,8 +236,8 @@ 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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 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= diff --git a/test/mux_test.go b/test/mux_test.go index b57c6cee99..564b936d8e 100644 --- a/test/mux_test.go +++ b/test/mux_test.go @@ -18,7 +18,7 @@ var muxProtocols = []string{ } func TestVMessSMux(t *testing.T) { - testVMessMux(t, option.MultiplexOptions{ + testVMessMux(t, option.OutboundMultiplexOptions{ Enabled: true, Protocol: "smux", }) @@ -27,7 +27,7 @@ func TestVMessSMux(t *testing.T) { func TestShadowsocksMux(t *testing.T) { for _, protocol := range muxProtocols { t.Run(protocol, func(t *testing.T) { - testShadowsocksMux(t, option.MultiplexOptions{ + testShadowsocksMux(t, option.OutboundMultiplexOptions{ Enabled: true, Protocol: protocol, }) @@ -36,7 +36,7 @@ func TestShadowsocksMux(t *testing.T) { } func TestShadowsockH2Mux(t *testing.T) { - testShadowsocksMux(t, option.MultiplexOptions{ + testShadowsocksMux(t, option.OutboundMultiplexOptions{ Enabled: true, Protocol: "h2mux", Padding: true, @@ -44,14 +44,14 @@ func TestShadowsockH2Mux(t *testing.T) { } func TestShadowsockSMuxPadding(t *testing.T) { - testShadowsocksMux(t, option.MultiplexOptions{ + testShadowsocksMux(t, option.OutboundMultiplexOptions{ Enabled: true, Protocol: "smux", Padding: true, }) } -func testShadowsocksMux(t *testing.T, options option.MultiplexOptions) { +func testShadowsocksMux(t *testing.T, options option.OutboundMultiplexOptions) { method := shadowaead_2022.List[0] password := mkBase64(t, 16) startInstance(t, option.Options{ @@ -90,9 +90,9 @@ func testShadowsocksMux(t *testing.T, options option.MultiplexOptions) { Server: "127.0.0.1", ServerPort: serverPort, }, - Method: method, - Password: password, - MultiplexOptions: &options, + Method: method, + Password: password, + Multiplex: &options, }, }, }, @@ -110,7 +110,7 @@ func testShadowsocksMux(t *testing.T, options option.MultiplexOptions) { testSuit(t, clientPort, testPort) } -func testVMessMux(t *testing.T, options option.MultiplexOptions) { +func testVMessMux(t *testing.T, options option.OutboundMultiplexOptions) { user, _ := uuid.NewV4() startInstance(t, option.Options{ Inbounds: []option.Inbound{ @@ -136,6 +136,9 @@ func testVMessMux(t *testing.T, options option.MultiplexOptions) { UUID: user.String(), }, }, + Multiplex: &option.InboundMultiplexOptions{ + Enabled: true, + }, }, }, }, diff --git a/test/shadowsocks_test.go b/test/shadowsocks_test.go index f3fc61d1e8..7d063d9a96 100644 --- a/test/shadowsocks_test.go +++ b/test/shadowsocks_test.go @@ -249,7 +249,7 @@ func TestShadowsocksUoT(t *testing.T) { }, Method: method, Password: password, - UDPOverTCPOptions: &option.UDPOverTCPOptions{ + UDPOverTCP: &option.UDPOverTCPOptions{ Enabled: true, }, }, From 83f6e022bb609f95294fa7fb9069cbe772cd3801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 14 Nov 2023 21:48:55 +0800 Subject: [PATCH 81/87] Update quic-go to v0.40.0 --- go.mod | 10 +++++----- go.sum | 27 +++++++++++---------------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 3386fa090a..52339704e8 100644 --- a/go.mod +++ b/go.mod @@ -24,12 +24,12 @@ require ( github.com/sagernet/cloudflare-tls v0.0.0-20230829051644-4a68352d0c4a github.com/sagernet/gomobile v0.0.0-20230915142329-c6740b6d2950 github.com/sagernet/gvisor v0.0.0-20231119034329-07cfb6aaf930 - github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 + github.com/sagernet/quic-go v0.40.0 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/sing v0.2.18-0.20231119032432-6a556bfa50cc github.com/sagernet/sing-dns v0.1.11 github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 - github.com/sagernet/sing-quic v0.1.4 + github.com/sagernet/sing-quic v0.1.5-0.20231120105530-5ad0ab6d8e42 github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.5 github.com/sagernet/sing-shadowtls v0.1.4 @@ -65,7 +65,7 @@ require ( github.com/gobwas/pool v0.2.1 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect + github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/native v1.1.0 // indirect @@ -73,11 +73,11 @@ require ( github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/libdns/libdns v0.2.1 // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - github.com/onsi/ginkgo/v2 v2.9.5 // indirect + github.com/onsi/ginkgo/v2 v2.9.7 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-20 v0.3.4 // indirect + github.com/quic-go/qtls-go1-20 v0.4.1 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect diff --git a/go.sum b/go.sum index de645a2a94..e88aa5f022 100644 --- a/go.sum +++ b/go.sum @@ -6,9 +6,6 @@ github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/ github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/caddyserver/certmagic v0.19.2 h1:HZd1AKLx4592MalEGQS39DKs2ZOAJCEM/xYPMQ2/ui0= github.com/caddyserver/certmagic v0.19.2/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG+MIO4ztnmG/zz8= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg= github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -44,11 +41,10 @@ github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk= +github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c h1:PgxFEySCI41sH0mB7/2XswdXbUykQsRUGod8Rn+NubM= @@ -80,9 +76,9 @@ github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= -github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss= +github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= +github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/ooni/go-libtor v1.1.8 h1:Wo3V3DVTxl5vZdxtQakqYP+DAHx7pPtAFSl1bnAa08w= github.com/ooni/go-libtor v1.1.8/go.mod h1:q1YyLwRD9GeMyeerVvwc0vJ2YgwDLTp2bdVcrh/JXyI= github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= @@ -93,8 +89,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= -github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= +github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= @@ -108,8 +104,8 @@ github.com/sagernet/gvisor v0.0.0-20231119034329-07cfb6aaf930 h1:dSPgjIw0CT6ISLe github.com/sagernet/gvisor v0.0.0-20231119034329-07cfb6aaf930/go.mod h1:JpKHkOYgh4wLwrX2BhH3ZIvCvazCkTnPeEcmigZJfHY= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 h1:dAe4OIJAtE0nHOzTHhAReQteh3+sa63rvXbuIpbeOTY= -github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460/go.mod h1:uJGpmJCOcMQqMlHKc3P1Vz6uygmpz4bPeVIoOhdVQnM= +github.com/sagernet/quic-go v0.40.0 h1:DvQNPb72lzvNQDe9tcUyHTw8eRv6PLtM2mNYmdlzUMo= +github.com/sagernet/quic-go v0.40.0/go.mod h1:VqtdhlbkeeG5Okhb3eDMb/9o0EoglReHunNT9ukrJAI= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= @@ -120,8 +116,8 @@ github.com/sagernet/sing-dns v0.1.11 h1:PPrMCVVrAeR3f5X23I+cmvacXJ+kzuyAsBiWyUKh github.com/sagernet/sing-dns v0.1.11/go.mod h1:zJ/YjnYB61SYE+ubMcMqVdpaSvsyQ2iShQGO3vuLvvE= github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 h1:ncKb5tVOsCQgCsv6UpsA0jinbNb5OQ5GMPJlyQP3EHM= github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07/go.mod h1:u/MZf32xPG8jEKe3t+xUV67EBnKtDtCaPhsJQOQGUYU= -github.com/sagernet/sing-quic v0.1.4 h1:F5KRGXMXKQEmP8VrzVollf9HWcRqggcuG9nRCL+5IJ8= -github.com/sagernet/sing-quic v0.1.4/go.mod h1:aXHVP+osF3w5wJzoWZbJSrX3ceJiU9QMd0KPnKV6C/o= +github.com/sagernet/sing-quic v0.1.5-0.20231120105530-5ad0ab6d8e42 h1:yyt9Tk6MvXtte2hPNQ0EKeLOQkMX9EwyPpjCflRXYfM= +github.com/sagernet/sing-quic v0.1.5-0.20231120105530-5ad0ab6d8e42/go.mod h1:B6OgRz+qLn3N1114dcZVExkdarArtsAX2MgWJIfB72c= github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY= github.com/sagernet/sing-shadowsocks v0.2.5/go.mod h1:MGWGkcU2xW2G2mfArT9/QqpVLOGU+dBaahZCtPHdt7A= github.com/sagernet/sing-shadowsocks2 v0.1.5 h1:JDeAJ4ZWlYZ7F6qEVdDKPhQEangxKw/JtmU+i/YfCYE= @@ -185,7 +181,6 @@ golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From 0e50872d0452fdfc8dd04bcac89a66494c195d4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sat, 18 Nov 2023 13:51:32 +0800 Subject: [PATCH 82/87] Add `wifi_ssid` and `wifi_bssid` route and DNS rules --- adapter/router.go | 6 ++++ experimental/clashapi/cachefile/cache.go | 8 ++++- experimental/clashapi/server.go | 2 +- experimental/libbox/command_log.go | 2 +- experimental/libbox/platform.go | 10 ++++++ experimental/libbox/platform/interface.go | 1 + experimental/libbox/service.go | 8 +++++ option/rule.go | 2 ++ option/rule_dns.go | 2 ++ route/router.go | 26 +++++++++++++++ route/router_geo_resources.go | 8 +++++ route/rule_default.go | 10 ++++++ route/rule_dns.go | 10 ++++++ route/rule_item_wifi_bssid.go | 39 +++++++++++++++++++++++ route/rule_item_wifi_ssid.go | 39 +++++++++++++++++++++++ 15 files changed, 170 insertions(+), 3 deletions(-) create mode 100644 route/rule_item_wifi_bssid.go create mode 100644 route/rule_item_wifi_ssid.go diff --git a/adapter/router.go b/adapter/router.go index ab2d916c65..e4c3904d51 100644 --- a/adapter/router.go +++ b/adapter/router.go @@ -41,6 +41,7 @@ type Router interface { NetworkMonitor() tun.NetworkUpdateMonitor InterfaceMonitor() tun.DefaultInterfaceMonitor PackageManager() tun.PackageManager + WIFIState() WIFIState Rules() []Rule ClashServer() ClashServer @@ -78,3 +79,8 @@ type DNSRule interface { type InterfaceUpdateListener interface { InterfaceUpdated() } + +type WIFIState struct { + SSID string + BSSID string +} diff --git a/experimental/clashapi/cachefile/cache.go b/experimental/clashapi/cachefile/cache.go index 0b96fa5def..0911829749 100644 --- a/experimental/clashapi/cachefile/cache.go +++ b/experimental/clashapi/cachefile/cache.go @@ -1,6 +1,7 @@ package cachefile import ( + "context" "errors" "net/netip" "os" @@ -13,6 +14,7 @@ import ( "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/service/filemanager" ) var ( @@ -41,7 +43,7 @@ type CacheFile struct { saveMetadataTimer *time.Timer } -func Open(path string, cacheID string) (*CacheFile, error) { +func Open(ctx context.Context, path string, cacheID string) (*CacheFile, error) { const fileMode = 0o666 options := bbolt.Options{Timeout: time.Second} var ( @@ -67,6 +69,10 @@ func Open(path string, cacheID string) (*CacheFile, error) { if err != nil { return nil, err } + err = filemanager.Chown(ctx, path) + if err != nil { + return nil, E.Cause(err, "platform chown") + } var cacheIDBytes []byte if cacheID != "" { cacheIDBytes = append([]byte{0}, []byte(cacheID)...) diff --git a/experimental/clashapi/server.go b/experimental/clashapi/server.go index 493d73972b..6a3d6f66f7 100644 --- a/experimental/clashapi/server.go +++ b/experimental/clashapi/server.go @@ -148,7 +148,7 @@ func NewServer(ctx context.Context, router adapter.Router, logFactory log.Observ func (s *Server) PreStart() error { if s.cacheFilePath != "" { - cacheFile, err := cachefile.Open(s.cacheFilePath, s.cacheID) + cacheFile, err := cachefile.Open(s.ctx, s.cacheFilePath, s.cacheID) if err != nil { return E.Cause(err, "open cache file") } diff --git a/experimental/libbox/command_log.go b/experimental/libbox/command_log.go index ce72010dd0..da142657e6 100644 --- a/experimental/libbox/command_log.go +++ b/experimental/libbox/command_log.go @@ -60,11 +60,11 @@ func (s *CommandServer) handleLogConn(conn net.Conn) error { for element := s.savedLines.Front(); element != nil; element = element.Next() { savedLines = append(savedLines, element.Value) } - s.access.Unlock() subscription, done, err := s.observer.Subscribe() if err != nil { return err } + s.access.Unlock() defer s.observer.UnSubscribe(subscription) for _, line := range savedLines { err = writeLog(conn, []byte(line)) diff --git a/experimental/libbox/platform.go b/experimental/libbox/platform.go index b7418bd279..451a72a9e1 100644 --- a/experimental/libbox/platform.go +++ b/experimental/libbox/platform.go @@ -19,6 +19,7 @@ type PlatformInterface interface { UsePlatformInterfaceGetter() bool GetInterfaces() (NetworkInterfaceIterator, error) UnderNetworkExtension() bool + ReadWIFIState() *WIFIState ClearDNSCache() } @@ -38,6 +39,15 @@ type NetworkInterface struct { Addresses StringIterator } +type WIFIState struct { + SSID string + BSSID string +} + +func NewWIFIState(wifiSSID string, wifiBSSID string) *WIFIState { + return &WIFIState{wifiSSID, wifiBSSID} +} + type NetworkInterfaceIterator interface { Next() *NetworkInterface HasNext() bool diff --git a/experimental/libbox/platform/interface.go b/experimental/libbox/platform/interface.go index 8c47197186..54d35fa315 100644 --- a/experimental/libbox/platform/interface.go +++ b/experimental/libbox/platform/interface.go @@ -23,6 +23,7 @@ type Interface interface { Interfaces() ([]NetworkInterface, error) UnderNetworkExtension() bool ClearDNSCache() + ReadWIFIState() adapter.WIFIState process.Searcher } diff --git a/experimental/libbox/service.go b/experimental/libbox/service.go index ce4d6d2aad..3375f7502c 100644 --- a/experimental/libbox/service.go +++ b/experimental/libbox/service.go @@ -210,6 +210,14 @@ func (w *platformInterfaceWrapper) ClearDNSCache() { w.iif.ClearDNSCache() } +func (w *platformInterfaceWrapper) ReadWIFIState() adapter.WIFIState { + wifiState := w.iif.ReadWIFIState() + if wifiState == nil { + return adapter.WIFIState{} + } + return (adapter.WIFIState)(*wifiState) +} + func (w *platformInterfaceWrapper) DisableColors() bool { return runtime.GOOS != "android" } diff --git a/option/rule.go b/option/rule.go index f78a752d91..8caba96e57 100644 --- a/option/rule.go +++ b/option/rule.go @@ -78,6 +78,8 @@ type DefaultRule struct { User Listable[string] `json:"user,omitempty"` UserID Listable[int32] `json:"user_id,omitempty"` ClashMode string `json:"clash_mode,omitempty"` + WIFISSID Listable[string] `json:"wifi_ssid,omitempty"` + WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"` Invert bool `json:"invert,omitempty"` Outbound string `json:"outbound,omitempty"` } diff --git a/option/rule_dns.go b/option/rule_dns.go index 563d30850b..ba572b9aa2 100644 --- a/option/rule_dns.go +++ b/option/rule_dns.go @@ -78,6 +78,8 @@ type DefaultDNSRule struct { UserID Listable[int32] `json:"user_id,omitempty"` Outbound Listable[string] `json:"outbound,omitempty"` ClashMode string `json:"clash_mode,omitempty"` + WIFISSID Listable[string] `json:"wifi_ssid,omitempty"` + WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"` Invert bool `json:"invert,omitempty"` Server string `json:"server,omitempty"` DisableCache bool `json:"disable_cache,omitempty"` diff --git a/route/router.go b/route/router.go index 2d2f2cde57..972c4ec048 100644 --- a/route/router.go +++ b/route/router.go @@ -86,6 +86,8 @@ type Router struct { clashServer adapter.ClashServer v2rayServer adapter.V2RayServer platformInterface platform.Interface + needWIFIState bool + wifiState adapter.WIFIState } func NewRouter( @@ -116,6 +118,7 @@ func NewRouter( defaultMark: options.DefaultMark, pauseManager: pause.ManagerFromContext(ctx), platformInterface: platformInterface, + needWIFIState: hasRule(options.Rules, isWIFIRule) || hasDNSRule(dnsOptions.Rules, isWIFIDNSRule), } router.dnsClient = dns.NewClient(dns.ClientOptions{ DisableCache: dnsOptions.DNSClientOptions.DisableCache, @@ -328,6 +331,11 @@ func NewRouter( service.ContextWith[serviceNTP.TimeService](ctx, timeService) router.timeService = timeService } + if platformInterface != nil && router.interfaceMonitor != nil && router.needWIFIState { + router.interfaceMonitor.RegisterCallback(func(_ int) { + router.updateWIFIState() + }) + } return router, nil } @@ -468,6 +476,9 @@ func (r *Router) Start() error { r.geositeCache = nil r.geositeReader = nil } + if r.needWIFIState { + r.updateWIFIState() + } for i, rule := range r.rules { err := rule.Start() if err != nil { @@ -940,6 +951,10 @@ func (r *Router) Rules() []adapter.Rule { return r.rules } +func (r *Router) WIFIState() adapter.WIFIState { + return r.wifiState +} + func (r *Router) NetworkMonitor() tun.NetworkUpdateMonitor { return r.networkMonitor } @@ -1019,3 +1034,14 @@ func (r *Router) ResetNetwork() error { } return nil } + +func (r *Router) updateWIFIState() { + if r.platformInterface == nil { + return + } + state := r.platformInterface.ReadWIFIState() + if state != r.wifiState { + r.wifiState = state + r.logger.Info("updated WIFI state: SSID=", state.SSID, ", BSSID=", state.BSSID) + } +} diff --git a/route/router_geo_resources.go b/route/router_geo_resources.go index 523833dcff..8715cf922c 100644 --- a/route/router_geo_resources.go +++ b/route/router_geo_resources.go @@ -307,3 +307,11 @@ func isProcessDNSRule(rule option.DefaultDNSRule) bool { func notPrivateNode(code string) bool { return code != "private" } + +func isWIFIRule(rule option.DefaultRule) bool { + return len(rule.WIFISSID) > 0 || len(rule.WIFIBSSID) > 0 +} + +func isWIFIDNSRule(rule option.DefaultDNSRule) bool { + return len(rule.WIFISSID) > 0 || len(rule.WIFIBSSID) > 0 +} diff --git a/route/rule_default.go b/route/rule_default.go index 01322c13aa..2d62f97a46 100644 --- a/route/rule_default.go +++ b/route/rule_default.go @@ -184,6 +184,16 @@ func NewDefaultRule(router adapter.Router, logger log.ContextLogger, options opt rule.items = append(rule.items, item) rule.allItems = append(rule.allItems, item) } + if len(options.WIFISSID) > 0 { + item := NewWIFISSIDItem(router, options.WIFISSID) + rule.items = append(rule.items, item) + rule.allItems = append(rule.allItems, item) + } + if len(options.WIFIBSSID) > 0 { + item := NewWIFIBSSIDItem(router, options.WIFIBSSID) + rule.items = append(rule.items, item) + rule.allItems = append(rule.allItems, item) + } return rule, nil } diff --git a/route/rule_dns.go b/route/rule_dns.go index 15e4b16ff1..5132f02456 100644 --- a/route/rule_dns.go +++ b/route/rule_dns.go @@ -180,6 +180,16 @@ func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options rule.items = append(rule.items, item) rule.allItems = append(rule.allItems, item) } + if len(options.WIFISSID) > 0 { + item := NewWIFISSIDItem(router, options.WIFISSID) + rule.items = append(rule.items, item) + rule.allItems = append(rule.allItems, item) + } + if len(options.WIFIBSSID) > 0 { + item := NewWIFIBSSIDItem(router, options.WIFIBSSID) + rule.items = append(rule.items, item) + rule.allItems = append(rule.allItems, item) + } return rule, nil } diff --git a/route/rule_item_wifi_bssid.go b/route/rule_item_wifi_bssid.go new file mode 100644 index 0000000000..3b1ff9c852 --- /dev/null +++ b/route/rule_item_wifi_bssid.go @@ -0,0 +1,39 @@ +package route + +import ( + "strings" + + "github.com/sagernet/sing-box/adapter" + F "github.com/sagernet/sing/common/format" +) + +var _ RuleItem = (*WIFIBSSIDItem)(nil) + +type WIFIBSSIDItem struct { + bssidList []string + bssidMap map[string]bool + router adapter.Router +} + +func NewWIFIBSSIDItem(router adapter.Router, bssidList []string) *WIFIBSSIDItem { + bssidMap := make(map[string]bool) + for _, bssid := range bssidList { + bssidMap[bssid] = true + } + return &WIFIBSSIDItem{ + bssidList, + bssidMap, + router, + } +} + +func (r *WIFIBSSIDItem) Match(metadata *adapter.InboundContext) bool { + return r.bssidMap[r.router.WIFIState().BSSID] +} + +func (r *WIFIBSSIDItem) String() string { + if len(r.bssidList) == 1 { + return F.ToString("wifi_bssid=", r.bssidList[0]) + } + return F.ToString("wifi_bssid=[", strings.Join(r.bssidList, " "), "]") +} diff --git a/route/rule_item_wifi_ssid.go b/route/rule_item_wifi_ssid.go new file mode 100644 index 0000000000..62cf935eb0 --- /dev/null +++ b/route/rule_item_wifi_ssid.go @@ -0,0 +1,39 @@ +package route + +import ( + "strings" + + "github.com/sagernet/sing-box/adapter" + F "github.com/sagernet/sing/common/format" +) + +var _ RuleItem = (*WIFISSIDItem)(nil) + +type WIFISSIDItem struct { + ssidList []string + ssidMap map[string]bool + router adapter.Router +} + +func NewWIFISSIDItem(router adapter.Router, ssidList []string) *WIFISSIDItem { + ssidMap := make(map[string]bool) + for _, ssid := range ssidList { + ssidMap[ssid] = true + } + return &WIFISSIDItem{ + ssidList, + ssidMap, + router, + } +} + +func (r *WIFISSIDItem) Match(metadata *adapter.InboundContext) bool { + return r.ssidMap[r.router.WIFIState().SSID] +} + +func (r *WIFISSIDItem) String() string { + if len(r.ssidList) == 1 { + return F.ToString("wifi_ssid=", r.ssidList[0]) + } + return F.ToString("wifi_ssid=[", strings.Join(r.ssidList, " "), "]") +} From 125691d59f607a7a76c5ac77e0894e2df5496d51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 9 Nov 2023 17:04:08 +0800 Subject: [PATCH 83/87] documentation: Bump version & Refactor docs --- Makefile | 10 +- docs/changelog.md | 113 +++++++ docs/clients/android/features.md | 64 ++++ docs/clients/android/index.md | 22 ++ docs/clients/apple/features.md | 52 ++++ docs/clients/apple/index.md | 32 ++ docs/clients/general.md | 63 ++++ docs/clients/index.md | 13 + docs/clients/index.zh.md | 12 + docs/clients/privacy.md | 8 + docs/configuration/dns/rule.md | 32 +- docs/configuration/dns/rule.zh.md | 30 +- docs/configuration/dns/server.md | 4 +- docs/configuration/experimental/index.md | 8 +- docs/configuration/experimental/index.zh.md | 4 +- docs/configuration/inbound/http.md | 2 +- docs/configuration/inbound/http.zh.md | 2 +- docs/configuration/inbound/hysteria.md | 2 +- docs/configuration/inbound/hysteria2.md | 13 +- docs/configuration/inbound/hysteria2.zh.md | 10 +- docs/configuration/inbound/mixed.md | 2 +- docs/configuration/inbound/mixed.zh.md | 2 +- docs/configuration/inbound/naive.md | 2 +- docs/configuration/inbound/redirect.md | 2 +- docs/configuration/inbound/redirect.zh.md | 2 +- docs/configuration/inbound/tproxy.md | 2 +- docs/configuration/inbound/tproxy.zh.md | 2 +- docs/configuration/inbound/trojan.md | 2 +- docs/configuration/inbound/trojan.zh.md | 2 +- docs/configuration/inbound/tuic.md | 2 +- docs/configuration/inbound/tun.md | 12 +- docs/configuration/inbound/tun.zh.md | 10 +- docs/configuration/outbound/hysteria.md | 2 +- docs/configuration/outbound/hysteria2.md | 10 +- docs/configuration/outbound/hysteria2.zh.md | 6 + docs/configuration/outbound/selector.md | 2 +- docs/configuration/outbound/selector.zh.md | 2 +- docs/configuration/outbound/shadowsocksr.md | 2 +- docs/configuration/outbound/tor.md | 2 +- docs/configuration/outbound/tuic.md | 2 +- docs/configuration/outbound/wireguard.md | 4 +- docs/configuration/route/index.md | 8 +- docs/configuration/route/index.zh.md | 8 +- docs/configuration/route/rule.md | 30 +- docs/configuration/route/rule.zh.md | 30 +- docs/configuration/shared/dial.md | 2 +- docs/configuration/shared/dial.zh.md | 2 +- docs/configuration/shared/tls.md | 10 +- docs/configuration/shared/v2ray-transport.md | 4 +- docs/contributing/environment.md | 50 --- docs/contributing/index.md | 17 -- docs/contributing/sub-projects.md | 67 ---- docs/deprecated.md | 6 + docs/deprecated.zh.md | 17 ++ docs/examples/clash-api.md | 52 ---- docs/examples/dns-hijack.md | 65 ---- docs/examples/dns-hijack.zh.md | 65 ---- docs/examples/fakeip.md | 106 ------- docs/examples/fakeip.zh.md | 106 ------- docs/examples/index.md | 11 - docs/examples/index.zh.md | 11 - docs/examples/linux-server-installation.md | 38 --- docs/examples/linux-server-installation.zh.md | 38 --- docs/examples/shadowsocks.md | 163 ---------- docs/examples/shadowtls.md | 70 ----- docs/examples/tun.md | 89 ------ docs/faq/fakeip.md | 19 -- docs/faq/fakeip.zh.md | 18 -- docs/faq/index.md | 58 ---- docs/faq/index.zh.md | 50 --- docs/faq/known-issues.md | 20 -- docs/faq/known-issues.zh.md | 19 -- docs/features.md | 121 -------- docs/index.md | 2 +- docs/index.zh.md | 2 +- docs/installation/build-from-source.md | 63 ++++ docs/installation/clients/sfa.md | 23 -- docs/installation/clients/sfa.zh.md | 23 -- docs/installation/clients/sfi.md | 23 -- docs/installation/clients/sfi.zh.md | 23 -- docs/installation/clients/sfm.md | 29 -- docs/installation/clients/sfm.zh.md | 29 -- docs/installation/clients/sft.md | 30 -- docs/installation/clients/sft.zh.md | 31 -- docs/installation/clients/specification.md | 25 -- docs/installation/docker.md | 31 ++ docs/installation/from-source.md | 50 --- docs/installation/from-source.zh.md | 39 --- docs/installation/package-manager.md | 90 ++++++ docs/installation/package-manager/android.md | 7 - docs/installation/package-manager/macOS.md | 14 - docs/installation/package-manager/windows.md | 13 - docs/installation/scripts/arch-install.sh | 22 ++ docs/installation/scripts/deb-install.sh | 23 ++ docs/installation/scripts/rpm-install.sh | 22 ++ docs/manual/proxy-protocol/hysteria2.md | 211 +++++++++++++ docs/manual/proxy-protocol/shadowsocks.md | 126 ++++++++ docs/manual/proxy-protocol/trojan.md | 214 +++++++++++++ docs/manual/proxy-protocol/tuic.md | 208 +++++++++++++ docs/manual/proxy/client.md | 287 ++++++++++++++++++ docs/manual/proxy/server.md | 10 + docs/manual/proxy/tun.md | 66 ++++ docs/support.md | 17 +- docs/support.zh.md | 18 +- mkdocs.yml | 145 +++++---- 105 files changed, 2089 insertions(+), 1767 deletions(-) create mode 100644 docs/clients/android/features.md create mode 100644 docs/clients/android/index.md create mode 100644 docs/clients/apple/features.md create mode 100644 docs/clients/apple/index.md create mode 100644 docs/clients/general.md create mode 100644 docs/clients/index.md create mode 100644 docs/clients/index.zh.md create mode 100644 docs/clients/privacy.md delete mode 100644 docs/contributing/environment.md delete mode 100644 docs/contributing/index.md delete mode 100644 docs/contributing/sub-projects.md create mode 100644 docs/deprecated.zh.md delete mode 100644 docs/examples/clash-api.md delete mode 100644 docs/examples/dns-hijack.md delete mode 100644 docs/examples/dns-hijack.zh.md delete mode 100644 docs/examples/fakeip.md delete mode 100644 docs/examples/fakeip.zh.md delete mode 100644 docs/examples/index.md delete mode 100644 docs/examples/index.zh.md delete mode 100644 docs/examples/linux-server-installation.md delete mode 100644 docs/examples/linux-server-installation.zh.md delete mode 100644 docs/examples/shadowsocks.md delete mode 100644 docs/examples/shadowtls.md delete mode 100644 docs/examples/tun.md delete mode 100644 docs/faq/fakeip.md delete mode 100644 docs/faq/fakeip.zh.md delete mode 100644 docs/faq/index.md delete mode 100644 docs/faq/index.zh.md delete mode 100644 docs/faq/known-issues.md delete mode 100644 docs/faq/known-issues.zh.md delete mode 100644 docs/features.md create mode 100644 docs/installation/build-from-source.md delete mode 100644 docs/installation/clients/sfa.md delete mode 100644 docs/installation/clients/sfa.zh.md delete mode 100644 docs/installation/clients/sfi.md delete mode 100644 docs/installation/clients/sfi.zh.md delete mode 100644 docs/installation/clients/sfm.md delete mode 100644 docs/installation/clients/sfm.zh.md delete mode 100644 docs/installation/clients/sft.md delete mode 100644 docs/installation/clients/sft.zh.md delete mode 100644 docs/installation/clients/specification.md create mode 100644 docs/installation/docker.md delete mode 100644 docs/installation/from-source.md delete mode 100644 docs/installation/from-source.zh.md create mode 100644 docs/installation/package-manager.md delete mode 100644 docs/installation/package-manager/android.md delete mode 100644 docs/installation/package-manager/macOS.md delete mode 100644 docs/installation/package-manager/windows.md create mode 100644 docs/installation/scripts/arch-install.sh create mode 100644 docs/installation/scripts/deb-install.sh create mode 100644 docs/installation/scripts/rpm-install.sh create mode 100644 docs/manual/proxy-protocol/hysteria2.md create mode 100644 docs/manual/proxy-protocol/shadowsocks.md create mode 100644 docs/manual/proxy-protocol/trojan.md create mode 100644 docs/manual/proxy-protocol/tuic.md create mode 100644 docs/manual/proxy/client.md create mode 100644 docs/manual/proxy/server.md create mode 100644 docs/manual/proxy/tun.md diff --git a/Makefile b/Makefile index ed62162a28..f1889ffc50 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ MAIN_PARAMS = $(PARAMS) -tags $(TAGS) MAIN = ./cmd/sing-box PREFIX ?= $(shell go env GOPATH) -.PHONY: test release +.PHONY: test release docs build: go build $(MAIN_PARAMS) $(MAIN) @@ -182,6 +182,14 @@ lib_install: go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.0.0-20230915142329-c6740b6d2950 go install -v github.com/sagernet/gomobile/cmd/gobind@v0.0.0-20230915142329-c6740b6d2950 +docs: + mkdocs serve + +publish_docs: + mkdocs gh-deploy -m "Update" --force --ignore-version --no-history + +docs_install: + pip install --force-reinstall mkdocs-material=="9.*" mkdocs-static-i18n=="1.2.*" clean: rm -rf bin dist sing-box rm -f $(shell go env GOPATH)/sing-box diff --git a/docs/changelog.md b/docs/changelog.md index c500a2f262..aa80e1fc9e 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,21 +1,71 @@ +--- +icon: material/alert-decagram +--- + +# ChangeLog + #### 1.6.6 * Fixes and improvements +#### 1.7.0-rc.1 + +* Fixes and improvements + +#### 1.7.0-beta.5 + +* Update gVisor to 20231113.0 +* Fixes and improvements + +#### 1.7.0-beta.4 + +* Add `wifi_ssid` and `wifi_bssid` route and DNS rules **1** +* Fixes and improvements + +**1**: + +Only supported in graphical clients on Android and iOS. + +#### 1.7.0-beta.3 + +* Fix zero TTL was incorrectly reset +* Fixes and improvements + #### 1.6.5 * Fix crash if TUIC inbound authentication failed * Fixes and improvements +#### 1.7.0-beta.2 + +* Fix crash if TUIC inbound authentication failed +* Update quic-go to v0.40.0 +* Fixes and improvements + #### 1.6.4 * Fixes and improvements +#### 1.7.0-beta.1 + +* Fixes and improvements + #### 1.6.3 * iOS/Android: Fix profile auto update * Fixes and improvements +#### 1.7.0-alpha.11 + +* iOS/Android: Fix profile auto update +* Fixes and improvements + +#### 1.7.0-alpha.10 + +* Fix tcp-brutal not working with TLS +* Fix Android client not closing in some cases +* Fixes and improvements + #### 1.6.2 * Fixes and improvements @@ -25,6 +75,34 @@ * Our [Android client](/installation/clients/sfa) is now available in the Google Play Store ▶️ * Fixes and improvements +#### 1.7.0-alpha.6 + +* Fixes and improvements + +#### 1.7.0-alpha.4 + +* Migrate multiplex and UoT server to inbound **1** +* Add TCP Brutal support for multiplex **2** + +**1**: + +Starting in 1.7.0, multiplexing support is no longer enabled by default and needs to be turned on explicitly in inbound options. + +**2** + +Hysteria Brutal Congestion Control Algorithm in TCP. A kernel module needs to be installed on the Linux server, see [TCP Brutal](/configuration/shared/tcp-brutal) for details. + +#### 1.7.0-alpha.3 + +* Add [HTTPUpgrade V2Ray transport](/configuration/shared/v2ray-transport#HTTPUpgrade) support **1** +* Fixes and improvements + +**1**: + +Introduced in V2Ray 5.10.0. + +The new HTTPUpgrade transport has better performance than WebSocket and is better suited for CDN abuse. + #### 1.6.0 * Fixes and improvements @@ -49,6 +127,23 @@ This update is intended to address the multi-send defects of the old implementat Based on discussions with the original author, the brutal CC and QUIC protocol parameters of the old protocol (Hysteria 1) have been updated to be consistent with Hysteria 2 +#### 1.7.0-alpha.2 + +* Fix bugs introduced in 1.7.0-alpha.1 + +#### 1.7.0-alpha.1 + +* Add [exclude route support](/configuration/inbound/tun) for TUN inbound +* Add `udp_disable_domain_unmapping` [inbound listen option](/configuration/shared/listen) **1** +* Fixes and improvements + +**1**: + +If enabled, for UDP proxy requests addressed to a domain, +the original packet address will be sent in the response instead of the mapped domain. + +This option is used for compatibility with clients that +do not support receiving UDP packets with domain addresses, such as Surge. #### 1.5.5 @@ -110,6 +205,24 @@ the old protocol (Hysteria 1) have been updated to be consistent with Hysteria 2 * Update golang.org/x/net to v0.17.0 * Fixes and improvements +#### 1.6.0-beta.3 + +* Update the legacy Hysteria protocol **1** +* Fixes and improvements + +**1** + +Based on discussions with the original author, the brutal CC and QUIC protocol parameters of +the old protocol (Hysteria 1) have been updated to be consistent with Hysteria 2 + +#### 1.6.0-beta.2 + +* Add TLS self sign key pair generate command +* Update brutal congestion control for Hysteria2 +* Fix Clash cache crash on arm32 devices +* Update golang.org/x/net to v0.17.0 +* Fixes and improvements + #### 1.5.3 * Fix compatibility with Android 14 diff --git a/docs/clients/android/features.md b/docs/clients/android/features.md new file mode 100644 index 0000000000..2702e6fa8c --- /dev/null +++ b/docs/clients/android/features.md @@ -0,0 +1,64 @@ +# :material-decagram: Features + +#### UI options + +* Display realtime network speed in the notification + +#### Service + +SFA allows you to run sing-box through ForegroundService or VpnService (when TUN is required). + +#### TUN + +SFA provides an unprivileged TUN implementation through Android VpnService. + +| TUN inbound option | Available | Note | +|-------------------------------|------------------|--------------------| +| `interface_name` | :material-close: | Managed by Android | +| `inet4_address` | :material-check: | / | +| `inet6_address` | :material-check: | / | +| `mtu` | :material-check: | / | +| `auto_route` | :material-check: | / | +| `strict_route` | :material-close: | Not implemented | +| `inet4_route_address` | :material-check: | / | +| `inet6_route_address` | :material-check: | / | +| `inet4_route_exclude_address` | :material-check: | / | +| `inet6_route_exclude_address` | :material-check: | / | +| `endpoint_independent_nat` | :material-check: | / | +| `stack` | :material-check: | / | +| `include_interface` | :material-close: | No permission | +| `exclude_interface` | :material-close: | No permission | +| `include_uid` | :material-close: | No permission | +| `exclude_uid` | :material-close: | No permission | +| `include_android_user` | :material-close: | No permission | +| `include_package` | :material-check: | / | +| `exclude_package` | :material-check: | / | +| `platform` | :material-check: | / | + +| Route/DNS rule option | Available | Note | +|-----------------------|------------------|-----------------------------------| +| `process_name` | :material-close: | No permission | +| `process_path` | :material-close: | No permission | +| `package_name` | :material-check: | / | +| `user` | :material-close: | Use `package_name` instead | +| `user_id` | :material-close: | Use `package_name` instead | +| `wifi_ssid` | :material-check: | Fine location permission required | +| `wifi_bssid` | :material-check: | Fine location permission required | + +### Override + +Overrides profile configuration items with platform-specific values. + +#### Per-app proxy + +SFA allows you to select a list of Android apps that require proxying or bypassing in the graphical interface to +override the `include_package` and `exclude_package` configuration items. + +In particular, the selector also provides the “China apps” scanning feature, providing Chinese users with an excellent +experience to bypass apps that do not require a proxy. Specifically, by scanning China application or SDK +characteristics through dex class path and other means, there will be almost no missed reports. + +### Chore + +* The working directory is located at `/sdcard/Android/data/io.nekohasekai.sfa/files` (External files directory) +* Crash logs is located in `$working_directory/stderr.log` diff --git a/docs/clients/android/index.md b/docs/clients/android/index.md new file mode 100644 index 0000000000..babef2831f --- /dev/null +++ b/docs/clients/android/index.md @@ -0,0 +1,22 @@ +--- +icon: material/android +--- + +# sing-box for Android + +SFA allows users to manage and run local or remote sing-box configuration files, and provides +platform-specific function implementation, such as TUN transparent proxy implementation. + +## :material-graph: Requirements + +* Android 5.0+ + +## :material-download: Download + +* [Play Store](https://play.google.com/store/apps/details?id=io.nekohasekai.sfa) +* [Play Store (Beta)](https://play.google.com/apps/testing/io.nekohasekai.sfa) +* [Github Releases](https://github.com/SagerNet/sing-box/releases) + +## :material-source-repository: Source code + +* [Github](https://github.com/SagerNet/sing-box-for-android) diff --git a/docs/clients/apple/features.md b/docs/clients/apple/features.md new file mode 100644 index 0000000000..95143d98f8 --- /dev/null +++ b/docs/clients/apple/features.md @@ -0,0 +1,52 @@ +# :material-decagram: Features + +#### UI options + +* Always On +* Include All Networks (Proxy traffic for LAN and cellular services) +* (Apple tvOS) Import profile from iPhone/iPad + +#### Service + +SFI/SFM/SFT allows you to run sing-box through NetworkExtension with Application Extension or System Extension. + +#### TUN + +SFI/SFM/SFT provides an unprivileged TUN implementation through NetworkExtension. + +| TUN inbound option | Available | Note | +|-------------------------------|-----------|-------------------| +| `interface_name` | ✖️ | Managed by Darwin | +| `inet4_address` | ✔️ | / | +| `inet6_address` | ✔️ | / | +| `mtu` | ✔️ | / | +| `auto_route` | ✔️ | / | +| `strict_route` | ✖️ | Not implemented | +| `inet4_route_address` | ✔️ | / | +| `inet6_route_address` | ✔️ | / | +| `inet4_route_exclude_address` | ✔️ | / | +| `inet6_route_exclude_address` | ✔️ | / | +| `endpoint_independent_nat` | ✔️ | / | +| `stack` | ✔️ | / | +| `include_interface` | ✖️ | Not implemented | +| `exclude_interface` | ✖️ | Not implemented | +| `include_uid` | ✖️ | Not implemented | +| `exclude_uid` | ✖️ | Not implemented | +| `include_android_user` | ✖️ | Not implemented | +| `include_package` | ✖️ | Not implemented | +| `exclude_package` | ✖️ | Not implemented | +| `platform` | ✔️ | / | + +| Route/DNS rule option | Available | Note | +|-----------------------|------------------|-----------------------| +| `process_name` | :material-close: | No permission | +| `process_path` | :material-close: | No permission | +| `package_name` | :material-close: | / | +| `user` | :material-close: | No permission | +| `user_id` | :material-close: | No permission | +| `wifi_ssid` | :material-alert: | Only supported on iOS | +| `wifi_bssid` | :material-alert: | Only supported on iOS | + +### Chore + +* Crash logs is located in `Settings` -> `View Service Log` diff --git a/docs/clients/apple/index.md b/docs/clients/apple/index.md new file mode 100644 index 0000000000..72cf5f4624 --- /dev/null +++ b/docs/clients/apple/index.md @@ -0,0 +1,32 @@ +--- +icon: material/apple +--- + +# sing-box for Apple platforms + +SFI/SFM/SFT allows users to manage and run local or remote sing-box configuration files, and provides +platform-specific function implementation, such as TUN transparent proxy implementation. + +## :material-graph: Requirements + +* iOS 15.0+ / macOS 13.0+ / Apple tvOS 17.0+ +* An Apple account outside of mainland China + +## :material-download: Download + +* [AppStore](https://apps.apple.com/us/app/sing-box/id6451272673) +* [TestFlight (Beta)](https://testflight.apple.com/join/AcqO44FH) + +## :material-file-download: Download (macOS standalone version) + +* [Homebrew Cask](https://formulae.brew.sh/cask/sfm) + +```bash +brew install sfm +``` + +* [Github Releases](https://github.com/SagerNet/sing-box/releases) + +## :material-source-repository: Source code + +* [Github](https://github.com/SagerNet/sing-box-for-apple) diff --git a/docs/clients/general.md b/docs/clients/general.md new file mode 100644 index 0000000000..4d57c991ce --- /dev/null +++ b/docs/clients/general.md @@ -0,0 +1,63 @@ +--- +icon: material/pencil-ruler +--- + +# General + +Describes and explains the functions implemented uniformly by sing-box graphical clients. + +### Profile + +Profile describes a sing-box configuration file and its state. + +#### Local + +* Local Profile represents a local sing-box configuration with minimal state +* The graphical client must provide an editor to modify configuration content + +#### iCloud (on iOS and macOS) + +* iCloud Profile represents a remote sing-box configuration with iCloud as the update source +* The configuration file is stored in the sing-box folder under iCloud +* The graphical client must provide an editor to modify configuration content + +#### Remote + +* Remote Profile represents a remote sing-box configuration with a URL as the update source. +* The graphical client should provide a configuration content viewer +* The graphical client must implement automatic profile update (default interval is 60 minutes) and HTTP Basic + authorization. + +At the same time, the graphical client must provide support for importing remote profiles +through a specific URL Scheme. The URL is defined as follows: + +``` +sing-box://import-remote-profile?url=urlEncodedURL#urlEncodedName +``` + +### Dashboard + +While the sing-box service is running, the graphical client should provide a Dashboard interface to manage the service. + +#### Status + +Dashboard should display status information such as memory, connection, and traffic. + +#### Mode + +Dashboard should provide a Mode selector for switching when the configuration uses at least two `clash_mode` values. + +#### Groups + +When the configuration includes group outbounds (specifically, Selector or URLTest), +the dashboard should provide a Group selector for status display or switching. + +### Chore + +#### Core + +Graphical clients should provide a Core region: + +* Display the current sing-box version +* Provides a button to clean the working directory +* Provides a memory limiter switch \ No newline at end of file diff --git a/docs/clients/index.md b/docs/clients/index.md new file mode 100644 index 0000000000..b80c161867 --- /dev/null +++ b/docs/clients/index.md @@ -0,0 +1,13 @@ +# :material-cellphone-link: Graphical Clients + +Maintained by Project S to provide a unified experience and platform-specific functionality. + +| Platform | Client | +|---------------------------------------|-----------------------------------------| +| :material-android: Android | [sing-box for Android](./android) | +| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple) | +| :material-laptop: Desktop | Working in progress | + +Some third-party projects that claim to use sing-box or use sing-box as a selling point are not listed here. The core +motivation of the maintainers of such projects is to acquire more users, and even though they provide friendly VPN +client features, the code is usually of poor quality and contains ads. diff --git a/docs/clients/index.zh.md b/docs/clients/index.zh.md new file mode 100644 index 0000000000..ef643086ac --- /dev/null +++ b/docs/clients/index.zh.md @@ -0,0 +1,12 @@ +# :material-cellphone-link: 图形界面客户端 + +由 Project S 维护,提供统一的体验与平台特定的功能。 + +| 平台 | 客户端 | +|---------------------------------------|-----------------------------------------| +| :material-android: Android | [sing-box for Android](./android) | +| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple) | +| :material-laptop: Desktop | 施工中 | + +此处没有列出一些声称使用或以 sing-box 为卖点的第三方项目。此类项目维护者的动机是获得更多用户,即使它们提供友好的商业 +VPN 客户端功能, 但代码质量很差且包含广告。 diff --git a/docs/clients/privacy.md b/docs/clients/privacy.md new file mode 100644 index 0000000000..f8b51afd1a --- /dev/null +++ b/docs/clients/privacy.md @@ -0,0 +1,8 @@ +--- +icon: material/security +--- + +# Privacy policy + +sing-box and official graphics clients do not collect or share personal data, +and the data generated by the software is always on your device. diff --git a/docs/configuration/dns/rule.md b/docs/configuration/dns/rule.md index f7c46db396..18e352b407 100644 --- a/docs/configuration/dns/rule.md +++ b/docs/configuration/dns/rule.md @@ -79,6 +79,12 @@ 1000 ], "clash_mode": "direct", + "wifi_ssid": [ + "My WIFI" + ], + "wifi_bssid": [ + "00:00:00:00:00:00" + ], "invert": false, "outbound": [ "direct" @@ -188,7 +194,7 @@ Match port range. #### process_name -!!! error "" +!!! quote "" Only supported on Linux, Windows, and macOS. @@ -196,7 +202,7 @@ Match process name. #### process_path -!!! error "" +!!! quote "" Only supported on Linux, Windows, and macOS. @@ -208,7 +214,7 @@ Match android package name. #### user -!!! error "" +!!! quote "" Only supported on Linux. @@ -216,7 +222,7 @@ Match user name. #### user_id -!!! error "" +!!! quote "" Only supported on Linux. @@ -226,6 +232,24 @@ Match user id. Match Clash mode. +#### wifi_ssid + + + +!!! quote "" + + Only supported in graphical clients on Android and iOS. + +Match WiFi SSID. + +#### wifi_bssid + +!!! quote "" + + Only supported in graphical clients on Android and iOS. + +Match WiFi BSSID. + #### invert Invert match result. diff --git a/docs/configuration/dns/rule.zh.md b/docs/configuration/dns/rule.zh.md index 9af71a40b3..98bfa8ab9a 100644 --- a/docs/configuration/dns/rule.zh.md +++ b/docs/configuration/dns/rule.zh.md @@ -78,6 +78,12 @@ 1000 ], "clash_mode": "direct", + "wifi_ssid": [ + "My WIFI" + ], + "wifi_bssid": [ + "00:00:00:00:00:00" + ], "invert": false, "outbound": [ "direct" @@ -185,7 +191,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。 #### process_name -!!! error "" +!!! quote "" 仅支持 Linux、Windows 和 macOS. @@ -193,7 +199,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。 #### process_path -!!! error "" +!!! quote "" 仅支持 Linux、Windows 和 macOS. @@ -205,7 +211,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。 #### user -!!! error "" +!!! quote "" 仅支持 Linux。 @@ -213,7 +219,7 @@ DNS 查询类型。值可以为整数或者类型名称字符串。 #### user_id -!!! error "" +!!! quote "" 仅支持 Linux。 @@ -223,6 +229,22 @@ DNS 查询类型。值可以为整数或者类型名称字符串。 匹配 Clash 模式。 +#### wifi_ssid + +!!! quote "" + + 仅在 Android 与 iOS 的图形客户端中支持。 + +匹配 WiFi SSID。 + +#### wifi_bssid + +!!! quote "" + + 仅在 Android 与 iOS 的图形客户端中支持。 + +匹配 WiFi BSSID。 + #### invert 反选匹配结果。 diff --git a/docs/configuration/dns/server.md b/docs/configuration/dns/server.md index 48fb1bb0c0..2ce50b38e1 100644 --- a/docs/configuration/dns/server.md +++ b/docs/configuration/dns/server.md @@ -49,7 +49,7 @@ The address of the dns server. !!! warning "" - QUIC and HTTP3 transport is not included by default, see [Installation](/#installation). + QUIC and HTTP3 transport is not included by default, see [Installation](./#installation). !!! info "" @@ -57,7 +57,7 @@ The address of the dns server. !!! warning "" - DHCP transport is not included by default, see [Installation](/#installation). + DHCP transport is not included by default, see [Installation](./#installation). | RCode | Description | |-------------------|-----------------------| diff --git a/docs/configuration/experimental/index.md b/docs/configuration/experimental/index.md index 9af9ec09a9..308e851c3b 100644 --- a/docs/configuration/experimental/index.md +++ b/docs/configuration/experimental/index.md @@ -44,9 +44,9 @@ ### Clash API Fields -!!! error "" +!!! quote "" - Clash API is not included by default, see [Installation](/#installation). + Clash API is not included by default, see [Installation](./#installation). #### external_controller @@ -110,9 +110,9 @@ If not empty, `store_selected` will use a separate store keyed by it. ### V2Ray API Fields -!!! error "" +!!! quote "" - V2Ray API is not included by default, see [Installation](/#installation). + V2Ray API is not included by default, see [Installation](./#installation). #### listen diff --git a/docs/configuration/experimental/index.zh.md b/docs/configuration/experimental/index.zh.md index 7bc2a62c9d..88a95852c9 100644 --- a/docs/configuration/experimental/index.zh.md +++ b/docs/configuration/experimental/index.zh.md @@ -44,7 +44,7 @@ ### Clash API 字段 -!!! error "" +!!! quote "" 默认安装不包含 Clash API,参阅 [安装](/zh/#_2)。 @@ -108,7 +108,7 @@ Clash 中的默认模式,默认使用 `Rule`。 ### V2Ray API 字段 -!!! error "" +!!! quote "" 默认安装不包含 V2Ray API,参阅 [安装](/zh/#_2)。 diff --git a/docs/configuration/inbound/http.md b/docs/configuration/inbound/http.md index dc80cf0aa9..3b14905015 100644 --- a/docs/configuration/inbound/http.md +++ b/docs/configuration/inbound/http.md @@ -36,7 +36,7 @@ No authentication required if empty. #### set_system_proxy -!!! error "" +!!! quote "" Only supported on Linux, Android, Windows, and macOS. diff --git a/docs/configuration/inbound/http.zh.md b/docs/configuration/inbound/http.zh.md index b7228eb9c3..2f3d44f556 100644 --- a/docs/configuration/inbound/http.zh.md +++ b/docs/configuration/inbound/http.zh.md @@ -36,7 +36,7 @@ HTTP 用户 #### set_system_proxy -!!! error "" +!!! quote "" 仅支持 Linux、Android、Windows 和 macOS。 diff --git a/docs/configuration/inbound/hysteria.md b/docs/configuration/inbound/hysteria.md index 5026010493..f027a05650 100644 --- a/docs/configuration/inbound/hysteria.md +++ b/docs/configuration/inbound/hysteria.md @@ -31,7 +31,7 @@ !!! warning "" - QUIC, which is required by hysteria is not included by default, see [Installation](/#installation). + QUIC, which is required by hysteria is not included by default, see [Installation](./#installation). ### Listen Fields diff --git a/docs/configuration/inbound/hysteria2.md b/docs/configuration/inbound/hysteria2.md index ab6f2e4dd1..4427b6517e 100644 --- a/docs/configuration/inbound/hysteria2.md +++ b/docs/configuration/inbound/hysteria2.md @@ -4,8 +4,8 @@ { "type": "hysteria2", "tag": "hy2-in", - - ... // Listen Fields + ... + // Listen Fields "up_mbps": 100, "down_mbps": 100, @@ -28,7 +28,14 @@ !!! warning "" - QUIC, which is required by Hysteria2 is not included by default, see [Installation](/#installation). + QUIC, which is required by Hysteria2 is not included by default, see [Installation](./#installation). + +!!! warning "Difference from official Hysteria2" + + The official program supports an authentication method called **userpass**, + which essentially uses a combination of `:` as the actual password, + while sing-box does not provide this alias. + To use sing-box with the official program, you need to fill in that combination as the actual password. ### Listen Fields diff --git a/docs/configuration/inbound/hysteria2.zh.md b/docs/configuration/inbound/hysteria2.zh.md index f43188c09f..4d5a94157c 100644 --- a/docs/configuration/inbound/hysteria2.zh.md +++ b/docs/configuration/inbound/hysteria2.zh.md @@ -4,8 +4,8 @@ { "type": "hysteria2", "tag": "hy2-in", - - ... // 监听字段 + ... + // 监听字段 "up_mbps": 100, "down_mbps": 100, @@ -30,6 +30,12 @@ 默认安装不包含被 Hysteria2 依赖的 QUIC,参阅 [安装](/zh/#_2)。 +!!! warning "与官方 Hysteria2 的区别" + + 官方程序支持一种名为 **userpass** 的验证方式, + 本质上上是将用户名与密码的组合 `:` 作为实际上的密码,而 sing-box 不提供此别名。 + 要将 sing-box 与官方程序一起使用, 您需要填写该组合作为实际密码。 + ### 监听字段 参阅 [监听字段](/zh/configuration/shared/listen/)。 diff --git a/docs/configuration/inbound/mixed.md b/docs/configuration/inbound/mixed.md index 9e262c7d57..62313f489d 100644 --- a/docs/configuration/inbound/mixed.md +++ b/docs/configuration/inbound/mixed.md @@ -33,7 +33,7 @@ No authentication required if empty. #### set_system_proxy -!!! error "" +!!! quote "" Only supported on Linux, Android, Windows, and macOS. diff --git a/docs/configuration/inbound/mixed.zh.md b/docs/configuration/inbound/mixed.zh.md index 8f00af14d4..448c66b464 100644 --- a/docs/configuration/inbound/mixed.zh.md +++ b/docs/configuration/inbound/mixed.zh.md @@ -33,7 +33,7 @@ SOCKS 和 HTTP 用户 #### set_system_proxy -!!! error "" +!!! quote "" 仅支持 Linux、Android、Windows 和 macOS。 diff --git a/docs/configuration/inbound/naive.md b/docs/configuration/inbound/naive.md index 35ad109616..562a70703d 100644 --- a/docs/configuration/inbound/naive.md +++ b/docs/configuration/inbound/naive.md @@ -20,7 +20,7 @@ !!! warning "" - HTTP3 transport is not included by default, see [Installation](/#installation). + HTTP3 transport is not included by default, see [Installation](./#installation). ### Listen Fields diff --git a/docs/configuration/inbound/redirect.md b/docs/configuration/inbound/redirect.md index 9ea418eef6..97736e286b 100644 --- a/docs/configuration/inbound/redirect.md +++ b/docs/configuration/inbound/redirect.md @@ -1,4 +1,4 @@ -!!! error "" +!!! quote "" Only supported on Linux and macOS. diff --git a/docs/configuration/inbound/redirect.zh.md b/docs/configuration/inbound/redirect.zh.md index 125dc73f84..a03049e5cd 100644 --- a/docs/configuration/inbound/redirect.zh.md +++ b/docs/configuration/inbound/redirect.zh.md @@ -1,4 +1,4 @@ -!!! error "" +!!! quote "" 仅支持 Linux 和 macOS。 diff --git a/docs/configuration/inbound/tproxy.md b/docs/configuration/inbound/tproxy.md index c637707294..4975931e89 100644 --- a/docs/configuration/inbound/tproxy.md +++ b/docs/configuration/inbound/tproxy.md @@ -1,4 +1,4 @@ -!!! error "" +!!! quote "" Only supported on Linux. diff --git a/docs/configuration/inbound/tproxy.zh.md b/docs/configuration/inbound/tproxy.zh.md index 9ab98e5782..6e35ad5e0c 100644 --- a/docs/configuration/inbound/tproxy.zh.md +++ b/docs/configuration/inbound/tproxy.zh.md @@ -1,4 +1,4 @@ -!!! error "" +!!! quote "" 仅支持 Linux。 diff --git a/docs/configuration/inbound/trojan.md b/docs/configuration/inbound/trojan.md index 787d2b11bf..cd45539ddc 100644 --- a/docs/configuration/inbound/trojan.md +++ b/docs/configuration/inbound/trojan.md @@ -47,7 +47,7 @@ TLS configuration, see [TLS](/configuration/shared/tls/#inbound). #### fallback -!!! error "" +!!! quote "" There is no evidence that GFW detects and blocks Trojan servers based on HTTP responses, and opening the standard http/s port on the server is a much bigger signature. diff --git a/docs/configuration/inbound/trojan.zh.md b/docs/configuration/inbound/trojan.zh.md index f52422af82..54144ae680 100644 --- a/docs/configuration/inbound/trojan.zh.md +++ b/docs/configuration/inbound/trojan.zh.md @@ -49,7 +49,7 @@ TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。 #### fallback -!!! error "" +!!! quote "" 没有证据表明 GFW 基于 HTTP 响应检测并阻止 Trojan 服务器,并且在服务器上打开标准 http/s 端口是一个更大的特征。 diff --git a/docs/configuration/inbound/tuic.md b/docs/configuration/inbound/tuic.md index 51724e5d84..d4d9aafdb2 100644 --- a/docs/configuration/inbound/tuic.md +++ b/docs/configuration/inbound/tuic.md @@ -24,7 +24,7 @@ !!! warning "" - QUIC, which is required by TUIC is not included by default, see [Installation](/#installation). + QUIC, which is required by TUIC is not included by default, see [Installation](./#installation). ### Listen Fields diff --git a/docs/configuration/inbound/tun.md b/docs/configuration/inbound/tun.md index e6c52c54c1..1d493d58e8 100644 --- a/docs/configuration/inbound/tun.md +++ b/docs/configuration/inbound/tun.md @@ -1,4 +1,4 @@ -!!! error "" +!!! quote "" Only supported on Linux, Windows and macOS. @@ -102,7 +102,7 @@ The maximum transmission unit. Set the default route to the Tun. -!!! error "" +!!! quote "" To avoid traffic loopback, set `route.auto_detect_interface` or `route.default_interface` or `outbound.bind_interface` @@ -171,11 +171,11 @@ TCP/IP stack. !!! warning "" - gVisor and LWIP stacks is not included by default, see [Installation](/#installation). + gVisor and LWIP stacks is not included by default, see [Installation](./#installation). #### include_interface -!!! error "" +!!! quote "" Interface rules are only supported on Linux and require auto_route. @@ -191,7 +191,7 @@ Conflict with `include_interface`. #### include_uid -!!! error "" +!!! quote "" UID rules are only supported on Linux and require auto_route. @@ -211,7 +211,7 @@ Exclude users in route, but in range. #### include_android_user -!!! error "" +!!! quote "" Android user and package rules are only supported on Android and require auto_route. diff --git a/docs/configuration/inbound/tun.zh.md b/docs/configuration/inbound/tun.zh.md index 8f246c042b..7ea3a6a030 100644 --- a/docs/configuration/inbound/tun.zh.md +++ b/docs/configuration/inbound/tun.zh.md @@ -1,4 +1,4 @@ -!!! error "" +!!! quote "" 仅支持 Linux、Windows 和 macOS。 @@ -102,7 +102,7 @@ tun 接口的 IPv6 前缀。 设置到 Tun 的默认路由。 -!!! error "" +!!! quote "" 为避免流量环回,请设置 `route.auto_detect_interface` 或 `route.default_interface` 或 `outbound.bind_interface`。 @@ -171,7 +171,7 @@ TCP/IP 栈。 #### include_interface -!!! error "" +!!! quote "" 接口规则仅在 Linux 下被支持,并且需要 `auto_route`。 @@ -187,7 +187,7 @@ TCP/IP 栈。 #### include_uid -!!! error "" +!!! quote "" UID 规则仅在 Linux 下被支持,并且需要 `auto_route`。 @@ -207,7 +207,7 @@ TCP/IP 栈。 #### include_android_user -!!! error "" +!!! quote "" Android 用户和应用规则仅在 Android 下被支持,并且需要 `auto_route`。 diff --git a/docs/configuration/outbound/hysteria.md b/docs/configuration/outbound/hysteria.md index 8eafa99c27..ff9974de61 100644 --- a/docs/configuration/outbound/hysteria.md +++ b/docs/configuration/outbound/hysteria.md @@ -26,7 +26,7 @@ !!! warning "" - QUIC, which is required by hysteria is not included by default, see [Installation](/#installation). + QUIC, which is required by hysteria is not included by default, see [Installation](./#installation). ### Fields diff --git a/docs/configuration/outbound/hysteria2.md b/docs/configuration/outbound/hysteria2.md index 9861e332ac..90860c1c4f 100644 --- a/docs/configuration/outbound/hysteria2.md +++ b/docs/configuration/outbound/hysteria2.md @@ -24,7 +24,15 @@ !!! warning "" - QUIC, which is required by Hysteria2 is not included by default, see [Installation](/#installation). + QUIC, which is required by Hysteria2 is not included by default, see [Installation](./#installation). + +!!! warning "Difference from official Hysteria2" + + The official Hysteria2 supports an authentication method called **userpass**, + which essentially uses a combination of `:` as the actual password, + while sing-box does not provide this alias. + If you are planning to use sing-box with the official program, + please note that you will need to fill the combination as the password. ### Fields diff --git a/docs/configuration/outbound/hysteria2.zh.md b/docs/configuration/outbound/hysteria2.zh.md index 1e490a63af..5d20802794 100644 --- a/docs/configuration/outbound/hysteria2.zh.md +++ b/docs/configuration/outbound/hysteria2.zh.md @@ -26,6 +26,12 @@ 默认安装不包含被 Hysteria2 依赖的 QUIC,参阅 [安装](/zh/#_2)。 +!!! warning "与官方 Hysteria2 的区别" + + 官方程序支持一种名为 **userpass** 的验证方式, + 本质上上是将用户名与密码的组合 `:` 作为实际上的密码,而 sing-box 不提供此别名。 + 要将 sing-box 与官方程序一起使用, 您需要填写该组合作为实际密码。 + ### 字段 #### server diff --git a/docs/configuration/outbound/selector.md b/docs/configuration/outbound/selector.md index 1d2c74a9ea..ee75358f5b 100644 --- a/docs/configuration/outbound/selector.md +++ b/docs/configuration/outbound/selector.md @@ -15,7 +15,7 @@ } ``` -!!! error "" +!!! quote "" The selector can only be controlled through the [Clash API](/configuration/experimental#clash-api-fields) currently. diff --git a/docs/configuration/outbound/selector.zh.md b/docs/configuration/outbound/selector.zh.md index 9e985ab1fa..ffe2d70ae1 100644 --- a/docs/configuration/outbound/selector.zh.md +++ b/docs/configuration/outbound/selector.zh.md @@ -15,7 +15,7 @@ } ``` -!!! error "" +!!! quote "" 选择器目前只能通过 [Clash API](/zh/configuration/experimental#clash-api) 来控制。 diff --git a/docs/configuration/outbound/shadowsocksr.md b/docs/configuration/outbound/shadowsocksr.md index 43c71b990f..0c7f1b32b7 100644 --- a/docs/configuration/outbound/shadowsocksr.md +++ b/docs/configuration/outbound/shadowsocksr.md @@ -25,7 +25,7 @@ !!! warning "" - ShadowsocksR is not included by default, see [Installation](/#installation). + ShadowsocksR is not included by default, see [Installation](./#installation). ### Fields diff --git a/docs/configuration/outbound/tor.md b/docs/configuration/outbound/tor.md index 2b0cc9f00e..fe7e4ff6f9 100644 --- a/docs/configuration/outbound/tor.md +++ b/docs/configuration/outbound/tor.md @@ -18,7 +18,7 @@ !!! info "" - Embedded tor is not included by default, see [Installation](/#installation). + Embedded tor is not included by default, see [Installation](./#installation). ### Fields diff --git a/docs/configuration/outbound/tuic.md b/docs/configuration/outbound/tuic.md index bbcc199ff2..522e78924a 100644 --- a/docs/configuration/outbound/tuic.md +++ b/docs/configuration/outbound/tuic.md @@ -23,7 +23,7 @@ !!! warning "" - QUIC, which is required by TUIC is not included by default, see [Installation](/#installation). + QUIC, which is required by TUIC is not included by default, see [Installation](./#installation). ### Fields diff --git a/docs/configuration/outbound/wireguard.md b/docs/configuration/outbound/wireguard.md index f4a8810895..c9c49c79b8 100644 --- a/docs/configuration/outbound/wireguard.md +++ b/docs/configuration/outbound/wireguard.md @@ -38,11 +38,11 @@ !!! warning "" - WireGuard is not included by default, see [Installation](/#installation). + WireGuard is not included by default, see [Installation](./#installation). !!! warning "" - gVisor, which is required by the unprivileged WireGuard is not included by default, see [Installation](/#installation). + gVisor, which is required by the unprivileged WireGuard is not included by default, see [Installation](./#installation). ### Fields diff --git a/docs/configuration/route/index.md b/docs/configuration/route/index.md index 8c6ca6e110..846d497330 100644 --- a/docs/configuration/route/index.md +++ b/docs/configuration/route/index.md @@ -31,7 +31,7 @@ Default outbound tag. the first outbound will be used if empty. #### auto_detect_interface -!!! error "" +!!! quote "" Only supported on Linux, Windows and macOS. @@ -41,7 +41,7 @@ Takes no effect if `outbound.bind_interface` is set. #### override_android_vpn -!!! error "" +!!! quote "" Only supported on Android. @@ -49,7 +49,7 @@ Accept Android VPN as upstream NIC when `auto_detect_interface` enabled. #### default_interface -!!! error "" +!!! quote "" Only supported on Linux, Windows and macOS. @@ -59,7 +59,7 @@ Takes no effect if `auto_detect_interface` is set. #### default_mark -!!! error "" +!!! quote "" Only supported on Linux. diff --git a/docs/configuration/route/index.zh.md b/docs/configuration/route/index.zh.md index c3ef2e54cf..8bef5bea9a 100644 --- a/docs/configuration/route/index.zh.md +++ b/docs/configuration/route/index.zh.md @@ -32,7 +32,7 @@ #### auto_detect_interface -!!! error "" +!!! quote "" 仅支持 Linux、Windows 和 macOS。 @@ -42,7 +42,7 @@ #### override_android_vpn -!!! error "" +!!! quote "" 仅支持 Android。 @@ -50,7 +50,7 @@ #### default_interface -!!! error "" +!!! quote "" 仅支持 Linux、Windows 和 macOS。 @@ -60,7 +60,7 @@ #### default_mark -!!! error "" +!!! quote "" 仅支持 Linux。 diff --git a/docs/configuration/route/rule.md b/docs/configuration/route/rule.md index 3cee478dc3..abbfde6fdc 100644 --- a/docs/configuration/route/rule.md +++ b/docs/configuration/route/rule.md @@ -83,6 +83,12 @@ 1000 ], "clash_mode": "direct", + "wifi_ssid": [ + "My WIFI" + ], + "wifi_bssid": [ + "00:00:00:00:00:00" + ], "invert": false, "outbound": "direct" }, @@ -190,7 +196,7 @@ Match port range. #### process_name -!!! error "" +!!! quote "" Only supported on Linux, Windows, and macOS. @@ -198,7 +204,7 @@ Match process name. #### process_path -!!! error "" +!!! quote "" Only supported on Linux, Windows, and macOS. @@ -210,7 +216,7 @@ Match android package name. #### user -!!! error "" +!!! quote "" Only supported on Linux. @@ -218,7 +224,7 @@ Match user name. #### user_id -!!! error "" +!!! quote "" Only supported on Linux. @@ -228,6 +234,22 @@ Match user id. Match Clash mode. +#### wifi_ssid + +!!! quote "" + + Only supported in graphical clients on Android and iOS. + +Match WiFi SSID. + +#### wifi_bssid + +!!! quote "" + + Only supported in graphical clients on Android and iOS. + +Match WiFi BSSID. + #### invert Invert match result. diff --git a/docs/configuration/route/rule.zh.md b/docs/configuration/route/rule.zh.md index 4a09ed8e64..f4ab7890a7 100644 --- a/docs/configuration/route/rule.zh.md +++ b/docs/configuration/route/rule.zh.md @@ -81,6 +81,12 @@ 1000 ], "clash_mode": "direct", + "wifi_ssid": [ + "My WIFI" + ], + "wifi_bssid": [ + "00:00:00:00:00:00" + ], "invert": false, "outbound": "direct" }, @@ -188,7 +194,7 @@ #### process_name -!!! error "" +!!! quote "" 仅支持 Linux、Windows 和 macOS。 @@ -196,7 +202,7 @@ #### process_path -!!! error "" +!!! quote "" 仅支持 Linux、Windows 和 macOS. @@ -208,7 +214,7 @@ #### user -!!! error "" +!!! quote "" 仅支持 Linux. @@ -216,7 +222,7 @@ #### user_id -!!! error "" +!!! quote "" 仅支持 Linux. @@ -226,6 +232,22 @@ 匹配 Clash 模式。 +#### wifi_ssid + +!!! quote "" + + 仅在 Android 与 iOS 的图形客户端中支持。 + +匹配 WiFi SSID。 + +#### wifi_bssid + +!!! quote "" + + 仅在 Android 与 iOS 的图形客户端中支持。 + +匹配 WiFi BSSID。 + #### invert 反选匹配结果。 diff --git a/docs/configuration/shared/dial.md b/docs/configuration/shared/dial.md index 1f524f0800..8139c7518c 100644 --- a/docs/configuration/shared/dial.md +++ b/docs/configuration/shared/dial.md @@ -41,7 +41,7 @@ The IPv6 address to bind to. #### routing_mark -!!! error "" +!!! quote "" Only supported on Linux. diff --git a/docs/configuration/shared/dial.zh.md b/docs/configuration/shared/dial.zh.md index 62b094f3fb..300e99ff7a 100644 --- a/docs/configuration/shared/dial.zh.md +++ b/docs/configuration/shared/dial.zh.md @@ -44,7 +44,7 @@ #### routing_mark -!!! error "" +!!! quote "" 仅支持 Linux。 diff --git a/docs/configuration/shared/tls.md b/docs/configuration/shared/tls.md index 4d395f7786..9a02bbff2f 100644 --- a/docs/configuration/shared/tls.md +++ b/docs/configuration/shared/tls.md @@ -201,7 +201,7 @@ The path to the server private key, in PEM format. !!! warning "" - uTLS is not included by default, see [Installation](/#installation). + uTLS is not included by default, see [Installation](./#installation). !!! note "" @@ -228,7 +228,7 @@ Chrome fingerprint will be used if empty. !!! warning "" - ECH is not included by default, see [Installation](/#installation). + ECH is not included by default, see [Installation](./#installation). ECH (Encrypted Client Hello) is a TLS extension that allows a client to encrypt the first part of its ClientHello message. @@ -280,7 +280,7 @@ If empty, load from DNS will be attempted. !!! warning "" - ACME is not included by default, see [Installation](/#installation). + ACME is not included by default, see [Installation](./#installation). #### domain @@ -359,11 +359,11 @@ See [DNS01 Challenge Fields](/configuration/shared/dns01_challenge) for details. !!! warning "" - reality server is not included by default, see [Installation](/#installation). + reality server is not included by default, see [Installation](./#installation). !!! warning "" - uTLS, which is required by reality client is not included by default, see [Installation](/#installation). + uTLS, which is required by reality client is not included by default, see [Installation](./#installation). #### handshake diff --git a/docs/configuration/shared/v2ray-transport.md b/docs/configuration/shared/v2ray-transport.md index 418ef28db2..b078bac8af 100644 --- a/docs/configuration/shared/v2ray-transport.md +++ b/docs/configuration/shared/v2ray-transport.md @@ -131,7 +131,7 @@ It needs to be consistent with the server. !!! warning "" - QUIC is not included by default, see [Installation](/#installation). + QUIC is not included by default, see [Installation](./#installation). !!! warning "Difference from v2ray-core" @@ -142,7 +142,7 @@ It needs to be consistent with the server. !!! note "" - standard gRPC has good compatibility but poor performance and is not included by default, see [Installation](/#installation). + standard gRPC has good compatibility but poor performance and is not included by default, see [Installation](./#installation). ```json { diff --git a/docs/contributing/environment.md b/docs/contributing/environment.md deleted file mode 100644 index db2ac91aff..0000000000 --- a/docs/contributing/environment.md +++ /dev/null @@ -1,50 +0,0 @@ -# Development environment - -#### For the documentation - -##### Setup - -You need to configure python3 and pip first. - -```shell -pip install mkdocs-material mkdocs-static-i18n -``` - -##### Run the site locally - -```shell -mkdocs serve -``` - -or - -```shell -python3 -m mkdocs serve -``` - -#### For the project - -By default you have the latest Go installed (currently 1.19), and added `GOPATH/bin` to the PATH environment variable. - -##### Setup - -```shell -make fmt_insalll -make lint_install -``` - -This installs the formatting and lint tools, which can be used via `make fmt` and `make lint`. - -For ProtoBuffer changes, you also need `make proto_install` and `make proto`. - -##### Build binary to the project directory - -```shell -make -``` - -##### Install binary to GOPATH/bin - -```shell -make install -``` \ No newline at end of file diff --git a/docs/contributing/index.md b/docs/contributing/index.md deleted file mode 100644 index d669bda62c..0000000000 --- a/docs/contributing/index.md +++ /dev/null @@ -1,17 +0,0 @@ -# Contributing to sing-box - -An introduction to contributing to the sing-box project. - -The sing-box project welcomes, and depends, on contributions from developers and users in the open source community. -Contributions can be made in a number of ways, a few examples are: - -* Code patches via pull requests -* Documentation improvements -* Bug reports and patch reviews - -### Reporting an Issue? - -Please follow -the [issue template](https://github.com/SagerNet/sing-box/issues/new?assignees=&labels=&template=bug_report.yml) to -submit bugs. Always include **FULL** log content, especially if you don't understand the code that generates it. - diff --git a/docs/contributing/sub-projects.md b/docs/contributing/sub-projects.md deleted file mode 100644 index 3f62a52cd9..0000000000 --- a/docs/contributing/sub-projects.md +++ /dev/null @@ -1,67 +0,0 @@ -The sing-box uses the following projects which also need to be maintained: - -#### sing - -Link: [GitHub repository](https://github.com/SagerNet/sing) - -As a base tool library, there are no dependencies other than `golang.org/x/sys`. - -#### sing-dns - -Link: [GitHub repository](https://github.com/SagerNet/sing-dns) - -Handles DNS lookups and caching. - -#### sing-tun - -Link: [GitHub repository](https://github.com/SagerNet/sing-tun) - -Handle Tun traffic forwarding, configure routing, monitor network and routing. - -This library needs to periodically update its dependency gVisor (according to tags), including checking for changes to -the used parts of the code and updating its usage. If you are involved in maintenance, you also need to check that if it -works or contains memory leaks. - -#### sing-shadowsocks - -Link: [GitHub repository](https://github.com/SagerNet/sing-shadowsocks) - -Provides Shadowsocks client and server - -#### sing-vmess - -Link: [GitHub repository](https://github.com/SagerNet/sing-vmess) - -Provides VMess client and server - -#### netlink - -Link: [GitHub repository](https://github.com/SagerNet/netlink) - -Fork of `vishvananda/netlink`, with some rule fixes. - -The library needs to be updated with the upstream. - -#### quic-go - -Link: [GitHub repository](https://github.com/SagerNet/quic-go) - -Fork of `lucas-clemente/quic-go` and `HyNetwork/quic-go`, contains quic flow control and other fixes used by Hysteria. - -Since the author of Hysteria does not follow the upstream updates in time, and the provided fork needs to use replace, -we need to do this. - -The library needs to be updated with the upstream. - -#### smux - -Link: [GitHub repository](https://github.com/SagerNet/smux) - -Fork of `xtaci/smux` - -Modify the code to support the writev it uses internally and unify the buffer pool, which prevents it from allocating -64k buffers for per connection and improves performance. - -Upstream doesn't seem to be updated anymore, maybe a replacement is needed. - -Note: while yamux is still actively maintained and better known, it seems to be less performant. diff --git a/docs/deprecated.md b/docs/deprecated.md index 521a399490..91a3b25e58 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -1,5 +1,11 @@ +--- +icon: material/delete-alert +--- + # Deprecated Feature List +### 1.6.0 + The following features will be marked deprecated in 1.5.0 and removed entirely in 1.6.0. #### ShadowsocksR diff --git a/docs/deprecated.zh.md b/docs/deprecated.zh.md new file mode 100644 index 0000000000..f1125565f9 --- /dev/null +++ b/docs/deprecated.zh.md @@ -0,0 +1,17 @@ +--- +icon: material/delete-alert +--- + +# 废弃功能列表 + +### 1.6.0 + +下列功能已在 1.5.0 中标记为已弃用,并在 1.6.0 中完全删除。 + +#### ShadowsocksR + +ShadowsocksR 支持从未默认启用,自从常用的黑产代理销售面板停止使用该协议,继续维护它是没有意义的。 + +#### Proxy Protocol + +Proxy Protocol 支持由 Pull Request 添加,存在问题且仅由 HTTP 多路复用器(如 nginx)的后端使用,具有侵入性,对于代理目的毫无意义。 diff --git a/docs/examples/clash-api.md b/docs/examples/clash-api.md deleted file mode 100644 index ca5a01338f..0000000000 --- a/docs/examples/clash-api.md +++ /dev/null @@ -1,52 +0,0 @@ -```json -{ - "dns": { - "rules": [ - { - "domain": [ - "clash.razord.top", - "yacd.haishan.me" - ], - "server": "local" - }, - { - "clash_mode": "direct", - "server": "local" - } - ] - }, - "outbounds": [ - { - "type": "selector", - "tag": "default", - "outbounds": [ - "proxy-a", - "proxy-b" - ] - } - ], - "route": { - "rules": [ - { - "clash_mode": "direct", - "outbound": "direct" - }, - { - "domain": [ - "clash.razord.top", - "yacd.haishan.me" - ], - "outbound": "direct" - } - ], - "final": "default" - }, - "experimental": { - "clash_api": { - "external_controller": "127.0.0.1:9090", - "store_selected": true - } - } -} - -``` \ No newline at end of file diff --git a/docs/examples/dns-hijack.md b/docs/examples/dns-hijack.md deleted file mode 100644 index db9e86b808..0000000000 --- a/docs/examples/dns-hijack.md +++ /dev/null @@ -1,65 +0,0 @@ -#### Sniff Mode - -```json -{ - "inbounds": [ - { - "type": "tun", - "inet4_address": "172.19.0.1/30", - "auto_route": true, - "sniff": true // required - } - ], - "outbounds": [ - { - "type": "direct" - }, - { - "type": "dns", - "tag": "dns-out" - } - ], - "route": { - "rules": [ - { - "protocol": "dns", - "outbound": "dns-out" - } - ], - "auto_detect_interface": true - } -} -``` - -#### Port Mode - -```json -{ - "inbounds": [ - { - "type": "tun", - "inet4_address": "172.19.0.1/30", - "auto_route": true, - "sniff": true // not required - } - ], - "outbounds": [ - { - "type": "direct" - }, - { - "type": "dns", - "tag": "dns-out" - } - ], - "route": { - "rules": [ - { - "port": 53, - "outbound": "dns-out" - } - ], - "auto_detect_interface": true - } -} -``` \ No newline at end of file diff --git a/docs/examples/dns-hijack.zh.md b/docs/examples/dns-hijack.zh.md deleted file mode 100644 index 2e75b13a7b..0000000000 --- a/docs/examples/dns-hijack.zh.md +++ /dev/null @@ -1,65 +0,0 @@ -#### 探测模式 - -```json -{ - "inbounds": [ - { - "type": "tun", - "inet4_address": "172.19.0.1/30", - "auto_route": true, - "sniff": true // 必须 - } - ], - "outbounds": [ - { - "type": "direct" - }, - { - "type": "dns", - "tag": "dns-out" - } - ], - "route": { - "rules": [ - { - "protocol": "dns", - "outbound": "dns-out" - } - ], - "auto_detect_interface": true - } -} -``` - -#### 端口模式 - -```json -{ - "inbounds": [ - { - "type": "tun", - "inet4_address": "172.19.0.1/30", - "auto_route": true, - "sniff": true // 非必须 - } - ], - "outbounds": [ - { - "type": "direct" - }, - { - "type": "dns", - "tag": "dns-out" - } - ], - "route": { - "rules": [ - { - "port": 53, - "outbound": "dns-out" - } - ], - "auto_detect_interface": true - } -} -``` \ No newline at end of file diff --git a/docs/examples/fakeip.md b/docs/examples/fakeip.md deleted file mode 100644 index 21407eced4..0000000000 --- a/docs/examples/fakeip.md +++ /dev/null @@ -1,106 +0,0 @@ -```json -{ - "dns": { - "servers": [ - { - "tag": "google", - "address": "tls://8.8.8.8" - }, - { - "tag": "local", - "address": "223.5.5.5", - "detour": "direct" - }, - { - "tag": "remote", - "address": "fakeip" - }, - { - "tag": "block", - "address": "rcode://success" - } - ], - "rules": [ - { - "geosite": "category-ads-all", - "server": "block", - "disable_cache": true - }, - { - "outbound": "any", - "server": "local" - }, - { - "geosite": "cn", - "server": "local" - }, - { - "query_type": [ - "A", - "AAAA" - ], - "server": "remote" - } - ], - "fakeip": { - "enabled": true, - "inet4_range": "198.18.0.0/15", - "inet6_range": "fc00::/18" - }, - "independent_cache": true, - "strategy": "ipv4_only" - }, - "inbounds": [ - { - "type": "tun", - "inet4_address": "172.19.0.1/30", - "auto_route": true, - "sniff": true, - "domain_strategy": "ipv4_only" // remove this line if you want to resolve the domain remotely (if the server is not sing-box, UDP may not work due to wrong behavior). - } - ], - "outbounds": [ - { - "type": "shadowsocks", - "tag": "proxy", - "server": "mydomain.com", - "server_port": 8080, - "method": "2022-blake3-aes-128-gcm", - "password": "8JCsPssfgS8tiRwiMlhARg==" - }, - { - "type": "direct", - "tag": "direct" - }, - { - "type": "block", - "tag": "block" - }, - { - "type": "dns", - "tag": "dns-out" - } - ], - "route": { - "rules": [ - { - "protocol": "dns", - "outbound": "dns-out" - }, - { - "geosite": "cn", - "geoip": [ - "private", - "cn" - ], - "outbound": "direct" - }, - { - "geosite": "category-ads-all", - "outbound": "block" - } - ], - "auto_detect_interface": true - } -} -``` \ No newline at end of file diff --git a/docs/examples/fakeip.zh.md b/docs/examples/fakeip.zh.md deleted file mode 100644 index 947ce387ae..0000000000 --- a/docs/examples/fakeip.zh.md +++ /dev/null @@ -1,106 +0,0 @@ -```json -{ - "dns": { - "servers": [ - { - "tag": "google", - "address": "tls://8.8.8.8" - }, - { - "tag": "local", - "address": "223.5.5.5", - "detour": "direct" - }, - { - "tag": "remote", - "address": "fakeip" - }, - { - "tag": "block", - "address": "rcode://success" - } - ], - "rules": [ - { - "geosite": "category-ads-all", - "server": "block", - "disable_cache": true - }, - { - "outbound": "any", - "server": "local" - }, - { - "geosite": "cn", - "server": "local" - }, - { - "query_type": [ - "A", - "AAAA" - ], - "server": "remote" - } - ], - "fakeip": { - "enabled": true, - "inet4_range": "198.18.0.0/15", - "inet6_range": "fc00::/18" - }, - "independent_cache": true, - "strategy": "ipv4_only" - }, - "inbounds": [ - { - "type": "tun", - "inet4_address": "172.19.0.1/30", - "auto_route": true, - "sniff": true, - "domain_strategy": "ipv4_only" // 如果您想在远程解析域,删除此行 (如果服务器程序不为 sing-box,可能由于错误的行为导致 UDP 无法使用)。 - } - ], - "outbounds": [ - { - "type": "shadowsocks", - "tag": "proxy", - "server": "mydomain.com", - "server_port": 8080, - "method": "2022-blake3-aes-128-gcm", - "password": "8JCsPssfgS8tiRwiMlhARg==" - }, - { - "type": "direct", - "tag": "direct" - }, - { - "type": "block", - "tag": "block" - }, - { - "type": "dns", - "tag": "dns-out" - } - ], - "route": { - "rules": [ - { - "protocol": "dns", - "outbound": "dns-out" - }, - { - "geosite": "cn", - "geoip": [ - "private", - "cn" - ], - "outbound": "direct" - }, - { - "geosite": "category-ads-all", - "outbound": "block" - } - ], - "auto_detect_interface": true - } -} -``` \ No newline at end of file diff --git a/docs/examples/index.md b/docs/examples/index.md deleted file mode 100644 index 6bbab74145..0000000000 --- a/docs/examples/index.md +++ /dev/null @@ -1,11 +0,0 @@ -# Examples - -Configuration examples for sing-box. - -* [Linux Server Installation](./linux-server-installation) -* [Tun](./tun) -* [DNS Hijack](./dns-hijack.md) -* [Shadowsocks](./shadowsocks) -* [ShadowTLS](./shadowtls) -* [Clash API](./clash-api) -* [FakeIP](./fakeip) diff --git a/docs/examples/index.zh.md b/docs/examples/index.zh.md deleted file mode 100644 index 7528e5d438..0000000000 --- a/docs/examples/index.zh.md +++ /dev/null @@ -1,11 +0,0 @@ -# 示例 - -sing-box 的配置示例。 - -* [Linux 服务器安装](./linux-server-installation) -* [Tun](./tun) -* [DNS 劫持](./dns-hijack.md) -* [Shadowsocks](./shadowsocks) -* [ShadowTLS](./shadowtls) -* [Clash API](./clash-api) -* [FakeIP](./fakeip) diff --git a/docs/examples/linux-server-installation.md b/docs/examples/linux-server-installation.md deleted file mode 100644 index a785b130b7..0000000000 --- a/docs/examples/linux-server-installation.md +++ /dev/null @@ -1,38 +0,0 @@ -#### Requirements - -* Linux & Systemd -* Git -* C compiler environment - -#### Install - -```shell -git clone -b main https://github.com/SagerNet/sing-box -cd sing-box -./release/local/install_go.sh # skip if you have golang already installed -./release/local/install.sh -``` - -Edit configuration file in `/usr/local/etc/sing-box/config.json` - -```shell -./release/local/enable.sh -``` - -#### Update - -```shell -./release/local/update.sh -``` - -#### Other commands - -| Operation | Command | -|-----------|-----------------------------------------------| -| Start | `sudo systemctl start sing-box` | -| Stop | `sudo systemctl stop sing-box` | -| Kill | `sudo systemctl kill sing-box` | -| Restart | `sudo systemctl restart sing-box` | -| Logs | `sudo journalctl -u sing-box --output cat -e` | -| New Logs | `sudo journalctl -u sing-box --output cat -f` | -| Uninstall | `./release/local/uninstall.sh` | \ No newline at end of file diff --git a/docs/examples/linux-server-installation.zh.md b/docs/examples/linux-server-installation.zh.md deleted file mode 100644 index 91d908d67d..0000000000 --- a/docs/examples/linux-server-installation.zh.md +++ /dev/null @@ -1,38 +0,0 @@ -#### 依赖 - -* Linux & Systemd -* Git -* C 编译器环境 - -#### 安装 - -```shell -git clone -b main https://github.com/SagerNet/sing-box -cd sing-box -./release/local/install_go.sh # 如果已安装 golang 则跳过 -./release/local/install.sh -``` - -编辑配置文件 `/usr/local/etc/sing-box/config.json` - -```shell -./release/local/enable.sh -``` - -#### 更新 - -```shell -./release/local/update.sh -``` - -#### 其他命令 - -| 操作 | 命令 | -|------|-----------------------------------------------| -| 启动 | `sudo systemctl start sing-box` | -| 停止 | `sudo systemctl stop sing-box` | -| 强制停止 | `sudo systemctl kill sing-box` | -| 重启 | `sudo systemctl restart sing-box` | -| 查看日志 | `sudo journalctl -u sing-box --output cat -e` | -| 实时日志 | `sudo journalctl -u sing-box --output cat -f` | -| 卸载 | `./release/local/uninstall.sh` | \ No newline at end of file diff --git a/docs/examples/shadowsocks.md b/docs/examples/shadowsocks.md deleted file mode 100644 index 7e002fab4d..0000000000 --- a/docs/examples/shadowsocks.md +++ /dev/null @@ -1,163 +0,0 @@ -# Shadowsocks - -!!! warning "" - - For censorship bypass usage in China, we recommend using UDP over TCP and disabling UDP on the server. - -## Single User - -#### Server - -```json -{ - "inbounds": [ - { - "type": "shadowsocks", - "listen": "::", - "listen_port": 8080, - "network": "tcp", - "method": "2022-blake3-aes-128-gcm", - "password": "8JCsPssfgS8tiRwiMlhARg==" - } - ] -} -``` - -#### Client - -```json -{ - "inbounds": [ - { - "type": "mixed", - "listen": "::", - "listen_port": 2080 - } - ], - "outbounds": [ - { - "type": "shadowsocks", - "server": "127.0.0.1", - "server_port": 8080, - "method": "2022-blake3-aes-128-gcm", - "password": "8JCsPssfgS8tiRwiMlhARg==", - "udp_over_tcp": true - } - ] -} - -``` - -## Multiple Users - -#### Server - -```json -{ - "inbounds": [ - { - "type": "shadowsocks", - "listen": "::", - "listen_port": 8080, - "method": "2022-blake3-aes-128-gcm", - "password": "8JCsPssfgS8tiRwiMlhARg==", - "users": [ - { - "name": "sekai", - "password": "BXYxVUXJ9NgF7c7KPLQjkg==" - } - ] - } - ] -} -``` - -#### Client - -```json -{ - "inbounds": [ - { - "type": "mixed", - "listen": "::", - "listen_port": 2080 - } - ], - "outbounds": [ - { - "type": "shadowsocks", - "server": "127.0.0.1", - "server_port": 8080, - "method": "2022-blake3-aes-128-gcm", - "password": "8JCsPssfgS8tiRwiMlhARg==:BXYxVUXJ9NgF7c7KPLQjkg==" - } - ] -} - -``` - -## Relay - -#### Server - -```json -{ - "inbounds": [ - { - "type": "shadowsocks", - "listen": "::", - "listen_port": 8080, - "method": "2022-blake3-aes-128-gcm", - "password": "8JCsPssfgS8tiRwiMlhARg==" - } - ] -} -``` - -#### Relay - -```json -{ - "inbounds": [ - { - "type": "shadowsocks", - "listen": "::", - "listen_port": 8081, - "method": "2022-blake3-aes-128-gcm", - "password": "BXYxVUXJ9NgF7c7KPLQjkg==", - "destinations": [ - { - "name": "my_server", - "password": "8JCsPssfgS8tiRwiMlhARg==", - "server": "127.0.0.1", - "server_port": 8080 - } - ] - } - ] -} -``` - -#### Client - -```json -{ - "inbounds": [ - { - "type": "mixed", - "listen": "::", - "listen_port": 2080 - } - ], - "outbounds": [ - { - "type": "shadowsocks", - "server": "127.0.0.1", - "server_port": 8081, - "method": "2022-blake3-aes-128-gcm", - "password": "8JCsPssfgS8tiRwiMlhARg==:BXYxVUXJ9NgF7c7KPLQjkg==" - } - ] -} - -``` \ No newline at end of file diff --git a/docs/examples/shadowtls.md b/docs/examples/shadowtls.md deleted file mode 100644 index 352a305846..0000000000 --- a/docs/examples/shadowtls.md +++ /dev/null @@ -1,70 +0,0 @@ -#### Server - -```json -{ - "inbounds": [ - { - "type": "shadowtls", - "listen": "::", - "listen_port": 4443, - "version": 3, - "users": [ - { - "name": "sekai", - "password": "8JCsPssfgS8tiRwiMlhARg==" - } - ], - "handshake": { - "server": "google.com", - "server_port": 443 - }, - "detour": "shadowsocks-in" - }, - { - "type": "shadowsocks", - "tag": "shadowsocks-in", - "listen": "127.0.0.1", - "network": "tcp", - "method": "2022-blake3-aes-128-gcm", - "password": "8JCsPssfgS8tiRwiMlhARg==" - } - ] -} -``` - -#### Client - -```json -{ - "outbounds": [ - { - "type": "shadowsocks", - "method": "2022-blake3-aes-128-gcm", - "password": "8JCsPssfgS8tiRwiMlhARg==", - "detour": "shadowtls-out", - "multiplex": { - "enabled": true, - "max_connections": 4, - "min_streams": 4 - } - // or "udp_over_tcp": true - }, - { - "type": "shadowtls", - "tag": "shadowtls-out", - "server": "127.0.0.1", - "server_port": 4443, - "version": 3, - "password": "8JCsPssfgS8tiRwiMlhARg==", - "tls": { - "enabled": true, - "server_name": "google.com", - "utls": { - "enabled": true, - "fingerprint": "chrome" - } - } - } - ] -} -``` diff --git a/docs/examples/tun.md b/docs/examples/tun.md deleted file mode 100644 index 8671ef76a6..0000000000 --- a/docs/examples/tun.md +++ /dev/null @@ -1,89 +0,0 @@ -```json -{ - "dns": { - "servers": [ - { - "tag": "google", - "address": "tls://8.8.8.8" - }, - { - "tag": "local", - "address": "223.5.5.5", - "detour": "direct" - }, - { - "tag": "block", - "address": "rcode://success" - } - ], - "rules": [ - { - "geosite": "category-ads-all", - "server": "block", - "disable_cache": true - }, - { - "outbound": "any", - "server": "local" - }, - { - "geosite": "cn", - "server": "local" - } - ], - "strategy": "ipv4_only" - }, - "inbounds": [ - { - "type": "tun", - "inet4_address": "172.19.0.1/30", - "auto_route": true, - "strict_route": false, - "sniff": true - } - ], - "outbounds": [ - { - "type": "shadowsocks", - "tag": "proxy", - "server": "mydomain.com", - "server_port": 8080, - "method": "2022-blake3-aes-128-gcm", - "password": "8JCsPssfgS8tiRwiMlhARg==" - }, - { - "type": "direct", - "tag": "direct" - }, - { - "type": "block", - "tag": "block" - }, - { - "type": "dns", - "tag": "dns-out" - } - ], - "route": { - "rules": [ - { - "protocol": "dns", - "outbound": "dns-out" - }, - { - "geosite": "cn", - "geoip": [ - "private", - "cn" - ], - "outbound": "direct" - }, - { - "geosite": "category-ads-all", - "outbound": "block" - } - ], - "auto_detect_interface": true - } -} -``` \ No newline at end of file diff --git a/docs/faq/fakeip.md b/docs/faq/fakeip.md deleted file mode 100644 index 59d9e730d9..0000000000 --- a/docs/faq/fakeip.md +++ /dev/null @@ -1,19 +0,0 @@ -# FakeIP - -FakeIP refers to a type of behavior in a program that simultaneously hijacks both DNS and connection requests. It -responds to DNS requests with virtual results and restores mapping when accepting connections. - -#### Advantage - -* - -#### Limitation - -* Its mechanism breaks applications that depend on returning correct remote addresses. -* Only A and AAAA (IP) requests are supported, which may break applications that rely on other requests. - -#### Recommendation - -* Enable `dns.independent_cache` unless you always resolve FakeIP domains remotely. -* If using tun, make sure FakeIP ranges is included in the tun's routes. -* Enable `experimental.clash_api.store_fakeip` to persist FakeIP records, or use `dns.rules.rewrite_ttl` to avoid losing records after program restart in DNS cached environments. diff --git a/docs/faq/fakeip.zh.md b/docs/faq/fakeip.zh.md deleted file mode 100644 index 3ab77d2c6a..0000000000 --- a/docs/faq/fakeip.zh.md +++ /dev/null @@ -1,18 +0,0 @@ -# FakeIP - -FakeIP 是指同时劫持 DNS 和连接请求的程序中的一种行为。它通过虚拟结果响应 DNS 请求,在接受连接时恢复映射。 - -#### 优点 - -* - -#### 限制 - -* 它的机制会破坏依赖于返回正确远程地址的应用程序。 -* 仅支持 A 和 AAAA(IP)请求,这可能会破坏依赖于其他请求的应用程序。 - -#### 建议 - -* 启用 `dns.independent_cache` 除非您始终远程解析 FakeIP 域。 -* 如果使用 tun,请确保 tun 路由中包含 FakeIP 地址范围。 -* 启用 `experimental.clash_api.store_fakeip` 以持久化 FakeIP 记录,或者使用 `dns.rules.rewrite_ttl` 避免程序重启后在 DNS 被缓存的环境中丢失记录。 diff --git a/docs/faq/index.md b/docs/faq/index.md deleted file mode 100644 index c7ce30ad65..0000000000 --- a/docs/faq/index.md +++ /dev/null @@ -1,58 +0,0 @@ -# Frequently Asked Questions (FAQ) - -## Design - -#### Why does sing-box not have feature X? - -Every program contains novel features and omits someone's favorite feature. sing-box is designed with an eye to the -needs of performance, lightweight, usability, modularity, and code quality. Your favorite feature may be missing because -it doesn't fit, because it compromises performance or design clarity, or because it's a bad idea. - -If it bothers you that sing-box is missing feature X, please forgive us and investigate the features that sing-box does -have. You might find that they compensate in interesting ways for the lack of X. - -#### Naive outbound - -NaïveProxy's main function is chromium's network stack, and it makes no sense to implement only its transport protocol. - -#### Protocol combinations - -The "underlying transport" in v2ray-core is actually a combination of a number of proprietary protocols and uses the -names of their upstream protocols, resulting in a great deal of Linguistic corruption. - -For example, Trojan with v2ray's proprietary gRPC protocol, called Trojan gRPC by the v2ray community, is not actually a -protocol and has no role outside of abusing CDNs. - -## Tun - -#### What is tun? - -tun is a virtual network device in unix systems, and in windows there is wintun developed by WireGuard as an -alternative. The tun module of sing-box includes traffic processing, automatic routing, and network device listening, -and is mainly used as a transparent proxy. - -#### How is it different from system proxy? - -System proxy usually only supports TCP and is not accepted by all applications, but tun can handle all traffic. - -#### How is it different from traditional transparent proxy? - -They are usually only supported under Linux and require manipulation of firewalls like iptables, while tun only modifies -the routing table. - -The tproxy UDP is considered to have poor performance due to the need to create a new connection every write back in -v2ray and clash, but it is optimized in sing-box so you can still use it if needed. - -#### How does it handle DNS? - -In traditional transparent proxies, it is usually necessary to manually hijack port 53 to the DNS proxy server, while -tun is more flexible. - -sing-box's `auto_route` will hijack all DNS requests except on [macOS and Android](./known-issues#dns). - -You need to manually configure how to handle tun hijacked DNS traffic, see [Hijack DNS](/examples/dns-hijack). - -#### Why I can't use it with other local proxies (e.g. via socks)? - -Tun will hijack all traffic, including other proxy applications. In order to make tun work with other applications, you -need to create an inbound to proxy traffic from other applications or make them bypass the route. \ No newline at end of file diff --git a/docs/faq/index.zh.md b/docs/faq/index.zh.md deleted file mode 100644 index 557c53c7fa..0000000000 --- a/docs/faq/index.zh.md +++ /dev/null @@ -1,50 +0,0 @@ -# 常见问题 - -## 设计 - -#### 为什么 sing-box 没有功能 X? - -每个程序都包含新颖的功能并省略了某人最喜欢的功能。 sing-box 的设计着眼于高性能、轻量、可用性、模块化和代码质量的需求。 -您最喜欢的功能可能会丢失,因为它不适合,因为它会影响性能或设计清晰度,或者因为它是一个坏主意。 - -如果 sing-box 缺少功能 X 让您感到困扰,请原谅我们并调查 sing-box 确实有的功能。 您可能会发现它们以有趣的方式弥补了 X 的缺失。 - -#### Naive 出站 - -NaïveProxy 的主要功能是 chromium 的网络栈,仅实现它的传输协议是舍本逐末的。 - -#### 协议组合 - -v2ray-core 中的 "底层传输协议" 实际上是一些专有协议的组合,并使用其上游协议的名称,造成了大量的语言腐败。 - -例如,v2ray 社区将 v2ray 专有的 gRPC 协议称为 Trojan gRPC,其实并不是一个 协议,在滥用 CDN 之外没有任何作用。 - -## Tun - -#### 什么是 tun? - -tun 是 unix 系统中的虚拟网络设备,在 windows 中有 WireGuard 开发的 wintun 作为替代。 -sing-box 的 tun 模块包括流量处理、自动路由和网络设备监听,并主要用作透明代理。 - -#### 它与系统代理有什么不同? - -系统代理通常只支持 TCP,且不被所有应用程序接受,但 tun 可以处理所有流量。 - -#### 它与传统的透明代理有什么不同? - -它们通常仅支持 Linux,并且需要操作防火墙像 iptables,而 tun 仅修改路由表。 - -tproxy UDP 被认为性能很差,因为在 v2ray 和 clash 中每次回写都需要创建一个新连接,但 sing-box 进行了优化,因此您仍然可以在需要时使用它。 - -#### 它如何处理 DNS? - -在传统的透明代理中,通常需要手动劫持 53 端口到 DNS 代理服务器,而 tun 更灵活。 - -sing-box 的 `auto_route` 将劫持所有 DNS 请求,除了 [特殊情况](./known-issues#dns)。 - -您需要手动配置以处理 tun 劫持的 DNS 流量,请参阅 [DNS劫持](/zh/examples/dns-hijack)。 - -#### 为什么我不能将它与其他本地代理一起使用(例如通过 socks)? - -tun 将劫持所有流量,包括其他代理应用程序。 -为了使 tun 与其他应用程序一起工作,您需要创建入站以代理来自其他程序的流量或让它们绕过路由。 \ No newline at end of file diff --git a/docs/faq/known-issues.md b/docs/faq/known-issues.md deleted file mode 100644 index ac6892e1ee..0000000000 --- a/docs/faq/known-issues.md +++ /dev/null @@ -1,20 +0,0 @@ -#### DNS - -##### on macOS - -`auto-route` cannot automatically hijack DNS requests sent to the LAN, so it's need to manually set DNS to servers on -the public internet. - -##### on Android - -`auto-route` cannot automatically hijack DNS requests when Android's `Private DNS` enabled or `strict_route` disabled. - -#### System proxy - -##### on Linux - -Usually only browsers and GNOME applications accept GNOME proxy settings. - -##### on Android - -With the system proxy enabled, some applications will error out (usually from China). \ No newline at end of file diff --git a/docs/faq/known-issues.zh.md b/docs/faq/known-issues.zh.md deleted file mode 100644 index 1d25e723cb..0000000000 --- a/docs/faq/known-issues.zh.md +++ /dev/null @@ -1,19 +0,0 @@ -#### DNS - -##### macOS - -`auto-route` 无法自动劫持发往局域网的 DNS 请求,需要手动设置位于公网的 DNS 服务器。 - -##### Android - -`auto-route` 无法自动劫持 DNS 请求如果 `私人 DNS` 开启或 `strict_route` 禁用。 - -#### 系统代理 - -##### Linux - -通常只有浏览器和 GNOME 应用程序接受 GNOME 代理设置。 - -##### Android - -启用系统代理后,某些应用程序会出错(通常来自中国)。 diff --git a/docs/features.md b/docs/features.md deleted file mode 100644 index 84185bca2b..0000000000 --- a/docs/features.md +++ /dev/null @@ -1,121 +0,0 @@ -#### Server - -| Feature | v2ray-core | clash | -|------------------------------------------------------------|------------|-------| -| Direct inbound | ✔ | X | -| SOCKS4a inbound | ✔ | X | -| Mixed (http/socks) inbound | X | ✔ | -| Shadowsocks AEAD 2022 single-user/multi-user/relay inbound | X | X | -| VMess/Trojan inbound | ✔ | X | -| Naive/Hysteria inbound | X | X | -| Resolve incoming domain names using custom policy | X | X | -| Set system proxy on Windows/Linux/macOS/Android | X | X | -| TLS certificate auto reload | X | X | -| TLS ACME certificate issuer | X | X | - -#### Client - -| Feature | v2ray-core | clash | -|--------------------------------------------------------|------------------------------------|----------| -| Set upstream client (proxy chain) | TCP only, and has poor performance | TCP only | -| Bind to network interface | Linux only | ✔ | -| Custom dns strategy for resolving server address | X | X | -| Fast fallback (RFC 6555) support for connect to server | X | X | -| SOCKS4/4a outbound | added by me | X | -| Shadowsocks AEAD 2022 outbound | X | X | -| Shadowsocks UDP over TCP | X | X | -| Multiplex (smux/yamux) | mux.cool | X | -| Tor/WireGuard/Hysteria outbound | X | X | -| Selector outbound and Clash API | X | ✔ | - -#### Sniffing - -| Protocol | v2ray-core | clash-premium | -|------------------|-------------|---------------| -| HTTP Host | ✔ | X | -| QUIC ClientHello | added by me | added by me | -| STUN | X | X | - -| Feature | v2ray-core | clash-premium | -|-----------------------------------------|---------------------------|---------------| -| For routing only | added by me | X | -| No performance impact (like TCP splice) | no general splice support | X | -| Set separately for each server | ✔ | X | - -#### Routing - -| Feature | v2ray-core | clash-premium | -|----------------------------|------------|---------------| -| Auto detect interface | X | tun only | -| Set default interface name | X | tun only | -| Set default firewall mark | X | X | - -#### Routing Rule - -| Rule | v2ray-core | clash | -|----------------------|----------------------------|-------| -| Inbound | ✔ | X | -| IP Version | X | X | -| User from inbound | vmess and shadowsocks only | X | -| Sniffed protocol | ✔ | X | -| GeoSite | ✔ | X | -| Process name | X | ✔ | -| Android package name | X | X | -| Linux user/user id | X | X | -| Invert rule | X | X | -| Logical rule | X | X | - -#### DNS - -| Feature | v2ray-core | clash | -|------------------------------------|-------------|-------| -| DNS proxy | A/AAAA only | ✔ | -| DNS cache | A/AAAA only | X | -| DNS routing | X | X | -| DNS Over QUIC | ✔ | X | -| DNS Over HTTP3 | X | X | -| Fake dns response with custom code | X | X | - -#### Tun - -| Feature | clash-premium | -|-------------------------------------------|---------------| -| Full IPv6 support | X | -| Auto route on Linux/Windows/macOS/Android | ✔ | -| Embed windows driver | X | -| Custom address/mtu | X | -| Limit uid (Linux) in routing | X | -| Limit android user in routing | X | -| Limit android package in routing | X | - -#### Memory usage - -| GeoSite code | sing-box | v2ray-core | -|-------------------|----------|------------| -| cn | 17.8M | 140.3M | -| cn (Loyalsoldier) | 74.3M | 246.7M | - -#### Benchmark - -##### Shadowsocks - -| / | none | aes-128-gcm | 2022-blake3-aes-128-gcm | -|------------------------------------|:---------:|:-----------:|:-----------------------:| -| v2ray-core (5.0.7) | 13.0 Gbps | 5.02 Gbps | / | -| shadowsocks-rust (v1.15.0-alpha.5) | 10.7 Gbps | / | 9.36 Gbps | -| sing-box | 29.0 Gbps | / | 11.8 Gbps | - -##### VMess - -| / | TCP | HTTP | H2 TLS | WebSocket TLS | gRPC TLS | -|--------------------|:---------:|:---------:|:---------:|:-------------:|:---------:| -| v2ray-core (5.1.0) | 7.86 GBps | 2.86 Gbps | 1.83 Gbps | 2.36 Gbps | 2.43 Gbps | -| sing-box | 7.96 Gbps | 8.09 Gbps | 6.11 Gbps | 8.02 Gbps | 6.35 Gbps | - -#### License - -| / | License | -|------------|-----------------------------------| -| sing-box | GPLv3 or later (Full open-source) | -| v2ray-core | MIT (Full open-source) | -| clash | GPLv3 | \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 2c34509c24..2af7222e7b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,7 +2,7 @@ description: Welcome to the wiki page for the sing-box project. --- -# Home +# :material-home: Home Welcome to the wiki page for the sing-box project. diff --git a/docs/index.zh.md b/docs/index.zh.md index 2453bb73b4..72877118f3 100644 --- a/docs/index.zh.md +++ b/docs/index.zh.md @@ -2,7 +2,7 @@ description: 欢迎来到该 sing-box 项目的文档页。 --- -# 开始 +# :material-home: 开始 欢迎来到该 sing-box 项目的文档页。 diff --git a/docs/installation/build-from-source.md b/docs/installation/build-from-source.md new file mode 100644 index 0000000000..0ac7169a14 --- /dev/null +++ b/docs/installation/build-from-source.md @@ -0,0 +1,63 @@ +--- +icon: material/file-code +--- + +# Build from source + +## :material-graph: Requirements + +Before sing-box 1.4.0: + +* Go 1.18.5 - 1.20.x + +Since sing-box 1.4.0: + +* Go 1.18.5 - ~ +* Go 1.20.0 - ~ if `with_quic` tag enabled + +You can download and install Go from: https://go.dev/doc/install, latest version is recommended. + +## :material-fast-forward: Simple Build + +```bash +make +``` + +Or build and install binary to `GOBIN`: + +```bash +make install +``` + +## :material-cog: Custom Build + +```bash +TAGS="tag_a tag_b" make +``` + +or + +```bash +go build -tags "tag_a tag_b" ./cmd/sing-box +``` + +## :material-folder-settings: Build Tags + +| Build Tag | Enabled by default | Description | +|------------------------------------|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `with_quic` | ✔ | Build with QUIC support, see [QUIC and HTTP3 DNS transports](/configuration/dns/server), [Naive inbound](/configuration/inbound/naive), [Hysteria Inbound](/configuration/inbound/hysteria), [Hysteria Outbound](/configuration/outbound/hysteria) and [V2Ray Transport#QUIC](/configuration/shared/v2ray-transport#quic). | +| `with_grpc` | ✖️ | Build with standard gRPC support, see [V2Ray Transport#gRPC](/configuration/shared/v2ray-transport#grpc). | +| `with_dhcp` | ✔ | Build with DHCP support, see [DHCP DNS transport](/configuration/dns/server). | +| `with_wireguard` | ✔ | Build with WireGuard support, see [WireGuard outbound](/configuration/outbound/wireguard). | +| `with_ech` | ✔ | Build with TLS ECH extension support for TLS outbound, see [TLS](/configuration/shared/tls#ech). | +| `with_utls` | ✔ | Build with [uTLS](https://github.com/refraction-networking/utls) support for TLS outbound, see [TLS](/configuration/shared/tls#utls). | +| `with_reality_server` | ✔ | Build with reality TLS server support, see [TLS](/configuration/shared/tls). | +| `with_acme` | ✔ | Build with ACME TLS certificate issuer support, see [TLS](/configuration/shared/tls). | +| `with_clash_api` | ✔ | Build with Clash API support, see [Experimental](/configuration/experimental#clash-api-fields). | +| `with_v2ray_api` | ✖️ | Build with V2Ray API support, see [Experimental](/configuration/experimental#v2ray-api-fields). | +| `with_gvisor` | ✔ | Build with gVisor support, see [Tun inbound](/configuration/inbound/tun#stack) and [WireGuard outbound](/configuration/outbound/wireguard#system_interface). | +| `with_embedded_tor` (CGO required) | ✖️ | Build with embedded Tor support, see [Tor outbound](/configuration/outbound/tor). | +| `with_lwip` (CGO required) | ✖️ | Build with LWIP Tun stack support, see [Tun inbound](/configuration/inbound/tun#stack). | + + +It is not recommended to change the default build tag list unless you really know what you are adding. diff --git a/docs/installation/clients/sfa.md b/docs/installation/clients/sfa.md deleted file mode 100644 index 54b4f3e553..0000000000 --- a/docs/installation/clients/sfa.md +++ /dev/null @@ -1,23 +0,0 @@ -# SFA - -Experimental Android client for sing-box. - -#### Requirements - -* Android 5.0+ - -#### Download - -* [Play Store](https://play.google.com/store/apps/details?id=io.nekohasekai.sfa) -* [Github Releases](https://github.com/SagerNet/sing-box/releases) - -#### Note - -* User Agent in remote profile request is `SFA/$version ($version_code; sing-box $sing_box_version)` -* The working directory is located at `/sdcard/Android/data/io.nekohasekai.sfa/files` (External files directory) -* Crash logs is located in `$working_directory/stderr.log` - -#### Privacy policy - -* SFA did not collect or share personal data. -* The data generated by the software is always on your device. diff --git a/docs/installation/clients/sfa.zh.md b/docs/installation/clients/sfa.zh.md deleted file mode 100644 index 7dfe63352e..0000000000 --- a/docs/installation/clients/sfa.zh.md +++ /dev/null @@ -1,23 +0,0 @@ -# SFA - -实验性的 Android sing-box 客户端。 - -#### 要求 - -* Android 5.0+ - -#### 下载 - -* [AppCenter](https://install.appcenter.ms/users/nekohasekai/apps/sfa/distribution_groups/publictest) -* [Github Releases](https://github.com/SagerNet/sing-box/releases) - -#### 注意事项 - -* 远程配置文件请求中的 User Agent 为 `SFA/$version ($version_code; sing-box $sing_box_version)` -* 工作目录位于 `/sdcard/Android/data/io.nekohasekai.sfa/files` (外部文件目录) -* 崩溃日志位于 `$working_directory/stderr.log` - -#### 隐私政策 - -* SFA 不收集或共享个人数据。 -* 软件生成的数据始终在您的设备上。 diff --git a/docs/installation/clients/sfi.md b/docs/installation/clients/sfi.md deleted file mode 100644 index 35c15c918b..0000000000 --- a/docs/installation/clients/sfi.md +++ /dev/null @@ -1,23 +0,0 @@ -# SFI - -Experimental iOS client for sing-box. - -#### Requirements - -* iOS 15.0+ -* An Apple account outside of mainland China - -#### Download - -* [AppStore](https://apps.apple.com/us/app/sing-box/id6451272673) -* [TestFlight](https://testflight.apple.com/join/AcqO44FH) - -#### Note - -* User Agent in remote profile request is `SFI/$version ($version_code; sing-box $sing_box_version)` -* Crash logs is located in `Settings` -> `View Service Log` - -#### Privacy policy - -* SFI did not collect or share personal data. -* The data generated by the software is always on your device. diff --git a/docs/installation/clients/sfi.zh.md b/docs/installation/clients/sfi.zh.md deleted file mode 100644 index 90c3845f4f..0000000000 --- a/docs/installation/clients/sfi.zh.md +++ /dev/null @@ -1,23 +0,0 @@ -# SFI - -实验性的 iOS sing-box 客户端。 - -#### 要求 - -* iOS 15.0+ -* 一个非中国大陆地区的 Apple 账号 - -#### 下载 - -* [AppStore](https://apps.apple.com/us/app/sing-box/id6451272673) -* [TestFlight](https://testflight.apple.com/join/AcqO44FH) - -#### 注意事项 - -* 远程配置文件请求中的 User Agent 为 `SFI/$version ($version_code; sing-box $sing_box_version)` -* 崩溃日志位于 `Settings` -> `View Service Log` - -#### 隐私政策 - -* SFI 不收集或共享个人数据。 -* 软件生成的数据始终在您的设备上。 diff --git a/docs/installation/clients/sfm.md b/docs/installation/clients/sfm.md deleted file mode 100644 index 8d2237c0a6..0000000000 --- a/docs/installation/clients/sfm.md +++ /dev/null @@ -1,29 +0,0 @@ -# SFM - -Experimental macOS client for sing-box. - -#### Requirements - -* macOS 13.0+ -* An Apple account outside of mainland China (App Store Version) - -#### Download (App Store Version) - -* [AppStore](https://apps.apple.com/us/app/sing-box/id6451272673) -* [TestFlight](https://testflight.apple.com/join/AcqO44FH) - -#### Download (Independent Version) - -* [GitHub Release](https://github.com/SagerNet/sing-box/releases/latest) -* Homebrew (Cask): `brew install sfm` -* Homebrew (Tap): `brew tap sagernet/sing-box && brew install sagernet/sing-box/sfm` - -#### Note - -* User Agent in remote profile request is `SFM/$version ($version_code; sing-box $sing_box_version)` -* Crash logs is located in `Settings` -> `View Service Log` - -#### Privacy policy - -* SFM did not collect or share personal data. -* The data generated by the software is always on your device. diff --git a/docs/installation/clients/sfm.zh.md b/docs/installation/clients/sfm.zh.md deleted file mode 100644 index a6e42b8186..0000000000 --- a/docs/installation/clients/sfm.zh.md +++ /dev/null @@ -1,29 +0,0 @@ -# SFM - -实验性的 macOS sing-box 客户端。 - -#### 要求 - -* macOS 13.0+ -* 一个非中国大陆地区的 Apple 账号 (商店版本) - -#### 下载 (商店版本) - -* [AppStore](https://apps.apple.com/us/app/sing-box/id6451272673) -* [TestFlight](https://testflight.apple.com/join/AcqO44FH) - -#### 下载 (独立版本) - -* [GitHub Release](https://github.com/SagerNet/sing-box/releases/latest) -* Homebrew (Cask): `brew install sfm` -* Homebrew (Tap): `brew tap sagernet/sing-box && brew install sagernet/sing-box/sfm` - -#### 注意事项 - -* 远程配置文件请求中的 User Agent 为 `SFM/$version ($version_code; sing-box $sing_box_version)` -* 崩溃日志位于 `Settings` -> `View Service Log` - -#### 隐私政策 - -* SFM 不收集或共享个人数据。 -* 软件生成的数据始终在您的设备上。 diff --git a/docs/installation/clients/sft.md b/docs/installation/clients/sft.md deleted file mode 100644 index b05bc07edf..0000000000 --- a/docs/installation/clients/sft.md +++ /dev/null @@ -1,30 +0,0 @@ -# SFT - -Experimental Apple tvOS client for sing-box. - -#### Requirements - -* tvOS 17.0+ - -#### Download - -* [AppStore](https://apps.apple.com/us/app/sing-box/id6451272673) -* [TestFlight](https://testflight.apple.com/join/AcqO44FH) - -#### Features - -Full functionality, except for: - -* Only remote configuration files can be created manually -* You need to update SFI to the latest version to import profiles from iPhone/iPad -* No iCloud profile support - -#### Note - -* User Agent in remote profile request is `SFT/$version ($version_code; sing-box $sing_box_version)` -* Crash logs is located in `Settings` -> `View Service Log` - -#### Privacy policy - -* SFT did not collect or share personal data. -* The data generated by the software is always on your device. diff --git a/docs/installation/clients/sft.zh.md b/docs/installation/clients/sft.zh.md deleted file mode 100644 index 239d76e2e1..0000000000 --- a/docs/installation/clients/sft.zh.md +++ /dev/null @@ -1,31 +0,0 @@ -# SFI - -实验性的 Apple tvOS sing-box 客户端。 - -#### 要求 - -* tvOS 17.0+ -* 一个非中国大陆地区的 Apple 账号 - -#### 下载 - -* [AppStore](https://apps.apple.com/us/app/sing-box/id6451272673) -* [TestFlight](https://testflight.apple.com/join/AcqO44FH) - -#### 特性 - -完整的功能,除了: - -* 只能手动创建远程配置文件 -* 您需要将 SFI 更新到最新版本才能从 iPhone/iPad 导入配置文件 -* 没有 iCloud 配置文件支持 - -#### 注意事项 - -* 远程配置文件请求中的 User Agent 为 `SFT/$version ($version_code; sing-box $sing_box_version)` -* 崩溃日志位于 `Settings` -> `View Service Log` - -#### 隐私政策 - -* SFT 不收集或共享个人数据。 -* 软件生成的数据始终在您的设备上。 diff --git a/docs/installation/clients/specification.md b/docs/installation/clients/specification.md deleted file mode 100644 index ec36dd78cf..0000000000 --- a/docs/installation/clients/specification.md +++ /dev/null @@ -1,25 +0,0 @@ -# Specification - -## Profile - -Profile defines a sing-box configuration with metadata in a GUI client. - -## Profile Types - -### Local - -Create a empty configuration or import from a local file. - -### iCloud (on Apple platforms) - -Create a new configuration or use an existing configuration on iCloud. - -### Remote - -Use a remote URL as the configuration source, with HTTP basic authentication and automatic update support. - -#### URL specification - -``` -sing-box://import-remote-profile?url=urlEncodedURL#urlEncodedName -``` \ No newline at end of file diff --git a/docs/installation/docker.md b/docs/installation/docker.md new file mode 100644 index 0000000000..ae1682dd70 --- /dev/null +++ b/docs/installation/docker.md @@ -0,0 +1,31 @@ +--- +icon: material/docker +--- + +# Docker + +## :material-console: Command + +```bash +docker run -d \ + -v /etc/sing-box:/etc/sing-box/ \ + --name=sing-box \ + --restart=always \ + ghcr.io/sagernet/sing-box \ + -D /var/lib/sing-box \ + -C /etc/sing-box/ run +``` + +## :material-box-shadow: Compose + +```yaml +version: "3.8" +services: + sing-box: + image: ghcr.io/sagernet/sing-box + container_name: sing-box + restart: always + volumes: + - /etc/sing-box:/etc/sing-box/ + command: -D /var/lib/sing-box -C /etc/sing-box/ run +``` diff --git a/docs/installation/from-source.md b/docs/installation/from-source.md deleted file mode 100644 index da0ffc02d8..0000000000 --- a/docs/installation/from-source.md +++ /dev/null @@ -1,50 +0,0 @@ -# Install from source - -## Requirements - -Before sing-box 1.4.0: - -* Go 1.18.5 - 1.20.x - -Since sing-box 1.4.0: - -* Go 1.18.5 - ~ -* Go 1.20.0 - ~ if `with_quic` tag enabled - -## Installation - -```bash -go install -v github.com/sagernet/sing-box/cmd/sing-box@latest -``` - -Install with options: - -```bash -go install -v -tags with_quic,with_wireguard github.com/sagernet/sing-box/cmd/sing-box@latest -``` - -| Build Tag | Description | -|------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `with_quic` | Build with QUIC support, see [QUIC and HTTP3 DNS transports](/configuration/dns/server), [Naive inbound](/configuration/inbound/naive), [Hysteria Inbound](/configuration/inbound/hysteria), [Hysteria Outbound](/configuration/outbound/hysteria) and [V2Ray Transport#QUIC](/configuration/shared/v2ray-transport#quic). | -| `with_grpc` | Build with standard gRPC support, see [V2Ray Transport#gRPC](/configuration/shared/v2ray-transport#grpc). | -| `with_dhcp` | Build with DHCP support, see [DHCP DNS transport](/configuration/dns/server). | -| `with_wireguard` | Build with WireGuard support, see [WireGuard outbound](/configuration/outbound/wireguard). | -| `with_shadowsocksr` | Build with ShadowsocksR support, see [ShadowsocksR outbound](/configuration/outbound/shadowsocksr). | -| `with_ech` | Build with TLS ECH extension support for TLS outbound, see [TLS](/configuration/shared/tls#ech). | -| `with_utls` | Build with [uTLS](https://github.com/refraction-networking/utls) support for TLS outbound, see [TLS](/configuration/shared/tls#utls). | -| `with_reality_server` | Build with reality TLS server support, see [TLS](/configuration/shared/tls). | -| `with_acme` | Build with ACME TLS certificate issuer support, see [TLS](/configuration/shared/tls). | -| `with_clash_api` | Build with Clash API support, see [Experimental](/configuration/experimental#clash-api-fields). | -| `with_v2ray_api` | Build with V2Ray API support, see [Experimental](/configuration/experimental#v2ray-api-fields). | -| `with_gvisor` | Build with gVisor support, see [Tun inbound](/configuration/inbound/tun#stack) and [WireGuard outbound](/configuration/outbound/wireguard#system_interface). | -| `with_embedded_tor` (CGO required) | Build with embedded Tor support, see [Tor outbound](/configuration/outbound/tor). | -| `with_lwip` (CGO required) | Build with LWIP Tun stack support, see [Tun inbound](/configuration/inbound/tun#stack). | - -The binary is built under $GOPATH/bin - -```bash -sing-box version -``` - -It is also recommended to use systemd to manage sing-box service, -see [Linux server installation example](/examples/linux-server-installation). \ No newline at end of file diff --git a/docs/installation/from-source.zh.md b/docs/installation/from-source.zh.md deleted file mode 100644 index fbcb9ba827..0000000000 --- a/docs/installation/from-source.zh.md +++ /dev/null @@ -1,39 +0,0 @@ -# 从源代码安装 - -sing-box 需要 Golang **1.18.5** 或更高版本。 - -```bash -go install -v github.com/sagernet/sing-box/cmd/sing-box@latest -``` - -自定义安装: - -```bash -go install -v -tags with_clash_api github.com/sagernet/sing-box/cmd/sing-box@latest -``` - -| 构建标志 | 描述 | -|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `with_quic` | 启用 QUIC 支持,参阅 [QUIC 和 HTTP3 DNS 传输层](/configuration/dns/server),[Naive 入站](/configuration/inbound/naive),[Hysteria 入站](/configuration/inbound/hysteria),[Hysteria 出站](/configuration/outbound/hysteria) 和 [V2Ray 传输层#QUIC](/configuration/shared/v2ray-transport#quic)。 | -| `with_grpc` | 启用标准 gRPC 支持,参阅 [V2Ray 传输层#gRPC](/configuration/shared/v2ray-transport#grpc)。 | -| `with_dhcp` | 启用 DHCP 支持,参阅 [DHCP DNS 传输层](/configuration/dns/server)。 | -| `with_wireguard` | 启用 WireGuard 支持,参阅 [WireGuard 出站](/configuration/outbound/wireguard)。 | -| `with_shadowsocksr` | 启用 ShadowsocksR 支持,参阅 [ShadowsocksR 出站](/configuration/outbound/shadowsocksr)。 | -| `with_ech` | 启用 TLS ECH 扩展支持,参阅 [TLS](/configuration/shared/tls#ech)。 | -| `with_utls` | 启用 [uTLS](https://github.com/refraction-networking/utls) 支持,参阅 [TLS](/configuration/shared/tls#utls)。 | -| `with_reality_server` | 启用 reality TLS 服务器支持,参阅 [TLS](/configuration/shared/tls)。 | -| `with_acme` | 启用 ACME TLS 证书签发支持,参阅 [TLS](/configuration/shared/tls)。 | -| `with_clash_api` | 启用 Clash API 支持,参阅 [实验性](/configuration/experimental#clash-api-fields)。 | -| `with_v2ray_api` | 启用 V2Ray API 支持,参阅 [实验性](/configuration/experimental#v2ray-api-fields)。 | -| `with_gvisor` | 启用 gVisor 支持,参阅 [Tun 入站](/configuration/inbound/tun#stack) 和 [WireGuard 出站](/configuration/outbound/wireguard#system_interface)。 | -| `with_embedded_tor` (需要 CGO) | 启用 嵌入式 Tor 支持,参阅 [Tor 出站](/configuration/outbound/tor)。 | -| `with_lwip` (需要 CGO) | 启用 LWIP Tun 栈支持,参阅 [Tun 入站](/configuration/inbound/tun#stack)。 | - -二进制文件将被构建在 `$GOPATH/bin` 下。 - -```bash -sing-box version -``` - -同时推荐使用 systemd 来管理 sing-box 服务器实例。 -参阅 [Linux 服务器安装示例](/examples/linux-server-installation)。 \ No newline at end of file diff --git a/docs/installation/package-manager.md b/docs/installation/package-manager.md new file mode 100644 index 0000000000..6ce1669d02 --- /dev/null +++ b/docs/installation/package-manager.md @@ -0,0 +1,90 @@ +--- +icon: material/package +--- + +# Package Manager + +## :material-download-box: Manual Installation + +=== ":material-debian: Debian / DEB" + + ```bash + bash <(curl -fsSL https://sing-box.app/deb-install.sh) + ``` + +=== ":material-redhat: Redhat / RPM" + + ```bash + bash <(curl -fsSL https://sing-box.app/rpm-install.sh) + ``` + +=== ":simple-archlinux: Archlinux / PKG" + + ```bash + bash <(curl -fsSL https://sing-box.app/arch-install.sh) + ``` + +## :material-book-lock-open: Managed Installation + +=== ":material-linux: Linux" + + | Type | Platform | Link | Command | Actively maintained | + |----------|--------------------|---------------------|------------------------------|---------------------| + | AUR | (Linux) Arch Linux | [sing-box][aur] ᴬᵁᴿ | `? -S sing-box` | :material-check: | + | nixpkgs | (Linux) NixOS | [sing-box][nixpkgs] | `nix-env -iA nixos.sing-box` | :material-check: | + | Homebrew | macOS / Linux | [sing-box][brew] | `brew install sing-box` | :material-check: | + | Alpine | (Linux) Alpine | [sing-box][alpine] | `apk add sing-box` | :material-alert: | + +=== ":material-apple: macOS" + + | Type | Platform | Link | Command | Actively maintained | + |----------|---------------|------------------|-------------------------|---------------------| + | Homebrew | macOS / Linux | [sing-box][brew] | `brew install sing-box` | :material-check: | + +=== ":material-microsoft-windows: Windows" + + | Type | Platform | Link | Command | Actively maintained | + |------------|--------------------|---------------------|------------------------------|---------------------| + | Scoop | Windows | [sing-box][scoop] | `scoop install sing-box` | :material-check: | + | Chocolatey | Windows | [sing-box][choco] | `choco install sing-box` | :material-check: | + | winget | Windows | [sing-box][winget] | `winget install sing-box` | :material-alert: | + +=== ":material-android: Android" + + | Type | Platform | Link | Command | Actively maintained | + |------------|--------------------|---------------------|------------------------------|---------------------| + | Termux | Android | [sing-box][termux] | `pkg add sing-box` | :material-check: | + +## :material-book-multiple: Service Management + +For Linux systems with [systemd][systemd], usually the installation already includes a sing-box service, +you can manage the service using the following command: + +| Operation | Command | +|-----------|-----------------------------------------------| +| Enable | `sudo systemctl enable sing-box` | +| Disable | `sudo systemctl disable sing-box` | +| Start | `sudo systemctl start sing-box` | +| Stop | `sudo systemctl stop sing-box` | +| Kill | `sudo systemctl kill sing-box` | +| Restart | `sudo systemctl restart sing-box` | +| Logs | `sudo journalctl -u sing-box --output cat -e` | +| New Logs | `sudo journalctl -u sing-box --output cat -f` | + +[alpine]: https://pkgs.alpinelinux.org/packages?name=sing-box + +[aur]: https://aur.archlinux.org/packages/sing-box + +[nixpkgs]: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/tools/networking/sing-box/default.nix + +[termux]: https://github.com/termux/termux-packages/tree/master/packages/sing-box + +[brew]: https://formulae.brew.sh/formula/sing-box + +[choco]: https://chocolatey.org/packages/sing-box + +[scoop]: https://github.com/ScoopInstaller/Main/blob/master/bucket/sing-box.json + +[winget]: https://github.com/microsoft/winget-pkgs/tree/master/manifests/s/SagerNet/sing-box + +[systemd]: https://systemd.io/ \ No newline at end of file diff --git a/docs/installation/package-manager/android.md b/docs/installation/package-manager/android.md deleted file mode 100644 index 1177b86b3a..0000000000 --- a/docs/installation/package-manager/android.md +++ /dev/null @@ -1,7 +0,0 @@ -# Android - -## Termux - -```shell -pkg add sing-box -``` diff --git a/docs/installation/package-manager/macOS.md b/docs/installation/package-manager/macOS.md deleted file mode 100644 index f0192b5a6c..0000000000 --- a/docs/installation/package-manager/macOS.md +++ /dev/null @@ -1,14 +0,0 @@ -# macOS - -## Homebrew (core) - -```shell -brew install sing-box -``` - -## Homebrew (Tap) - -```shell -brew tap sagernet/sing-box -brew install sagernet/sing-box/sing-box -``` \ No newline at end of file diff --git a/docs/installation/package-manager/windows.md b/docs/installation/package-manager/windows.md deleted file mode 100644 index 46e078b93f..0000000000 --- a/docs/installation/package-manager/windows.md +++ /dev/null @@ -1,13 +0,0 @@ -# Windows - -## Chocolatey - -```shell -choco install sing-box -``` - -## winget - -```shell -winget install sing-box -``` \ No newline at end of file diff --git a/docs/installation/scripts/arch-install.sh b/docs/installation/scripts/arch-install.sh new file mode 100644 index 0000000000..50ce57679d --- /dev/null +++ b/docs/installation/scripts/arch-install.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +set -e -o pipefail + +ARCH_RAW=$(uname -m) +case "${ARCH_RAW}" in + 'x86_64') ARCH='amd64';; + 'x86' | 'i686' | 'i386') ARCH='386';; + 'aarch64' | 'arm64') ARCH='arm64';; + 'armv7l') ARCH='armv7';; + 's390x') ARCH='s390x';; + *) echo "Unsupported architecture: ${ARCH_RAW}"; exit 1;; +esac + +VERSION=$(curl -s https://api.github.com/repos/SagerNet/sing-box/releases/latest \ + | grep tag_name \ + | cut -d ":" -f2 \ + | sed 's/\"//g;s/\,//g;s/\ //g;s/v//') + +curl -Lo sing-box.pkg.tar.zst "https://github.com/SagerNet/sing-box/releases/download/v${VERSION}/sing-box_${VERSION}_linux_${ARCH}.pkg.tar.zst" +sudo pacman -U sing-box.pkg.tar.zst +rm sing-box.pkg.tar.zst diff --git a/docs/installation/scripts/deb-install.sh b/docs/installation/scripts/deb-install.sh new file mode 100644 index 0000000000..587b6f61ba --- /dev/null +++ b/docs/installation/scripts/deb-install.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -e -o pipefail + +ARCH_RAW=$(uname -m) +case "${ARCH_RAW}" in + 'x86_64') ARCH='amd64';; + 'x86' | 'i686' | 'i386') ARCH='386';; + 'aarch64' | 'arm64') ARCH='arm64';; + 'armv7l') ARCH='armv7';; + 's390x') ARCH='s390x';; + *) echo "Unsupported architecture: ${ARCH_RAW}"; exit 1;; +esac + +VERSION=$(curl -s https://api.github.com/repos/SagerNet/sing-box/releases/latest \ + | grep tag_name \ + | cut -d ":" -f2 \ + | sed 's/\"//g;s/\,//g;s/\ //g;s/v//') + +curl -Lo sing-box.deb "https://github.com/SagerNet/sing-box/releases/download/v${VERSION}/sing-box_${VERSION}_linux_${ARCH}.deb" +sudo dpkg -i sing-box.deb +rm sing-box.deb + diff --git a/docs/installation/scripts/rpm-install.sh b/docs/installation/scripts/rpm-install.sh new file mode 100644 index 0000000000..fc3d731400 --- /dev/null +++ b/docs/installation/scripts/rpm-install.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +set -e -o pipefail + +ARCH_RAW=$(uname -m) +case "${ARCH_RAW}" in + 'x86_64') ARCH='amd64';; + 'x86' | 'i686' | 'i386') ARCH='386';; + 'aarch64' | 'arm64') ARCH='arm64';; + 'armv7l') ARCH='armv7';; + 's390x') ARCH='s390x';; + *) echo "Unsupported architecture: ${ARCH_RAW}"; exit 1;; +esac + +VERSION=$(curl -s https://api.github.com/repos/SagerNet/sing-box/releases/latest \ + | grep tag_name \ + | cut -d ":" -f2 \ + | sed 's/\"//g;s/\,//g;s/\ //g;s/v//') + +curl -Lo sing-box.rpm "https://github.com/SagerNet/sing-box/releases/download/v${VERSION}/sing-box_${VERSION}_linux_${ARCH}.rpm" +sudo rpm -i sing-box.rpm +rm sing-box.rpm diff --git a/docs/manual/proxy-protocol/hysteria2.md b/docs/manual/proxy-protocol/hysteria2.md new file mode 100644 index 0000000000..9cc07e6f12 --- /dev/null +++ b/docs/manual/proxy-protocol/hysteria2.md @@ -0,0 +1,211 @@ +--- +icon: material/lightning-bolt +--- + +# Hysteria 2 + +The most popular Chinese-made simple protocol based on QUIC, the selling point is Brutal, +a congestion control algorithm that can resist packet loss by manually specifying the required rate by the user. + +!!! warning + + Even though GFW rarely blocks UDP-based proxies, such protocols actually have far more characteristics than TCP based proxies. + +| Specification | Binary Characteristics | Active Detect Hiddenness | +|---------------------------------------------------------------------------|------------------------|--------------------------| +| [hysteria.network](https://v2.hysteria.network/docs/developers/Protocol/) | :material-alert: | :material-check: | + +## :material-text-box-check: Password Generator + +| Generate Password | Action | +|----------------------------|-----------------------------------------------------------------| +| | | + + + +## :material-alert: Difference from official Hysteria + +The official program supports an authentication method called **userpass**, +which essentially uses a combination of `:` as the actual password, +while sing-box does not provide this alias. +To use sing-box with the official program, you need to fill in that combination as the actual password. + +## :material-server: Server Example + +!!! info "" + + Replace `up_mbps` and `down_mbps` values with the actual bandwidth of your server. + +=== ":material-harddisk: With local certificate" + + ```json + { + "inbounds": [ + { + "type": "hysteria2", + "listen": "::", + "listen_port": 8080, + "up_mbps": 100, + "down_mbps": 100, + "users": [ + { + "name": "sekai", + "password": "" + } + ], + "tls": { + "enabled": true, + "server_name": "example.org", + "key_path": "/path/to/key.pem", + "certificate_path": "/path/to/certificate.pem" + } + } + ] + } + ``` + +=== ":material-auto-fix: With ACME" + + ```json + { + "inbounds": [ + { + "type": "hysteria2", + "listen": "::", + "listen_port": 8080, + "up_mbps": 100, + "down_mbps": 100, + "users": [ + { + "name": "sekai", + "password": "" + } + ], + "tls": { + "enabled": true, + "server_name": "example.org", + "acme": { + "domain": "example.org", + "email": "admin@example.org" + } + } + } + ] + } + ``` + +=== ":material-cloud: With ACME and Cloudflare API" + + ```json + { + "inbounds": [ + { + "type": "hysteria2", + "listen": "::", + "listen_port": 8080, + "up_mbps": 100, + "down_mbps": 100, + "users": [ + { + "name": "sekai", + "password": "" + } + ], + "tls": { + "enabled": true, + "server_name": "example.org", + "acme": { + "domain": "example.org", + "email": "admin@example.org", + "dns01_challenge": { + "provider": "cloudflare", + "api_token": "my_token" + } + } + } + } + ] + } + ``` + +## :material-cellphone-link: Client Example + +!!! info "" + + Replace `up_mbps` and `down_mbps` values with the actual bandwidth of your client. + +=== ":material-web-check: With valid certificate" + + ```json + { + "outbounds": [ + { + "type": "hysteria2", + "server": "127.0.0.1", + "server_port": 8080, + "up_mbps": 100, + "down_mbps": 100, + "password": "", + "tls": { + "enabled": true, + "server_name": "example.org" + } + } + ] + } + ``` + +=== ":material-check: With self-sign certificate" + + !!! info "Tip" + + Use `sing-box merge` command to merge configuration and certificate into one file. + + ```json + { + "outbounds": [ + { + "type": "hysteria2", + "server": "127.0.0.1", + "server_port": 8080, + "up_mbps": 100, + "down_mbps": 100, + "password": "", + "tls": { + "enabled": true, + "server_name": "example.org", + "certificate_path": "/path/to/certificate.pem" + } + } + ] + } + ``` + +=== ":material-alert: Ignore certificate verification" + + ```json + { + "outbounds": [ + { + "type": "hysteria2", + "server": "127.0.0.1", + "server_port": 8080, + "up_mbps": 100, + "down_mbps": 100, + "password": "", + "tls": { + "enabled": true, + "server_name": "example.org", + "insecure": true + } + } + ] + } + ``` diff --git a/docs/manual/proxy-protocol/shadowsocks.md b/docs/manual/proxy-protocol/shadowsocks.md new file mode 100644 index 0000000000..be0bc20800 --- /dev/null +++ b/docs/manual/proxy-protocol/shadowsocks.md @@ -0,0 +1,126 @@ +--- +icon: material/send +--- + +# Shadowsocks + +As the most well-known Chinese-made proxy protocol, +Shadowsocks exists in multiple versions, +but only AEAD 2022 ciphers TCP with multiplexing is recommended. + +| Ciphers | Specification | Cryptographic Security | Binary Characteristics | Active Detect Hiddenness | +|----------------|------------------------------------------------------------|------------------------|------------------------|--------------------------| +| Stream Ciphers | [shadowsocks.org](https://shadowsocks.org/doc/stream.html) | :material-alert: | :material-alert: | :material-alert: | +| AEAD | [shadowsocks.org](https://shadowsocks.org/doc/aead.html) | :material-check: | :material-alert: | :material-alert: | +| AEAD 2022 | [shadowsocks.org](https://shadowsocks.org/doc/sip022.html) | :material-check: | :material-check: | :material-help: | + +## :material-text-box-check: Password Generator + +| For `2022-blake3-aes-128-gcm` cipher | For other ciphers | Action | +|--------------------------------------|-------------------------------|-----------------------------------------------------------------| +| | | | + + + +## :material-server: Server Example + +!!! info "" + + Password of cipher `2022-blake3-aes-128-gcm` can be generated by command `sing-box generate rand 16 --base64` + +=== ":material-account: Single-user" + + ```json + { + "inbounds": [ + { + "type": "shadowsocks", + "listen": "::", + "listen_port": 8080, + "network": "tcp", + "method": "2022-blake3-aes-128-gcm", + "password": "", + "multiplex": { + "enabled": true + } + } + ] + } + ``` + +=== ":material-account-multiple: Multi-user" + + ```json + { + "inbounds": [ + { + "type": "shadowsocks", + "listen": "::", + "listen_port": 8080, + "network": "tcp", + "method": "2022-blake3-aes-128-gcm", + "password": "", + "users": [ + { + "name": "sekai", + "password": "" + } + ], + "multiplex": { + "enabled": true + } + } + ] + } + ``` + +## :material-cellphone-link: Client Example + +=== ":material-account: Single-user" + + ```json + { + "outbounds": [ + { + "type": "shadowsocks", + "server": "127.0.0.1", + "server_port": 8080, + "method": "2022-blake3-aes-128-gcm", + "password": "", + "multiplex": { + "enabled": true + } + } + ] + } + ``` + +=== ":material-account-multiple: Multi-user" + + ```json + { + "outbounds": [ + { + "type": "shadowsocks", + "server": "127.0.0.1", + "server_port": 8080, + "method": "2022-blake3-aes-128-gcm", + "password": ":", + "multiplex": { + "enabled": true + } + } + ] + } + ``` diff --git a/docs/manual/proxy-protocol/trojan.md b/docs/manual/proxy-protocol/trojan.md new file mode 100644 index 0000000000..4c2e16f17e --- /dev/null +++ b/docs/manual/proxy-protocol/trojan.md @@ -0,0 +1,214 @@ +--- +icon: material/horse +--- + +# Trojan + +As the most commonly used TLS proxy made in China, Trojan can be used in various combinations, +but only the combination of uTLS and multiplexing is recommended. + +| Protocol and implementation combination | Specification | Binary Characteristics | Active Detect Hiddenness | +|-----------------------------------------|----------------------------------------------------------------------|------------------------|--------------------------| +| Origin / trojan-gfw | [trojan-gfw.github.io](https://trojan-gfw.github.io/trojan/protocol) | :material-check: | :material-check: | +| Basic Go implementation | / | :material-alert: | :material-check: | +| with privates transport by V2Ray | No formal definition | :material-alert: | :material-alert: | +| with uTLS enabled | No formal definition | :material-help: | :material-check: | + +## :material-text-box-check: Password Generator + +| Generate Password | Action | +|----------------------------|-----------------------------------------------------------------| +| | | + + + +## :material-server: Server Example + +=== ":material-harddisk: With local certificate" + + ```json + { + "inbounds": [ + { + "type": "trojan", + "listen": "::", + "listen_port": 8080, + "users": [ + { + "name": "example", + "password": "password" + } + ], + "tls": { + "enabled": true, + "server_name": "example.org", + "key_path": "/path/to/key.pem", + "certificate_path": "/path/to/certificate.pem" + }, + "multiplex": { + "enabled": true + } + } + ] + } + ``` + +=== ":material-auto-fix: With ACME" + + ```json + { + "inbounds": [ + { + "type": "trojan", + "listen": "::", + "listen_port": 8080, + "users": [ + { + "name": "example", + "password": "password" + } + ], + "tls": { + "enabled": true, + "server_name": "example.org", + "acme": { + "domain": "example.org", + "email": "admin@example.org" + } + }, + "multiplex": { + "enabled": true + } + } + ] + } + ``` + +=== ":material-cloud: With ACME and Cloudflare API" + + ```json + { + "inbounds": [ + { + "type": "trojan", + "listen": "::", + "listen_port": 8080, + "users": [ + { + "name": "example", + "password": "password" + } + ], + "tls": { + "enabled": true, + "server_name": "example.org", + "acme": { + "domain": "example.org", + "email": "admin@example.org", + "dns01_challenge": { + "provider": "cloudflare", + "api_token": "my_token" + } + } + }, + "multiplex": { + "enabled": true + } + } + ] + } + ``` + +## :material-cellphone-link: Client Example + +=== ":material-web-check: With valid certificate" + + ```json + { + "outbounds": [ + { + "type": "trojan", + "server": "127.0.0.1", + "server_port": 8080, + "password": "password", + "tls": { + "enabled": true, + "server_name": "example.org", + "utls": { + "enabled": true, + "fingerprint": "firefox" + } + }, + "multiplex": { + "enabled": true + } + } + ] + } + ``` + +=== ":material-check: With self-sign certificate" + + !!! info "Tip" + + Use `sing-box merge` command to merge configuration and certificate into one file. + + ```json + { + "outbounds": [ + { + "type": "trojan", + "server": "127.0.0.1", + "server_port": 8080, + "password": "password", + "tls": { + "enabled": true, + "server_name": "example.org", + "certificate_path": "/path/to/certificate.pem", + "utls": { + "enabled": true, + "fingerprint": "firefox" + } + }, + "multiplex": { + "enabled": true + } + } + ] + } + ``` + +=== ":material-alert: Ignore certificate verification" + + ```json + { + "outbounds": [ + { + "type": "trojan", + "server": "127.0.0.1", + "server_port": 8080, + "password": "password", + "tls": { + "enabled": true, + "server_name": "example.org", + "insecure": true, + "utls": { + "enabled": true, + "fingerprint": "firefox" + } + }, + "multiplex": { + "enabled": true + } + } + ] + } + ``` + diff --git a/docs/manual/proxy-protocol/tuic.md b/docs/manual/proxy-protocol/tuic.md new file mode 100644 index 0000000000..632be317c8 --- /dev/null +++ b/docs/manual/proxy-protocol/tuic.md @@ -0,0 +1,208 @@ +--- +icon: material/alpha-t-box +--- + +# TUIC + +A recently popular Chinese-made simple protocol based on QUIC, the selling point is the BBR congestion control algorithm. + +!!! warning + + Even though GFW rarely blocks UDP-based proxies, such protocols actually have far more characteristics than TCP based proxies. + +| Specification | Binary Characteristics | Active Detect Hiddenness | +|-----------------------------------------------------------|------------------------|--------------------------| +| [Github](https://github.com/EAimTY/tuic/blob/dev/SPEC.md) | :material-alert: | :material-check: | + +## Password Generator + +| Generated UUID | Generated Password | Action | +|------------------------|----------------------------|-----------------------------------------------------------------| +| | | | + + + +## :material-server: Server Example + +=== ":material-harddisk: With local certificate" + + ```json + { + "inbounds": [ + { + "type": "tuic", + "listen": "::", + "listen_port": 8080, + "users": [ + { + "name": "sekai", + "uuid": "", + "password": "" + } + ], + "congestion_control": "bbr", + "tls": { + "enabled": true, + "server_name": "example.org", + "key_path": "/path/to/key.pem", + "certificate_path": "/path/to/certificate.pem" + } + } + ] + } + ``` + +=== ":material-auto-fix: With ACME" + + ```json + { + "inbounds": [ + { + "type": "tuic", + "listen": "::", + "listen_port": 8080, + "users": [ + { + "name": "sekai", + "uuid": "", + "password": "" + } + ], + "congestion_control": "bbr", + "tls": { + "enabled": true, + "server_name": "example.org", + "acme": { + "domain": "example.org", + "email": "admin@example.org" + } + } + } + ] + } + ``` + +=== ":material-cloud: With ACME and Cloudflare API" + + ```json + { + "inbounds": [ + { + "type": "tuic", + "listen": "::", + "listen_port": 8080, + "users": [ + { + "name": "sekai", + "uuid": "", + "password": "" + } + ], + "congestion_control": "bbr", + "tls": { + "enabled": true, + "server_name": "example.org", + "acme": { + "domain": "example.org", + "email": "admin@example.org", + "dns01_challenge": { + "provider": "cloudflare", + "api_token": "my_token" + } + } + } + } + ] + } + ``` + +## :material-cellphone-link: Client Example + +=== ":material-web-check: With valid certificate" + + ```json + { + "outbounds": [ + { + "type": "tuic", + "server": "127.0.0.1", + "server_port": 8080, + "uuid": "", + "password": "", + "congestion_control": "bbr", + "tls": { + "enabled": true, + "server_name": "example.org" + } + } + ] + } + ``` + +=== ":material-check: With self-sign certificate" + + !!! info "Tip" + + Use `sing-box merge` command to merge configuration and certificate into one file. + + ```json + { + "outbounds": [ + { + "type": "tuic", + "server": "127.0.0.1", + "server_port": 8080, + "uuid": "", + "password": "", + "congestion_control": "bbr", + "tls": { + "enabled": true, + "server_name": "example.org", + "certificate_path": "/path/to/certificate.pem" + } + } + ] + } + ``` + +=== ":material-alert: Ignore certificate verification" + + ```json + { + "outbounds": [ + { + "type": "tuic", + "server": "127.0.0.1", + "server_port": 8080, + "uuid": "", + "password": "", + "congestion_control": "bbr", + "tls": { + "enabled": true, + "server_name": "example.org", + "insecure": true + } + } + ] + } + ``` + diff --git a/docs/manual/proxy/client.md b/docs/manual/proxy/client.md new file mode 100644 index 0000000000..675c2af095 --- /dev/null +++ b/docs/manual/proxy/client.md @@ -0,0 +1,287 @@ +--- +icon: material/cellphone-link +--- + +# Client + +### :material-ray-start: Introduction + +For a long time, the modern usage and principles of proxy clients +for graphical operating systems have not been clearly described. +However, we can categorize them into three types: +system proxy, firewall redirection, and virtual interface. + +### :material-web-refresh: System Proxy + +Almost all graphical environments support system-level proxies, +which are essentially ordinary HTTP proxies that only support TCP. + +| Operating System / Desktop Environment | System Proxy | Application Support | +|:---------------------------------------------|:-------------------------------------|:--------------------| +| Windows | :material-check: | :material-check: | +| macOS | :material-check: | :material-check: | +| GNOME/KDE | :material-check: | :material-check: | +| Android | ROOT or adb (permission) is required | :material-check: | +| Android/iOS (with sing-box graphical client) | via `tun.platform.http_proxy` | :material-check: | + +As one of the most well-known proxy methods, it has many shortcomings: +many TCP clients that are not based on HTTP do not check and use the system proxy. +Moreover, UDP and ICMP traffics bypass the proxy. + +```mermaid +flowchart LR + dns[DNS query] -- Is HTTP request? --> proxy[HTTP proxy] + dns --> leak[Leak] + tcp[TCP connection] -- Is HTTP request? --> proxy + tcp -- Check and use HTTP CONNECT? --> proxy + tcp --> leak + udp[UDP packet] --> leak +``` + +### :material-wall-fire: Firewall Redirection + +This type of usage typically relies on the firewall or hook interface provided by the operating system, +such as Windows’ WFP, Linux’s redirect, TProxy and eBPF, and macOS’s pf. +Although it is intrusive and cumbersome to configure, +it remains popular within the community of amateur proxy open source projects like V2Ray, +due to the low technical requirements it imposes on the software. + +### :material-expansion-card: Virtual Interface + +All L2/L3 proxies (seriously defined VPNs, such as OpenVPN, WireGuard) are based on virtual network interfaces, +which is also the only way for all L4 proxies to work as VPNs on mobile platforms like Android, iOS. + +The sing-box inherits and develops clash-premium’s TUN inbound (L3 to L4 conversion) +as the most reasonable method for performing transparent proxying. + +```mermaid +flowchart TB + packet[IP Packet] + packet --> windows[Windows / macOS] + packet --> linux[Linux] + tun[TUN interface] + windows -. route .-> tun + linux -. iproute2 route/rule .-> tun + tun --> gvisor[gVisor TUN stack] + tun --> system[system TUN stack] + assemble([L3 to L4 assemble]) + gvisor --> assemble + system --> assemble + assemble --> conn[TCP and UDP connections] + conn --> router[sing-box Router] + router --> direct[Direct outbound] + router --> proxy[Proxy outbounds] + router -- DNS hijack --> dns_out[DNS outbound] + dns_out --> dns_router[DNS router] + dns_router --> router + direct --> adi([auto detect interface]) + proxy --> adi + adi --> default[Default network interface in the system] + default --> destination[Destination server] + default --> proxy_server[Proxy server] + proxy_server --> destination +``` + +## :material-cellphone-link: Examples + +### Basic TUN usage for Chinese users + +=== ":material-numeric-4-box: IPv4 only" + + ```json + { + "dns": { + "servers": [ + { + "tag": "google", + "address": "tls://8.8.8.8" + }, + { + "tag": "local", + "address": "223.5.5.5", + "detour": "direct" + } + ], + "rules": [ + { + "outbound": "any", + "server": "local" + } + ], + "strategy": "ipv4_only" + }, + "inbounds": [ + { + "type": "tun", + "inet4_address": "172.19.0.1/30", + "auto_route": true, + "strict_route": false + } + ], + "outbounds": [ + // ... + { + "type": "direct", + "tag": "direct" + }, + { + "type": "dns", + "tag": "dns-out" + } + ], + "route": { + "rules": [ + { + "protocol": "dns", + "outbound": "dns-out" + }, + { + "geoip": [ + "private" + ], + "outbound": "direct" + } + ], + "auto_detect_interface": true + } + } + ``` + +=== ":material-numeric-6-box: IPv4 & IPv6" + + ```json + { + "dns": { + "servers": [ + { + "tag": "google", + "address": "tls://8.8.8.8" + }, + { + "tag": "local", + "address": "223.5.5.5", + "detour": "direct" + } + ], + "rules": [ + { + "outbound": "any", + "server": "local" + } + ] + }, + "inbounds": [ + { + "type": "tun", + "inet4_address": "172.19.0.1/30", + "inet6_address": "fdfe:dcba:9876::1/126", + "auto_route": true, + "strict_route": false + } + ], + "outbounds": [ + // ... + { + "type": "direct", + "tag": "direct" + }, + { + "type": "dns", + "tag": "dns-out" + } + ], + "route": { + "rules": [ + { + "protocol": "dns", + "outbound": "dns-out" + }, + { + "geoip": [ + "private" + ], + "outbound": "direct" + } + ], + "auto_detect_interface": true + } + } + ``` + +=== ":material-domain-switch: FakeIP" + + ```json + { + "dns": { + "servers": [ + { + "tag": "google", + "address": "tls://8.8.8.8" + }, + { + "tag": "local", + "address": "223.5.5.5", + "detour": "direct" + }, + { + "tag": "remote", + "address": "fakeip" + } + ], + "rules": [ + { + "outbound": "any", + "server": "local" + }, + { + "query_type": [ + "A", + "AAAA" + ], + "server": "remote" + } + ], + "fakeip": { + "enabled": true, + "inet4_range": "198.18.0.0/15", + "inet6_range": "fc00::/18" + }, + "independent_cache": true + }, + "inbounds": [ + { + "type": "tun", + "inet4_address": "172.19.0.1/30", + "inet6_address": "fdfe:dcba:9876::1/126", + "auto_route": true, + "strict_route": true + } + ], + "outbounds": [ + // ... + { + "type": "direct", + "tag": "direct" + }, + { + "type": "dns", + "tag": "dns-out" + } + ], + "route": { + "rules": [ + { + "protocol": "dns", + "outbound": "dns-out" + }, + { + "geoip": [ + "private" + ], + "outbound": "direct" + } + ], + "auto_detect_interface": true + } + } + ``` \ No newline at end of file diff --git a/docs/manual/proxy/server.md b/docs/manual/proxy/server.md new file mode 100644 index 0000000000..4d2667e039 --- /dev/null +++ b/docs/manual/proxy/server.md @@ -0,0 +1,10 @@ +--- +icon: material/server +--- + +# Server + +To use sing-box as a proxy protocol server, you pretty much only need to configure the inbound for that protocol. + +The Proxy Protocol menu below contains descriptions and configuration examples +of recommended protocols for bypassing GFW. diff --git a/docs/manual/proxy/tun.md b/docs/manual/proxy/tun.md new file mode 100644 index 0000000000..65cfb1cfd1 --- /dev/null +++ b/docs/manual/proxy/tun.md @@ -0,0 +1,66 @@ +# :material-expansion-card: TUN + +## :material-text-box: Definition + +Refers to TUNnel, a virtual network device supported by the kernel. +It’s also used in sing-box to denote the extensive functionality surrounding TUN inbound: +including traffic assembly, automatic routing, and network and default interface monitoring. + +The following flow chart describes the minimal TUN-based transparent proxy process in sing-box: + +``` mermaid +flowchart LR + subgraph inbound [Inbound] + direction TB + packet[IP Packet] + packet --> windows[Windows / macOS] + packet --> linux[Linux] + tun[TUN interface] + windows -. route .-> tun + linux -. iproute2 route/rule .-> tun + tun --> gvisor[gVisor TUN stack] + tun --> system[system TUN stack] + assemble([L3 to L4 assemble]) + gvisor --> assemble + system --> assemble + assemble --> conn[TCP and UDP connections] + conn --> router[sing-box Router] + end + + subgraph outbound [Outbound] + direction TB + direct[Direct outbound] + proxy[Proxy outbounds] + direct --> adi([auto detect interface]) + proxy --> adi + adi --> default[Default network interface in the system] + default --> destination[Destination server] + default --> proxy_server[Proxy server] + proxy_server --> destination + end + + inbound --> outbound +``` + +## :material-help-box: How to + +A basic TUN-based transparent proxy configuration file includes: an TUN inbound, `route.auto_detect_interface`, like: + +```json +{ + "inbounds": [ + { + "type": "tun", + "inet4_address": "172.19.0.1/30", + "inet6_address": "fdfe:dcba:9876::1/126", + "auto_route": true, + "strict_route": true + } + ], + "route": { + "auto_detect_interface": true + } +} +``` + +TODO: finish this wiki \ No newline at end of file diff --git a/docs/support.md b/docs/support.md index 257b343992..ec5aaecc91 100644 --- a/docs/support.md +++ b/docs/support.md @@ -1,4 +1,13 @@ -Github Issue: [Issues · SagerNet/sing-box](https://github.com/SagerNet/sing-box/issues) -Telegram Notification channel: [@yapnc](https://t.me/yapnc) -Telegram User group: [@yapug](https://t.me/yapug) -Email: [contact@sagernet.org](mailto:contact@sagernet.org) +--- +icon: material/forum +--- + +# Support + +| Channel | Link | +|:------------------------------|:--------------------------------------------| +| Community | https://community.sagernet.org | +| Github Issues | https://github.com/SagerNet/sing-box/issues | +| Telegram notification channel | https://t.me/yapnc | +| Telegram user group | https://t.me/yapug | +| Email | contact@sagernet.org | diff --git a/docs/support.zh.md b/docs/support.zh.md index 031bf6f9a4..11e04218f3 100644 --- a/docs/support.zh.md +++ b/docs/support.zh.md @@ -1,4 +1,14 @@ -Github 工单: [Issues · SagerNet/sing-box](https://github.com/SagerNet/sing-box/issues) -Telegram 通知频道: [@yapnc](https://t.me/yapnc) -Telegram 用户组: [@yapug](https://t.me/yapug) -Email: [contact@sagernet.org](mailto:contact@sagernet.org) +--- +icon: material/forum +--- + +# 支持 + +| 通道 | 链接 | +|:--------------|:--------------------------------------------| +| 社区 | https://community.sagernet.org | +| Github Issues | https://github.com/SagerNet/sing-box/issues | +| Telegram 通知频道 | https://t.me/yapnc | +| Telegram 用户组 | https://t.me/yapug | +| 邮件 | contact@sagernet.org | + diff --git a/mkdocs.yml b/mkdocs.yml index 98c46c6fb9..1d4b1d8b0e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -29,25 +29,39 @@ theme: - navigation.expand - navigation.sections - header.autohide + - content.code.copy + - content.code.select + - content.code.annotate nav: - Home: - index.md - - Features: features.md - Deprecated: deprecated.md - Support: support.md - Change Log: changelog.md - Installation: - - From source: installation/from-source.md - - Package Manager: - - macOS: installation/package-manager/macOS.md - - Windows: installation/package-manager/windows.md - - Android: installation/package-manager/android.md - - Clients: - - Specification: installation/clients/specification.md - - iOS: installation/clients/sfi.md - - macOS: installation/clients/sfm.md - - Apple tvOS: installation/clients/sft.md - - Android: installation/clients/sfa.md + - Package Manager: installation/package-manager.md + - Docker: installation/docker.md + - Build from source: installation/build-from-source.md + - Graphical Clients: + - clients/index.md + - Android: + - clients/android/index.md + - Features: clients/android/features.md + - Apple platforms: + - clients/apple/index.md + - Features: clients/apple/features.md + - General: clients/general.md + - Privacy policy: clients/privacy.md + - Manual: + - Proxy: + - Server: manual/proxy/server.md + - Client: manual/proxy/client.md +# - TUN: manual/proxy/tun.md + - Proxy Protocol: + - Shadowsocks: manual/proxy-protocol/shadowsocks.md + - Trojan: manual/proxy-protocol/trojan.md + - TUIC: manual/proxy-protocol/tuic.md + - Hysteria 2: manual/proxy-protocol/hysteria2.md - Configuration: - configuration/index.md - Log: @@ -115,24 +129,6 @@ nav: - DNS: configuration/outbound/dns.md - Selector: configuration/outbound/selector.md - URLTest: configuration/outbound/urltest.md - - FAQ: - - faq/index.md - - FakeIP: faq/fakeip.md - - Known Issues: faq/known-issues.md - - Examples: - - examples/index.md - - Linux Server Installation: examples/linux-server-installation.md - - Tun: examples/tun.md - - DNS Hijack: examples/dns-hijack.md - - Shadowsocks: examples/shadowsocks.md - - ShadowTLS: examples/shadowtls.md - - Clash API: examples/clash-api.md - - FakeIP: examples/fakeip.md - - Contributing: - - contributing/index.md - - Developing: - - Environment: contributing/environment.md - - Sub projects: contributing/sub-projects.md markdown_extensions: - pymdownx.inlinehilite - pymdownx.snippets @@ -143,6 +139,7 @@ markdown_extensions: - pymdownx.keys - pymdownx.mark - pymdownx.tilde + - pymdownx.magiclink - admonition - attr_list - md_in_html @@ -154,6 +151,14 @@ markdown_extensions: alternate_style: true - pymdownx.tasklist: custom_checkbox: true + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format extra: social: - icon: fontawesome/brands/github @@ -162,48 +167,58 @@ extra: plugins: - search - i18n: - default_language: en + docs_structure: suffix + fallback_to_default: true languages: - en: + - build: true + default: true + locale: en name: English - build: false - zh: + - build: true + default: false + locale: zh name: 简体中文 - material_alternate: true - nav_translations: - zh: - Getting Started: 开始 - Features: 特性 - Support: 支持 - Change Log: 更新日志 + nav_translations: + Home: 开始 + Deprecated: 废弃功能列表 + Support: 支持 + Change Log: 更新日志 - Installation: 安装 - From source: 从源代码 - Clients: 客户端 + Installation: 安装 + Package Manager: 包管理器 + Build from source: 从源代码构建 - Configuration: 配置 - Log: 日志 - DNS Server: DNS 服务器 - DNS Rule: DNS 规则 + Graphical Clients: 图形界面客户端 + Features: 特性 + Apple platforms: Apple 平台 + General: 通用 + Privacy policy: 隐私政策 - Route: 路由 - Route Rule: 路由规则 - Protocol Sniff: 协议探测 + Configuration: 配置 + Log: 日志 + DNS Server: DNS 服务器 + DNS Rule: DNS 规则 - Experimental: 实验性 + Route: 路由 + Route Rule: 路由规则 + Protocol Sniff: 协议探测 - Shared: 通用 - Listen Fields: 监听字段 - Dial Fields: 拨号字段 - DNS01 Challenge Fields: DNS01 验证字段 - Multiplex: 多路复用 - V2Ray Transport: V2Ray 传输层 + Experimental: 实验性 - Inbound: 入站 - Outbound: 出站 + Shared: 通用 + Listen Fields: 监听字段 + Dial Fields: 拨号字段 + DNS01 Challenge Fields: DNS01 验证字段 + Multiplex: 多路复用 + V2Ray Transport: V2Ray 传输层 - FAQ: 常见问题 - Known Issues: 已知问题 - Examples: 示例 - Linux Server Installation: Linux 服务器安装 - DNS Hijack: DNS 劫持 + Inbound: 入站 + Outbound: 出站 + + FAQ: 常见问题 + Known Issues: 已知问题 + Examples: 示例 + Linux Server Installation: Linux 服务器安装 + DNS Hijack: DNS 劫持 + reconfigure_material: true + reconfigure_search: true \ No newline at end of file From dda4909bc874976dd346b27dd83cd70d6cad40f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 21 Nov 2023 17:42:07 +0800 Subject: [PATCH 84/87] Remove unused code --- experimental/clashapi/trafficontrol/manager.go | 3 --- experimental/libbox/command_status.go | 1 - 2 files changed, 4 deletions(-) diff --git a/experimental/clashapi/trafficontrol/manager.go b/experimental/clashapi/trafficontrol/manager.go index 17efe1abda..eac7aee4d8 100644 --- a/experimental/clashapi/trafficontrol/manager.go +++ b/experimental/clashapi/trafficontrol/manager.go @@ -70,9 +70,6 @@ func (m *Manager) Snapshot() *Snapshot { return true }) - //if memoryInfo, err := m.process.MemoryInfo(); err == nil { - // m.memory = memoryInfo.RSS - //} else { var memStats runtime.MemStats runtime.ReadMemStats(&memStats) m.memory = memStats.StackInuse + memStats.HeapInuse + memStats.HeapIdle - memStats.HeapReleased diff --git a/experimental/libbox/command_status.go b/experimental/libbox/command_status.go index dbf1ad2efa..7f1eca8c03 100644 --- a/experimental/libbox/command_status.go +++ b/experimental/libbox/command_status.go @@ -14,7 +14,6 @@ import ( type StatusMessage struct { Memory int64 - MemoryInuse int64 Goroutines int32 ConnectionsIn int32 ConnectionsOut int32 From 0923c5dc98d85b61b7721c3c7d48c820b69253c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 23 Nov 2023 22:30:31 +0800 Subject: [PATCH 85/87] documentation: Fix typo --- docs/clients/android/index.md | 4 ++-- docs/clients/apple/index.md | 6 +++--- docs/manual/proxy-protocol/tuic.md | 2 +- docs/support.md | 2 +- docs/support.zh.md | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/clients/android/index.md b/docs/clients/android/index.md index babef2831f..cbd1d387de 100644 --- a/docs/clients/android/index.md +++ b/docs/clients/android/index.md @@ -15,8 +15,8 @@ platform-specific function implementation, such as TUN transparent proxy impleme * [Play Store](https://play.google.com/store/apps/details?id=io.nekohasekai.sfa) * [Play Store (Beta)](https://play.google.com/apps/testing/io.nekohasekai.sfa) -* [Github Releases](https://github.com/SagerNet/sing-box/releases) +* [GitHub Releases](https://github.com/SagerNet/sing-box/releases) ## :material-source-repository: Source code -* [Github](https://github.com/SagerNet/sing-box-for-android) +* [GitHub](https://github.com/SagerNet/sing-box-for-android) diff --git a/docs/clients/apple/index.md b/docs/clients/apple/index.md index 72cf5f4624..36a4edd9f4 100644 --- a/docs/clients/apple/index.md +++ b/docs/clients/apple/index.md @@ -14,7 +14,7 @@ platform-specific function implementation, such as TUN transparent proxy impleme ## :material-download: Download -* [AppStore](https://apps.apple.com/us/app/sing-box/id6451272673) +* [App Store](https://apps.apple.com/us/app/sing-box/id6451272673) * [TestFlight (Beta)](https://testflight.apple.com/join/AcqO44FH) ## :material-file-download: Download (macOS standalone version) @@ -25,8 +25,8 @@ platform-specific function implementation, such as TUN transparent proxy impleme brew install sfm ``` -* [Github Releases](https://github.com/SagerNet/sing-box/releases) +* [GitHub Releases](https://github.com/SagerNet/sing-box/releases) ## :material-source-repository: Source code -* [Github](https://github.com/SagerNet/sing-box-for-apple) +* [GitHub](https://github.com/SagerNet/sing-box-for-apple) diff --git a/docs/manual/proxy-protocol/tuic.md b/docs/manual/proxy-protocol/tuic.md index 632be317c8..a2e01d882b 100644 --- a/docs/manual/proxy-protocol/tuic.md +++ b/docs/manual/proxy-protocol/tuic.md @@ -12,7 +12,7 @@ A recently popular Chinese-made simple protocol based on QUIC, the selling point | Specification | Binary Characteristics | Active Detect Hiddenness | |-----------------------------------------------------------|------------------------|--------------------------| -| [Github](https://github.com/EAimTY/tuic/blob/dev/SPEC.md) | :material-alert: | :material-check: | +| [GitHub](https://github.com/EAimTY/tuic/blob/dev/SPEC.md) | :material-alert: | :material-check: | ## Password Generator diff --git a/docs/support.md b/docs/support.md index ec5aaecc91..9ddb4ecfff 100644 --- a/docs/support.md +++ b/docs/support.md @@ -7,7 +7,7 @@ icon: material/forum | Channel | Link | |:------------------------------|:--------------------------------------------| | Community | https://community.sagernet.org | -| Github Issues | https://github.com/SagerNet/sing-box/issues | +| GitHub Issues | https://github.com/SagerNet/sing-box/issues | | Telegram notification channel | https://t.me/yapnc | | Telegram user group | https://t.me/yapug | | Email | contact@sagernet.org | diff --git a/docs/support.zh.md b/docs/support.zh.md index 11e04218f3..eb07ea8292 100644 --- a/docs/support.zh.md +++ b/docs/support.zh.md @@ -7,7 +7,7 @@ icon: material/forum | 通道 | 链接 | |:--------------|:--------------------------------------------| | 社区 | https://community.sagernet.org | -| Github Issues | https://github.com/SagerNet/sing-box/issues | +| GitHub Issues | https://github.com/SagerNet/sing-box/issues | | Telegram 通知频道 | https://t.me/yapnc | | Telegram 用户组 | https://t.me/yapug | | 邮件 | contact@sagernet.org | From 2cae7ae39f74885285c364d2d11538763b78e36d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 23 Nov 2023 23:03:12 +0800 Subject: [PATCH 86/87] sing-quic: Fix missing user context in packet connections --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 52339704e8..b02f14239b 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/sagernet/sing v0.2.18-0.20231119032432-6a556bfa50cc github.com/sagernet/sing-dns v0.1.11 github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 - github.com/sagernet/sing-quic v0.1.5-0.20231120105530-5ad0ab6d8e42 + github.com/sagernet/sing-quic v0.1.5-0.20231123150216-00957d136203 github.com/sagernet/sing-shadowsocks v0.2.5 github.com/sagernet/sing-shadowsocks2 v0.1.5 github.com/sagernet/sing-shadowtls v0.1.4 diff --git a/go.sum b/go.sum index e88aa5f022..5973219c3f 100644 --- a/go.sum +++ b/go.sum @@ -116,8 +116,8 @@ github.com/sagernet/sing-dns v0.1.11 h1:PPrMCVVrAeR3f5X23I+cmvacXJ+kzuyAsBiWyUKh github.com/sagernet/sing-dns v0.1.11/go.mod h1:zJ/YjnYB61SYE+ubMcMqVdpaSvsyQ2iShQGO3vuLvvE= github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 h1:ncKb5tVOsCQgCsv6UpsA0jinbNb5OQ5GMPJlyQP3EHM= github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07/go.mod h1:u/MZf32xPG8jEKe3t+xUV67EBnKtDtCaPhsJQOQGUYU= -github.com/sagernet/sing-quic v0.1.5-0.20231120105530-5ad0ab6d8e42 h1:yyt9Tk6MvXtte2hPNQ0EKeLOQkMX9EwyPpjCflRXYfM= -github.com/sagernet/sing-quic v0.1.5-0.20231120105530-5ad0ab6d8e42/go.mod h1:B6OgRz+qLn3N1114dcZVExkdarArtsAX2MgWJIfB72c= +github.com/sagernet/sing-quic v0.1.5-0.20231123150216-00957d136203 h1:e3C94gdfTDal52fk0BS/BRcDeF3USqBr8OjQc7XBk4E= +github.com/sagernet/sing-quic v0.1.5-0.20231123150216-00957d136203/go.mod h1:B6OgRz+qLn3N1114dcZVExkdarArtsAX2MgWJIfB72c= github.com/sagernet/sing-shadowsocks v0.2.5 h1:qxIttos4xu6ii7MTVJYA8EFQR7Q3KG6xMqmLJIFtBaY= github.com/sagernet/sing-shadowsocks v0.2.5/go.mod h1:MGWGkcU2xW2G2mfArT9/QqpVLOGU+dBaahZCtPHdt7A= github.com/sagernet/sing-shadowsocks2 v0.1.5 h1:JDeAJ4ZWlYZ7F6qEVdDKPhQEangxKw/JtmU+i/YfCYE= From ec6ccfa0a864f37ff1b094ff9cd36d7a843e9192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 23 Nov 2023 23:15:49 +0800 Subject: [PATCH 87/87] documentation: Bump version --- docs/changelog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index aa80e1fc9e..9837ffc74a 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -4,6 +4,11 @@ icon: material/alert-decagram # ChangeLog +#### 1.7.0-rc.2 + +* Fix missing UDP user context on TUIC/Hysteria2 inbounds +* macOS: Add button for uninstall SystemExtension in the standalone graphical client + #### 1.6.6 * Fixes and improvements