tailscale: Add system interface support
This commit is contained in:
@@ -4,8 +4,11 @@ icon: material/new-box
|
|||||||
|
|
||||||
!!! quote "Changes in sing-box 1.13.0"
|
!!! quote "Changes in sing-box 1.13.0"
|
||||||
|
|
||||||
:material-plus: [relay_server_port](#relay_server_port)
|
:material-plus: [relay_server_port](#relay_server_port)
|
||||||
:material-plus: [relay_server_static_endpoints](#relay_server_static_endpoints)
|
:material-plus: [relay_server_static_endpoints](#relay_server_static_endpoints)
|
||||||
|
:material-plus: [system_interface](#system_interface)
|
||||||
|
:material-plus: [system_interface_name](#system_interface_name)
|
||||||
|
:material-plus: [system_interface_mtu](#system_interface_mtu)
|
||||||
|
|
||||||
!!! question "Since sing-box 1.12.0"
|
!!! question "Since sing-box 1.12.0"
|
||||||
|
|
||||||
@@ -27,8 +30,11 @@ icon: material/new-box
|
|||||||
"advertise_exit_node": false,
|
"advertise_exit_node": false,
|
||||||
"relay_server_port": 0,
|
"relay_server_port": 0,
|
||||||
"relay_server_static_endpoints": [],
|
"relay_server_static_endpoints": [],
|
||||||
|
"system_interface": false,
|
||||||
|
"system_interface_name": "",
|
||||||
|
"system_interface_mtu": 0,
|
||||||
"udp_timeout": "5m",
|
"udp_timeout": "5m",
|
||||||
|
|
||||||
... // Dial Fields
|
... // Dial Fields
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -98,12 +104,34 @@ Indicates whether the node should advertise itself as an exit node.
|
|||||||
|
|
||||||
#### relay_server_port
|
#### relay_server_port
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.13.0"
|
||||||
|
|
||||||
The port to listen on for incoming relay connections from other Tailscale nodes.
|
The port to listen on for incoming relay connections from other Tailscale nodes.
|
||||||
|
|
||||||
#### relay_server_static_endpoints
|
#### relay_server_static_endpoints
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.13.0"
|
||||||
|
|
||||||
Static endpoints to advertise for the relay server.
|
Static endpoints to advertise for the relay server.
|
||||||
|
|
||||||
|
#### system_interface
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.13.0"
|
||||||
|
|
||||||
|
Create a system TUN interface for Tailscale.
|
||||||
|
|
||||||
|
#### system_interface_name
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.13.0"
|
||||||
|
|
||||||
|
Custom TUN interface name. By default, `tailscale` (or `utun` on macOS) will be used.
|
||||||
|
|
||||||
|
#### system_interface_mtu
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.13.0"
|
||||||
|
|
||||||
|
Override the TUN MTU. By default, Tailscale's own MTU is used.
|
||||||
|
|
||||||
#### udp_timeout
|
#### udp_timeout
|
||||||
|
|
||||||
UDP NAT expiration time.
|
UDP NAT expiration time.
|
||||||
|
|||||||
@@ -4,8 +4,11 @@ icon: material/new-box
|
|||||||
|
|
||||||
!!! quote "sing-box 1.13.0 中的更改"
|
!!! quote "sing-box 1.13.0 中的更改"
|
||||||
|
|
||||||
:material-plus: [relay_server_port](#relay_server_port)
|
:material-plus: [relay_server_port](#relay_server_port)
|
||||||
:material-plus: [relay_server_static_endpoints](#relay_server_static_endpoints)
|
:material-plus: [relay_server_static_endpoints](#relay_server_static_endpoints)
|
||||||
|
:material-plus: [system_interface](#system_interface)
|
||||||
|
:material-plus: [system_interface_name](#system_interface_name)
|
||||||
|
:material-plus: [system_interface_mtu](#system_interface_mtu)
|
||||||
|
|
||||||
!!! question "自 sing-box 1.12.0 起"
|
!!! question "自 sing-box 1.12.0 起"
|
||||||
|
|
||||||
@@ -27,6 +30,9 @@ icon: material/new-box
|
|||||||
"advertise_exit_node": false,
|
"advertise_exit_node": false,
|
||||||
"relay_server_port": 0,
|
"relay_server_port": 0,
|
||||||
"relay_server_static_endpoints": [],
|
"relay_server_static_endpoints": [],
|
||||||
|
"system_interface": false,
|
||||||
|
"system_interface_name": "",
|
||||||
|
"system_interface_mtu": 0,
|
||||||
"udp_timeout": "5m",
|
"udp_timeout": "5m",
|
||||||
|
|
||||||
... // 拨号字段
|
... // 拨号字段
|
||||||
@@ -97,12 +103,34 @@ icon: material/new-box
|
|||||||
|
|
||||||
#### relay_server_port
|
#### relay_server_port
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.13.0 起"
|
||||||
|
|
||||||
监听来自其他 Tailscale 节点的中继连接的端口。
|
监听来自其他 Tailscale 节点的中继连接的端口。
|
||||||
|
|
||||||
#### relay_server_static_endpoints
|
#### relay_server_static_endpoints
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.13.0 起"
|
||||||
|
|
||||||
为中继服务器通告的静态端点。
|
为中继服务器通告的静态端点。
|
||||||
|
|
||||||
|
#### system_interface
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.13.0 起"
|
||||||
|
|
||||||
|
为 Tailscale 创建系统 TUN 接口。
|
||||||
|
|
||||||
|
#### system_interface_name
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.13.0 起"
|
||||||
|
|
||||||
|
自定义 TUN 接口名。默认使用 `tailscale`(macOS 上为 `utun`)。
|
||||||
|
|
||||||
|
#### system_interface_mtu
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.13.0 起"
|
||||||
|
|
||||||
|
覆盖 TUN 的 MTU。默认使用 Tailscale 自己的 MTU。
|
||||||
|
|
||||||
#### udp_timeout
|
#### udp_timeout
|
||||||
|
|
||||||
UDP NAT 过期时间。
|
UDP NAT 过期时间。
|
||||||
@@ -115,4 +143,4 @@ UDP NAT 过期时间。
|
|||||||
|
|
||||||
Tailscale 端点中的拨号字段仅控制它如何连接到控制平面,与实际连接无关。
|
Tailscale 端点中的拨号字段仅控制它如何连接到控制平面,与实际连接无关。
|
||||||
|
|
||||||
参阅 [拨号字段](/zh/configuration/shared/dial/) 了解详情。
|
参阅 [拨号字段](/zh/configuration/shared/dial/) 了解详情。
|
||||||
|
|||||||
7
go.mod
7
go.mod
@@ -38,10 +38,10 @@ require (
|
|||||||
github.com/sagernet/sing-shadowsocks v0.2.8
|
github.com/sagernet/sing-shadowsocks v0.2.8
|
||||||
github.com/sagernet/sing-shadowsocks2 v0.2.1
|
github.com/sagernet/sing-shadowsocks2 v0.2.1
|
||||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
|
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
|
||||||
github.com/sagernet/sing-tun v0.8.0-beta.11.0.20251230194736-a5db80d71081
|
github.com/sagernet/sing-tun v0.8.0-beta.11.0.20260107060547-525f783d005b
|
||||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1
|
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1
|
||||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1
|
github.com/sagernet/smux v1.5.50-sing-box-mod.1
|
||||||
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.4
|
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.5
|
||||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288
|
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288
|
||||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
||||||
github.com/spf13/cobra v1.10.2
|
github.com/spf13/cobra v1.10.2
|
||||||
@@ -68,6 +68,7 @@ require (
|
|||||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||||
github.com/caddyserver/zerossl v0.1.3 // indirect
|
github.com/caddyserver/zerossl v0.1.3 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.3.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/database64128/netx-go v0.1.1 // indirect
|
github.com/database64128/netx-go v0.1.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
|
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
|
||||||
@@ -85,6 +86,7 @@ require (
|
|||||||
github.com/google/btree v1.1.3 // indirect
|
github.com/google/btree v1.1.3 // indirect
|
||||||
github.com/google/go-cmp v0.7.0 // indirect
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
|
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/hashicorp/yamux v0.1.2 // indirect
|
github.com/hashicorp/yamux v0.1.2 // indirect
|
||||||
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
|
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
|
||||||
@@ -131,6 +133,7 @@ require (
|
|||||||
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect
|
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect
|
||||||
github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect
|
github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect
|
||||||
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a // indirect
|
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a // indirect
|
||||||
|
github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 // indirect
|
||||||
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect
|
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect
|
||||||
github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 // indirect
|
github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 // indirect
|
||||||
github.com/tidwall/gjson v1.18.0 // indirect
|
github.com/tidwall/gjson v1.18.0 // indirect
|
||||||
|
|||||||
17
go.sum
17
go.sum
@@ -22,6 +22,8 @@ github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk=
|
|||||||
github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso=
|
github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso=
|
||||||
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
|
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
|
||||||
github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
|
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/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
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 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||||
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
|
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
|
||||||
@@ -79,6 +81,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
|||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
|
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdFk6Vl1yPGtSRtwGpVkWyZww1OCil2MI=
|
||||||
|
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
|
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
|
||||||
@@ -216,14 +220,14 @@ github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnq
|
|||||||
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w=
|
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w=
|
||||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
|
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
|
||||||
github.com/sagernet/sing-tun v0.8.0-beta.11.0.20251230194736-a5db80d71081 h1:ZFw+y1RIKasXENuy8jOYfwpyiKBh92HcSqzDFQLd7Yc=
|
github.com/sagernet/sing-tun v0.8.0-beta.11.0.20260107060547-525f783d005b h1:MqPEFejgxqechqBn1OkL+9JPW0W4AiGCI0Y1JhglIlQ=
|
||||||
github.com/sagernet/sing-tun v0.8.0-beta.11.0.20251230194736-a5db80d71081/go.mod h1:+HAK/y9GZljdT0KYKMYDR8MjjqnqDDQZYp5ZZQoRzS8=
|
github.com/sagernet/sing-tun v0.8.0-beta.11.0.20260107060547-525f783d005b/go.mod h1:+HAK/y9GZljdT0KYKMYDR8MjjqnqDDQZYp5ZZQoRzS8=
|
||||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 h1:aSwUNYUkVyVvdmBSufR8/nRFonwJeKSIROxHcm5br9o=
|
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 h1:aSwUNYUkVyVvdmBSufR8/nRFonwJeKSIROxHcm5br9o=
|
||||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1/go.mod h1:P11scgTxMxVVQ8dlM27yNm3Cro40mD0+gHbnqrNGDuY=
|
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1/go.mod h1:P11scgTxMxVVQ8dlM27yNm3Cro40mD0+gHbnqrNGDuY=
|
||||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478=
|
github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478=
|
||||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1/go.mod h1:NjhsCEWedJm7eFLyhuBgIEzwfhRmytrUoiLluxs5Sk8=
|
github.com/sagernet/smux v1.5.50-sing-box-mod.1/go.mod h1:NjhsCEWedJm7eFLyhuBgIEzwfhRmytrUoiLluxs5Sk8=
|
||||||
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.4 h1:p+9JllOL5Q2pj6bmP9gu+LdjyRg/XxHLTpMfuhuQsY4=
|
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.5 h1:nn9or1e5sTDXay/dfsB4E/A4jYaYdPVCXV8mME/maEc=
|
||||||
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.4/go.mod h1:HZxL3asFIkcIJtHdnqsdcXsY6d+1iMtq0SPUlX17TGM=
|
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.5/go.mod h1:m87GAn4UcesHQF3leaPFEINZETO5za1LGn1GJdNDgNc=
|
||||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288 h1:E2tZFeg9mGYGQ7E7BbxMv1cU35HxwgRm6tPKI2Pp7DA=
|
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288 h1:E2tZFeg9mGYGQ7E7BbxMv1cU35HxwgRm6tPKI2Pp7DA=
|
||||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288/go.mod h1:WUxgxUDZoCF2sxVmW+STSxatP02Qn3FcafTiI2BLtE0=
|
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288/go.mod h1:WUxgxUDZoCF2sxVmW+STSxatP02Qn3FcafTiI2BLtE0=
|
||||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
||||||
@@ -244,6 +248,8 @@ github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 h1:4chzWmimtJPx
|
|||||||
github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05/go.mod h1:PdCqy9JzfWMJf1H5UJW2ip33/d4YkoKN0r67yKH1mG8=
|
github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05/go.mod h1:PdCqy9JzfWMJf1H5UJW2ip33/d4YkoKN0r67yKH1mG8=
|
||||||
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw=
|
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw=
|
||||||
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8=
|
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8=
|
||||||
|
github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 h1:uFsXVBE9Qr4ZoF094vE6iYTLDl0qCiKzYXlL6UeWObU=
|
||||||
|
github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7/go.mod h1:NzVQi3Mleb+qzq8VmcWpSkcSYxXIg0DkI6XDzpVkhJ0=
|
||||||
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc h1:24heQPtnFR+yfntqhI3oAu9i27nEojcQ4NuBQOo5ZFA=
|
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc h1:24heQPtnFR+yfntqhI3oAu9i27nEojcQ4NuBQOo5ZFA=
|
||||||
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc/go.mod h1:f93CXfllFsO9ZQVq+Zocb1Gp4G5Fz0b0rXHLOzt/Djc=
|
github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc/go.mod h1:f93CXfllFsO9ZQVq+Zocb1Gp4G5Fz0b0rXHLOzt/Djc=
|
||||||
github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 h1:UBPHPtv8+nEAy2PD8RyAhOYvau1ek0HDJqLS/Pysi14=
|
github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 h1:UBPHPtv8+nEAy2PD8RyAhOYvau1ek0HDJqLS/Pysi14=
|
||||||
@@ -262,6 +268,7 @@ 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/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM=
|
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM=
|
||||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA=
|
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=
|
||||||
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
@@ -315,6 +322,8 @@ golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwE
|
|||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
|
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ type TailscaleEndpointOptions struct {
|
|||||||
AdvertiseExitNode bool `json:"advertise_exit_node,omitempty"`
|
AdvertiseExitNode bool `json:"advertise_exit_node,omitempty"`
|
||||||
RelayServerPort *uint16 `json:"relay_server_port,omitempty"`
|
RelayServerPort *uint16 `json:"relay_server_port,omitempty"`
|
||||||
RelayServerStaticEndpoints []netip.AddrPort `json:"relay_server_static_endpoints,omitempty"`
|
RelayServerStaticEndpoints []netip.AddrPort `json:"relay_server_static_endpoints,omitempty"`
|
||||||
|
SystemInterface bool `json:"system_interface,omitempty"`
|
||||||
|
SystemInterfaceName string `json:"system_interface_name,omitempty"`
|
||||||
|
SystemInterfaceMTU uint32 `json:"system_interface_mtu,omitempty"`
|
||||||
UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"`
|
UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ import (
|
|||||||
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
||||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||||
"github.com/sagernet/gvisor/pkg/tcpip/transport/icmp"
|
"github.com/sagernet/gvisor/pkg/tcpip/transport/icmp"
|
||||||
"github.com/sagernet/gvisor/pkg/tcpip/transport/tcp"
|
|
||||||
"github.com/sagernet/gvisor/pkg/tcpip/transport/udp"
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/adapter/endpoint"
|
"github.com/sagernet/sing-box/adapter/endpoint"
|
||||||
"github.com/sagernet/sing-box/common/dialer"
|
"github.com/sagernet/sing-box/common/dialer"
|
||||||
@@ -49,8 +47,10 @@ import (
|
|||||||
tsDNS "github.com/sagernet/tailscale/net/dns"
|
tsDNS "github.com/sagernet/tailscale/net/dns"
|
||||||
"github.com/sagernet/tailscale/net/netmon"
|
"github.com/sagernet/tailscale/net/netmon"
|
||||||
"github.com/sagernet/tailscale/net/tsaddr"
|
"github.com/sagernet/tailscale/net/tsaddr"
|
||||||
|
tsTUN "github.com/sagernet/tailscale/net/tstun"
|
||||||
"github.com/sagernet/tailscale/tsnet"
|
"github.com/sagernet/tailscale/tsnet"
|
||||||
"github.com/sagernet/tailscale/types/ipproto"
|
"github.com/sagernet/tailscale/types/ipproto"
|
||||||
|
"github.com/sagernet/tailscale/types/nettype"
|
||||||
"github.com/sagernet/tailscale/version"
|
"github.com/sagernet/tailscale/version"
|
||||||
"github.com/sagernet/tailscale/wgengine"
|
"github.com/sagernet/tailscale/wgengine"
|
||||||
"github.com/sagernet/tailscale/wgengine/filter"
|
"github.com/sagernet/tailscale/wgengine/filter"
|
||||||
@@ -101,6 +101,51 @@ type Endpoint struct {
|
|||||||
relayServerStaticEndpoints []netip.AddrPort
|
relayServerStaticEndpoints []netip.AddrPort
|
||||||
|
|
||||||
udpTimeout time.Duration
|
udpTimeout time.Duration
|
||||||
|
|
||||||
|
systemInterface bool
|
||||||
|
systemInterfaceName string
|
||||||
|
systemInterfaceMTU uint32
|
||||||
|
systemTun tun.Tun
|
||||||
|
fallbackTCPCloser func()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Endpoint) registerNetstackHandlers() {
|
||||||
|
netstack := t.server.ExportNetstack()
|
||||||
|
if netstack == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
previousTCP := netstack.GetTCPHandlerForFlow
|
||||||
|
netstack.GetTCPHandlerForFlow = func(src, dst netip.AddrPort) (handler func(net.Conn), intercept bool) {
|
||||||
|
if previousTCP != nil {
|
||||||
|
handler, intercept = previousTCP(src, dst)
|
||||||
|
if handler != nil || !intercept {
|
||||||
|
return handler, intercept
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return func(conn net.Conn) {
|
||||||
|
ctx := log.ContextWithNewID(t.ctx)
|
||||||
|
source := M.SocksaddrFrom(src.Addr(), src.Port())
|
||||||
|
destination := M.SocksaddrFrom(dst.Addr(), dst.Port())
|
||||||
|
t.NewConnectionEx(ctx, conn, source, destination, nil)
|
||||||
|
}, true
|
||||||
|
}
|
||||||
|
|
||||||
|
previousUDP := netstack.GetUDPHandlerForFlow
|
||||||
|
netstack.GetUDPHandlerForFlow = func(src, dst netip.AddrPort) (handler func(nettype.ConnPacketConn), intercept bool) {
|
||||||
|
if previousUDP != nil {
|
||||||
|
handler, intercept = previousUDP(src, dst)
|
||||||
|
if handler != nil || !intercept {
|
||||||
|
return handler, intercept
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return func(conn nettype.ConnPacketConn) {
|
||||||
|
ctx := log.ContextWithNewID(t.ctx)
|
||||||
|
source := M.SocksaddrFrom(src.Addr(), src.Port())
|
||||||
|
destination := M.SocksaddrFrom(dst.Addr(), dst.Port())
|
||||||
|
packetConn := bufio.NewPacketConn(conn)
|
||||||
|
t.NewPacketConnectionEx(ctx, packetConn, source, destination, nil)
|
||||||
|
}, true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TailscaleEndpointOptions) (adapter.Endpoint, error) {
|
func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TailscaleEndpointOptions) (adapter.Endpoint, error) {
|
||||||
@@ -202,6 +247,9 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||||||
relayServerPort: options.RelayServerPort,
|
relayServerPort: options.RelayServerPort,
|
||||||
relayServerStaticEndpoints: options.RelayServerStaticEndpoints,
|
relayServerStaticEndpoints: options.RelayServerStaticEndpoints,
|
||||||
udpTimeout: udpTimeout,
|
udpTimeout: udpTimeout,
|
||||||
|
systemInterface: options.SystemInterface,
|
||||||
|
systemInterfaceName: options.SystemInterfaceName,
|
||||||
|
systemInterfaceMTU: options.SystemInterfaceMTU,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,10 +285,59 @@ func (t *Endpoint) Start(stage adapter.StartStage) error {
|
|||||||
setAndroidProtectFunc(t.platformInterface)
|
setAndroidProtectFunc(t.platformInterface)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if t.systemInterface {
|
||||||
|
mtu := t.systemInterfaceMTU
|
||||||
|
if mtu == 0 {
|
||||||
|
mtu = uint32(tsTUN.DefaultTUNMTU())
|
||||||
|
}
|
||||||
|
tunName := t.systemInterfaceName
|
||||||
|
if tunName == "" {
|
||||||
|
tunName = tun.CalculateInterfaceName("tailscale")
|
||||||
|
}
|
||||||
|
tunOptions := tun.Options{
|
||||||
|
Name: tunName,
|
||||||
|
MTU: mtu,
|
||||||
|
GSO: true,
|
||||||
|
InterfaceScope: true,
|
||||||
|
InterfaceMonitor: t.network.InterfaceMonitor(),
|
||||||
|
InterfaceFinder: t.network.InterfaceFinder(),
|
||||||
|
Logger: t.logger,
|
||||||
|
EXP_ExternalConfiguration: true,
|
||||||
|
}
|
||||||
|
systemTun, err := tun.New(tunOptions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = systemTun.Start()
|
||||||
|
if err != nil {
|
||||||
|
_ = systemTun.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
wgTunDevice, err := newTunDeviceAdapter(systemTun, int(mtu), t.logger)
|
||||||
|
if err != nil {
|
||||||
|
_ = systemTun.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t.systemTun = systemTun
|
||||||
|
t.server.TunDevice = wgTunDevice
|
||||||
|
}
|
||||||
err := t.server.Start()
|
err := t.server.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if t.systemTun != nil {
|
||||||
|
_ = t.systemTun.Close()
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if t.fallbackTCPCloser == nil {
|
||||||
|
t.fallbackTCPCloser = t.server.RegisterFallbackTCPHandler(func(src, dst netip.AddrPort) (handler func(net.Conn), intercept bool) {
|
||||||
|
return func(conn net.Conn) {
|
||||||
|
ctx := log.ContextWithNewID(t.ctx)
|
||||||
|
source := M.SocksaddrFrom(src.Addr(), src.Port())
|
||||||
|
destination := M.SocksaddrFrom(dst.Addr(), dst.Port())
|
||||||
|
t.NewConnectionEx(ctx, conn, source, destination, nil)
|
||||||
|
}, true
|
||||||
|
})
|
||||||
|
}
|
||||||
t.server.ExportLocalBackend().ExportEngine().(wgengine.ExportedUserspaceEngine).SetOnReconfigListener(t.onReconfig)
|
t.server.ExportLocalBackend().ExportEngine().(wgengine.ExportedUserspaceEngine).SetOnReconfigListener(t.onReconfig)
|
||||||
|
|
||||||
ipStack := t.server.ExportNetstack().ExportIPStack()
|
ipStack := t.server.ExportNetstack().ExportIPStack()
|
||||||
@@ -252,13 +349,12 @@ func (t *Endpoint) Start(stage adapter.StartStage) error {
|
|||||||
if gErr != nil {
|
if gErr != nil {
|
||||||
return gonet.TranslateNetstackError(gErr)
|
return gonet.TranslateNetstackError(gErr)
|
||||||
}
|
}
|
||||||
ipStack.SetTransportProtocolHandler(tcp.ProtocolNumber, tun.NewTCPForwarder(t.ctx, ipStack, t).HandlePacket)
|
|
||||||
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, tun.NewUDPForwarder(t.ctx, ipStack, t, t.udpTimeout).HandlePacket)
|
|
||||||
icmpForwarder := tun.NewICMPForwarder(t.ctx, ipStack, t, t.udpTimeout)
|
icmpForwarder := tun.NewICMPForwarder(t.ctx, ipStack, t, t.udpTimeout)
|
||||||
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber4, icmpForwarder.HandlePacket)
|
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber4, icmpForwarder.HandlePacket)
|
||||||
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber6, icmpForwarder.HandlePacket)
|
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber6, icmpForwarder.HandlePacket)
|
||||||
t.stack = ipStack
|
t.stack = ipStack
|
||||||
t.icmpForwarder = icmpForwarder
|
t.icmpForwarder = icmpForwarder
|
||||||
|
t.registerNetstackHandlers()
|
||||||
|
|
||||||
localBackend := t.server.ExportLocalBackend()
|
localBackend := t.server.ExportLocalBackend()
|
||||||
perfs := &ipn.MaskedPrefs{
|
perfs := &ipn.MaskedPrefs{
|
||||||
@@ -355,6 +451,10 @@ func (t *Endpoint) Close() error {
|
|||||||
if runtime.GOOS == "android" {
|
if runtime.GOOS == "android" {
|
||||||
setAndroidProtectFunc(nil)
|
setAndroidProtectFunc(nil)
|
||||||
}
|
}
|
||||||
|
if t.fallbackTCPCloser != nil {
|
||||||
|
t.fallbackTCPCloser()
|
||||||
|
t.fallbackTCPCloser = nil
|
||||||
|
}
|
||||||
return common.Close(common.PtrOrNil(t.server))
|
return common.Close(common.PtrOrNil(t.server))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
156
protocol/tailscale/tun_device_unix.go
Normal file
156
protocol/tailscale/tun_device_unix.go
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package tailscale
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
singTun "github.com/sagernet/sing-tun"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
|
wgTun "github.com/sagernet/wireguard-go/tun"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tunDeviceAdapter struct {
|
||||||
|
tun singTun.Tun
|
||||||
|
linuxTUN singTun.LinuxTUN
|
||||||
|
events chan wgTun.Event
|
||||||
|
mtu int
|
||||||
|
logger logger.ContextLogger
|
||||||
|
debugTun bool
|
||||||
|
readCount atomic.Uint32
|
||||||
|
writeCount atomic.Uint32
|
||||||
|
closeOnce sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTunDeviceAdapter(tun singTun.Tun, mtu int, logger logger.ContextLogger) (wgTun.Device, error) {
|
||||||
|
if tun == nil {
|
||||||
|
return nil, os.ErrInvalid
|
||||||
|
}
|
||||||
|
if mtu == 0 {
|
||||||
|
mtu = 1500
|
||||||
|
}
|
||||||
|
adapter := &tunDeviceAdapter{
|
||||||
|
tun: tun,
|
||||||
|
events: make(chan wgTun.Event, 1),
|
||||||
|
mtu: mtu,
|
||||||
|
logger: logger,
|
||||||
|
debugTun: os.Getenv("SINGBOX_TS_TUN_DEBUG") != "",
|
||||||
|
}
|
||||||
|
if linuxTUN, ok := tun.(singTun.LinuxTUN); ok {
|
||||||
|
adapter.linuxTUN = linuxTUN
|
||||||
|
}
|
||||||
|
adapter.events <- wgTun.EventUp
|
||||||
|
return adapter, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) File() *os.File {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) Read(bufs [][]byte, sizes []int, offset int) (count int, err error) {
|
||||||
|
if a.linuxTUN != nil {
|
||||||
|
n, err := a.linuxTUN.BatchRead(bufs, offset-singTun.PacketOffset, sizes)
|
||||||
|
if err == nil {
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
a.debugPacket("read", bufs[i][offset:offset+sizes[i]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
if offset < singTun.PacketOffset {
|
||||||
|
return 0, io.ErrShortBuffer
|
||||||
|
}
|
||||||
|
readBuf := bufs[0][offset-singTun.PacketOffset:]
|
||||||
|
n, err := a.tun.Read(readBuf)
|
||||||
|
if err == nil {
|
||||||
|
if n < singTun.PacketOffset {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
sizes[0] = n - singTun.PacketOffset
|
||||||
|
a.debugPacket("read", readBuf[singTun.PacketOffset:n])
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
if errors.Is(err, singTun.ErrTooManySegments) {
|
||||||
|
err = wgTun.ErrTooManySegments
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) Write(bufs [][]byte, offset int) (count int, err error) {
|
||||||
|
if a.linuxTUN != nil {
|
||||||
|
for i := range bufs {
|
||||||
|
a.debugPacket("write", bufs[i][offset:])
|
||||||
|
}
|
||||||
|
return a.linuxTUN.BatchWrite(bufs, offset)
|
||||||
|
}
|
||||||
|
for _, packet := range bufs {
|
||||||
|
a.debugPacket("write", packet[offset:])
|
||||||
|
if singTun.PacketOffset > 0 {
|
||||||
|
common.ClearArray(packet[offset-singTun.PacketOffset : offset])
|
||||||
|
singTun.PacketFillHeader(packet[offset-singTun.PacketOffset:], singTun.PacketIPVersion(packet[offset:]))
|
||||||
|
}
|
||||||
|
_, err = a.tun.Write(packet[offset-singTun.PacketOffset:])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// WireGuard will not read count.
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) MTU() (int, error) {
|
||||||
|
return a.mtu, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) Name() (string, error) {
|
||||||
|
return a.tun.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) Events() <-chan wgTun.Event {
|
||||||
|
return a.events
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) Close() error {
|
||||||
|
var err error
|
||||||
|
a.closeOnce.Do(func() {
|
||||||
|
close(a.events)
|
||||||
|
err = a.tun.Close()
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) BatchSize() int {
|
||||||
|
if a.linuxTUN != nil {
|
||||||
|
return a.linuxTUN.BatchSize()
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) debugPacket(direction string, packet []byte) {
|
||||||
|
if !a.debugTun || a.logger == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var counter *atomic.Uint32
|
||||||
|
switch direction {
|
||||||
|
case "read":
|
||||||
|
counter = &a.readCount
|
||||||
|
case "write":
|
||||||
|
counter = &a.writeCount
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if counter.Add(1) > 8 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sample := packet
|
||||||
|
if len(sample) > 64 {
|
||||||
|
sample = sample[:64]
|
||||||
|
}
|
||||||
|
a.logger.Trace("tailscale tun ", direction, " len=", len(packet), " head=", hex.EncodeToString(sample))
|
||||||
|
}
|
||||||
117
protocol/tailscale/tun_device_windows.go
Normal file
117
protocol/tailscale/tun_device_windows.go
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package tailscale
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
|
singTun "github.com/sagernet/sing-tun"
|
||||||
|
"github.com/sagernet/sing/common/logger"
|
||||||
|
wgTun "github.com/sagernet/wireguard-go/tun"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tunDeviceAdapter struct {
|
||||||
|
tun singTun.WinTun
|
||||||
|
nativeTun *singTun.NativeTun
|
||||||
|
events chan wgTun.Event
|
||||||
|
mtu atomic.Int64
|
||||||
|
closeOnce sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTunDeviceAdapter(tun singTun.Tun, mtu int, _ logger.ContextLogger) (wgTun.Device, error) {
|
||||||
|
winTun, ok := tun.(singTun.WinTun)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("not a windows tun device")
|
||||||
|
}
|
||||||
|
nativeTun, ok := winTun.(*singTun.NativeTun)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("unsupported windows tun device")
|
||||||
|
}
|
||||||
|
if mtu == 0 {
|
||||||
|
mtu = 1500
|
||||||
|
}
|
||||||
|
adapter := &tunDeviceAdapter{
|
||||||
|
tun: winTun,
|
||||||
|
nativeTun: nativeTun,
|
||||||
|
events: make(chan wgTun.Event, 1),
|
||||||
|
}
|
||||||
|
adapter.mtu.Store(int64(mtu))
|
||||||
|
adapter.events <- wgTun.EventUp
|
||||||
|
return adapter, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) File() *os.File {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) Read(bufs [][]byte, sizes []int, offset int) (count int, err error) {
|
||||||
|
packet, release, err := a.tun.ReadPacket()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer release()
|
||||||
|
sizes[0] = copy(bufs[0][offset-singTun.PacketOffset:], packet)
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) Write(bufs [][]byte, offset int) (count int, err error) {
|
||||||
|
for _, packet := range bufs {
|
||||||
|
if singTun.PacketOffset > 0 {
|
||||||
|
singTun.PacketFillHeader(packet[offset-singTun.PacketOffset:], singTun.PacketIPVersion(packet[offset:]))
|
||||||
|
}
|
||||||
|
_, err = a.tun.Write(packet[offset-singTun.PacketOffset:])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) MTU() (int, error) {
|
||||||
|
return int(a.mtu.Load()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) ForceMTU(mtu int) {
|
||||||
|
if mtu <= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
update := int(a.mtu.Load()) != mtu
|
||||||
|
a.mtu.Store(int64(mtu))
|
||||||
|
if update {
|
||||||
|
select {
|
||||||
|
case a.events <- wgTun.EventMTUUpdate:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) LUID() uint64 {
|
||||||
|
if a.nativeTun == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return a.nativeTun.LUID()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) Name() (string, error) {
|
||||||
|
return a.tun.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) Events() <-chan wgTun.Event {
|
||||||
|
return a.events
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) Close() error {
|
||||||
|
var err error
|
||||||
|
a.closeOnce.Do(func() {
|
||||||
|
close(a.events)
|
||||||
|
err = a.tun.Close()
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *tunDeviceAdapter) BatchSize() int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user