diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml index f751fcfa82..2bca96e050 100644 --- a/.github/workflows/debug.yml +++ b/.github/workflows/debug.yml @@ -28,8 +28,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.22 - continue-on-error: true + go-version: ^1.23 - name: Run Test run: | go test -v ./... @@ -73,6 +72,26 @@ jobs: key: go121-${{ hashFiles('**/go.sum') }} - name: Run Test run: make ci_build + build_go122: + name: Debug build (Go 1.22) + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + with: + fetch-depth: 0 + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: ~1.22 + - name: Cache go module + uses: actions/cache@v4 + with: + path: | + ~/go/pkg/mod + key: go122-${{ hashFiles('**/go.sum') }} + - name: Run Test + run: make ci_build cross: strategy: matrix: diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8e75954d22..9eb21d3281 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -4,6 +4,7 @@ on: release: types: - released + - prereleased workflow_dispatch: inputs: tag: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 98c4388171..a994cf4acd 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -15,7 +15,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.22 + go-version: ^1.23 - name: golangci-lint uses: golangci/golangci-lint-action@v6 with: diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 1e6aeff363..bd2f1023f2 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -16,7 +16,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ^1.22 + go-version: ^1.23 - name: Extract signing key run: |- mkdir -p $HOME/.gnupg diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index b6307da29f..1715a9434d 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -12,4 +12,5 @@ jobs: with: stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days' days-before-stale: 60 - days-before-close: 5 \ No newline at end of file + days-before-close: 5 + exempt-issue-labels: 'bug,enhancement' diff --git a/.golangci.yml b/.golangci.yml index 3aa6657264..6cf053f580 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -6,14 +6,7 @@ linters: - gci - staticcheck - paralleltest - -run: - skip-dirs: - - transport/simple-obfs - - transport/clashssr - - transport/cloudflaretls - - transport/shadowtls/tls - - transport/shadowtls/tls_go119 + - ineffassign linters-settings: gci: @@ -23,4 +16,13 @@ linters-settings: - prefix(github.com/sagernet/) - default staticcheck: - go: '1.20' + checks: + - all + - -SA1003 + +run: + go: "1.23" + +issues: + exclude-dirs: + - transport/simple-obfs diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 64c23c9d3e..a6b19554fd 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -7,7 +7,10 @@ builds: - -v - -trimpath ldflags: - - -X github.com/sagernet/sing-box/constant.Version={{ .Version }} -s -w -buildid= + - -X github.com/sagernet/sing-box/constant.Version={{ .Version }} + - -s + - -buildid= + - -checklinkname=0 tags: - with_gvisor - with_quic @@ -46,6 +49,10 @@ builds: - with_reality_server - with_acme - with_clash_api + ldflags: + - -X github.com/sagernet/sing-box/constant.Version={{ .Version }} + - -s + - -buildid= env: - CGO_ENABLED=0 - GOROOT={{ .Env.GOPATH }}/go1.20.14 diff --git a/Dockerfile b/Dockerfile index db890fd439..af121d40b1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM golang:1.22-alpine AS builder +FROM --platform=$BUILDPLATFORM golang:1.23-alpine AS builder LABEL maintainer="nekohasekai " COPY . /go/src/github.com/sagernet/sing-box WORKDIR /go/src/github.com/sagernet/sing-box @@ -15,7 +15,7 @@ RUN set -ex \ && go build -v -trimpath -tags \ "with_gvisor,with_quic,with_dhcp,with_wireguard,with_ech,with_utls,with_reality_server,with_acme,with_clash_api" \ -o /go/bin/sing-box \ - -ldflags "-X \"github.com/sagernet/sing-box/constant.Version=$VERSION\" -s -w -buildid=" \ + -ldflags "-X \"github.com/sagernet/sing-box/constant.Version=$VERSION\" -s -w -buildid= -checklinkname=0" \ ./cmd/sing-box FROM --platform=$TARGETPLATFORM alpine AS dist LABEL maintainer="nekohasekai " diff --git a/README.md b/README.md index 0dc4f4525a..27ad0919dd 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,6 @@ The universal proxy platform. [![Packaging status](https://repology.org/badge/vertical-allrepos/sing-box.svg)](https://repology.org/project/sing-box/versions) -## Documentation - -https://sing-box.sagernet.org - ## Support https://community.sagernet.org/c/sing-box/ diff --git a/clients/apple b/clients/apple index 0cbe335cbb..aa4ce98421 160000 --- a/clients/apple +++ b/clients/apple @@ -1 +1 @@ -Subproject commit 0cbe335cbbaef9747171c44b169c23daf2d89261 +Subproject commit aa4ce9842174af85e4d3b2bd5e1651e4f87d3526 diff --git a/common/dialer/dialer.go b/common/dialer/dialer.go index a1721b281f..56c5f2ad15 100644 --- a/common/dialer/dialer.go +++ b/common/dialer/dialer.go @@ -28,13 +28,12 @@ func New(router adapter.Router, options option.DialerOptions) (N.Dialer, error) } else { dialer = NewDetour(router, options.Detour) } - domainStrategy := dns.DomainStrategy(options.DomainStrategy) - if domainStrategy != dns.DomainStrategyAsIS || options.Detour == "" { + if options.Detour == "" { dialer = NewResolveDialer( router, dialer, options.Detour == "" && !options.TCPFastOpen, - domainStrategy, + dns.DomainStrategy(options.DomainStrategy), time.Duration(options.FallbackDelay)) } return dialer, nil diff --git a/common/sniff/ssh.go b/common/sniff/ssh.go new file mode 100644 index 0000000000..194d0bda8c --- /dev/null +++ b/common/sniff/ssh.go @@ -0,0 +1,26 @@ +package sniff + +import ( + "bufio" + "context" + "io" + "os" + "strings" + + "github.com/sagernet/sing-box/adapter" + C "github.com/sagernet/sing-box/constant" +) + +func SSH(_ context.Context, metadata *adapter.InboundContext, reader io.Reader) error { + scanner := bufio.NewScanner(reader) + if !scanner.Scan() { + return os.ErrInvalid + } + fistLine := scanner.Text() + if !strings.HasPrefix(fistLine, "SSH-2.0-") { + return os.ErrInvalid + } + metadata.Protocol = C.ProtocolSSH + metadata.Client = fistLine[8:] + return nil +} diff --git a/common/sniff/ssh_test.go b/common/sniff/ssh_test.go new file mode 100644 index 0000000000..be53098079 --- /dev/null +++ b/common/sniff/ssh_test.go @@ -0,0 +1,26 @@ +package sniff_test + +import ( + "bytes" + "context" + "encoding/hex" + "testing" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/sniff" + C "github.com/sagernet/sing-box/constant" + + "github.com/stretchr/testify/require" +) + +func TestSniffSSH(t *testing.T) { + t.Parallel() + + pkt, err := hex.DecodeString("5353482d322e302d64726f70626561720d0a000001a40a1492892570d1223aef61b0d647972c8bd30000009f637572766532353531392d7368613235362c637572766532353531392d736861323536406c69627373682e6f72672c6469666669652d68656c6c6d616e2d67726f757031342d7368613235362c6469666669652d68656c6c6d616e2d67726f757031342d736861312c6b6578677565737332406d6174742e7563632e61736e2e61752c6b65782d7374726963742d732d763030406f70656e7373682e636f6d000000207373682d656432353531392c7273612d736861322d3235362c7373682d7273610000003363686163686132302d706f6c7931333035406f70656e7373682e636f6d2c6165733132382d6374722c6165733235362d6374720000003363686163686132302d706f6c7931333035406f70656e7373682e636f6d2c6165733132382d6374722c6165733235362d63747200000017686d61632d736861312c686d61632d736861322d32353600000017686d61632d736861312c686d61632d736861322d323536000000046e6f6e65000000046e6f6e65000000000000000000000000002aa6ed090585b7d635b6") + require.NoError(t, err) + var metadata adapter.InboundContext + err = sniff.SSH(context.TODO(), &metadata, bytes.NewReader(pkt)) + require.NoError(t, err) + require.Equal(t, C.ProtocolSSH, metadata.Protocol) + require.Equal(t, "dropbear", metadata.Client) +} diff --git a/constant/protocol.go b/constant/protocol.go index 8b1854d419..f867f428f6 100644 --- a/constant/protocol.go +++ b/constant/protocol.go @@ -8,6 +8,7 @@ const ( ProtocolSTUN = "stun" ProtocolBitTorrent = "bittorrent" ProtocolDTLS = "dtls" + ProtocolSSH = "ssh" ) const ( diff --git a/docs/changelog.md b/docs/changelog.md index 39940253f3..c84d2d8770 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,41 @@ icon: material/alert-decagram --- +!!! failure "Help needed" + + Due to problems with our Apple developer account, sing-box apps on Apple platforms are temporarily unavailable for download or update. + + If your company or organization is willing to help us return to the App Store, please [contact us](mailto:contact@sagernet.org). + +#### 1.10.0-beta.4 + +* Fixes and improvements + +#### 1.10.0-beta.3 + +* Add SSH sniffer +* Fixes and improvements + +#### 1.10.0-beta.2 + +* Build with go1.23 +* Fixes and improvements + +### 1.9.4 + +* Update quic-go to v0.46.0 +* Update Hysteria2 BBR congestion control +* Filter HTTPS ipv4hint/ipv6hint with domain strategy +* Fix crash on Android when using process rules +* Fix non-IP queries accepted by address filter rules +* Fix UDP server for shadowsocks AEAD multi-user inbounds +* Fix default next protos for v2ray QUIC transport +* Fix default end value of port range configuration options +* Fix reset v2ray transports +* Fix panic caused by rule-set generation of duplicate keys for `domain_suffix` +* Fix UDP connnection leak when sniffing +* Fixes and improvements + #### 1.10.0-alpha.29 * Update quic-go to v0.46.0 @@ -13,7 +48,7 @@ icon: material/alert-decagram **1**: -The new feature allows you to use AdGuard DNS Filter lists in a sing-box without AdGuard Home. +The new feature allows you to use AdGuard DNS Filter lists in a sing-box without AdGuard Home. See [AdGuard DNS Filter](/configuration/rule-set/adguard/). diff --git a/docs/clients/apple/index.md b/docs/clients/apple/index.md index cd090776ef..98cc342602 100644 --- a/docs/clients/apple/index.md +++ b/docs/clients/apple/index.md @@ -7,6 +7,13 @@ icon: material/apple SFI/SFM/SFT allows users to manage and run local or remote sing-box configuration files, and provides platform-specific function implementation, such as TUN transparent proxy implementation. +!!! failure "Unavailable" + + Due to problems with our Apple developer account, sing-box apps on Apple platforms are temporarily unavailable for download or update. + + If your company or organization is willing to help us return to the App Store, please [contact us](mailto:contact@sagernet.org). + + ## :material-graph: Requirements * iOS 15.0+ / macOS 13.0+ / Apple tvOS 17.0+ diff --git a/docs/clients/index.md b/docs/clients/index.md index 45d2c9a948..9dacff6e60 100644 --- a/docs/clients/index.md +++ b/docs/clients/index.md @@ -3,9 +3,9 @@ Maintained by Project S to provide a unified experience and platform-specific functionality. | Platform | Client | -|---------------------------------------|------------------------------------------| +| ------------------------------------- | ---------------------------------------- | | :material-android: Android | [sing-box for Android](./android/) | -| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple/) | +| :material-apple: iOS/macOS/Apple tvOS | :material-alert: [Unavailable](./apple/) | | :material-laptop: Desktop | Working in progress | Some third-party projects that claim to use sing-box or use sing-box as a selling point are not listed here. The core diff --git a/docs/clients/index.zh.md b/docs/clients/index.zh.md index 81e4129183..6717fa6106 100644 --- a/docs/clients/index.zh.md +++ b/docs/clients/index.zh.md @@ -2,11 +2,11 @@ 由 Project S 维护,提供统一的体验与平台特定的功能。 -| 平台 | 客户端 | -|---------------------------------------|-----------------------------------------| -| :material-android: Android | [sing-box for Android](./android/) | -| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple/) | -| :material-laptop: Desktop | 施工中 | +| 平台 | 客户端 | +| ------------------------------------- | ----------------------------------- | +| :material-android: Android | [sing-box for Android](./android/) | +| :material-apple: iOS/macOS/Apple tvOS | :material-alert: [不可用](./apple/) | +| :material-laptop: Desktop | 施工中 | 此处没有列出一些声称使用或以 sing-box 为卖点的第三方项目。此类项目维护者的动机是获得更多用户,即使它们提供友好的商业 VPN 客户端功能, 但代码质量很差且包含广告。 diff --git a/docs/configuration/experimental/clash-api.md b/docs/configuration/experimental/clash-api.md index e1ca981521..7425143eb3 100644 --- a/docs/configuration/experimental/clash-api.md +++ b/docs/configuration/experimental/clash-api.md @@ -1,3 +1,12 @@ +--- +icon: material/new-box +--- + +!!! quote "Changes in sing-box 1.10.0" + + :material-plus: [access_control_allow_origin](#access_control_allow_origin) + :material-plus: [access_control_allow_private_network](#access_control_allow_private_network) + !!! quote "Changes in sing-box 1.8.0" :material-delete-alert: [store_mode](#store_mode) @@ -8,24 +17,59 @@ ### Structure -```json -{ - "external_controller": "127.0.0.1:9090", - "external_ui": "", - "external_ui_download_url": "", - "external_ui_download_detour": "", - "secret": "", - "default_mode": "", - - // Deprecated - - "store_mode": false, - "store_selected": false, - "store_fakeip": false, - "cache_file": "", - "cache_id": "" -} -``` +=== "Structure" + + ```json + { + "external_controller": "127.0.0.1:9090", + "external_ui": "", + "external_ui_download_url": "", + "external_ui_download_detour": "", + "secret": "", + "default_mode": "", + "access_control_allow_origin": [], + "access_control_allow_private_network": false, + + // Deprecated + + "store_mode": false, + "store_selected": false, + "store_fakeip": false, + "cache_file": "", + "cache_id": "" + } + ``` + +=== "Example (online)" + + !!! question "Since sing-box 1.10.0" + + ```json + { + "external_controller": "127.0.0.1:9090", + "access_control_allow_origin": [ + "http://127.0.0.1", + "http://yacd.haishan.me" + ], + "access_control_allow_private_network": true + } + ``` + +=== "Example (download)" + + !!! question "Since sing-box 1.10.0" + + ```json + { + "external_controller": "0.0.0.0:9090", + "external_ui": "dashboard" + // external_ui_download_detour: "direct" + } + ``` + +!!! note "" + + You can ignore the JSON Array [] tag when the content is only one item ### Fields @@ -63,6 +107,22 @@ Default mode in clash, `Rule` will be used if empty. This setting has no direct effect, but can be used in routing and DNS rules via the `clash_mode` rule item. +#### access_control_allow_origin + +!!! question "Since sing-box 1.10.0" + +CORS allowed origins, `*` will be used if empty. + +To access the Clash API on a private network from a public website, you must explicitly specify it in `access_control_allow_origin` instead of using `*`. + +#### access_control_allow_private_network + +!!! question "Since sing-box 1.10.0" + +Allow access from private network. + +To access the Clash API on a private network from a public website, `access_control_allow_private_network` must be enabled. + #### store_mode !!! failure "Deprecated in sing-box 1.8.0" diff --git a/docs/configuration/experimental/clash-api.zh.md b/docs/configuration/experimental/clash-api.zh.md index 092769ac93..b3d8aeaf99 100644 --- a/docs/configuration/experimental/clash-api.zh.md +++ b/docs/configuration/experimental/clash-api.zh.md @@ -1,3 +1,12 @@ +--- +icon: material/new-box +--- + +!!! quote "sing-box 1.10.0 中的更改" + + :material-plus: [access_control_allow_origin](#access_control_allow_origin) + :material-plus: [access_control_allow_private_network](#access_control_allow_private_network) + !!! quote "sing-box 1.8.0 中的更改" :material-delete-alert: [store_mode](#store_mode) @@ -8,24 +17,59 @@ ### 结构 -```json -{ - "external_controller": "127.0.0.1:9090", - "external_ui": "", - "external_ui_download_url": "", - "external_ui_download_detour": "", - "secret": "", - "default_mode": "", - - // Deprecated - - "store_mode": false, - "store_selected": false, - "store_fakeip": false, - "cache_file": "", - "cache_id": "" -} -``` +=== "结构" + + ```json + { + "external_controller": "127.0.0.1:9090", + "external_ui": "", + "external_ui_download_url": "", + "external_ui_download_detour": "", + "secret": "", + "default_mode": "", + "access_control_allow_origin": [], + "access_control_allow_private_network": false, + + // Deprecated + + "store_mode": false, + "store_selected": false, + "store_fakeip": false, + "cache_file": "", + "cache_id": "" + } + ``` + +=== "示例 (在线)" + + !!! question "自 sing-box 1.10.0 起" + + ```json + { + "external_controller": "127.0.0.1:9090", + "access_control_allow_origin": [ + "http://127.0.0.1", + "http://yacd.haishan.me" + ], + "access_control_allow_private_network": true + } + ``` + +=== "示例 (下载)" + + !!! question "自 sing-box 1.10.0 起" + + ```json + { + "external_controller": "0.0.0.0:9090", + "external_ui": "dashboard" + // external_ui_download_detour: "direct" + } + ``` + +!!! note "" + + 当内容只有一项时,可以忽略 JSON 数组 [] 标签 ### Fields @@ -61,6 +105,22 @@ Clash 中的默认模式,默认使用 `Rule`。 此设置没有直接影响,但可以通过 `clash_mode` 规则项在路由和 DNS 规则中使用。 +#### access_control_allow_origin + +!!! question "自 sing-box 1.10.0 起" + +允许的 CORS 来源,默认使用 `*`。 + +要从公共网站访问私有网络上的 Clash API,必须在 `access_control_allow_origin` 中明确指定它而不是使用 `*`。 + +#### access_control_allow_private_network + +!!! question "自 sing-box 1.10.0 起" + +允许从私有网络访问。 + +要从公共网站访问私有网络上的 Clash API,必须启用 `access_control_allow_private_network`。 + #### store_mode !!! failure "已在 sing-box 1.8.0 废弃" diff --git a/docs/configuration/inbound/index.md b/docs/configuration/inbound/index.md index 9591ae866f..9ff4a7cf3e 100644 --- a/docs/configuration/inbound/index.md +++ b/docs/configuration/inbound/index.md @@ -15,24 +15,24 @@ ### Fields -| Type | Format | Injectable | -|---------------|-------------------------------|------------| -| `direct` | [Direct](./direct/) | X | -| `mixed` | [Mixed](./mixed/) | TCP | -| `socks` | [SOCKS](./socks/) | TCP | -| `http` | [HTTP](./http/) | TCP | -| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP | -| `vmess` | [VMess](./vmess/) | TCP | -| `trojan` | [Trojan](./trojan/) | TCP | -| `naive` | [Naive](./naive/) | X | -| `hysteria` | [Hysteria](./hysteria/) | X | -| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP | -| `tuic` | [TUIC](./tuic/) | X | -| `hysteria2` | [Hysteria2](./hysteria2/) | X | -| `vless` | [VLESS](./vless/) | TCP | -| `tun` | [Tun](./tun/) | X | -| `redirect` | [Redirect](./redirect/) | X | -| `tproxy` | [TProxy](./tproxy/) | X | +| Type | Format | Injectable | +|---------------|-------------------------------|------------------| +| `direct` | [Direct](./direct/) | :material-close: | +| `mixed` | [Mixed](./mixed/) | TCP | +| `socks` | [SOCKS](./socks/) | TCP | +| `http` | [HTTP](./http/) | TCP | +| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP | +| `vmess` | [VMess](./vmess/) | TCP | +| `trojan` | [Trojan](./trojan/) | TCP | +| `naive` | [Naive](./naive/) | :material-close: | +| `hysteria` | [Hysteria](./hysteria/) | :material-close: | +| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP | +| `tuic` | [TUIC](./tuic/) | :material-close: | +| `hysteria2` | [Hysteria2](./hysteria2/) | :material-close: | +| `vless` | [VLESS](./vless/) | TCP | +| `tun` | [Tun](./tun/) | :material-close: | +| `redirect` | [Redirect](./redirect/) | :material-close: | +| `tproxy` | [TProxy](./tproxy/) | :material-close: | #### tag diff --git a/docs/configuration/inbound/index.zh.md b/docs/configuration/inbound/index.zh.md index 458cd602d4..2c036340a7 100644 --- a/docs/configuration/inbound/index.zh.md +++ b/docs/configuration/inbound/index.zh.md @@ -15,24 +15,24 @@ ### 字段 -| 类型 | 格式 | 注入支持 | -|---------------|------------------------------|------| -| `direct` | [Direct](./direct/) | X | -| `mixed` | [Mixed](./mixed/) | TCP | -| `socks` | [SOCKS](./socks/) | TCP | -| `http` | [HTTP](./http/) | TCP | -| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP | -| `vmess` | [VMess](./vmess/) | TCP | -| `trojan` | [Trojan](./trojan/) | TCP | -| `naive` | [Naive](./naive/) | X | -| `hysteria` | [Hysteria](./hysteria/) | X | -| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP | -| `tuic` | [TUIC](./tuic/) | X | -| `hysteria2` | [Hysteria2](./hysteria2/) | X | -| `vless` | [VLESS](./vless/) | TCP | -| `tun` | [Tun](./tun/) | X | -| `redirect` | [Redirect](./redirect/) | X | -| `tproxy` | [TProxy](./tproxy/) | X | +| 类型 | 格式 | 注入支持 | +|---------------|-------------------------------|------------------| +| `direct` | [Direct](./direct/) | :material-close: | +| `mixed` | [Mixed](./mixed/) | TCP | +| `socks` | [SOCKS](./socks/) | TCP | +| `http` | [HTTP](./http/) | TCP | +| `shadowsocks` | [Shadowsocks](./shadowsocks/) | TCP | +| `vmess` | [VMess](./vmess/) | TCP | +| `trojan` | [Trojan](./trojan/) | TCP | +| `naive` | [Naive](./naive/) | :material-close: | +| `hysteria` | [Hysteria](./hysteria/) | :material-close: | +| `shadowtls` | [ShadowTLS](./shadowtls/) | TCP | +| `tuic` | [TUIC](./tuic/) | :material-close: | +| `hysteria2` | [Hysteria2](./hysteria2/) | :material-close: | +| `vless` | [VLESS](./vless/) | TCP | +| `tun` | [Tun](./tun/) | :material-close: | +| `redirect` | [Redirect](./redirect/) | :material-close: | +| `tproxy` | [TProxy](./tproxy/) | :material-close: | #### tag diff --git a/docs/configuration/route/sniff.md b/docs/configuration/route/sniff.md index ab96e75a6f..70e2acc85a 100644 --- a/docs/configuration/route/sniff.md +++ b/docs/configuration/route/sniff.md @@ -7,14 +7,15 @@ icon: material/new-box :material-plus: QUIC client type detect support for QUIC :material-plus: Chromium support for QUIC :material-plus: BitTorrent support - :material-plus: DTLS support + :material-plus: DTLS support + :material-plus: SSH support If enabled in the inbound, the protocol and domain name (if present) of by the connection can be sniffed. #### Supported Protocols | Network | Protocol | Domain Name | Client | -|:-------:|:------------:|:-----------:|:----------------:| +| :-----: | :----------: | :---------: | :--------------: | | TCP | `http` | Host | / | | TCP | `tls` | Server Name | / | | UDP | `quic` | Server Name | QUIC Client Type | @@ -22,9 +23,10 @@ If enabled in the inbound, the protocol and domain name (if present) of by the c | TCP/UDP | `dns` | / | / | | TCP/UDP | `bittorrent` | / | / | | UDP | `dtls` | / | / | +| TCP | `ssh` | / | SSH Client Name | | QUIC Client | Type | -|:------------------------:|:----------:| +| :----------------------: | :--------: | | Chromium/Cronet | `chrimium` | | Safari/Apple Network API | `safari` | | Firefox / uquic firefox | `firefox` | diff --git a/docs/configuration/route/sniff.zh.md b/docs/configuration/route/sniff.zh.md index 1ebc6d38d1..7421fd07e1 100644 --- a/docs/configuration/route/sniff.zh.md +++ b/docs/configuration/route/sniff.zh.md @@ -7,24 +7,26 @@ icon: material/new-box :material-plus: QUIC 的 客户端类型探测支持 :material-plus: QUIC 的 Chromium 支持 :material-plus: BitTorrent 支持 - :material-plus: DTLS 支持 + :material-plus: DTLS 支持 + :material-plus: SSH 支持 如果在入站中启用,则可以嗅探连接的协议和域名(如果存在)。 #### 支持的协议 -| 网络 | 协议 | 域名 | 客户端 | -|:-------:|:------------:|:-----------:|:----------:| -| TCP | `http` | Host | / | -| TCP | `tls` | Server Name | / | +| 网络 | 协议 | 域名 | 客户端 | +| :-----: | :----------: | :---------: | :-------------: | +| TCP | `http` | Host | / | +| TCP | `tls` | Server Name | / | | UDP | `quic` | Server Name | QUIC 客户端类型 | -| UDP | `stun` | / | / | -| TCP/UDP | `dns` | / | / | -| TCP/UDP | `bittorrent` | / | / | -| UDP | `dtls` | / | / | +| UDP | `stun` | / | / | +| TCP/UDP | `dns` | / | / | +| TCP/UDP | `bittorrent` | / | / | +| UDP | `dtls` | / | / | +| TCP | `SSH` | / | SSH 客户端名称 | -| QUIC 客户端 | 类型 | -|:------------------------:|:----------:| +| QUIC 客户端 | 类型 | +| :----------------------: | :--------: | | Chromium/Cronet | `chrimium` | | Safari/Apple Network API | `safari` | | Firefox / uquic firefox | `firefox` | diff --git a/docs/index.md b/docs/index.md index 2af7222e7b..8260109683 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,6 +4,12 @@ description: Welcome to the wiki page for the sing-box project. # :material-home: Home +!!! failure "Help needed" + + Due to problems with our Apple developer account, sing-box apps on Apple platforms are temporarily unavailable for download or update. + + If your company or organization is willing to help us return to the App Store, please [contact us](mailto:contact@sagernet.org). + Welcome to the wiki page for the sing-box project. The universal proxy platform. diff --git a/docs/index.zh.md b/docs/index.zh.md index 72877118f3..d2f253dde3 100644 --- a/docs/index.zh.md +++ b/docs/index.zh.md @@ -4,6 +4,13 @@ description: 欢迎来到该 sing-box 项目的文档页。 # :material-home: 开始 +!!! failure "需要帮助" + + 由于我们的 Apple 开发者账户出现问题,Apple 平台上的 sing-box 应用暂时无法下载或更新。 + + 如果您的公司或组织愿意帮助我们重返 App Store,请[联系我们](mailto:contact@sagernet.org)。 + + 欢迎来到该 sing-box 项目的文档页。 通用代理平台。 diff --git a/docs/installation/package-manager.md b/docs/installation/package-manager.md index bb5b6abb47..b4140666f5 100644 --- a/docs/installation/package-manager.md +++ b/docs/installation/package-manager.md @@ -24,14 +24,7 @@ icon: material/package sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo sudo dnf install sing-box # or sing-box-beta ``` - -=== ":material-redhat: CentOS / YUM" - - ```bash - sudo yum install -y yum-utils - sudo yum-config-manager --add-repo https://sing-box.app/sing-box.repo - sudo yum install sing-box # or sing-box-beta - ``` + (This applies to any distribution that uses `dnf` as the package manager: Fedora, CentOS, even OpenSUSE with DNF installed.) ## :material-download-box: Manual Installation @@ -46,6 +39,7 @@ icon: material/package ```bash bash <(curl -fsSL https://sing-box.app/rpm-install.sh) ``` + (This applies to any distribution that uses `rpm` and `systemd`. Because of how `rpm` defines dependencies, if it installs, it probably works.) === ":simple-archlinux: Archlinux / PKG" @@ -63,6 +57,7 @@ icon: material/package | nixpkgs | NixOS | `nix-env -iA nixos.sing-box` | [![nixpkgs unstable package](https://repology.org/badge/version-for-repo/nix_unstable/sing-box.svg)][nixpkgs] | | Homebrew | macOS / Linux | `brew install sing-box` | [![Homebrew package](https://repology.org/badge/version-for-repo/homebrew/sing-box.svg)][brew] | | APK | Alpine | `apk add sing-box` | [![Alpine Linux Edge package](https://repology.org/badge/version-for-repo/alpine_edge/sing-box.svg)][alpine] | + | DEB | AOSC | `apt install sing-box` | [![AOSC package](https://repology.org/badge/version-for-repo/aosc/sing-box.svg)][aosc] | === ":material-apple: macOS" @@ -90,6 +85,22 @@ icon: material/package |------------|----------|------------------------|--------------------------------------------------------------------------------------------| | FreshPorts | FreeBSD | `pkg install sing-box` | [![FreeBSD port](https://repology.org/badge/version-for-repo/freebsd/sing-box.svg)][ports] | +## :material-alert: Problematic Sources + +| Type | Platform | Link | Promblem(s) | +|------------|----------|-------------------------------------------------------------------------------------------|------------------------------------------------------------------| +| DEB | AOSC | [aosc-os-abbs](https://github.com/AOSC-Dev/aosc-os-abbs/tree/stable/app-network/sing-box) | Problematic build tag list modification; Not actively maintained | +| Homebrew | / | [homebrew-core][brew] | Problematic build tag list modification | +| Termux | Android | [termux-packages][termux] | Problematic build tag list modification | +| FreshPorts | FreeBSD | [FreeBSD ports][ports] | Old Go (go1.20) | + +If you are a user of them, please report issues to them: + +1. Please do not modify release build tags without full understanding of the related functionality: enabling non-default + labels may result in decreased performance; the lack of default labels may cause user confusion. +2. sing-box supports compiling with some older Go versions, but it is not recommended (especially versions that are no + longer supported by Go). + ## :material-book-multiple: Service Management For Linux systems with [systemd][systemd], usually the installation already includes a sing-box service, @@ -128,4 +139,6 @@ you can manage the service using the following command: [ports]: https://www.freshports.org/net/sing-box +[aosc]: https://packages.aosc.io/packages/sing-box + [systemd]: https://systemd.io/ diff --git a/docs/installation/package-manager.zh.md b/docs/installation/package-manager.zh.md index a786450a0d..3bc03e571c 100644 --- a/docs/installation/package-manager.zh.md +++ b/docs/installation/package-manager.zh.md @@ -24,14 +24,7 @@ icon: material/package sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo sudo dnf install sing-box # or sing-box-beta ``` - -=== ":material-redhat: CentOS / YUM" - - ```bash - sudo yum install -y yum-utils - sudo yum-config-manager --add-repo https://sing-box.app/sing-box.repo - sudo yum install sing-box # or sing-box-beta - ``` + (这适用于任何使用 `dnf` 作为包管理器的发行版:Fedora、CentOS,甚至安装了 DNF 的 OpenSUSE。) ## :material-download-box: 手动安装 @@ -46,6 +39,7 @@ icon: material/package ```bash bash <(curl -fsSL https://sing-box.app/rpm-install.sh) ``` + (这适用于任何使用 `rpm` 和 `systemd` 的发行版。由于 `rpm` 定义依赖关系的方式,如果安装成功,就多半能用。) === ":simple-archlinux: Archlinux / PKG" @@ -63,6 +57,7 @@ icon: material/package | nixpkgs | NixOS | `nix-env -iA nixos.sing-box` | [![nixpkgs unstable package](https://repology.org/badge/version-for-repo/nix_unstable/sing-box.svg)][nixpkgs] | | Homebrew | macOS / Linux | `brew install sing-box` | [![Homebrew package](https://repology.org/badge/version-for-repo/homebrew/sing-box.svg)][brew] | | APK | Alpine | `apk add sing-box` | [![Alpine Linux Edge package](https://repology.org/badge/version-for-repo/alpine_edge/sing-box.svg)][alpine] | + | DEB | AOSC | `apt install sing-box` | [![AOSC package](https://repology.org/badge/version-for-repo/aosc/sing-box.svg)][aosc] | === ":material-apple: macOS" @@ -90,6 +85,21 @@ icon: material/package |------------|---------|------------------------|--------------------------------------------------------------------------------------------| | FreshPorts | FreeBSD | `pkg install sing-box` | [![FreeBSD port](https://repology.org/badge/version-for-repo/freebsd/sing-box.svg)][ports] | + +## :material-alert: 存在问题的源 + +| 类型 | 平台 | 链接 | 原因 | +|------------|---------|-------------------------------------------------------------------------------------------|-----------------------| +| DEB | AOSC | [aosc-os-abbs](https://github.com/AOSC-Dev/aosc-os-abbs/tree/stable/app-network/sing-box) | 存在问题的构建标志列表修改; 没有活跃维护 | +| Homebrew | / | [homebrew-core][brew] | 存在问题的构建标志列表修改 | +| Termux | Android | [termux-packages][termux] | 存在问题的构建标志列表修改 | +| FreshPorts | FreeBSD | [FreeBSD ports][ports] | 太旧的 Go (go1.20) | + +如果您是其用户,请向他们报告问题: + +1. 在未完全了解相关功能的情况下,请勿修改发布版本标签:启用非默认标签可能会导致性能下降;缺少默认标签可能会引起用户混淆。 +2. sing-box 支持使用一些较旧的 Go 版本进行编译,但不推荐使用(特别是已不再受 Go 支持的版本)。 + ## :material-book-multiple: 服务管理 对于带有 [systemd][systemd] 的 Linux 系统,通常安装已经包含 sing-box 服务, @@ -124,4 +134,6 @@ icon: material/package [ports]: https://www.freshports.org/net/sing-box +[aosc]: https://packages.aosc.io/packages/sing-box + [systemd]: https://systemd.io/ diff --git a/docs/manual/proxy-protocol/hysteria2.md b/docs/manual/proxy-protocol/hysteria2.md index 9cc07e6f12..fe605b4576 100644 --- a/docs/manual/proxy-protocol/hysteria2.md +++ b/docs/manual/proxy-protocol/hysteria2.md @@ -4,16 +4,17 @@ icon: material/lightning-bolt # Hysteria 2 -The most popular Chinese-made simple protocol based on QUIC, the selling point is Brutal, -a congestion control algorithm that can resist packet loss by manually specifying the required rate by the user. +Hysteria 2 is a simple, Chinese-made protocol based on QUIC. +The selling point is Brutal, a congestion control algorithm that +tries to achieve a user-defined bandwidth despite packet loss. !!! warning - Even though GFW rarely blocks UDP-based proxies, such protocols actually have far more characteristics than TCP based proxies. + Even though GFW rarely blocks UDP-based proxies, such protocols actually have far more obvious characteristics than TCP based proxies. -| Specification | Binary Characteristics | Active Detect Hiddenness | -|---------------------------------------------------------------------------|------------------------|--------------------------| -| [hysteria.network](https://v2.hysteria.network/docs/developers/Protocol/) | :material-alert: | :material-check: | +| Specification | Resists passive detection | Resists active probes | +|---------------------------------------------------------------------------|---------------------------|-----------------------| +| [hysteria.network](https://v2.hysteria.network/docs/developers/Protocol/) | :material-alert: | :material-check: | ## :material-text-box-check: Password Generator @@ -44,7 +45,7 @@ To use sing-box with the official program, you need to fill in that combination Replace `up_mbps` and `down_mbps` values with the actual bandwidth of your server. === ":material-harddisk: With local certificate" - + ```json { "inbounds": [ diff --git a/docs/manual/proxy-protocol/shadowsocks.md b/docs/manual/proxy-protocol/shadowsocks.md index 94821d83d1..19f9d4cf93 100644 --- a/docs/manual/proxy-protocol/shadowsocks.md +++ b/docs/manual/proxy-protocol/shadowsocks.md @@ -4,15 +4,18 @@ icon: material/send # Shadowsocks -As the most well-known Chinese-made proxy protocol, -Shadowsocks exists in multiple versions, -but only AEAD 2022 ciphers TCP with multiplexing is recommended. - -| Ciphers | Specification | Cryptographic Security | Binary Characteristics | Active Detect Hiddenness | -|----------------|------------------------------------------------------------|------------------------|------------------------|--------------------------| -| Stream Ciphers | [shadowsocks.org](https://shadowsocks.org/doc/stream.html) | :material-alert: | :material-alert: | :material-alert: | -| AEAD | [shadowsocks.org](https://shadowsocks.org/doc/aead.html) | :material-check: | :material-alert: | :material-alert: | -| AEAD 2022 | [shadowsocks.org](https://shadowsocks.org/doc/sip022.html) | :material-check: | :material-check: | :material-help: | +Shadowsocks is the most well-known Chinese-made proxy protocol. +It exists in multiple versions, but only AEAD 2022 ciphers +over TCP with multiplexing is recommended. + +| Ciphers | Specification | Cryptographically sound | Resists passive detection | Resists active probes | +|----------------|------------------------------------------------------------|-------------------------|---------------------------|-----------------------| +| Stream Ciphers | [shadowsocks.org](https://shadowsocks.org/doc/stream.html) | :material-alert: | :material-alert: | :material-alert: | +| AEAD | [shadowsocks.org](https://shadowsocks.org/doc/aead.html) | :material-check: | :material-alert: | :material-alert: | +| AEAD 2022 | [shadowsocks.org](https://shadowsocks.org/doc/sip022.html) | :material-check: | :material-check: | :material-help: | + +(We strongly recommend using multiplexing to send UDP traffic over TCP, because +doing otherwise is vulnerable to passive detection.) ## :material-text-box-check: Password Generator diff --git a/docs/manual/proxy-protocol/trojan.md b/docs/manual/proxy-protocol/trojan.md index 4c2e16f17e..731322f3a0 100644 --- a/docs/manual/proxy-protocol/trojan.md +++ b/docs/manual/proxy-protocol/trojan.md @@ -4,15 +4,15 @@ icon: material/horse # Trojan -As the most commonly used TLS proxy made in China, Trojan can be used in various combinations, +Torjan is the most commonly used TLS proxy made in China. It can be used in various combinations, but only the combination of uTLS and multiplexing is recommended. -| Protocol and implementation combination | Specification | Binary Characteristics | Active Detect Hiddenness | -|-----------------------------------------|----------------------------------------------------------------------|------------------------|--------------------------| -| Origin / trojan-gfw | [trojan-gfw.github.io](https://trojan-gfw.github.io/trojan/protocol) | :material-check: | :material-check: | -| Basic Go implementation | / | :material-alert: | :material-check: | -| with privates transport by V2Ray | No formal definition | :material-alert: | :material-alert: | -| with uTLS enabled | No formal definition | :material-help: | :material-check: | +| Protocol and implementation combination | Specification | Resists passive detection | Resists active probes | +|-----------------------------------------|----------------------------------------------------------------------|---------------------------|-----------------------| +| Origin / trojan-gfw | [trojan-gfw.github.io](https://trojan-gfw.github.io/trojan/protocol) | :material-check: | :material-check: | +| Basic Go implementation | / | :material-alert: | :material-check: | +| with privates transport by V2Ray | No formal definition | :material-alert: | :material-alert: | +| with uTLS enabled | No formal definition | :material-help: | :material-check: | ## :material-text-box-check: Password Generator @@ -211,4 +211,3 @@ but only the combination of uTLS and multiplexing is recommended. ] } ``` - diff --git a/docs/support.md b/docs/support.md index 9ddb4ecfff..8443ffaaf0 100644 --- a/docs/support.md +++ b/docs/support.md @@ -5,8 +5,7 @@ icon: material/forum # Support | Channel | Link | -|:------------------------------|:--------------------------------------------| -| Community | https://community.sagernet.org | +| :---------------------------- | :------------------------------------------ | | GitHub Issues | https://github.com/SagerNet/sing-box/issues | | Telegram notification channel | https://t.me/yapnc | | Telegram user group | https://t.me/yapug | diff --git a/docs/support.zh.md b/docs/support.zh.md index eb07ea8292..ff1978ee3e 100644 --- a/docs/support.zh.md +++ b/docs/support.zh.md @@ -4,11 +4,10 @@ icon: material/forum # 支持 -| 通道 | 链接 | -|:--------------|:--------------------------------------------| -| 社区 | https://community.sagernet.org | -| GitHub Issues | https://github.com/SagerNet/sing-box/issues | +| 通道 | 链接 | +| :---------------- | :------------------------------------------ | +| GitHub Issues | https://github.com/SagerNet/sing-box/issues | | Telegram 通知频道 | https://t.me/yapnc | -| Telegram 用户组 | https://t.me/yapug | -| 邮件 | contact@sagernet.org | +| Telegram 用户组 | https://t.me/yapug | +| 邮件 | contact@sagernet.org | diff --git a/experimental/clashapi/server.go b/experimental/clashapi/server.go index 1e7804ce44..889d191e0e 100644 --- a/experimental/clashapi/server.go +++ b/experimental/clashapi/server.go @@ -12,6 +12,7 @@ import ( "syscall" "time" + "github.com/sagernet/cors" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/urltest" C "github.com/sagernet/sing-box/constant" @@ -29,7 +30,6 @@ import ( "github.com/sagernet/ws/wsutil" "github.com/go-chi/chi/v5" - "github.com/go-chi/cors" "github.com/go-chi/render" ) @@ -90,11 +90,16 @@ func NewServer(ctx context.Context, router adapter.Router, logFactory log.Observ if options.StoreMode || options.StoreSelected || options.StoreFakeIP || options.CacheFile != "" || options.CacheID != "" { return nil, E.New("cache_file and related fields in Clash API is deprecated in sing-box 1.8.0, use experimental.cache_file instead.") } + allowedOrigins := options.AccessControlAllowOrigin + if len(allowedOrigins) == 0 { + allowedOrigins = []string{"*"} + } cors := cors.New(cors.Options{ - AllowedOrigins: []string{"*"}, - AllowedMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE"}, - AllowedHeaders: []string{"Content-Type", "Authorization"}, - MaxAge: 300, + AllowedOrigins: allowedOrigins, + AllowedMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE"}, + AllowedHeaders: []string{"Content-Type", "Authorization"}, + AllowPrivateNetwork: options.AccessControlAllowPrivateNetwork, + MaxAge: 300, }) chiRouter.Use(cors.Handler) chiRouter.Group(func(r chi.Router) { @@ -277,10 +282,11 @@ func authentication(serverSecret string) func(next http.Handler) http.Handler { func hello(redirect bool) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { - if redirect { - http.Redirect(w, r, "/ui/", http.StatusTemporaryRedirect) - } else { + contentType := r.Header.Get("Content-Type") + if !redirect || contentType == "application/json" { render.JSON(w, r, render.M{"hello": "clash"}) + } else { + http.Redirect(w, r, "/ui/", http.StatusTemporaryRedirect) } } } diff --git a/experimental/libbox/dns.go b/experimental/libbox/dns.go index e1f8bcc3b6..a46d9b4241 100644 --- a/experimental/libbox/dns.go +++ b/experimental/libbox/dns.go @@ -69,7 +69,8 @@ func (p *platformLocalDNSTransport) Exchange(ctx context.Context, message *mDNS. context: ctx, } var responseMessage *mDNS.Msg - return responseMessage, task.Run(ctx, func() error { + var group task.Group + group.Append0(func(ctx context.Context) error { err = p.iif.Exchange(response, messageBytes) if err != nil { return err @@ -80,6 +81,11 @@ func (p *platformLocalDNSTransport) Exchange(ctx context.Context, message *mDNS. responseMessage = &response.message return nil }) + err = group.Run(ctx) + if err != nil { + return nil, err + } + return responseMessage, nil } func (p *platformLocalDNSTransport) Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) { @@ -96,7 +102,8 @@ func (p *platformLocalDNSTransport) Lookup(ctx context.Context, domain string, s context: ctx, } var responseAddr []netip.Addr - return responseAddr, task.Run(ctx, func() error { + var group task.Group + group.Append0(func(ctx context.Context) error { err := p.iif.Lookup(response, network, domain) if err != nil { return err @@ -121,6 +128,11 @@ func (p *platformLocalDNSTransport) Lookup(ctx context.Context, domain string, s }*/ return nil }) + err := group.Run(ctx) + if err != nil { + return nil, err + } + return responseAddr, nil } type Func interface { diff --git a/go.mod b/go.mod index a149d35b5d..f1413fc196 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,6 @@ require ( github.com/cloudflare/circl v1.3.7 github.com/cretz/bine v0.2.0 github.com/go-chi/chi/v5 v5.0.12 - github.com/go-chi/cors v1.2.1 github.com/go-chi/render v1.0.3 github.com/gofrs/uuid/v5 v5.2.0 github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 @@ -25,15 +24,16 @@ require ( github.com/pires/go-proxyproto v0.7.0 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 + github.com/sagernet/cors v1.2.1 github.com/sagernet/fswatch v0.1.1 github.com/sagernet/gomobile v0.1.3 github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f - github.com/sagernet/quic-go v0.46.0-beta.2 + github.com/sagernet/quic-go v0.46.0-beta.4 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 - github.com/sagernet/sing v0.5.0-alpha.15 + github.com/sagernet/sing v0.5.0-beta.1 github.com/sagernet/sing-dns v0.3.0-beta.14 github.com/sagernet/sing-mux v0.2.0 - github.com/sagernet/sing-quic v0.2.0-beta.12 + github.com/sagernet/sing-quic v0.3.0-beta.2 github.com/sagernet/sing-shadowsocks v0.2.7 github.com/sagernet/sing-shadowsocks2 v0.2.0 github.com/sagernet/sing-shadowtls v0.1.4 diff --git a/go.sum b/go.sum index ed8cc9f430..561ef0d27a 100644 --- a/go.sum +++ b/go.sum @@ -25,8 +25,6 @@ github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXb github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= -github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= @@ -110,6 +108,8 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 h1:YbmpqPQEMdlk9oFSKYWRqVuu9qzNiOayIonKmv1gCXY= github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1/go.mod h1:J2yAxTFPDjrDPhuAi9aWFz2L3ox9it4qAluBBbN0H5k= +github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ= +github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI= github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs= github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o= github.com/sagernet/gomobile v0.1.3 h1:ohjIb1Ou2+1558PnZour3od69suSuvkdSVOlO1tC4B8= @@ -120,19 +120,19 @@ github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZN github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I= github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= -github.com/sagernet/quic-go v0.46.0-beta.2 h1:D/k9P3btgg0CvtUFVlQsUyN9GkLj0fMG59FOlEz1In8= -github.com/sagernet/quic-go v0.46.0-beta.2/go.mod h1:Zt3LVudHvhFRa7uO7hjtLAYJ9wFzYv4F17+LedJSw44= +github.com/sagernet/quic-go v0.46.0-beta.4 h1:k9f7VSKaM47AY6MPND0Qf1KRN7HwimPg9zdOFTXTiCk= +github.com/sagernet/quic-go v0.46.0-beta.4/go.mod h1:zJmVdJUNqEDXfubf4KtIOUHHerggjBduiGRLNzJspcM= 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.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= -github.com/sagernet/sing v0.5.0-alpha.15 h1:Jqc+8MukOIdwyzAK48bK0uHmYUnfMdfGcXTxrB7OTVE= -github.com/sagernet/sing v0.5.0-alpha.15/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing v0.5.0-beta.1 h1:THZMZgJcDQxutE++6Ckih1HlvMtXple94RBGa6GSg2I= +github.com/sagernet/sing v0.5.0-beta.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-dns v0.3.0-beta.14 h1:/s+fJzYKsvLaNDt/2rjpsrDcN8wmCO2JbX6OFrl8Nww= github.com/sagernet/sing-dns v0.3.0-beta.14/go.mod h1:rscgSr5ixOPk8XM9ZMLuMXCyldEQ1nLvdl0nfv+lp00= github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo= github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ= -github.com/sagernet/sing-quic v0.2.0-beta.12 h1:BhvA5mmrDFEyDUQB5eeu+9UhF+ieyuNJ5Rsb0dAG3QY= -github.com/sagernet/sing-quic v0.2.0-beta.12/go.mod h1:YVpLfVi8BvYM7NMrjmnvcRm3E8iMETf1gFQmTQDN9jI= +github.com/sagernet/sing-quic v0.3.0-beta.2 h1:9TiaW4js4fXD6GPCGMbwb3/bIRKpXm7skJBdV1OdvMs= +github.com/sagernet/sing-quic v0.3.0-beta.2/go.mod h1:YLV1dUDv8Eyp/8e55O/EvfsrwxOgEDVgDCIoPqmDREE= github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8= github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE= github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg= diff --git a/option/experimental.go b/option/experimental.go index 9f6071baee..6ab6638550 100644 --- a/option/experimental.go +++ b/option/experimental.go @@ -17,13 +17,15 @@ type CacheFileOptions struct { } type ClashAPIOptions struct { - ExternalController string `json:"external_controller,omitempty"` - ExternalUI string `json:"external_ui,omitempty"` - ExternalUIDownloadURL string `json:"external_ui_download_url,omitempty"` - ExternalUIDownloadDetour string `json:"external_ui_download_detour,omitempty"` - Secret string `json:"secret,omitempty"` - DefaultMode string `json:"default_mode,omitempty"` - ModeList []string `json:"-"` + ExternalController string `json:"external_controller,omitempty"` + ExternalUI string `json:"external_ui,omitempty"` + ExternalUIDownloadURL string `json:"external_ui_download_url,omitempty"` + ExternalUIDownloadDetour string `json:"external_ui_download_detour,omitempty"` + Secret string `json:"secret,omitempty"` + DefaultMode string `json:"default_mode,omitempty"` + ModeList []string `json:"-"` + AccessControlAllowOrigin Listable[string] `json:"access_control_allow_origin,omitempty"` + AccessControlAllowPrivateNetwork bool `json:"access_control_allow_private_network,omitempty"` // Deprecated: migrated to global cache file CacheFile string `json:"cache_file,omitempty"` diff --git a/route/router.go b/route/router.go index e313c6f71d..742f5bd2ee 100644 --- a/route/router.go +++ b/route/router.go @@ -860,9 +860,10 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad conn, buffer, time.Duration(metadata.InboundOptions.SniffTimeout), - sniff.StreamDomainNameQuery, sniff.TLSClientHello, sniff.HTTPHost, + sniff.StreamDomainNameQuery, + sniff.SSH, sniff.BitTorrent, ) if err == nil { @@ -979,56 +980,79 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m if metadata.InboundOptions.SniffEnabled || metadata.Destination.Addr.IsUnspecified() { var bufferList []*buf.Buffer for { - buffer := buf.NewPacket() - destination, err := conn.ReadPacket(buffer) + var ( + buffer = buf.NewPacket() + destination M.Socksaddr + done = make(chan struct{}) + err error + ) + go func() { + sniffTimeout := C.ReadPayloadTimeout + if metadata.InboundOptions.SniffTimeout > 0 { + sniffTimeout = time.Duration(metadata.InboundOptions.SniffTimeout) + } + conn.SetReadDeadline(time.Now().Add(sniffTimeout)) + destination, err = conn.ReadPacket(buffer) + conn.SetReadDeadline(time.Time{}) + close(done) + }() + select { + case <-done: + case <-ctx.Done(): + conn.Close() + return ctx.Err() + } if err != nil { buffer.Release() - return err - } - if metadata.Destination.Addr.IsUnspecified() { - metadata.Destination = destination - } - if metadata.InboundOptions.SniffEnabled { - if len(bufferList) > 0 { - err = sniff.PeekPacket( - ctx, - &metadata, - buffer.Bytes(), - sniff.QUICClientHello, - ) - } else { - err = sniff.PeekPacket( - ctx, - &metadata, - buffer.Bytes(), - sniff.DomainNameQuery, - sniff.QUICClientHello, - sniff.STUNMessage, - sniff.UTP, - sniff.UDPTracker, - sniff.DTLSRecord, - ) + if !errors.Is(err, os.ErrDeadlineExceeded) { + return err } - if E.IsMulti(err, sniff.ErrClientHelloFragmented) && len(bufferList) == 0 { - bufferList = append(bufferList, buffer) - r.logger.DebugContext(ctx, "attempt to sniff fragmented QUIC client hello") - continue + } else { + if metadata.Destination.Addr.IsUnspecified() { + metadata.Destination = destination } - if metadata.Protocol != "" { - if metadata.InboundOptions.SniffOverrideDestination && M.IsDomainName(metadata.Domain) { - metadata.Destination = M.Socksaddr{ - Fqdn: metadata.Domain, - Port: metadata.Destination.Port, - } - } - if metadata.Domain != "" && metadata.Client != "" { - r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain, ", client: ", metadata.Client) - } else if metadata.Domain != "" { - r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain) - } else if metadata.Client != "" { - r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", client: ", metadata.Client) + if metadata.InboundOptions.SniffEnabled { + if len(bufferList) > 0 { + err = sniff.PeekPacket( + ctx, + &metadata, + buffer.Bytes(), + sniff.QUICClientHello, + ) } else { - r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol) + err = sniff.PeekPacket( + ctx, + &metadata, + buffer.Bytes(), + sniff.DomainNameQuery, + sniff.QUICClientHello, + sniff.STUNMessage, + sniff.UTP, + sniff.UDPTracker, + sniff.DTLSRecord, + ) + } + if E.IsMulti(err, sniff.ErrClientHelloFragmented) && len(bufferList) == 0 { + bufferList = append(bufferList, buffer) + r.logger.DebugContext(ctx, "attempt to sniff fragmented QUIC client hello") + continue + } + if metadata.Protocol != "" { + if metadata.InboundOptions.SniffOverrideDestination && M.IsDomainName(metadata.Domain) { + metadata.Destination = M.Socksaddr{ + Fqdn: metadata.Domain, + Port: metadata.Destination.Port, + } + } + if metadata.Domain != "" && metadata.Client != "" { + r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain, ", client: ", metadata.Client) + } else if metadata.Domain != "" { + r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain) + } else if metadata.Client != "" { + r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", client: ", metadata.Client) + } else { + r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol) + } } } } diff --git a/route/router_dns.go b/route/router_dns.go index eeb4ce2034..ead8c28943 100644 --- a/route/router_dns.go +++ b/route/router_dns.go @@ -189,6 +189,9 @@ func (r *Router) Lookup(ctx context.Context, domain string, strategy dns.DomainS ) responseAddrs, cached = r.dnsClient.LookupCache(ctx, domain, strategy) if cached { + if len(responseAddrs) == 0 { + return nil, dns.RCodeNameError + } return responseAddrs, nil } r.dnsLogger.DebugContext(ctx, "lookup domain ", domain)