mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-11 17:47:20 +10:00
Add cloudflared inbound
This commit is contained in:
@@ -25,6 +25,7 @@ const (
|
||||
TypeTUIC = "tuic"
|
||||
TypeHysteria2 = "hysteria2"
|
||||
TypeTailscale = "tailscale"
|
||||
TypeCloudflared = "cloudflared"
|
||||
TypeDERP = "derp"
|
||||
TypeResolved = "resolved"
|
||||
TypeSSMAPI = "ssm-api"
|
||||
@@ -90,6 +91,8 @@ func ProxyDisplayName(proxyType string) string {
|
||||
return "AnyTLS"
|
||||
case TypeTailscale:
|
||||
return "Tailscale"
|
||||
case TypeCloudflared:
|
||||
return "Cloudflared"
|
||||
case TypeSelector:
|
||||
return "Selector"
|
||||
case TypeURLTest:
|
||||
|
||||
89
docs/configuration/inbound/cloudflared.md
Normal file
89
docs/configuration/inbound/cloudflared.md
Normal file
@@ -0,0 +1,89 @@
|
||||
---
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! question "Since sing-box 1.14.0"
|
||||
|
||||
`cloudflared` inbound runs an embedded Cloudflare Tunnel client and routes all
|
||||
incoming tunnel traffic (TCP, UDP, ICMP) through sing-box's routing engine.
|
||||
|
||||
### Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "cloudflared",
|
||||
"tag": "",
|
||||
|
||||
"token": "",
|
||||
"ha_connections": 0,
|
||||
"protocol": "",
|
||||
"post_quantum": false,
|
||||
"edge_ip_version": 0,
|
||||
"datagram_version": "",
|
||||
"grace_period": "",
|
||||
"region": "",
|
||||
"control_dialer": {
|
||||
... // Dial Fields
|
||||
},
|
||||
"tunnel_dialer": {
|
||||
... // Dial Fields
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Fields
|
||||
|
||||
#### token
|
||||
|
||||
==Required==
|
||||
|
||||
Base64-encoded tunnel token from the Cloudflare Zero Trust dashboard
|
||||
(`Networks → Tunnels → Install connector`).
|
||||
|
||||
#### ha_connections
|
||||
|
||||
Number of high-availability connections to the Cloudflare edge.
|
||||
|
||||
Capped by the number of discovered edge addresses.
|
||||
|
||||
#### protocol
|
||||
|
||||
Transport protocol for edge connections.
|
||||
|
||||
One of `quic` `http2`.
|
||||
|
||||
#### post_quantum
|
||||
|
||||
Enable post-quantum key exchange on the control connection.
|
||||
|
||||
#### edge_ip_version
|
||||
|
||||
IP version used when connecting to the Cloudflare edge.
|
||||
|
||||
One of `0` (automatic) `4` `6`.
|
||||
|
||||
#### datagram_version
|
||||
|
||||
Datagram protocol version used for UDP proxying over QUIC.
|
||||
|
||||
One of `v2` `v3`. Only meaningful when `protocol` is `quic`.
|
||||
|
||||
#### grace_period
|
||||
|
||||
Graceful shutdown window for in-flight edge connections.
|
||||
|
||||
#### region
|
||||
|
||||
Cloudflare edge region selector.
|
||||
|
||||
Conflict with endpoints embedded in `token`.
|
||||
|
||||
#### control_dialer
|
||||
|
||||
[Dial Fields](/configuration/shared/dial/) used when the tunnel client dials the
|
||||
Cloudflare control plane.
|
||||
|
||||
#### tunnel_dialer
|
||||
|
||||
[Dial Fields](/configuration/shared/dial/) used when the tunnel client dials the
|
||||
Cloudflare edge data plane.
|
||||
89
docs/configuration/inbound/cloudflared.zh.md
Normal file
89
docs/configuration/inbound/cloudflared.zh.md
Normal file
@@ -0,0 +1,89 @@
|
||||
---
|
||||
icon: material/new-box
|
||||
---
|
||||
|
||||
!!! question "自 sing-box 1.14.0 起"
|
||||
|
||||
`cloudflared` 入站运行一个内嵌的 Cloudflare Tunnel 客户端,并将所有传入的隧道流量
|
||||
(TCP、UDP、ICMP)通过 sing-box 的路由引擎转发。
|
||||
|
||||
### 结构
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "cloudflared",
|
||||
"tag": "",
|
||||
|
||||
"token": "",
|
||||
"ha_connections": 0,
|
||||
"protocol": "",
|
||||
"post_quantum": false,
|
||||
"edge_ip_version": 0,
|
||||
"datagram_version": "",
|
||||
"grace_period": "",
|
||||
"region": "",
|
||||
"control_dialer": {
|
||||
... // 拨号字段
|
||||
},
|
||||
"tunnel_dialer": {
|
||||
... // 拨号字段
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 字段
|
||||
|
||||
#### token
|
||||
|
||||
==必填==
|
||||
|
||||
来自 Cloudflare Zero Trust 仪表板的 Base64 编码隧道令牌
|
||||
(`Networks → Tunnels → Install connector`)。
|
||||
|
||||
#### ha_connections
|
||||
|
||||
到 Cloudflare edge 的高可用连接数。
|
||||
|
||||
上限为已发现的 edge 地址数量。
|
||||
|
||||
#### protocol
|
||||
|
||||
edge 连接使用的传输协议。
|
||||
|
||||
`quic` `http2` 之一。
|
||||
|
||||
#### post_quantum
|
||||
|
||||
在控制连接上启用后量子密钥交换。
|
||||
|
||||
#### edge_ip_version
|
||||
|
||||
连接 Cloudflare edge 时使用的 IP 版本。
|
||||
|
||||
`0`(自动)`4` `6` 之一。
|
||||
|
||||
#### datagram_version
|
||||
|
||||
通过 QUIC 进行 UDP 代理时使用的数据报协议版本。
|
||||
|
||||
`v2` `v3` 之一。仅在 `protocol` 为 `quic` 时有效。
|
||||
|
||||
#### grace_period
|
||||
|
||||
正在处理的 edge 连接的优雅关闭窗口。
|
||||
|
||||
#### region
|
||||
|
||||
Cloudflare edge 区域选择器。
|
||||
|
||||
与 `token` 中嵌入的 endpoint 冲突。
|
||||
|
||||
#### control_dialer
|
||||
|
||||
隧道客户端拨向 Cloudflare 控制面时使用的
|
||||
[拨号字段](/zh/configuration/shared/dial/)。
|
||||
|
||||
#### tunnel_dialer
|
||||
|
||||
隧道客户端拨向 Cloudflare edge 数据面时使用的
|
||||
[拨号字段](/zh/configuration/shared/dial/)。
|
||||
@@ -34,6 +34,7 @@
|
||||
| `tun` | [Tun](./tun/) | :material-close: |
|
||||
| `redirect` | [Redirect](./redirect/) | :material-close: |
|
||||
| `tproxy` | [TProxy](./tproxy/) | :material-close: |
|
||||
| `cloudflared` | [Cloudflared](./cloudflared/) | :material-close: |
|
||||
|
||||
#### tag
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
| `tun` | [Tun](./tun/) | :material-close: |
|
||||
| `redirect` | [Redirect](./redirect/) | :material-close: |
|
||||
| `tproxy` | [TProxy](./tproxy/) | :material-close: |
|
||||
| `cloudflared` | [Cloudflared](./cloudflared/) | :material-close: |
|
||||
|
||||
#### tag
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ go build -tags "tag_a tag_b" ./cmd/sing-box
|
||||
| `with_ccm` | :material-check: | Build with Claude Code Multiplexer service support. |
|
||||
| `with_ocm` | :material-check: | Build with OpenAI Codex Multiplexer service support. |
|
||||
| `with_naive_outbound` | :material-check: | Build with NaiveProxy outbound support, see [NaiveProxy outbound](/configuration/outbound/naive/). |
|
||||
| `with_cloudflared` | :material-check: | Build with Cloudflare Tunnel inbound support, see [Cloudflared inbound](/configuration/inbound/cloudflared/). |
|
||||
| `badlinkname` | :material-check: | Enable `go:linkname` access to internal standard library functions. Required because the Go standard library does not expose many low-level APIs needed by this project, and reimplementing them externally is impractical. Used for kTLS (kernel TLS offload) and raw TLS record manipulation. |
|
||||
| `tfogo_checklinkname0` | :material-check: | Companion to `badlinkname`. Go 1.23+ enforces `go:linkname` restrictions via the linker; this tag signals the build uses `-checklinkname=0` to bypass that enforcement. |
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ go build -tags "tag_a tag_b" ./cmd/sing-box
|
||||
| `with_ccm` | :material-check: | 构建 Claude Code Multiplexer 服务支持。 |
|
||||
| `with_ocm` | :material-check: | 构建 OpenAI Codex Multiplexer 服务支持。 |
|
||||
| `with_naive_outbound` | :material-check: | 构建 NaiveProxy 出站支持,参阅 [NaiveProxy 出站](/zh/configuration/outbound/naive/)。 |
|
||||
| `with_cloudflared` | :material-check: | 构建 Cloudflare Tunnel 入站支持,参阅 [Cloudflared 入站](/zh/configuration/inbound/cloudflared/)。 |
|
||||
| `badlinkname` | :material-check: | 启用 `go:linkname` 以访问标准库内部函数。Go 标准库未提供本项目需要的许多底层 API,且在外部重新实现不切实际。用于 kTLS(内核 TLS 卸载)和原始 TLS 记录操作。 |
|
||||
| `tfogo_checklinkname0` | :material-check: | `badlinkname` 的伴随标记。Go 1.23+ 链接器强制限制 `go:linkname` 使用;此标记表示构建使用 `-checklinkname=0` 以绕过该限制。 |
|
||||
|
||||
|
||||
5
go.mod
5
go.mod
@@ -38,6 +38,7 @@ require (
|
||||
github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1
|
||||
github.com/sagernet/quic-go v0.59.0-sing-box-mod.4
|
||||
github.com/sagernet/sing v0.8.5-0.20260404181712-947827ec3849
|
||||
github.com/sagernet/sing-cloudflared v0.0.0-20260407120610-7715dc2523fa
|
||||
github.com/sagernet/sing-mux v0.3.4
|
||||
github.com/sagernet/sing-quic v0.6.2-0.20260330152607-bf674c163212
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8
|
||||
@@ -73,6 +74,7 @@ require (
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.17.0 // indirect
|
||||
github.com/database64128/netx-go v0.1.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
|
||||
@@ -82,6 +84,7 @@ require (
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gaissmai/bart v0.18.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
|
||||
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
@@ -99,6 +102,7 @@ require (
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/mdlayher/socket v0.5.1 // indirect
|
||||
github.com/mitchellh/go-ps v1.0.0 // indirect
|
||||
github.com/philhofer/fwd v1.2.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||
github.com/pires/go-proxyproto v0.8.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
@@ -165,4 +169,5 @@ require (
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/blake3 v1.3.0 // indirect
|
||||
zombiezen.com/go/capnproto2 v2.18.2+incompatible // indirect
|
||||
)
|
||||
|
||||
12
go.sum
12
go.sum
@@ -28,6 +28,8 @@ github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9
|
||||
github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
|
||||
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0=
|
||||
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
||||
github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc=
|
||||
github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
|
||||
@@ -110,6 +112,8 @@ github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zt
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/letsencrypt/challtestsrv v1.4.2 h1:0ON3ldMhZyWlfVNYYpFuWRTmZNnyfiL9Hh5YzC3JVwU=
|
||||
github.com/letsencrypt/challtestsrv v1.4.2/go.mod h1:GhqMqcSoeGpYd5zX5TgwA6er/1MbWzx/o7yuuVya+Wk=
|
||||
github.com/letsencrypt/pebble/v2 v2.10.0 h1:Wq6gYXlsY6ubqI3hhxsTzdyotvfdjFBxuwYqCLCnj/U=
|
||||
@@ -142,6 +146,8 @@ github.com/openai/openai-go/v3 v3.26.0 h1:bRt6H/ozMNt/dDkN4gobnLqaEGrRGBzmbVs0xx
|
||||
github.com/openai/openai-go/v3 v3.26.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
|
||||
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
|
||||
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
|
||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
|
||||
@@ -238,6 +244,8 @@ github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 h1:6qvrUW79S+CrPwWz6cMePXohgj
|
||||
github.com/sagernet/quic-go v0.59.0-sing-box-mod.4/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4=
|
||||
github.com/sagernet/sing v0.8.5-0.20260404181712-947827ec3849 h1:P8jaGN561IbHBxjlU8IGrFK65n1vDOrHo8FOMgHfn14=
|
||||
github.com/sagernet/sing v0.8.5-0.20260404181712-947827ec3849/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-cloudflared v0.0.0-20260407120610-7715dc2523fa h1:165HiOfgfofJIirEp1NGSmsoJAi+++WhR29IhtAu4A4=
|
||||
github.com/sagernet/sing-cloudflared v0.0.0-20260407120610-7715dc2523fa/go.mod h1:bH2NKX+NpDTY1Zkxfboxw6MXB/ZywaNLmrDJYgKMJ2Y=
|
||||
github.com/sagernet/sing-mux v0.3.4 h1:ZQplKl8MNXutjzbMVtWvWG31fohhgOfCuUZR4dVQ8+s=
|
||||
github.com/sagernet/sing-mux v0.3.4/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk=
|
||||
github.com/sagernet/sing-quic v0.6.2-0.20260330152607-bf674c163212 h1:7mFOUqy+DyOj7qKGd1X54UMXbnbJiiMileK/tn17xYc=
|
||||
@@ -294,6 +302,8 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s=
|
||||
github.com/tinylib/msgp v1.6.3/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM=
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA=
|
||||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
@@ -401,3 +411,5 @@ lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
|
||||
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
|
||||
software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k=
|
||||
software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=
|
||||
zombiezen.com/go/capnproto2 v2.18.2+incompatible h1:v3BD1zbruvffn7zjJUU5Pn8nZAB11bhZSQC4W+YnnKo=
|
||||
zombiezen.com/go/capnproto2 v2.18.2+incompatible/go.mod h1:XO5Pr2SbXgqZwn0m0Ru54QBqpOf4K5AYBO+8LAOBQEQ=
|
||||
|
||||
12
include/cloudflared.go
Normal file
12
include/cloudflared.go
Normal file
@@ -0,0 +1,12 @@
|
||||
//go:build with_cloudflared
|
||||
|
||||
package include
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing-box/adapter/inbound"
|
||||
"github.com/sagernet/sing-box/protocol/cloudflare"
|
||||
)
|
||||
|
||||
func registerCloudflaredInbound(registry *inbound.Registry) {
|
||||
cloudflare.RegisterInbound(registry)
|
||||
}
|
||||
20
include/cloudflared_stub.go
Normal file
20
include/cloudflared_stub.go
Normal file
@@ -0,0 +1,20 @@
|
||||
//go:build !with_cloudflared
|
||||
|
||||
package include
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/adapter/inbound"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
|
||||
func registerCloudflaredInbound(registry *inbound.Registry) {
|
||||
inbound.Register[option.CloudflaredInboundOptions](registry, C.TypeCloudflared, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.CloudflaredInboundOptions) (adapter.Inbound, error) {
|
||||
return nil, E.New(`Cloudflared is not included in this build, rebuild with -tags with_cloudflared`)
|
||||
})
|
||||
}
|
||||
@@ -66,6 +66,7 @@ func InboundRegistry() *inbound.Registry {
|
||||
anytls.RegisterInbound(registry)
|
||||
|
||||
registerQUICInbounds(registry)
|
||||
registerCloudflaredInbound(registry)
|
||||
registerStubForRemovedInbounds(registry)
|
||||
|
||||
return registry
|
||||
|
||||
@@ -158,6 +158,7 @@ nav:
|
||||
- Tun: configuration/inbound/tun.md
|
||||
- Redirect: configuration/inbound/redirect.md
|
||||
- TProxy: configuration/inbound/tproxy.md
|
||||
- Cloudflared: configuration/inbound/cloudflared.md
|
||||
- Outbound:
|
||||
- configuration/outbound/index.md
|
||||
- Direct: configuration/outbound/direct.md
|
||||
|
||||
16
option/cloudflared.go
Normal file
16
option/cloudflared.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package option
|
||||
|
||||
import "github.com/sagernet/sing/common/json/badoption"
|
||||
|
||||
type CloudflaredInboundOptions struct {
|
||||
Token string `json:"token,omitempty"`
|
||||
HighAvailabilityConnections int `json:"ha_connections,omitempty"`
|
||||
Protocol string `json:"protocol,omitempty"`
|
||||
PostQuantum bool `json:"post_quantum,omitempty"`
|
||||
EdgeIPVersion int `json:"edge_ip_version,omitempty"`
|
||||
DatagramVersion string `json:"datagram_version,omitempty"`
|
||||
GracePeriod badoption.Duration `json:"grace_period,omitempty"`
|
||||
Region string `json:"region,omitempty"`
|
||||
ControlDialer DialerOptions `json:"control_dialer,omitempty"`
|
||||
TunnelDialer DialerOptions `json:"tunnel_dialer,omitempty"`
|
||||
}
|
||||
160
protocol/cloudflare/inbound.go
Normal file
160
protocol/cloudflare/inbound.go
Normal file
@@ -0,0 +1,160 @@
|
||||
//go:build with_cloudflared
|
||||
|
||||
package cloudflare
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/adapter/inbound"
|
||||
boxDialer "github.com/sagernet/sing-box/common/dialer"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-box/route/rule"
|
||||
cloudflared "github.com/sagernet/sing-cloudflared"
|
||||
tun "github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/pipe"
|
||||
)
|
||||
|
||||
func RegisterInbound(registry *inbound.Registry) {
|
||||
inbound.Register[option.CloudflaredInboundOptions](registry, C.TypeCloudflared, NewInbound)
|
||||
}
|
||||
|
||||
func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.CloudflaredInboundOptions) (adapter.Inbound, error) {
|
||||
controlDialer, err := boxDialer.NewWithOptions(boxDialer.Options{
|
||||
Context: ctx,
|
||||
Options: options.ControlDialer,
|
||||
RemoteIsDomain: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "build cloudflared control dialer")
|
||||
}
|
||||
tunnelDialer, err := boxDialer.NewWithOptions(boxDialer.Options{
|
||||
Context: ctx,
|
||||
Options: options.TunnelDialer,
|
||||
RemoteIsDomain: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "build cloudflared tunnel dialer")
|
||||
}
|
||||
|
||||
service, err := cloudflared.NewService(cloudflared.ServiceOptions{
|
||||
Logger: logger,
|
||||
ConnectionDialer: &routerDialer{router: router, tag: tag},
|
||||
ControlDialer: controlDialer,
|
||||
TunnelDialer: tunnelDialer,
|
||||
ICMPHandler: &icmpRouterHandler{router: router, logger: logger, tag: tag},
|
||||
ConnContext: func(connCtx context.Context) context.Context {
|
||||
return adapter.WithContext(connCtx, &adapter.InboundContext{
|
||||
Inbound: tag,
|
||||
InboundType: C.TypeCloudflared,
|
||||
})
|
||||
},
|
||||
Token: options.Token,
|
||||
HAConnections: options.HighAvailabilityConnections,
|
||||
Protocol: options.Protocol,
|
||||
PostQuantum: options.PostQuantum,
|
||||
EdgeIPVersion: options.EdgeIPVersion,
|
||||
DatagramVersion: options.DatagramVersion,
|
||||
GracePeriod: time.Duration(options.GracePeriod),
|
||||
Region: options.Region,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Inbound{
|
||||
Adapter: inbound.NewAdapter(C.TypeCloudflared, tag),
|
||||
service: service,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Inbound struct {
|
||||
inbound.Adapter
|
||||
service *cloudflared.Service
|
||||
}
|
||||
|
||||
func (i *Inbound) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
return i.service.Start()
|
||||
}
|
||||
|
||||
func (i *Inbound) Close() error {
|
||||
return i.service.Close()
|
||||
}
|
||||
|
||||
type routerDialer struct {
|
||||
router adapter.Router
|
||||
tag string
|
||||
}
|
||||
|
||||
func (d *routerDialer) newMetadata(network string, destination M.Socksaddr) adapter.InboundContext {
|
||||
return adapter.InboundContext{
|
||||
Inbound: d.tag,
|
||||
InboundType: C.TypeCloudflared,
|
||||
Network: network,
|
||||
Destination: destination,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *routerDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
input, output := pipe.Pipe()
|
||||
go d.router.RouteConnectionEx(ctx, output, d.newMetadata(N.NetworkTCP, destination), N.OnceClose(func(it error) {
|
||||
input.Close()
|
||||
}))
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (d *routerDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
input, output := pipe.Pipe()
|
||||
routerConn := bufio.NewUnbindPacketConn(output)
|
||||
go d.router.RoutePacketConnectionEx(ctx, routerConn, d.newMetadata(N.NetworkUDP, destination), N.OnceClose(func(it error) {
|
||||
input.Close()
|
||||
}))
|
||||
return bufio.NewUnbindPacketConn(input), nil
|
||||
}
|
||||
|
||||
type icmpRouterHandler struct {
|
||||
router adapter.Router
|
||||
logger log.ContextLogger
|
||||
tag string
|
||||
}
|
||||
|
||||
func (h *icmpRouterHandler) RouteICMPConnection(ctx context.Context, session tun.DirectRouteSession, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
|
||||
var ipVersion uint8
|
||||
if session.Destination.Is4() {
|
||||
ipVersion = 4
|
||||
} else {
|
||||
ipVersion = 6
|
||||
}
|
||||
destination := M.SocksaddrFrom(session.Destination, 0)
|
||||
routeDestination, err := h.router.PreMatch(adapter.InboundContext{
|
||||
Inbound: h.tag,
|
||||
InboundType: C.TypeCloudflared,
|
||||
IPVersion: ipVersion,
|
||||
Network: N.NetworkICMP,
|
||||
Source: M.SocksaddrFrom(session.Source, 0),
|
||||
Destination: destination,
|
||||
OriginDestination: destination,
|
||||
}, routeContext, timeout, false)
|
||||
if err != nil {
|
||||
switch {
|
||||
case rule.IsBypassed(err):
|
||||
err = nil
|
||||
case rule.IsRejected(err):
|
||||
h.logger.Trace("reject ICMP connection from ", session.Source, " to ", session.Destination)
|
||||
default:
|
||||
h.logger.Warn(E.Cause(err, "link ICMP connection from ", session.Source, " to ", session.Destination))
|
||||
}
|
||||
}
|
||||
return routeDestination, err
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_naive_outbound,badlinkname,tfogo_checklinkname0
|
||||
with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_cloudflared,with_naive_outbound,badlinkname,tfogo_checklinkname0
|
||||
@@ -1 +1 @@
|
||||
with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,badlinkname,tfogo_checklinkname0
|
||||
with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_cloudflared,badlinkname,tfogo_checklinkname0
|
||||
@@ -1 +1 @@
|
||||
with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_naive_outbound,with_purego,badlinkname,tfogo_checklinkname0
|
||||
with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_cloudflared,with_naive_outbound,with_purego,badlinkname,tfogo_checklinkname0
|
||||
Reference in New Issue
Block a user