From 4b88168c027709ba290f2d195d5da0d7c9cb0894 Mon Sep 17 00:00:00 2001 From: daodao97 Date: Thu, 9 Nov 2023 07:54:12 +0800 Subject: [PATCH] up --- build.sh | 2 +- go.mod | 78 ++- go.sum | 169 +++--- pkg/sing-box/.github/workflows/debug.yml | 2 + pkg/sing-box/.github/workflows/lint.yml | 6 +- pkg/sing-box/.gitignore | 4 + pkg/sing-box/.goreleaser.yaml | 43 ++ pkg/sing-box/Makefile | 13 +- pkg/sing-box/adapter/conn_router.go | 104 ++++ pkg/sing-box/adapter/inbound.go | 8 + pkg/sing-box/adapter/router.go | 5 +- pkg/sing-box/box_outbound.go | 2 +- pkg/sing-box/cmd/sing-box/cmd_generate.go | 49 +- pkg/sing-box/cmd/sing-box/cmd_generate_tls.go | 40 ++ .../cmd/sing-box/cmd_generate_vapid.go | 40 ++ .../cmd/sing-box/cmd_generate_wireguard.go | 61 ++ pkg/sing-box/common/dialer/default.go | 8 +- pkg/sing-box/common/dialer/detour.go | 10 +- pkg/sing-box/common/dialer/resolve.go | 4 +- pkg/sing-box/common/mux/client.go | 4 +- pkg/sing-box/common/mux/protocol.go | 14 - pkg/sing-box/common/mux/router.go | 65 +++ pkg/sing-box/common/mux/v2ray_legacy.go | 32 ++ pkg/sing-box/common/tls/mkcert.go | 34 +- pkg/sing-box/common/tls/std_server.go | 2 +- pkg/sing-box/common/uot/router.go | 53 ++ pkg/sing-box/constant/speed.go | 3 + pkg/sing-box/constant/v2ray.go | 9 +- pkg/sing-box/docs/changelog.md | 191 +++++++ .../docs/configuration/inbound/hysteria2.md | 15 +- .../configuration/inbound/hysteria2.zh.md | 17 +- .../docs/configuration/inbound/shadowsocks.md | 55 +- .../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/tun.md | 14 + .../docs/configuration/inbound/tun.zh.md | 14 + .../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.md | 5 + .../configuration/outbound/hysteria2.zh.md | 6 +- .../configuration/outbound/shadowsocks.md | 2 +- .../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/listen.md | 54 +- .../docs/configuration/shared/listen.zh.md | 38 +- .../docs/configuration/shared/multiplex.md | 35 +- .../docs/configuration/shared/multiplex.zh.md | 35 +- .../docs/configuration/shared/tcp-brutal.md | 28 + .../configuration/shared/tcp-brutal.zh.md | 28 + .../configuration/shared/v2ray-transport.md | 30 + .../shared/v2ray-transport.zh.md | 30 + pkg/sing-box/docs/deprecated.md | 4 +- pkg/sing-box/docs/installation/clients/sfa.md | 5 + .../docs/installation/clients/sfa.zh.md | 5 + pkg/sing-box/docs/installation/clients/sft.md | 3 +- .../docs/installation/clients/sft.zh.md | 31 + .../experimental/clashapi/api_meta.go | 17 +- .../experimental/clashapi/cachefile/cache.go | 28 +- .../experimental/clashapi/cachefile/fakeip.go | 3 +- .../experimental/clashapi/connections.go | 9 +- pkg/sing-box/experimental/clashapi/server.go | 38 +- .../experimental/libbox/build_info.go | 234 ++++++++ .../experimental/libbox/command_client.go | 1 + .../experimental/libbox/command_log.go | 38 +- .../experimental/libbox/command_server.go | 11 +- pkg/sing-box/experimental/libbox/service.go | 7 +- pkg/sing-box/experimental/libbox/tun.go | 9 +- pkg/sing-box/go.mod | 38 +- pkg/sing-box/go.sum | 82 +-- pkg/sing-box/inbound/default.go | 2 +- pkg/sing-box/inbound/http.go | 3 +- pkg/sing-box/inbound/hysteria.go | 352 +++--------- pkg/sing-box/inbound/hysteria2.go | 4 +- pkg/sing-box/inbound/mixed.go | 3 +- pkg/sing-box/inbound/naive.go | 15 +- pkg/sing-box/inbound/shadowsocks.go | 12 +- pkg/sing-box/inbound/shadowsocks_multi.go | 14 +- pkg/sing-box/inbound/shadowsocks_relay.go | 9 +- pkg/sing-box/inbound/socks.go | 3 +- pkg/sing-box/inbound/tuic.go | 1 + pkg/sing-box/inbound/tun.go | 36 +- pkg/sing-box/inbound/vless.go | 10 +- pkg/sing-box/inbound/vmess.go | 11 +- pkg/sing-box/mkdocs.yml | 1 + pkg/sing-box/option/dns.go | 6 +- pkg/sing-box/option/hysteria2.go | 14 +- pkg/sing-box/option/inbound.go | 9 +- pkg/sing-box/option/multiplex.go | 23 + pkg/sing-box/option/outbound.go | 9 - pkg/sing-box/option/shadowsocks.go | 15 +- pkg/sing-box/option/simple.go | 20 +- pkg/sing-box/option/trojan.go | 11 +- pkg/sing-box/option/tun.go | 46 +- pkg/sing-box/option/types.go | 41 +- pkg/sing-box/option/v2ray_transport.go | 41 +- pkg/sing-box/option/vless.go | 21 +- pkg/sing-box/option/vmess.go | 27 +- pkg/sing-box/option/wireguard.go | 4 +- pkg/sing-box/outbound/default.go | 20 +- pkg/sing-box/outbound/direct.go | 2 +- pkg/sing-box/outbound/http.go | 10 +- pkg/sing-box/outbound/hysteria.go | 324 ++--------- pkg/sing-box/outbound/hysteria2.go | 4 +- pkg/sing-box/outbound/proxy_provider.go | 2 +- pkg/sing-box/outbound/shadowsocks.go | 4 +- pkg/sing-box/outbound/shadowsocksr.go | 15 +- pkg/sing-box/outbound/socks.go | 7 +- pkg/sing-box/outbound/wireguard.go | 15 +- pkg/sing-box/route/router.go | 43 +- pkg/sing-box/test/box_test.go | 27 + pkg/sing-box/test/domain_inbound_test.go | 83 +++ pkg/sing-box/test/go.mod | 59 +- pkg/sing-box/test/go.sum | 116 ++-- pkg/sing-box/test/hysteria2_test.go | 2 +- pkg/sing-box/test/hysteria_test.go | 4 +- pkg/sing-box/test/mux_test.go | 21 +- pkg/sing-box/test/shadowsocks_test.go | 2 +- pkg/sing-box/test/v2ray_httpupgrade_test.go | 16 + pkg/sing-box/test/wireguard_test.go | 2 +- pkg/sing-box/transport/hysteria/frag.go | 65 --- pkg/sing-box/transport/hysteria/protocol.go | 539 ------------------ pkg/sing-box/transport/hysteria/speed.go | 36 -- pkg/sing-box/transport/hysteria/wrap.go | 68 --- pkg/sing-box/transport/hysteria/xplus.go | 118 ---- pkg/sing-box/transport/v2ray/transport.go | 8 +- .../transport/v2raygrpclite/client.go | 2 +- .../transport/v2raygrpclite/server.go | 8 +- pkg/sing-box/transport/v2rayhttp/client.go | 9 +- pkg/sing-box/transport/v2rayhttp/server.go | 13 +- .../transport/v2rayhttpupgrade/client.go | 118 ++++ .../transport/v2rayhttpupgrade/server.go | 139 +++++ pkg/sing-box/transport/v2rayquic/client.go | 3 +- pkg/sing-box/transport/v2rayquic/server.go | 3 +- pkg/sing-box/transport/v2rayquic/stream.go | 41 ++ .../transport/v2raywebsocket/client.go | 88 +-- pkg/sing-box/transport/v2raywebsocket/conn.go | 114 ++-- pkg/sing-box/transport/v2raywebsocket/mask.go | 6 - .../transport/v2raywebsocket/server.go | 13 +- .../transport/v2raywebsocket/writer.go | 27 +- 149 files changed, 2746 insertions(+), 2308 deletions(-) create mode 100644 pkg/sing-box/adapter/conn_router.go create mode 100644 pkg/sing-box/cmd/sing-box/cmd_generate_tls.go create mode 100644 pkg/sing-box/cmd/sing-box/cmd_generate_vapid.go create mode 100644 pkg/sing-box/cmd/sing-box/cmd_generate_wireguard.go delete mode 100644 pkg/sing-box/common/mux/protocol.go create mode 100644 pkg/sing-box/common/mux/router.go create mode 100644 pkg/sing-box/common/mux/v2ray_legacy.go create mode 100644 pkg/sing-box/common/uot/router.go create mode 100644 pkg/sing-box/constant/speed.go create mode 100644 pkg/sing-box/docs/configuration/shared/tcp-brutal.md create mode 100644 pkg/sing-box/docs/configuration/shared/tcp-brutal.zh.md create mode 100644 pkg/sing-box/docs/installation/clients/sft.zh.md create mode 100644 pkg/sing-box/experimental/libbox/build_info.go create mode 100644 pkg/sing-box/option/multiplex.go create mode 100644 pkg/sing-box/test/domain_inbound_test.go create mode 100644 pkg/sing-box/test/v2ray_httpupgrade_test.go delete mode 100644 pkg/sing-box/transport/hysteria/frag.go delete mode 100644 pkg/sing-box/transport/hysteria/protocol.go delete mode 100644 pkg/sing-box/transport/hysteria/speed.go delete mode 100644 pkg/sing-box/transport/hysteria/wrap.go delete mode 100644 pkg/sing-box/transport/hysteria/xplus.go create mode 100644 pkg/sing-box/transport/v2rayhttpupgrade/client.go create mode 100644 pkg/sing-box/transport/v2rayhttpupgrade/server.go create mode 100644 pkg/sing-box/transport/v2rayquic/stream.go delete mode 100644 pkg/sing-box/transport/v2raywebsocket/mask.go diff --git a/build.sh b/build.sh index c8b44351..7776f1ff 100644 --- a/build.sh +++ b/build.sh @@ -6,7 +6,7 @@ set -x export LDFLAGS="-L/usr/local/opt/openssl@3/lib" export CPPFLAGS="-I/usr/local/opt/openssl@3/include" -gobuild="go build --tags with_grpc,with_wireguard,with_shadowsocksr,with_ech,with_utls,with_acme,with_clash_api,with_gvisor" +gobuild="go build --tags with_grpc,with_wireguard,with_ech,with_utls,with_acme,with_clash_api,with_gvisor" function buildMacIcon() { rm -rf icons.iconset diff --git a/go.mod b/go.mod index 847391b5..9b6e7c1e 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/emersion/go-autostart v0.0.0-20210130080809-00ed301c8e9a - github.com/fsnotify/fsnotify v1.6.0 + github.com/fsnotify/fsnotify v1.7.0 github.com/getlantern/notifier v0.0.0-20220715102006-f432f7e83f94 github.com/getlantern/systray v1.2.1 github.com/pkg/errors v0.9.1 @@ -16,14 +16,11 @@ 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/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.5 // indirect - github.com/caddyserver/certmagic v0.19.1 // indirect - github.com/cloudflare/circl v1.2.1-0.20221019164342-6ab4dfed8f3c // indirect + github.com/caddyserver/certmagic v0.19.2 // indirect + github.com/cloudflare/circl v1.3.6 // indirect github.com/cretz/bine v0.2.0 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect github.com/getlantern/errors v1.0.1 // indirect github.com/getlantern/golog v0.0.0-20211223150227-d4d95a44d873 // indirect @@ -33,72 +30,73 @@ require ( github.com/go-chi/chi/v5 v5.0.10 // indirect github.com/go-chi/cors v1.2.1 // indirect github.com/go-chi/render v1.0.3 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-stack/stack v1.8.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/gofrs/uuid v4.4.0+incompatible // indirect github.com/gofrs/uuid/v5 v5.0.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/hashicorp/yamux v0.1.1 // indirect - github.com/insomniacslk/dhcp v0.0.0-20230720093626-5648422c16cd // 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 + github.com/libdns/alidns v1.0.3 // indirect + github.com/libdns/cloudflare v0.1.0 // indirect 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.55 // indirect + github.com/miekg/dns v1.1.56 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/ooni/go-libtor v1.1.8 // indirect - github.com/oschwald/maxminddb-golang v1.11.0 // indirect + github.com/oschwald/maxminddb-golang v1.12.0 // indirect github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect - github.com/pires/go-proxyproto v0.7.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-18 v0.2.0 // indirect - github.com/quic-go/qtls-go1-19 v0.3.2 // indirect - github.com/quic-go/qtls-go1-20 v0.2.2 // indirect - github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 // 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/gvisor v0.0.0-20230930141345-5fef6f2e17ab // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect - github.com/sagernet/quic-go v0.0.0-20230731012313-1327e4015111 // indirect + github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect - github.com/sagernet/sing v0.2.10-0.20230731010140-26d3f3d91bda // indirect - github.com/sagernet/sing-dns v0.1.9-0.20230731012726-ad50da89b659 // indirect - github.com/sagernet/sing-mux v0.1.2 // indirect - github.com/sagernet/sing-shadowsocks v0.2.4 // indirect - github.com/sagernet/sing-shadowsocks2 v0.1.3 // indirect + github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2 // indirect + github.com/sagernet/sing-dns v0.1.10 // indirect + github.com/sagernet/sing-mux v0.1.4-0.20231102172319-a36b95857a9b // indirect + github.com/sagernet/sing-quic v0.1.3-0.20231026034240-fa3d997246b6 // indirect + github.com/sagernet/sing-shadowsocks v0.2.5 // indirect + github.com/sagernet/sing-shadowsocks2 v0.1.4 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect - github.com/sagernet/sing-tun v0.1.11 // indirect - github.com/sagernet/sing-vmess v0.1.7 // indirect + github.com/sagernet/sing-tun v0.1.17-0.20231103103951-3540ea7680d8 // 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-20230303015439-ffcfd8c41cf9 // indirect + github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 // indirect github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect - github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect - github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 // 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/spf13/cast v1.5.1 // indirect github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/zeebo/blake3 v0.2.3 // indirect - go.etcd.io/bbolt v1.3.7 // indirect - go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.24.0 // indirect - go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28 // indirect - golang.org/x/crypto v0.11.0 // indirect - golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect - golang.org/x/mod v0.11.0 // indirect - golang.org/x/net v0.12.0 // indirect - golang.org/x/sys v0.10.0 // indirect - golang.org/x/text v0.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/net v0.17.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.10.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect - google.golang.org/grpc v1.57.0 // 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.v2 v2.4.0 // indirect lukechampine.com/blake3 v1.2.1 // indirect diff --git a/go.sum b/go.sum index 8fdf8e8d..a1b7f5d8 100644 --- a/go.sum +++ b/go.sum @@ -40,25 +40,20 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -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= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/caddyserver/certmagic v0.19.1 h1:4jyOYm2DHvQI8YM0sk6qm62Gl5XznHxiMBMWjMTlQkw= -github.com/caddyserver/certmagic v0.19.1/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG+MIO4ztnmG/zz8= +github.com/caddyserver/certmagic v0.19.2 h1:HZd1AKLx4592MalEGQS39DKs2ZOAJCEM/xYPMQ2/ui0= +github.com/caddyserver/certmagic v0.19.2/go.mod h1:fsL01NomQ6N+kE2j37ZCnig2MFosG+MIO4ztnmG/zz8= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.2.1-0.20221019164342-6ab4dfed8f3c h1:K1VdSnBZiGapczwcUKnE1qcsMBclA84DUOD2NG/78VY= -github.com/cloudflare/circl v1.2.1-0.20221019164342-6ab4dfed8f3c/go.mod h1:+CauBF6R70Jqcyl8N2hC8pAXYbWkGIezuSbuGLtRhnw= +github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg= +github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -68,8 +63,6 @@ github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbe github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emersion/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:M88ob4TyDnEqNuL3PgsE/p3bDujfspnulR+0dQWNYZs= github.com/emersion/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:buzQsO8HHkZX2Q45fdfGH1xejPjuDQaXH8btcYMFzPM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -79,8 +72,8 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= -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/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4= github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY= github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A= @@ -107,12 +100,16 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 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 v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= @@ -128,7 +125,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -187,8 +183,8 @@ 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-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20230720093626-5648422c16cd h1:D772X7igTag7yKErVWAR7boXpOml3fqqBzH1wNaD/jk= -github.com/insomniacslk/dhcp v0.0.0-20230720093626-5648422c16cd/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= +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= @@ -206,28 +202,31 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/libdns/alidns v1.0.3 h1:LFHuGnbseq5+HCeGa1aW8awyX/4M2psB9962fdD2+yQ= +github.com/libdns/alidns v1.0.3/go.mod h1:e18uAG6GanfRhcJj6/tps2rCMzQJaYVcGKT+ELjdjGE= +github.com/libdns/cloudflare v0.1.0 h1:93WkJaGaiXCe353LHEP36kAWCUw0YjFqwhkBkU2/iic= +github.com/libdns/cloudflare v0.1.0/go.mod h1:a44IP6J1YH6nvcNl1PverfJviADgXUnsozR3a7vBKN8= +github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis= github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= 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.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= -github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= 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/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.11.0 h1:aSXMqYR/EPNjGE8epgqwDay+P30hCBZIveY0WZbAWh0= -github.com/oschwald/maxminddb-golang v1.11.0/go.mod h1:YmVI+H0zh3ySFR3w+oz8PCfglAFj3PuCmui13+P9zDg= +github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= +github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= 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.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -237,54 +236,54 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 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-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U= -github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc= -github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U= -github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= -github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= +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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 h1:KyhtFFt1Jtp5vW2ohNvstvQffTOQ/s5vENuGXzdA+TM= -github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0/go.mod h1:D4SFEOkJK+4W1v86ZhX0jPM0rAL498fyQAChqMtes/I= +github.com/sagernet/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= 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-20230731012313-1327e4015111 h1:BjZBIgwzlIbRSijdGQYZf0CaqHY1ZEIOUqVEKEICU0U= -github.com/sagernet/quic-go v0.0.0-20230731012313-1327e4015111/go.mod h1:5rilP6WxqIl/4ypZbMjr+MK+STxuCEvO5yVtEyYNZ6g= +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.10-0.20230731010140-26d3f3d91bda h1:gTIL4AFP/jFXChtjWBJ6i9SaCUZP4BiL628i15El7QI= -github.com/sagernet/sing v0.2.10-0.20230731010140-26d3f3d91bda/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= -github.com/sagernet/sing-dns v0.1.9-0.20230731012726-ad50da89b659 h1:1DAKccGNqTYJ8nsBR765FS0LVBVXfuFlFAHqKsGN3EI= -github.com/sagernet/sing-dns v0.1.9-0.20230731012726-ad50da89b659/go.mod h1:W7GHTZFS8RkoLI3bA2LFY27/0E+uoQESWtMFLepO/JA= -github.com/sagernet/sing-mux v0.1.2 h1:av2/m6e+Gh+ECTuJZqYCjJz55BNkot0VyRMkREqyF/g= -github.com/sagernet/sing-mux v0.1.2/go.mod h1:r2V8AlOzXaRCHXK7fILCUGzuI2iILweTaG8C5xlpHxo= -github.com/sagernet/sing-shadowsocks v0.2.4 h1:s/CqXlvFAZhlIoHWUwPw5CoNnQ9Ibki9pckjuugtVfY= -github.com/sagernet/sing-shadowsocks v0.2.4/go.mod h1:80fNKP0wnqlu85GZXV1H1vDPC/2t+dQbFggOw4XuFUM= -github.com/sagernet/sing-shadowsocks2 v0.1.3 h1:WXoLvCFi5JTFBRYorf1YePGYIQyJ/zbsBM6Fwbl5kGA= -github.com/sagernet/sing-shadowsocks2 v0.1.3/go.mod h1:DOhJc/cLeqRv0wuePrQso+iUmDxOnWF4eT/oMcRzYFw= +github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2 h1:PW18IgRodvppd09d4mewYM3Hedu3PtFERN8yOqkTVk0= +github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2/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.4-0.20231102172319-a36b95857a9b h1:zfF0WjELB9E6eHrF1m4SeZ+tiGFFrI2GVeoRoQj/0lg= +github.com/sagernet/sing-mux v0.1.4-0.20231102172319-a36b95857a9b/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-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.11 h1:wUfRQZ4eHk8suHkGKEFxjV5uXl3tfZhPm/v14/4lHvk= -github.com/sagernet/sing-tun v0.1.11/go.mod h1:XsyIVKd/Qp+2SdLZWGbavHtcpE7J7XU3S1zJmcoj9Ck= -github.com/sagernet/sing-vmess v0.1.7 h1:TM8FFLsXmlXH9XT8/oDgc6PC5BOzrg6OzyEe01is2r4= -github.com/sagernet/sing-vmess v0.1.7/go.mod h1:1qkC1L1T2sxnS/NuO6HU72S8TkltV+EXoKGR29m/Yss= +github.com/sagernet/sing-tun v0.1.17-0.20231103103951-3540ea7680d8 h1:MAxenoNTNwOu1rhKCjWNNoTP9BrzEI9KE5E8VMOnysY= +github.com/sagernet/sing-tun v0.1.17-0.20231103103951-3540ea7680d8/go.mod h1:4ACZp3C6TDSy1rsMrfwtSyLrKPtm9Wm2eKHwhYIojbU= +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= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0= -github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE= -github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9/go.mod h1:FUyTEc5ye5NjKnDTDMuiLF2M6T4BE6y6KZuax//UCEg= +github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 h1:Px+hN4Vzgx+iCGVnWH5A8eR7JhNnIV3rGQmBxA7cw6Q= +github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6/go.mod h1:zovq6vTvEM6ECiqE3Eeb9rpIylPpamPcmrJ9tv0Bt0M= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= -github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs= -github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY= -github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 h1:g6QtRWQ2dKX7EQP++1JLNtw4C2TNxd4/ov8YUpOPOSo= -github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77/go.mod h1:pJDdXzZIwJ+2vmnT0TKzmf8meeum+e2mTDSehw79eE0= +github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f h1:Kvo8w8Y9lzFGB/7z09MJ3TR99TFtfI/IuY87Ygcycho= +github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f/go.mod h1:mySs0abhpc/gLlvhoq7HP1RzOaRmIXVeZGCh++zoApk= +github.com/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/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= @@ -317,8 +316,6 @@ 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.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -326,18 +323,16 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 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.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28 h1:zLxFnORHDFTSkJPawMU7LzsuGQJ4MUFS653jJHpORow= -go4.org/netipx v0.0.0-20230728184502-ec4c8b891b28/go.mod h1:TQvodOM+hJTioNQJilmLXu08JNb8i+ccq418+KWu1/Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ= +go4.org/netipx v0.0.0-20230824141953-6213f710f925/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -347,8 +342,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +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-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -359,8 +354,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/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/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -385,8 +380,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= -golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.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-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -420,8 +415,8 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -442,7 +437,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -453,7 +448,6 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -485,12 +479,13 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.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.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -498,8 +493,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +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/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -553,8 +548,8 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= -golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= +golang.org/x/tools v0.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= @@ -621,8 +616,8 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +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.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -639,8 +634,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +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 v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/pkg/sing-box/.github/workflows/debug.yml b/pkg/sing-box/.github/workflows/debug.yml index fab33d34..20dd4ca6 100644 --- a/pkg/sing-box/.github/workflows/debug.yml +++ b/pkg/sing-box/.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/pkg/sing-box/.github/workflows/lint.yml b/pkg/sing-box/.github/workflows/lint.yml index c81f4a64..05b36a1e 100644 --- a/pkg/sing-box/.github/workflows/lint.yml +++ b/pkg/sing-box/.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 diff --git a/pkg/sing-box/.gitignore b/pkg/sing-box/.gitignore index a2ab17e3..e45a5314 100644 --- a/pkg/sing-box/.gitignore +++ b/pkg/sing-box/.gitignore @@ -14,3 +14,7 @@ .DS_Store /config.d/ .conf +cmd/sing-box/config.json +cmd/sing-box/*.db +cmd/sing-box/provider/ +cmd/sing-box/sing-box diff --git a/pkg/sing-box/.goreleaser.yaml b/pkg/sing-box/.goreleaser.yaml index 8e434d93..c0703ee1 100644 --- a/pkg/sing-box/.goreleaser.yaml +++ b/pkg/sing-box/.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 diff --git a/pkg/sing-box/Makefile b/pkg/sing-box/Makefile index d688fc6a..e73d73e7 100644 --- a/pkg/sing-box/Makefile +++ b/pkg/sing-box/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 @@ -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: @@ -93,7 +96,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 +107,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 +118,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 +144,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 diff --git a/pkg/sing-box/adapter/conn_router.go b/pkg/sing-box/adapter/conn_router.go new file mode 100644 index 00000000..a87c45e8 --- /dev/null +++ b/pkg/sing-box/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/pkg/sing-box/adapter/inbound.go b/pkg/sing-box/adapter/inbound.go index 6a566dc2..2d24083c 100644 --- a/pkg/sing-box/adapter/inbound.go +++ b/pkg/sing-box/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/pkg/sing-box/adapter/router.go b/pkg/sing-box/adapter/router.go index ec23d931..ab2d916c 100644 --- a/pkg/sing-box/adapter/router.go +++ b/pkg/sing-box/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/pkg/sing-box/box_outbound.go b/pkg/sing-box/box_outbound.go index ed96cd84..676ae7af 100644 --- a/pkg/sing-box/box_outbound.go +++ b/pkg/sing-box/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) } diff --git a/pkg/sing-box/cmd/sing-box/cmd_generate.go b/pkg/sing-box/cmd/sing-box/cmd_generate.go index cf00d58a..74d64c55 100644 --- a/pkg/sing-box/cmd/sing-box/cmd_generate.go +++ b/pkg/sing-box/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/pkg/sing-box/cmd/sing-box/cmd_generate_tls.go b/pkg/sing-box/cmd/sing-box/cmd_generate_tls.go new file mode 100644 index 00000000..d871566f --- /dev/null +++ b/pkg/sing-box/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/pkg/sing-box/cmd/sing-box/cmd_generate_vapid.go b/pkg/sing-box/cmd/sing-box/cmd_generate_vapid.go new file mode 100644 index 00000000..e83e6d80 --- /dev/null +++ b/pkg/sing-box/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/pkg/sing-box/cmd/sing-box/cmd_generate_wireguard.go b/pkg/sing-box/cmd/sing-box/cmd_generate_wireguard.go new file mode 100644 index 00000000..087e74b2 --- /dev/null +++ b/pkg/sing-box/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/pkg/sing-box/common/dialer/default.go b/pkg/sing-box/common/dialer/default.go index f8546fa6..9fbd1d8e 100644 --- a/pkg/sing-box/common/dialer/default.go +++ b/pkg/sing-box/common/dialer/default.go @@ -137,10 +137,12 @@ func (d *DefaultDialer) DialContext(ctx context.Context, network string, address } func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - if !destination.IsIPv6() { - return trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr4)) - } else { + if destination.IsIPv6() { return trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr6)) + } else if destination.IsIPv4() && !destination.Addr.IsUnspecified() { + return trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP+"4", d.udpAddr4)) + } else { + return trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr4)) } } diff --git a/pkg/sing-box/common/dialer/detour.go b/pkg/sing-box/common/dialer/detour.go index 81600913..ff484da2 100644 --- a/pkg/sing-box/common/dialer/detour.go +++ b/pkg/sing-box/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/pkg/sing-box/common/dialer/resolve.go b/pkg/sing-box/common/dialer/resolve.go index 9e20c81d..f2ee50db 100644 --- a/pkg/sing-box/common/dialer/resolve.go +++ b/pkg/sing-box/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/pkg/sing-box/common/mux/client.go b/pkg/sing-box/common/mux/client.go index 36dd3137..54b2d3f5 100644 --- a/pkg/sing-box/common/mux/client.go +++ b/pkg/sing-box/common/mux/client.go @@ -6,7 +6,9 @@ import ( 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, options option.OutboundMultiplexOptions) (*Client, error) { if !options.Enabled { return nil, nil } diff --git a/pkg/sing-box/common/mux/protocol.go b/pkg/sing-box/common/mux/protocol.go deleted file mode 100644 index abb0e268..00000000 --- a/pkg/sing-box/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/pkg/sing-box/common/mux/router.go b/pkg/sing-box/common/mux/router.go new file mode 100644 index 00000000..8a229685 --- /dev/null +++ b/pkg/sing-box/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/pkg/sing-box/common/mux/v2ray_legacy.go b/pkg/sing-box/common/mux/v2ray_legacy.go new file mode 100644 index 00000000..f53aff2d --- /dev/null +++ b/pkg/sing-box/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/pkg/sing-box/common/tls/mkcert.go b/pkg/sing-box/common/tls/mkcert.go index 9598cffa..1e71a763 100644 --- a/pkg/sing-box/common/tls/mkcert.go +++ b/pkg/sing-box/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/pkg/sing-box/common/tls/std_server.go b/pkg/sing-box/common/tls/std_server.go index 36ce67b6..28a94cf1 100644 --- a/pkg/sing-box/common/tls/std_server.go +++ b/pkg/sing-box/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 { diff --git a/pkg/sing-box/common/uot/router.go b/pkg/sing-box/common/uot/router.go new file mode 100644 index 00000000..fb2d23d5 --- /dev/null +++ b/pkg/sing-box/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/pkg/sing-box/constant/speed.go b/pkg/sing-box/constant/speed.go new file mode 100644 index 00000000..7a2ec130 --- /dev/null +++ b/pkg/sing-box/constant/speed.go @@ -0,0 +1,3 @@ +package constant + +const MbpsToBps = 125000 diff --git a/pkg/sing-box/constant/v2ray.go b/pkg/sing-box/constant/v2ray.go index 2243d736..c3089a6c 100644 --- a/pkg/sing-box/constant/v2ray.go +++ b/pkg/sing-box/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/pkg/sing-box/docs/changelog.md b/pkg/sing-box/docs/changelog.md index 7d2f39c0..0c753aa5 100644 --- a/pkg/sing-box/docs/changelog.md +++ b/pkg/sing-box/docs/changelog.md @@ -1,3 +1,194 @@ +#### 1.7.0-alpha.5 + +* 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 + +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.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 + +* 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.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.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** diff --git a/pkg/sing-box/docs/configuration/inbound/hysteria2.md b/pkg/sing-box/docs/configuration/inbound/hysteria2.md index b65304e2..ab6f2e4d 100644 --- a/pkg/sing-box/docs/configuration/inbound/hysteria2.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/inbound/hysteria2.zh.md b/pkg/sing-box/docs/configuration/inbound/hysteria2.zh.md index 49d2258a..f43188c0 100644 --- a/pkg/sing-box/docs/configuration/inbound/hysteria2.zh.md +++ b/pkg/sing-box/docs/configuration/inbound/hysteria2.zh.md @@ -20,8 +20,9 @@ } ], "ignore_client_bandwidth": false, + "tls": {}, "masquerade": "", - "tls": {} + "brutal_debug": false } ``` @@ -61,10 +62,16 @@ Hysteria 用户 #### ignore_client_bandwidth -命令客户端使用 BBR 流量控制算法而不是 Hysteria CC。 +命令客户端使用 BBR 拥塞控制算法而不是 Hysteria CC。 与 `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/pkg/sing-box/docs/configuration/inbound/shadowsocks.md b/pkg/sing-box/docs/configuration/inbound/shadowsocks.md index e69c9cb9..415a5913 100644 --- a/pkg/sing-box/docs/configuration/inbound/shadowsocks.md +++ b/pkg/sing-box/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": {} } ``` @@ -83,48 +86,6 @@ Both if empty. | 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 +#### multiplex -Parse [Proxy Protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) in the connection header. \ No newline at end of file +See [Multiplex](/configuration/shared/multiplex#inbound) for details. diff --git a/pkg/sing-box/docs/configuration/inbound/shadowsocks.zh.md b/pkg/sing-box/docs/configuration/inbound/shadowsocks.zh.md index 11edd057..36a292bb 100644 --- a/pkg/sing-box/docs/configuration/inbound/shadowsocks.zh.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/inbound/trojan.md b/pkg/sing-box/docs/configuration/inbound/trojan.md index cdaf8f50..787d2b11 100644 --- a/pkg/sing-box/docs/configuration/inbound/trojan.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/inbound/trojan.zh.md b/pkg/sing-box/docs/configuration/inbound/trojan.zh.md index 6cc8c475..f52422af 100644 --- a/pkg/sing-box/docs/configuration/inbound/trojan.zh.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/inbound/tuic.zh.md b/pkg/sing-box/docs/configuration/inbound/tuic.zh.md index 9a6f395e..60a7ccf6 100644 --- a/pkg/sing-box/docs/configuration/inbound/tuic.zh.md +++ b/pkg/sing-box/docs/configuration/inbound/tuic.zh.md @@ -48,7 +48,7 @@ TUIC 用户密码 #### congestion_control -QUIC 流量控制算法 +QUIC 拥塞控制算法 可选值: `cubic`, `new_reno`, `bbr` diff --git a/pkg/sing-box/docs/configuration/inbound/tun.md b/pkg/sing-box/docs/configuration/inbound/tun.md index 4c9670a2..e6c52c54 100644 --- a/pkg/sing-box/docs/configuration/inbound/tun.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/inbound/tun.zh.md b/pkg/sing-box/docs/configuration/inbound/tun.zh.md index fbd10abf..8f246c04 100644 --- a/pkg/sing-box/docs/configuration/inbound/tun.zh.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/inbound/vless.md b/pkg/sing-box/docs/configuration/inbound/vless.md index a8d0c426..f78ae01c 100644 --- a/pkg/sing-box/docs/configuration/inbound/vless.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/inbound/vless.zh.md b/pkg/sing-box/docs/configuration/inbound/vless.zh.md index 3ce1261c..4beecd6f 100644 --- a/pkg/sing-box/docs/configuration/inbound/vless.zh.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/inbound/vmess.md b/pkg/sing-box/docs/configuration/inbound/vmess.md index 2439d6e1..0e559d1e 100644 --- a/pkg/sing-box/docs/configuration/inbound/vmess.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/inbound/vmess.zh.md b/pkg/sing-box/docs/configuration/inbound/vmess.zh.md index ae90145b..9554ab79 100644 --- a/pkg/sing-box/docs/configuration/inbound/vmess.zh.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/outbound/hysteria2.md b/pkg/sing-box/docs/configuration/outbound/hysteria2.md index 115c1f25..9861e332 100644 --- a/pkg/sing-box/docs/configuration/outbound/hysteria2.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/outbound/hysteria2.zh.md b/pkg/sing-box/docs/configuration/outbound/hysteria2.zh.md index ba699b58..1e490a63 100644 --- a/pkg/sing-box/docs/configuration/outbound/hysteria2.zh.md +++ b/pkg/sing-box/docs/configuration/outbound/hysteria2.zh.md @@ -16,6 +16,7 @@ "password": "goofy_ahh_password", "network": "tcp", "tls": {}, + "brutal_debug": false, ... // 拨号字段 } @@ -43,7 +44,7 @@ 最大带宽。 -如果为空,将使用 BBR 流量控制算法而不是 Hysteria CC。 +如果为空,将使用 BBR 拥塞控制算法而不是 Hysteria CC。 #### obfs.type @@ -73,6 +74,9 @@ QUIC 流量混淆器密码. TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#outbound)。 +#### brutal_debug + +启用 Hysteria Brutal CC 的调试信息日志记录。 ### 拨号字段 diff --git a/pkg/sing-box/docs/configuration/outbound/shadowsocks.md b/pkg/sing-box/docs/configuration/outbound/shadowsocks.md index e004d77b..6fc93484 100644 --- a/pkg/sing-box/docs/configuration/outbound/shadowsocks.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/outbound/shadowsocks.zh.md b/pkg/sing-box/docs/configuration/outbound/shadowsocks.zh.md index 16c627e3..6d9b7a5c 100644 --- a/pkg/sing-box/docs/configuration/outbound/shadowsocks.zh.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/outbound/trojan.md b/pkg/sing-box/docs/configuration/outbound/trojan.md index cee13401..34b16c7d 100644 --- a/pkg/sing-box/docs/configuration/outbound/trojan.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/outbound/trojan.zh.md b/pkg/sing-box/docs/configuration/outbound/trojan.zh.md index ac919187..55bb9709 100644 --- a/pkg/sing-box/docs/configuration/outbound/trojan.zh.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/outbound/tuic.zh.md b/pkg/sing-box/docs/configuration/outbound/tuic.zh.md index ce5a1899..11d44448 100644 --- a/pkg/sing-box/docs/configuration/outbound/tuic.zh.md +++ b/pkg/sing-box/docs/configuration/outbound/tuic.zh.md @@ -51,7 +51,7 @@ TUIC 用户密码 #### congestion_control -QUIC 流量控制算法 +QUIC 拥塞控制算法 可选值: `cubic`, `new_reno`, `bbr` diff --git a/pkg/sing-box/docs/configuration/outbound/vless.md b/pkg/sing-box/docs/configuration/outbound/vless.md index 5fc69bf4..0d2fadc6 100644 --- a/pkg/sing-box/docs/configuration/outbound/vless.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/outbound/vless.zh.md b/pkg/sing-box/docs/configuration/outbound/vless.zh.md index 75713bf5..3d3f24ee 100644 --- a/pkg/sing-box/docs/configuration/outbound/vless.zh.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/outbound/vmess.md b/pkg/sing-box/docs/configuration/outbound/vmess.md index 45220477..ac29559e 100644 --- a/pkg/sing-box/docs/configuration/outbound/vmess.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/outbound/vmess.zh.md b/pkg/sing-box/docs/configuration/outbound/vmess.zh.md index 16fcfc7a..dbf1612e 100644 --- a/pkg/sing-box/docs/configuration/outbound/vmess.zh.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/shared/listen.md b/pkg/sing-box/docs/configuration/shared/listen.md index d4a0e58e..c1b1ed33 100644 --- a/pkg/sing-box/docs/configuration/shared/listen.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/shared/listen.zh.md b/pkg/sing-box/docs/configuration/shared/listen.zh.md index b25ce295..b7fd7487 100644 --- a/pkg/sing-box/docs/configuration/shared/listen.zh.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/shared/multiplex.md b/pkg/sing-box/docs/configuration/shared/multiplex.md index 833efaff..eab21163 100644 --- a/pkg/sing-box/docs/configuration/shared/multiplex.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/shared/multiplex.zh.md b/pkg/sing-box/docs/configuration/shared/multiplex.zh.md index 99a0ba03..ae1cad64 100644 --- a/pkg/sing-box/docs/configuration/shared/multiplex.zh.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/shared/tcp-brutal.md b/pkg/sing-box/docs/configuration/shared/tcp-brutal.md new file mode 100644 index 00000000..d248a463 --- /dev/null +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/shared/tcp-brutal.zh.md b/pkg/sing-box/docs/configuration/shared/tcp-brutal.zh.md new file mode 100644 index 00000000..efb8c51f --- /dev/null +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/shared/v2ray-transport.md b/pkg/sing-box/docs/configuration/shared/v2ray-transport.md index 4b5b6f66..418ef28d 100644 --- a/pkg/sing-box/docs/configuration/shared/v2ray-transport.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/configuration/shared/v2ray-transport.zh.md b/pkg/sing-box/docs/configuration/shared/v2ray-transport.zh.md index deab5589..2ea93562 100644 --- a/pkg/sing-box/docs/configuration/shared/v2ray-transport.zh.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/deprecated.md b/pkg/sing-box/docs/deprecated.md index 28391e5f..521a3994 100644 --- a/pkg/sing-box/docs/deprecated.md +++ b/pkg/sing-box/docs/deprecated.md @@ -1,8 +1,6 @@ # Deprecated Feature List -### 1.6.0 - -The following features were marked deprecated in 1.5.0 and removed entirely in 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/pkg/sing-box/docs/installation/clients/sfa.md b/pkg/sing-box/docs/installation/clients/sfa.md index 2ec79ec1..e2709af5 100644 --- a/pkg/sing-box/docs/installation/clients/sfa.md +++ b/pkg/sing-box/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/pkg/sing-box/docs/installation/clients/sfa.zh.md b/pkg/sing-box/docs/installation/clients/sfa.zh.md index fa005f11..7dfe6335 100644 --- a/pkg/sing-box/docs/installation/clients/sfa.zh.md +++ b/pkg/sing-box/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 不收集或共享个人数据。 +* 软件生成的数据始终在您的设备上。 diff --git a/pkg/sing-box/docs/installation/clients/sft.md b/pkg/sing-box/docs/installation/clients/sft.md index 2cb1f0fa..b05bc07e 100644 --- a/pkg/sing-box/docs/installation/clients/sft.md +++ b/pkg/sing-box/docs/installation/clients/sft.md @@ -8,6 +8,7 @@ Experimental Apple tvOS client for sing-box. #### Download +* [AppStore](https://apps.apple.com/us/app/sing-box/id6451272673) * [TestFlight](https://testflight.apple.com/join/AcqO44FH) #### Features @@ -15,7 +16,7 @@ Experimental Apple tvOS client for sing-box. Full functionality, except for: * Only remote configuration files can be created manually -* You need to update SFI to the latest beta version to import profiles from iPhone/iPad +* You need to update SFI to the latest version to import profiles from iPhone/iPad * No iCloud profile support #### Note diff --git a/pkg/sing-box/docs/installation/clients/sft.zh.md b/pkg/sing-box/docs/installation/clients/sft.zh.md new file mode 100644 index 00000000..239d76e2 --- /dev/null +++ b/pkg/sing-box/docs/installation/clients/sft.zh.md @@ -0,0 +1,31 @@ +# 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/pkg/sing-box/experimental/clashapi/api_meta.go b/pkg/sing-box/experimental/clashapi/api_meta.go index bfdee1b8..876f9869 100644 --- a/pkg/sing-box/experimental/clashapi/api_meta.go +++ b/pkg/sing-box/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/pkg/sing-box/experimental/clashapi/cachefile/cache.go b/pkg/sing-box/experimental/clashapi/cachefile/cache.go index f7355562..0b96fa5d 100644 --- a/pkg/sing-box/experimental/clashapi/cachefile/cache.go +++ b/pkg/sing-box/experimental/clashapi/cachefile/cache.go @@ -1,16 +1,18 @@ package cachefile import ( + "errors" "net/netip" "os" "strings" "sync" "time" + "github.com/sagernet/bbolt" + bboltErrors "github.com/sagernet/bbolt/errors" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing/common" - - "go.etcd.io/bbolt" + 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 bbolt.ErrInvalid, bbolt.ErrChecksum, bbolt.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 diff --git a/pkg/sing-box/experimental/clashapi/cachefile/fakeip.go b/pkg/sing-box/experimental/clashapi/cachefile/fakeip.go index a2396b59..2242342a 100644 --- a/pkg/sing-box/experimental/clashapi/cachefile/fakeip.go +++ b/pkg/sing-box/experimental/clashapi/cachefile/fakeip.go @@ -5,11 +5,10 @@ import ( "os" "time" + "github.com/sagernet/bbolt" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing/common/logger" M "github.com/sagernet/sing/common/metadata" - - "go.etcd.io/bbolt" ) const fakeipBucketPrefix = "fakeip_" diff --git a/pkg/sing-box/experimental/clashapi/connections.go b/pkg/sing-box/experimental/clashapi/connections.go index 94cfb9a3..042bdd36 100644 --- a/pkg/sing-box/experimental/clashapi/connections.go +++ b/pkg/sing-box/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/pkg/sing-box/experimental/clashapi/server.go b/pkg/sing-box/experimental/clashapi/server.go index 1b058ebb..1c98c46e 100644 --- a/pkg/sing-box/experimental/clashapi/server.go +++ b/pkg/sing-box/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/pkg/sing-box/experimental/libbox/build_info.go b/pkg/sing-box/experimental/libbox/build_info.go new file mode 100644 index 00000000..5a02593c --- /dev/null +++ b/pkg/sing-box/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 +} diff --git a/pkg/sing-box/experimental/libbox/command_client.go b/pkg/sing-box/experimental/libbox/command_client.go index 9701d949..f3c9ad2a 100644 --- a/pkg/sing-box/experimental/libbox/command_client.go +++ b/pkg/sing-box/experimental/libbox/command_client.go @@ -25,6 +25,7 @@ type CommandClientOptions struct { type CommandClientHandler interface { Connected() Disconnected(message string) + ClearLog() WriteLog(message string) WriteStatus(message *StatusMessage) WriteGroups(message OutboundGroupIterator) diff --git a/pkg/sing-box/experimental/libbox/command_log.go b/pkg/sing-box/experimental/libbox/command_log.go index 7cb1696b..ce72010d 100644 --- a/pkg/sing-box/experimental/libbox/command_log.go +++ b/pkg/sing-box/experimental/libbox/command_log.go @@ -23,6 +23,9 @@ func readLog(reader io.Reader) ([]byte, error) { if err != nil { return nil, err } + if messageLength == 0 { + return nil, nil + } data := make([]byte, messageLength) _, err = io.ReadFull(reader, data) if err != nil { @@ -32,14 +35,24 @@ func readLog(reader io.Reader) ([]byte, error) { } func writeLog(writer io.Writer, message []byte) error { - err := binary.Write(writer, binary.BigEndian, uint16(len(message))) + err := binary.Write(writer, binary.BigEndian, uint8(0)) + if err != nil { + return err + } + err = binary.Write(writer, binary.BigEndian, uint16(len(message))) if err != nil { return err } - _, err = writer.Write(message) + if len(message) > 0 { + _, err = writer.Write(message) + } return err } +func writeClearLog(writer io.Writer) error { + return binary.Write(writer, binary.BigEndian, uint8(1)) +} + func (s *CommandServer) handleLogConn(conn net.Conn) error { var savedLines []string s.access.Lock() @@ -69,6 +82,11 @@ func (s *CommandServer) handleLogConn(conn net.Conn) error { if err != nil { return err } + case <-s.logReset: + err = writeClearLog(conn) + if err != nil { + return err + } case <-done: return nil } @@ -77,12 +95,24 @@ func (s *CommandServer) handleLogConn(conn net.Conn) error { func (c *CommandClient) handleLogConn(conn net.Conn) { for { - message, err := readLog(conn) + var messageType uint8 + err := binary.Read(conn, binary.BigEndian, &messageType) if err != nil { c.handler.Disconnected(err.Error()) return } - c.handler.WriteLog(string(message)) + var message []byte + switch messageType { + case 0: + message, err = readLog(conn) + if err != nil { + c.handler.Disconnected(err.Error()) + return + } + c.handler.WriteLog(string(message)) + case 1: + c.handler.ClearLog() + } } } diff --git a/pkg/sing-box/experimental/libbox/command_server.go b/pkg/sing-box/experimental/libbox/command_server.go index 19f98870..f5aabb4a 100644 --- a/pkg/sing-box/experimental/libbox/command_server.go +++ b/pkg/sing-box/experimental/libbox/command_server.go @@ -23,14 +23,16 @@ type CommandServer struct { handler CommandServerHandler access sync.Mutex - savedLines *list.List[string] + savedLines list.List[string] maxLines int subscriber *observable.Subscriber[string] observer *observable.Observer[string] service *BoxService + // These channels only work with a single client. if multi-client support is needed, replace with Subscriber/Observer urlTestUpdate chan struct{} modeUpdate chan struct{} + logReset chan struct{} } type CommandServerHandler interface { @@ -42,11 +44,11 @@ type CommandServerHandler interface { func NewCommandServer(handler CommandServerHandler, maxLines int32) *CommandServer { server := &CommandServer{ handler: handler, - savedLines: new(list.List[string]), maxLines: int(maxLines), subscriber: observable.NewSubscriber[string](128), urlTestUpdate: make(chan struct{}, 1), modeUpdate: make(chan struct{}, 1), + logReset: make(chan struct{}, 1), } server.observer = observable.NewObserver[string](server.subscriber, 64) return server @@ -56,6 +58,11 @@ func (s *CommandServer) SetService(newService *BoxService) { if newService != nil { service.PtrFromContext[urltest.HistoryStorage](newService.ctx).SetHook(s.urlTestUpdate) newService.instance.Router().ClashServer().(*clashapi.Server).SetModeUpdateHook(s.modeUpdate) + s.savedLines.Init() + select { + case s.logReset <- struct{}{}: + default: + } } s.service = newService s.notifyURLTestUpdate() diff --git a/pkg/sing-box/experimental/libbox/service.go b/pkg/sing-box/experimental/libbox/service.go index 6c98c179..133c955a 100644 --- a/pkg/sing-box/experimental/libbox/service.go +++ b/pkg/sing-box/experimental/libbox/service.go @@ -80,6 +80,7 @@ func (s *BoxService) Sleep() { func (s *BoxService) Wake() { s.pauseManager.DeviceWake() + _ = s.instance.Router().ResetNetwork() } var _ platform.Interface = (*platformInterfaceWrapper)(nil) @@ -114,7 +115,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() + if err != nil { + return nil, err + } + tunFd, err := w.iif.OpenTun(&tunOptions{options, routeRanges, platformOptions}) if err != nil { return nil, err } diff --git a/pkg/sing-box/experimental/libbox/tun.go b/pkg/sing-box/experimental/libbox/tun.go index e692a5d6..e40ad58b 100644 --- a/pkg/sing-box/experimental/libbox/tun.go +++ b/pkg/sing-box/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/pkg/sing-box/go.mod b/pkg/sing-box/go.mod index 746068c8..866994a3 100644 --- a/pkg/sing-box/go.mod +++ b/pkg/sing-box/go.mod @@ -5,15 +5,15 @@ go 1.20 require ( berty.tech/go-libtor v1.0.385 github.com/caddyserver/certmagic v0.19.2 - github.com/cloudflare/circl v1.3.3 + github.com/cloudflare/circl v1.3.6 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 v4.4.0+incompatible 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 @@ -21,37 +21,36 @@ 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/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/quic-go v0.0.0-20231001051131-0fc736a289bb + 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.13-0.20231001070509-81a98bf16263 + github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2 github.com/sagernet/sing-dns v0.1.10 - github.com/sagernet/sing-mux v0.1.3 - github.com/sagernet/sing-quic v0.1.2-0.20231001061659-f0ec0e24dd4d + github.com/sagernet/sing-mux v0.1.4-0.20231102172319-a36b95857a9b + 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.15-0.20230930170051-6cfee41a5684 + github.com/sagernet/sing-tun v0.1.17-0.20231103103951-3540ea7680d8 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/sagernet/ws v0.0.0-20231030053741-7d481eb31bed github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 - go.etcd.io/bbolt v1.3.7 go.uber.org/zap v1.26.0 go4.org/netipx v0.0.0-20230824141953-6213f710f925 - golang.org/x/crypto v0.13.0 - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 - golang.org/x/net v0.15.0 - golang.org/x/sys v0.12.0 + golang.org/x/crypto v0.14.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 + google.golang.org/grpc v1.59.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v2 v2.4.0 howett.net/plist v1.0.0 @@ -65,6 +64,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 @@ -88,11 +89,12 @@ 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/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 - 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/pkg/sing-box/go.sum b/pkg/sing-box/go.sum index 2de721f9..16b61f2e 100644 --- a/pkg/sing-box/go.sum +++ b/pkg/sing-box/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.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= -github.com/cloudflare/circl v1.3.3/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= @@ -19,8 +19,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs 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/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= -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= @@ -32,6 +32,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 v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= @@ -50,8 +54,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= @@ -97,6 +101,8 @@ github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNV github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= 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= 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= @@ -107,28 +113,28 @@ 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-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-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.13-0.20231001070509-81a98bf16263 h1:+cmTvGzqCrQ+PltlyL6wgxbwHcMb1YopH+sz0WaofpY= -github.com/sagernet/sing v0.2.13-0.20231001070509-81a98bf16263/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= +github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2 h1:PW18IgRodvppd09d4mewYM3Hedu3PtFERN8yOqkTVk0= +github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2/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-0.20231001061659-f0ec0e24dd4d h1:+ubevTEvVRejF+6R+gqnbPJc8BsEJ4myd94owNFYCx8= -github.com/sagernet/sing-quic v0.1.2-0.20231001061659-f0ec0e24dd4d/go.mod h1:OmPaIkWEgtOLwUgHYXRK+0Ho87m37PVzNsvm+OAoKIY= +github.com/sagernet/sing-mux v0.1.4-0.20231102172319-a36b95857a9b h1:zfF0WjELB9E6eHrF1m4SeZ+tiGFFrI2GVeoRoQj/0lg= +github.com/sagernet/sing-mux v0.1.4-0.20231102172319-a36b95857a9b/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-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.15-0.20230930170051-6cfee41a5684 h1:F4cEIq+UpXxFoprR1xpC0mAMvPI8Jky6MfVPktFZ9yE= -github.com/sagernet/sing-tun v0.1.15-0.20230930170051-6cfee41a5684/go.mod h1:D+13Yc2j9CJ/EP25hs0vHn4kgH9JVfe0PIpdZwIbYZs= +github.com/sagernet/sing-tun v0.1.17-0.20231103103951-3540ea7680d8 h1:MAxenoNTNwOu1rhKCjWNNoTP9BrzEI9KE5E8VMOnysY= +github.com/sagernet/sing-tun v0.1.17-0.20231103103951-3540ea7680d8/go.mod h1:4ACZp3C6TDSy1rsMrfwtSyLrKPtm9Wm2eKHwhYIojbU= 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= @@ -137,10 +143,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/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= @@ -165,8 +171,6 @@ 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.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -176,17 +180,17 @@ 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.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/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +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.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.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +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.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= @@ -194,13 +198,13 @@ 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.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.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.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= @@ -208,15 +212,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/pkg/sing-box/inbound/default.go b/pkg/sing-box/inbound/default.go index de538e17..44c580de 100644 --- a/pkg/sing-box/inbound/default.go +++ b/pkg/sing-box/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/pkg/sing-box/inbound/http.go b/pkg/sing-box/inbound/http.go index 14a614b1..fa6c3d58 100644 --- a/pkg/sing-box/inbound/http.go +++ b/pkg/sing-box/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/pkg/sing-box/inbound/hysteria.go b/pkg/sing-box/inbound/hysteria.go index b96327c1..29707f65 100644 --- a/pkg/sing-box/inbound/hysteria.go +++ b/pkg/sing-box/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/pkg/sing-box/inbound/hysteria2.go b/pkg/sing-box/inbound/hysteria2.go index fd650ae9..5db881c3 100644 --- a/pkg/sing-box/inbound/hysteria2.go +++ b/pkg/sing-box/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 } @@ -89,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/pkg/sing-box/inbound/mixed.go b/pkg/sing-box/inbound/mixed.go index fceefe4d..8c3bf3b4 100644 --- a/pkg/sing-box/inbound/mixed.go +++ b/pkg/sing-box/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/pkg/sing-box/inbound/naive.go b/pkg/sing-box/inbound/naive.go index 7542ae0c..1ff159d1 100644 --- a/pkg/sing-box/inbound/naive.go +++ b/pkg/sing-box/inbound/naive.go @@ -2,7 +2,6 @@ package inbound import ( "context" - "encoding/base64" "encoding/binary" "io" "math/rand" @@ -14,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" @@ -44,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, @@ -139,14 +139,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) diff --git a/pkg/sing-box/inbound/shadowsocks.go b/pkg/sing-box/inbound/shadowsocks.go index 822a5f57..a45b6daf 100644 --- a/pkg/sing-box/inbound/shadowsocks.go +++ b/pkg/sing-box/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/pkg/sing-box/inbound/shadowsocks_multi.go b/pkg/sing-box/inbound/shadowsocks_multi.go index 6a1baac2..c3c7d2ab 100644 --- a/pkg/sing-box/inbound/shadowsocks_multi.go +++ b/pkg/sing-box/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/pkg/sing-box/inbound/shadowsocks_relay.go b/pkg/sing-box/inbound/shadowsocks_relay.go index 2f624447..44f39c9f 100644 --- a/pkg/sing-box/inbound/shadowsocks_relay.go +++ b/pkg/sing-box/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/pkg/sing-box/inbound/socks.go b/pkg/sing-box/inbound/socks.go index 8cc256ef..65dfb1e6 100644 --- a/pkg/sing-box/inbound/socks.go +++ b/pkg/sing-box/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/pkg/sing-box/inbound/tuic.go b/pkg/sing-box/inbound/tuic.go index 19b4b3d7..bdef1c5d 100644 --- a/pkg/sing-box/inbound/tuic.go +++ b/pkg/sing-box/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, diff --git a/pkg/sing-box/inbound/tun.go b/pkg/sing-box/inbound/tun.go index 9156d203..7d1f5199 100644 --- a/pkg/sing-box/inbound/tun.go +++ b/pkg/sing-box/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: common.Map(options.Inet4Address, option.ListenPrefix.Build), - Inet6Address: common.Map(options.Inet6Address, option.ListenPrefix.Build), - AutoRoute: options.AutoRoute, - StrictRoute: options.StrictRoute, - IncludeInterface: options.IncludeInterface, - ExcludeInterface: options.ExcludeInterface, - Inet4RouteAddress: common.Map(options.Inet4RouteAddress, option.ListenPrefix.Build), - Inet6RouteAddress: common.Map(options.Inet6RouteAddress, option.ListenPrefix.Build), - IncludeUID: includeUID, - 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/pkg/sing-box/inbound/vless.go b/pkg/sing-box/inbound/vless.go index 11df86bf..029fdaf7 100644 --- a/pkg/sing-box/inbound/vless.go +++ b/pkg/sing-box/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/pkg/sing-box/inbound/vmess.go b/pkg/sing-box/inbound/vmess.go index 77a8b28a..70676bbd 100644 --- a/pkg/sing-box/inbound/vmess.go +++ b/pkg/sing-box/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/pkg/sing-box/mkdocs.yml b/pkg/sing-box/mkdocs.yml index 5632affa..98c46c6f 100644 --- a/pkg/sing-box/mkdocs.yml +++ b/pkg/sing-box/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/pkg/sing-box/option/dns.go b/pkg/sing-box/option/dns.go index 1e73fb5f..e0d237b7 100644 --- a/pkg/sing-box/option/dns.go +++ b/pkg/sing-box/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/pkg/sing-box/option/hysteria2.go b/pkg/sing-box/option/hysteria2.go index 48396ca1..feab475b 100644 --- a/pkg/sing-box/option/hysteria2.go +++ b/pkg/sing-box/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/pkg/sing-box/option/inbound.go b/pkg/sing-box/option/inbound.go index 06408f58..c61428ad 100644 --- a/pkg/sing-box/option/inbound.go +++ b/pkg/sing-box/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/pkg/sing-box/option/multiplex.go b/pkg/sing-box/option/multiplex.go new file mode 100644 index 00000000..a2c5f662 --- /dev/null +++ b/pkg/sing-box/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 bool `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/pkg/sing-box/option/outbound.go b/pkg/sing-box/option/outbound.go index b7bbd80f..251781d6 100644 --- a/pkg/sing-box/option/outbound.go +++ b/pkg/sing-box/option/outbound.go @@ -159,12 +159,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/pkg/sing-box/option/shadowsocks.go b/pkg/sing-box/option/shadowsocks.go index 38a18b83..187b9b63 100644 --- a/pkg/sing-box/option/shadowsocks.go +++ b/pkg/sing-box/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/pkg/sing-box/option/simple.go b/pkg/sing-box/option/simple.go index dec1e0e0..b8692e0c 100644 --- a/pkg/sing-box/option/simple.go +++ b/pkg/sing-box/option/simple.go @@ -17,19 +17,19 @@ 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 { 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/pkg/sing-box/option/trojan.go b/pkg/sing-box/option/trojan.go index 11392cd5..d24ed16a 100644 --- a/pkg/sing-box/option/trojan.go +++ b/pkg/sing-box/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/pkg/sing-box/option/tun.go b/pkg/sing-box/option/tun.go index f566f098..306d4541 100644 --- a/pkg/sing-box/option/tun.go +++ b/pkg/sing-box/option/tun.go @@ -1,26 +1,30 @@ 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"` - 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"` - 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 } diff --git a/pkg/sing-box/option/types.go b/pkg/sing-box/option/types.go index 8a5e6cfc..f2fed663 100644 --- a/pkg/sing-box/option/types.go +++ b/pkg/sing-box/option/types.go @@ -1,6 +1,7 @@ package option import ( + "net/http" "net/netip" "strings" "time" @@ -171,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) { @@ -235,3 +208,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/pkg/sing-box/option/v2ray_transport.go b/pkg/sing-box/option/v2ray_transport.go index b01cafa7..63af28a3 100644 --- a/pkg/sing-box/option/v2ray_transport.go +++ b/pkg/sing-box/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) } @@ -61,19 +66,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{} @@ -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/pkg/sing-box/option/vless.go b/pkg/sing-box/option/vless.go index 5547bd88..09010922 100644 --- a/pkg/sing-box/option/vless.go +++ b/pkg/sing-box/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/pkg/sing-box/option/vmess.go b/pkg/sing-box/option/vmess.go index a2ba2103..8045e9d6 100644 --- a/pkg/sing-box/option/vmess.go +++ b/pkg/sing-box/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/pkg/sing-box/option/wireguard.go b/pkg/sing-box/option/wireguard.go index 21b6715b..5ede7a61 100644 --- a/pkg/sing-box/option/wireguard.go +++ b/pkg/sing-box/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/pkg/sing-box/outbound/default.go b/pkg/sing-box/outbound/default.go index 72cb93aa..b0ced5ac 100644 --- a/pkg/sing-box/outbound/default.go +++ b/pkg/sing-box/outbound/default.go @@ -11,11 +11,13 @@ import ( C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing-dns" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/buf" "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" ) @@ -74,7 +76,7 @@ func NewConnection(ctx context.Context, this N.Dialer, conn net.Conn, metadata a return CopyEarlyConn(ctx, conn, outConn) } -func NewDirectConnection(ctx context.Context, router adapter.Router, this N.Dialer, conn net.Conn, metadata adapter.InboundContext) error { +func NewDirectConnection(ctx context.Context, router adapter.Router, this N.Dialer, conn net.Conn, metadata adapter.InboundContext, domainStrategy dns.DomainStrategy) error { ctx = adapter.WithContext(ctx, &metadata) var outConn net.Conn var err error @@ -82,7 +84,7 @@ func NewDirectConnection(ctx context.Context, router adapter.Router, this N.Dial outConn, err = N.DialSerial(ctx, this, N.NetworkTCP, metadata.Destination, metadata.DestinationAddresses) } else if metadata.Destination.IsFqdn() { var destinationAddresses []netip.Addr - destinationAddresses, err = router.LookupDefault(ctx, metadata.Destination.Fqdn) + destinationAddresses, err = router.Lookup(ctx, metadata.Destination.Fqdn, domainStrategy) if err != nil { return N.ReportHandshakeFailure(conn, err) } @@ -118,6 +120,13 @@ func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn, return err } if destinationAddress.IsValid() { + if metadata.Destination.IsFqdn() { + 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 { natConn.UpdateDestination(destinationAddress) } @@ -133,7 +142,7 @@ func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn, return bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(outConn)) } -func NewDirectPacketConnection(ctx context.Context, router adapter.Router, this N.Dialer, conn N.PacketConn, metadata adapter.InboundContext) error { +func NewDirectPacketConnection(ctx context.Context, router adapter.Router, this N.Dialer, conn N.PacketConn, metadata adapter.InboundContext, domainStrategy dns.DomainStrategy) error { ctx = adapter.WithContext(ctx, &metadata) var outConn net.PacketConn var destinationAddress netip.Addr @@ -142,7 +151,7 @@ func NewDirectPacketConnection(ctx context.Context, router adapter.Router, this outConn, destinationAddress, err = N.ListenSerial(ctx, this, metadata.Destination, metadata.DestinationAddresses) } else if metadata.Destination.IsFqdn() { var destinationAddresses []netip.Addr - destinationAddresses, err = router.LookupDefault(ctx, metadata.Destination.Fqdn) + destinationAddresses, err = router.Lookup(ctx, metadata.Destination.Fqdn, domainStrategy) if err != nil { return N.ReportHandshakeFailure(conn, err) } @@ -158,6 +167,9 @@ func NewDirectPacketConnection(ctx context.Context, router adapter.Router, this return err } if destinationAddress.IsValid() { + 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/pkg/sing-box/outbound/direct.go b/pkg/sing-box/outbound/direct.go index f74285b6..3bf80494 100644 --- a/pkg/sing-box/outbound/direct.go +++ b/pkg/sing-box/outbound/direct.go @@ -120,7 +120,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/pkg/sing-box/outbound/http.go b/pkg/sing-box/outbound/http.go index cd9dc959..cfc03216 100644 --- a/pkg/sing-box/outbound/http.go +++ b/pkg/sing-box/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/pkg/sing-box/outbound/hysteria.go b/pkg/sing-box/outbound/hysteria.go index ffdf61bb..8c130e33 100644 --- a/pkg/sing-box/outbound/hysteria.go +++ b/pkg/sing-box/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/pkg/sing-box/outbound/hysteria2.go b/pkg/sing-box/outbound/hysteria2.go index 120865a9..f2ffe2fd 100644 --- a/pkg/sing-box/outbound/hysteria2.go +++ b/pkg/sing-box/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" @@ -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), diff --git a/pkg/sing-box/outbound/proxy_provider.go b/pkg/sing-box/outbound/proxy_provider.go index 7486b1f6..d9acb800 100644 --- a/pkg/sing-box/outbound/proxy_provider.go +++ b/pkg/sing-box/outbound/proxy_provider.go @@ -224,7 +224,7 @@ func (s *Provider) updateSelected(outboundMap map[string]adapter.Outbound) error s.logger.Debug("NewURLTestGroup ", len(outbounds)) - s.group = NewURLTestGroup(s.ctx, s.router, s.logger, outbounds, s.urlTest.Url, interval, 100) + s.group = NewURLTestGroup(s.ctx, s.router, s.logger, outbounds, s.urlTest.Url, interval, 100, true) s.group.Start() s.logger.Debug("start NewURLTestGroup") diff --git a/pkg/sing-box/outbound/shadowsocks.go b/pkg/sing-box/outbound/shadowsocks.go index e436e124..a7495021 100644 --- a/pkg/sing-box/outbound/shadowsocks.go +++ b/pkg/sing-box/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), common.PtrValueOrDefault(options.Multiplex)) if err != nil { return nil, err } diff --git a/pkg/sing-box/outbound/shadowsocksr.go b/pkg/sing-box/outbound/shadowsocksr.go index 6ba3e8d3..615a71e4 100644 --- a/pkg/sing-box/outbound/shadowsocksr.go +++ b/pkg/sing-box/outbound/shadowsocksr.go @@ -2,4 +2,17 @@ package outbound -var _ = "ShadowsocksR is deprecated and removed in sing-box 1.6.0" +import ( + "context" + "os" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" +) + +var _ int = "ShadowsocksR is deprecated and removed in sing-box 1.6.0" + +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/pkg/sing-box/outbound/socks.go b/pkg/sing-box/outbound/socks.go index ab26fd3f..063f7b95 100644 --- a/pkg/sing-box/outbound/socks.go +++ b/pkg/sing-box/outbound/socks.go @@ -9,6 +9,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-dns" "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" @@ -53,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, @@ -114,7 +115,7 @@ func (h *Socks) ListenPacket(ctx context.Context, destination M.Socksaddr) (net. func (h *Socks) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { if h.resolve { - return NewDirectConnection(ctx, h.router, h, conn, metadata) + return NewDirectConnection(ctx, h.router, h, conn, metadata, dns.DomainStrategyUseIPv4) } else { return NewConnection(ctx, h, conn, metadata) } @@ -122,7 +123,7 @@ func (h *Socks) NewConnection(ctx context.Context, conn net.Conn, metadata adapt func (h *Socks) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { if h.resolve { - return NewDirectPacketConnection(ctx, h.router, h, conn, metadata) + return NewDirectPacketConnection(ctx, h.router, h, conn, metadata, dns.DomainStrategyUseIPv4) } else { return NewPacketConnection(ctx, h, conn, metadata) } diff --git a/pkg/sing-box/outbound/wireguard.go b/pkg/sing-box/outbound/wireguard.go index e141fbb5..e645f056 100644 --- a/pkg/sing-box/outbound/wireguard.go +++ b/pkg/sing-box/outbound/wireguard.go @@ -16,8 +16,8 @@ import ( "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "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" @@ -70,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 @@ -142,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 { @@ -162,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") @@ -228,11 +227,11 @@ func (w *WireGuard) ListenPacket(ctx context.Context, destination M.Socksaddr) ( } func (w *WireGuard) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { - return NewDirectConnection(ctx, w.router, w, conn, metadata) + return NewDirectConnection(ctx, w.router, w, conn, metadata, dns.DomainStrategyAsIS) } func (w *WireGuard) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { - return NewDirectPacketConnection(ctx, w.router, w, conn, metadata) + return NewDirectPacketConnection(ctx, w.router, w, conn, metadata, dns.DomainStrategyAsIS) } func (w *WireGuard) Start() error { diff --git a/pkg/sing-box/route/router.go b/pkg/sing-box/route/router.go index c1dc228d..2d2f2cde 100644 --- a/pkg/sing-box/route/router.go +++ b/pkg/sing-box/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" @@ -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) } @@ -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) { @@ -694,6 +677,11 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad metadata.DestinationAddresses = addresses r.dnsLogger.DebugContext(ctx, "resolved [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]") } + if metadata.Destination.IsIPv4() { + metadata.IPVersion = 4 + } else if metadata.Destination.IsIPv6() { + metadata.IPVersion = 6 + } ctx, matchedRule, detour, err := r.match(ctx, &metadata, r.defaultOutboundForConnection) if err != nil { return err @@ -807,6 +795,11 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m metadata.DestinationAddresses = addresses r.dnsLogger.DebugContext(ctx, "resolved [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]") } + if metadata.Destination.IsIPv4() { + metadata.IPVersion = 4 + } else if metadata.Destination.IsIPv6() { + metadata.IPVersion = 6 + } ctx, matchedRule, detour, err := r.match(ctx, &metadata, r.defaultOutboundForPacketConnection) if err != nil { return err @@ -825,7 +818,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/pkg/sing-box/test/box_test.go b/pkg/sing-box/test/box_test.go index 4092979f..5009cc63 100644 --- a/pkg/sing-box/test/box_test.go +++ b/pkg/sing-box/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/pkg/sing-box/test/domain_inbound_test.go b/pkg/sing-box/test/domain_inbound_test.go new file mode 100644 index 00000000..bf43aa98 --- /dev/null +++ b/pkg/sing-box/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/pkg/sing-box/test/go.mod b/pkg/sing-box/test/go.mod index ad95208f..8409874a 100644 --- a/pkg/sing-box/test/go.mod +++ b/pkg/sing-box/test/go.mod @@ -6,45 +6,48 @@ 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/docker v24.0.7+incompatible github.com/docker/go-connections v0.4.0 github.com/gofrs/uuid/v5 v5.0.0 - github.com/sagernet/sing v0.2.13-0.20231001063649-e0ec961fb1ab - github.com/sagernet/sing-quic v0.1.1 + github.com/sagernet/quic-go v0.0.0-20231008035953-32727fef9460 + github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2 + github.com/sagernet/sing-dns v0.1.10 + 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 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/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.6 // 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 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 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 @@ -54,7 +57,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 @@ -66,41 +69,39 @@ 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/gvisor v0.0.0-20230930141345-5fef6f2e17ab // 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/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-mux v0.1.4-0.20231102172319-a36b95857a9b // 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.17-0.20231103030016-7f4ef65c32eb // 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 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/pkg/sing-box/test/go.sum b/pkg/sing-box/test/go.sum index c3ceccb0..b2bc33f4 100644 --- a/pkg/sing-box/test/go.sum +++ b/pkg/sing-box/test/go.sum @@ -1,8 +1,8 @@ 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/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= @@ -12,24 +12,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.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= 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/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/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.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.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= @@ -41,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= @@ -57,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= @@ -83,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= @@ -109,34 +115,38 @@ 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= 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-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-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.13-0.20231001063649-e0ec961fb1ab h1:ccXgrc2HGcPlFFtNISITE95YeUiChU+7GCQaeWriylk= -github.com/sagernet/sing v0.2.13-0.20231001063649-e0ec961fb1ab/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= +github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2 h1:PW18IgRodvppd09d4mewYM3Hedu3PtFERN8yOqkTVk0= +github.com/sagernet/sing v0.2.16-0.20231028125948-afcc9cb766c2/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-mux v0.1.4-0.20231102172319-a36b95857a9b h1:zfF0WjELB9E6eHrF1m4SeZ+tiGFFrI2GVeoRoQj/0lg= +github.com/sagernet/sing-mux v0.1.4-0.20231102172319-a36b95857a9b/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-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.17-0.20231103030016-7f4ef65c32eb h1:iYopGh4nbVsvQ+oR2Xkc+hO5s+aacsmq5nQkEFPPhxY= +github.com/sagernet/sing-tun v0.1.17-0.20231103030016-7f4ef65c32eb/go.mod h1:4ACZp3C6TDSy1rsMrfwtSyLrKPtm9Wm2eKHwhYIojbU= 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= @@ -145,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= @@ -171,10 +181,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= @@ -186,26 +194,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= @@ -213,17 +221,16 @@ 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.6.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= @@ -235,17 +242,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= @@ -255,7 +261,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= diff --git a/pkg/sing-box/test/hysteria2_test.go b/pkg/sing-box/test/hysteria2_test.go index 695e598b..04735eeb 100644 --- a/pkg/sing-box/test/hysteria2_test.go +++ b/pkg/sing-box/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/pkg/sing-box/test/hysteria_test.go b/pkg/sing-box/test/hysteria_test.go index df0ae3a2..664e5a7c 100644 --- a/pkg/sing-box/test/hysteria_test.go +++ b/pkg/sing-box/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/pkg/sing-box/test/mux_test.go b/pkg/sing-box/test/mux_test.go index b57c6cee..564b936d 100644 --- a/pkg/sing-box/test/mux_test.go +++ b/pkg/sing-box/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/pkg/sing-box/test/shadowsocks_test.go b/pkg/sing-box/test/shadowsocks_test.go index 07b324d2..f8871586 100644 --- a/pkg/sing-box/test/shadowsocks_test.go +++ b/pkg/sing-box/test/shadowsocks_test.go @@ -232,7 +232,7 @@ func TestShadowsocksUoT(t *testing.T) { }, Method: method, Password: password, - UDPOverTCPOptions: &option.UDPOverTCPOptions{ + UDPOverTCP: &option.UDPOverTCPOptions{ Enabled: true, }, }, diff --git a/pkg/sing-box/test/v2ray_httpupgrade_test.go b/pkg/sing-box/test/v2ray_httpupgrade_test.go new file mode 100644 index 00000000..9a79aa3a --- /dev/null +++ b/pkg/sing-box/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/pkg/sing-box/test/wireguard_test.go b/pkg/sing-box/test/wireguard_test.go index 1889a3a6..50e87ee0 100644 --- a/pkg/sing-box/test/wireguard_test.go +++ b/pkg/sing-box/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=", }, diff --git a/pkg/sing-box/transport/hysteria/frag.go b/pkg/sing-box/transport/hysteria/frag.go deleted file mode 100644 index 721341f1..00000000 --- a/pkg/sing-box/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/pkg/sing-box/transport/hysteria/protocol.go b/pkg/sing-box/transport/hysteria/protocol.go deleted file mode 100644 index a338988f..00000000 --- a/pkg/sing-box/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/pkg/sing-box/transport/hysteria/speed.go b/pkg/sing-box/transport/hysteria/speed.go deleted file mode 100644 index 161e0d58..00000000 --- a/pkg/sing-box/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/pkg/sing-box/transport/hysteria/wrap.go b/pkg/sing-box/transport/hysteria/wrap.go deleted file mode 100644 index e89ac95e..00000000 --- a/pkg/sing-box/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/pkg/sing-box/transport/hysteria/xplus.go b/pkg/sing-box/transport/hysteria/xplus.go deleted file mode 100644 index 14e0eaa8..00000000 --- a/pkg/sing-box/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/pkg/sing-box/transport/v2ray/transport.go b/pkg/sing-box/transport/v2ray/transport.go index 3481c852..deb8a7f0 100644 --- a/pkg/sing-box/transport/v2ray/transport.go +++ b/pkg/sing-box/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) } @@ -50,13 +53,14 @@ 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 } 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/pkg/sing-box/transport/v2raygrpclite/client.go b/pkg/sing-box/transport/v2raygrpclite/client.go index 8480ac53..588a8133 100644 --- a/pkg/sing-box/transport/v2raygrpclite/client.go +++ b/pkg/sing-box/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/pkg/sing-box/transport/v2raygrpclite/server.go b/pkg/sing-box/transport/v2raygrpclite/server.go index a3025ca6..6d3e42eb 100644 --- a/pkg/sing-box/transport/v2raygrpclite/server.go +++ b/pkg/sing-box/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/pkg/sing-box/transport/v2rayhttp/client.go b/pkg/sing-box/transport/v2rayhttp/client.go index 4d660fef..333784fc 100644 --- a/pkg/sing-box/transport/v2rayhttp/client.go +++ b/pkg/sing-box/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, } @@ -81,10 +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()) - } - for key, valueList := range options.Headers { - client.headers[key] = valueList + return nil, E.New("parse path: " + err.Error()) } client.url = &uri return client, nil @@ -146,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/pkg/sing-box/transport/v2rayhttp/server.go b/pkg/sing-box/transport/v2rayhttp/server.go index a635e8f3..ef5fffcd 100644 --- a/pkg/sing-box/transport/v2rayhttp/server.go +++ b/pkg/sing-box/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, @@ -55,7 +51,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 +59,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, @@ -156,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/pkg/sing-box/transport/v2rayhttpupgrade/client.go b/pkg/sing-box/transport/v2rayhttpupgrade/client.go new file mode 100644 index 00000000..c10e1b8f --- /dev/null +++ b/pkg/sing-box/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/pkg/sing-box/transport/v2rayhttpupgrade/server.go b/pkg/sing-box/transport/v2rayhttpupgrade/server.go new file mode 100644 index 00000000..653778f9 --- /dev/null +++ b/pkg/sing-box/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)) +} diff --git a/pkg/sing-box/transport/v2rayquic/client.go b/pkg/sing-box/transport/v2rayquic/client.go index c3345780..f5184615 100644 --- a/pkg/sing-box/transport/v2rayquic/client.go +++ b/pkg/sing-box/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/pkg/sing-box/transport/v2rayquic/server.go b/pkg/sing-box/transport/v2rayquic/server.go index 71960e58..0ef8d2a1 100644 --- a/pkg/sing-box/transport/v2rayquic/server.go +++ b/pkg/sing-box/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/pkg/sing-box/transport/v2rayquic/stream.go b/pkg/sing-box/transport/v2rayquic/stream.go new file mode 100644 index 00000000..d9c3beba --- /dev/null +++ b/pkg/sing-box/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 +} diff --git a/pkg/sing-box/transport/v2raywebsocket/client.go b/pkg/sing-box/transport/v2raywebsocket/client.go index 9f14f676..4fcc251a 100644 --- a/pkg/sing-box/transport/v2raywebsocket/client.go +++ b/pkg/sing-box/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) (*Client, 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,62 @@ 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 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/pkg/sing-box/transport/v2raywebsocket/conn.go b/pkg/sing-box/transport/v2raywebsocket/conn.go index 1faeaa36..54f782c3 100644 --- a/pkg/sing-box/transport/v2raywebsocket/conn.go +++ b/pkg/sing-box/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,19 +169,16 @@ 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) - } - if err != nil { - return wrapDialError(response, err) + conn, err = c.dialContext(c.ctx, &c.requestURL, c.headers) } - c.conn = &WebsocketConn{Conn: conn, Writer: NewWriter(conn, false)} + c.conn = conn if len(lateData) > 0 { _, err = c.conn.Write(lateData) } @@ -224,13 +262,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/pkg/sing-box/transport/v2raywebsocket/mask.go b/pkg/sing-box/transport/v2raywebsocket/mask.go deleted file mode 100644 index 01ea8437..00000000 --- a/pkg/sing-box/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/pkg/sing-box/transport/v2raywebsocket/server.go b/pkg/sing-box/transport/v2raywebsocket/server.go index 9d8bc69a..ae6e15f3 100644 --- a/pkg/sing-box/transport/v2raywebsocket/server.go +++ b/pkg/sing-box/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/pkg/sing-box/transport/v2raywebsocket/writer.go b/pkg/sing-box/transport/v2raywebsocket/writer.go index fbb61f0f..5bd0d0a1 100644 --- a/pkg/sing-box/transport/v2raywebsocket/writer.go +++ b/pkg/sing-box/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 }