mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-11-10 21:21:02 +08:00
Remove dependency on gVisor
This commit is contained in:
68 files changed
+770
-1805
No files matched your search
@@ -2,7 +2,6 @@ version: "2"
|
||||
run:
|
||||
go: "1.24"
|
||||
build-tags:
|
||||
- with_gvisor
|
||||
- with_quic
|
||||
- with_dhcp
|
||||
- with_wireguard
|
||||
|
||||
@@ -63,7 +63,7 @@ func init() {
|
||||
sharedFlags = append(sharedFlags, "-ldflags", build_shared.LinkerFlags(currentTag, false))
|
||||
debugFlags = append(debugFlags, "-ldflags", build_shared.LinkerFlags(currentTag, true))
|
||||
|
||||
sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_utls", "with_naive_outbound", "with_clash_api", "with_usbip", "with_openvpn", "with_openconnect", "badlinkname", "tfogo_checklinkname0")
|
||||
sharedTags = append(sharedTags, "with_quic", "with_wireguard", "with_utls", "with_naive_outbound", "with_clash_api", "with_usbip", "with_openvpn", "with_openconnect", "badlinkname", "tfogo_checklinkname0")
|
||||
darwinTags = append(darwinTags, "with_dhcp", "grpcnotrace")
|
||||
// memcTags = append(memcTags, "with_tailscale")
|
||||
sharedTags = append(sharedTags, "with_tailscale", "ts_omit_logtail", "ts_omit_ssh", "ts_omit_drive", "ts_omit_taildrop", "ts_omit_webclient", "ts_omit_doctor", "ts_omit_capture", "ts_omit_kube", "ts_omit_aws", "ts_omit_synology", "ts_omit_bird")
|
||||
|
||||
@@ -76,8 +76,6 @@ Use system interface.
|
||||
|
||||
Requires privilege and cannot conflict with exists system interfaces.
|
||||
|
||||
Forced if gVisor not included in the build.
|
||||
|
||||
#### interface_name
|
||||
|
||||
Custom interface name for system interface.
|
||||
|
||||
@@ -64,8 +64,6 @@ icon: material/delete-clock
|
||||
|
||||
需要特权且不能与已有系统接口冲突。
|
||||
|
||||
如果 gVisor 未包含在构建中,则强制执行。
|
||||
|
||||
#### interface_name
|
||||
|
||||
为系统接口自定义设备名称。
|
||||
|
||||
@@ -55,7 +55,7 @@ go build -tags "tag_a tag_b" ./cmd/sing-box
|
||||
| `with_acme` | :material-check: | Build with ACME TLS certificate issuer support, see [TLS](/configuration/shared/tls/). |
|
||||
| `with_clash_api` | :material-check: | Build with Clash API support, see [Experimental](/configuration/experimental#clash-api-fields). |
|
||||
| `with_v2ray_api` | :material-close:️ | Build with V2Ray API support, see [Experimental](/configuration/experimental#v2ray-api-fields). |
|
||||
| `with_gvisor` | :material-check: | Build with gVisor support, see [Tun inbound](/configuration/inbound/tun#stack) and [WireGuard outbound](/configuration/outbound/wireguard#system_interface). |
|
||||
| `with_gvisor` | :material-close: | Build with gVisor support, required by the deprecated `gvisor` / `mixed` [Tun stacks](/configuration/inbound/tun#stack). |
|
||||
| `with_embedded_tor` (CGO required) | :material-close:️ | Build with embedded Tor support, see [Tor outbound](/configuration/outbound/tor/). |
|
||||
| `with_tailscale` | :material-check: | Build with Tailscale support, see [Tailscale endpoint](/configuration/endpoint/tailscale). |
|
||||
| `with_ccm` | :material-check: | Build with Claude Code Multiplexer service support. |
|
||||
|
||||
@@ -59,7 +59,7 @@ go build -tags "tag_a tag_b" ./cmd/sing-box
|
||||
| `with_acme` | :material-check: | Build with ACME TLS certificate issuer support, see [TLS](/zh/configuration/shared/tls/). |
|
||||
| `with_clash_api` | :material-check: | Build with Clash API support, see [Experimental](/zh/configuration/experimental#clash-api-fields). |
|
||||
| `with_v2ray_api` | :material-close:️ | Build with V2Ray API support, see [Experimental](/zh/configuration/experimental#v2ray-api-fields). |
|
||||
| `with_gvisor` | :material-check: | Build with gVisor support, see [Tun inbound](/zh/configuration/inbound/tun#stack) and [WireGuard outbound](/zh/configuration/outbound/wireguard#system_interface). |
|
||||
| `with_gvisor` | :material-close: | 构建 gVisor 支持,已弃用的 `gvisor` / `mixed` [Tun 栈](/zh/configuration/inbound/tun#stack) 需要。 |
|
||||
| `with_embedded_tor` (CGO required) | :material-close:️ | Build with embedded Tor support, see [Tor outbound](/zh/configuration/outbound/tor/). |
|
||||
| `with_tailscale` | :material-check: | 构建 Tailscale 支持,参阅 [Tailscale 端点](/zh/configuration/endpoint/tailscale)。 |
|
||||
| `with_ccm` | :material-check: | 构建 Claude Code Multiplexer 服务支持。 |
|
||||
|
||||
@@ -1,257 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"variables": {
|
||||
"VERSION": "$(go run github.com/sagernet/sing-box/cmd/internal/read_tag@latest)",
|
||||
"WORKSPACE_ROOT": "../../..",
|
||||
"DEPLOY_ANDROID": "${WORKSPACE_ROOT}/sing-box-for-android/app/libs",
|
||||
"DEPLOY_APPLE": "${WORKSPACE_ROOT}/sing-box-for-apple",
|
||||
"DEPLOY_WINDOWS": "${WORKSPACE_ROOT}/sing-box-for-windows/local-packages"
|
||||
},
|
||||
"packages": [
|
||||
{
|
||||
"id": "libbox",
|
||||
"path": ".",
|
||||
"java_package": "io.nekohasekai.libbox",
|
||||
"csharp_namespace": "SagerNet",
|
||||
"csharp_entrypoint": "Libbox",
|
||||
"apple_prefix": "Libbox"
|
||||
}
|
||||
],
|
||||
"builds": [
|
||||
{
|
||||
"id": "android-main",
|
||||
"packages": ["libbox"],
|
||||
"default": {
|
||||
"tags": [
|
||||
"with_gvisor",
|
||||
"with_quic",
|
||||
"with_wireguard",
|
||||
"with_utls",
|
||||
"with_naive_outbound",
|
||||
"with_clash_api",
|
||||
"badlinkname",
|
||||
"tfogo_checklinkname0",
|
||||
"with_tailscale",
|
||||
"ts_omit_logtail",
|
||||
"ts_omit_ssh",
|
||||
"ts_omit_drive",
|
||||
"ts_omit_taildrop",
|
||||
"ts_omit_webclient",
|
||||
"ts_omit_doctor",
|
||||
"ts_omit_capture",
|
||||
"ts_omit_kube",
|
||||
"ts_omit_aws",
|
||||
"ts_omit_synology",
|
||||
"ts_omit_bird"
|
||||
],
|
||||
"ldflags": "-X github.com/sagernet/sing-box/constant.Version=${VERSION} -X runtime.godebugDefault=multipathtcp=0,tlssha1=1,tlsunsafeekm=1 -s -w -buildid= -checklinkname=0",
|
||||
"trimpath": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "android-legacy",
|
||||
"packages": ["libbox"],
|
||||
"default": {
|
||||
"tags": [
|
||||
"with_gvisor",
|
||||
"with_quic",
|
||||
"with_wireguard",
|
||||
"with_utls",
|
||||
"with_clash_api",
|
||||
"badlinkname",
|
||||
"tfogo_checklinkname0",
|
||||
"with_tailscale",
|
||||
"ts_omit_logtail",
|
||||
"ts_omit_ssh",
|
||||
"ts_omit_drive",
|
||||
"ts_omit_taildrop",
|
||||
"ts_omit_webclient",
|
||||
"ts_omit_doctor",
|
||||
"ts_omit_capture",
|
||||
"ts_omit_kube",
|
||||
"ts_omit_aws",
|
||||
"ts_omit_synology",
|
||||
"ts_omit_bird"
|
||||
],
|
||||
"ldflags": "-X github.com/sagernet/sing-box/constant.Version=${VERSION} -X runtime.godebugDefault=multipathtcp=0,tlssha1=1,tlsunsafeekm=1 -s -w -buildid= -checklinkname=0",
|
||||
"trimpath": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "apple",
|
||||
"packages": ["libbox"],
|
||||
"default": {
|
||||
"tags": [
|
||||
"with_gvisor",
|
||||
"with_quic",
|
||||
"with_wireguard",
|
||||
"with_utls",
|
||||
"with_naive_outbound",
|
||||
"with_clash_api",
|
||||
"badlinkname",
|
||||
"tfogo_checklinkname0",
|
||||
"with_dhcp",
|
||||
"grpcnotrace",
|
||||
"with_tailscale",
|
||||
"ts_omit_logtail",
|
||||
"ts_omit_ssh",
|
||||
"ts_omit_drive",
|
||||
"ts_omit_taildrop",
|
||||
"ts_omit_webclient",
|
||||
"ts_omit_doctor",
|
||||
"ts_omit_capture",
|
||||
"ts_omit_kube",
|
||||
"ts_omit_aws",
|
||||
"ts_omit_synology",
|
||||
"ts_omit_bird"
|
||||
],
|
||||
"ldflags": "-X github.com/sagernet/sing-box/constant.Version=${VERSION} -X runtime.godebugDefault=multipathtcp=0,tlssha1=1,tlsunsafeekm=1 -s -w -buildid= -checklinkname=0",
|
||||
"trimpath": true
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"match": { "os": "ios" },
|
||||
"tags_append": ["with_low_memory"]
|
||||
},
|
||||
{
|
||||
"match": { "os": "tvos" },
|
||||
"tags_append": ["with_low_memory"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "windows",
|
||||
"packages": ["libbox"],
|
||||
"default": {
|
||||
"tags": [
|
||||
"with_gvisor",
|
||||
"with_quic",
|
||||
"with_wireguard",
|
||||
"with_utls",
|
||||
"with_naive_outbound",
|
||||
"with_purego",
|
||||
"with_clash_api",
|
||||
"badlinkname",
|
||||
"tfogo_checklinkname0",
|
||||
"with_tailscale",
|
||||
"ts_omit_logtail",
|
||||
"ts_omit_ssh",
|
||||
"ts_omit_drive",
|
||||
"ts_omit_taildrop",
|
||||
"ts_omit_webclient",
|
||||
"ts_omit_doctor",
|
||||
"ts_omit_capture",
|
||||
"ts_omit_kube",
|
||||
"ts_omit_aws",
|
||||
"ts_omit_synology",
|
||||
"ts_omit_bird"
|
||||
],
|
||||
"ldflags": "-X github.com/sagernet/sing-box/constant.Version=${VERSION} -X runtime.godebugDefault=multipathtcp=0,tlssha1=1,tlsunsafeekm=1 -s -w -buildid= -checklinkname=0",
|
||||
"trimpath": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"platforms": [
|
||||
{
|
||||
"type": "android",
|
||||
"build": "android-main",
|
||||
"min_sdk": 23,
|
||||
"ndk_version": "28.0.13004108",
|
||||
"lib_name": "box",
|
||||
"languages": [{ "type": "java" }],
|
||||
"artifacts": [
|
||||
{
|
||||
"type": "aar",
|
||||
"output_path": "libbox.aar",
|
||||
"execute_after": [
|
||||
"if [ -d \"${DEPLOY_ANDROID}\" ]; then",
|
||||
" rm -f \"${DEPLOY_ANDROID}/$$(basename \"${OUTPUT_PATH}\")\"",
|
||||
" mv \"${OUTPUT_PATH}\" \"${DEPLOY_ANDROID}/\"",
|
||||
"fi"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "android",
|
||||
"build": "android-legacy",
|
||||
"min_sdk": 21,
|
||||
"ndk_version": "28.0.13004108",
|
||||
"lib_name": "box",
|
||||
"languages": [{ "type": "java" }],
|
||||
"artifacts": [
|
||||
{
|
||||
"type": "aar",
|
||||
"output_path": "libbox-legacy.aar",
|
||||
"execute_after": [
|
||||
"if [ -d \"${DEPLOY_ANDROID}\" ]; then",
|
||||
" rm -f \"${DEPLOY_ANDROID}/$$(basename \"${OUTPUT_PATH}\")\"",
|
||||
" mv \"${OUTPUT_PATH}\" \"${DEPLOY_ANDROID}/\"",
|
||||
"fi"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "apple",
|
||||
"build": "apple",
|
||||
"targets": [
|
||||
"ios/arm64",
|
||||
"ios/simulator/arm64",
|
||||
"ios/simulator/amd64",
|
||||
"tvos/arm64",
|
||||
"tvos/simulator/arm64",
|
||||
"tvos/simulator/amd64",
|
||||
"macos/arm64",
|
||||
"macos/amd64"
|
||||
],
|
||||
"languages": [{ "type": "objc" }],
|
||||
"artifacts": [
|
||||
{
|
||||
"type": "xcframework",
|
||||
"module_name": "Libbox",
|
||||
"execute_after": [
|
||||
"if [ -d \"${DEPLOY_APPLE}\" ]; then",
|
||||
" rm -rf \"${DEPLOY_APPLE}/${MODULE_NAME}.xcframework\"",
|
||||
" mv \"${OUTPUT_PATH}\" \"${DEPLOY_APPLE}/\"",
|
||||
"fi"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "csharp",
|
||||
"build": "windows",
|
||||
"targets": [
|
||||
"windows/amd64"
|
||||
],
|
||||
"languages": [{ "type": "csharp" }],
|
||||
"artifacts": [
|
||||
{
|
||||
"type": "nuget",
|
||||
"package_id": "SagerNet.Libbox",
|
||||
"package_version": "0.0.0-local",
|
||||
"execute_after": {
|
||||
"windows": [
|
||||
"$$deployPath = '${DEPLOY_WINDOWS}'",
|
||||
"if (Test-Path $$deployPath) {",
|
||||
" Remove-Item \"$$deployPath\\${PACKAGE_ID}.*.nupkg\" -ErrorAction SilentlyContinue",
|
||||
" Move-Item -Force '${OUTPUT_PATH}' \"$$deployPath\\\"",
|
||||
" $$cachePath = if ($$env:NUGET_PACKAGES) { $$env:NUGET_PACKAGES } else { \"$$env:USERPROFILE\\.nuget\\packages\" }",
|
||||
" Remove-Item -Recurse -Force \"$$cachePath\\sagernet.libbox\\${PACKAGE_VERSION}\" -ErrorAction SilentlyContinue",
|
||||
"}"
|
||||
],
|
||||
"default": [
|
||||
"if [ -d \"${DEPLOY_WINDOWS}\" ]; then",
|
||||
" rm -f \"${DEPLOY_WINDOWS}/${PACKAGE_ID}.*.nupkg\"",
|
||||
" mv \"${OUTPUT_PATH}\" \"${DEPLOY_WINDOWS}/\"",
|
||||
" cache_path=\"$${NUGET_PACKAGES:-$${HOME}/.nuget/packages}\"",
|
||||
" rm -rf \"$${cache_path}/sagernet.libbox/${PACKAGE_VERSION}\"",
|
||||
"fi"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -40,7 +40,6 @@ require (
|
||||
github.com/sagernet/fswatch v0.1.2
|
||||
github.com/sagernet/gliderssh v0.3.4-0.20261023092853-e0cad6d28647
|
||||
github.com/sagernet/gomobile v0.1.12
|
||||
github.com/sagernet/gvisor v0.0.0-20260727.0-sing-box-mod.1
|
||||
github.com/sagernet/netlink v0.0.0-20260814022025-64455d367bbf
|
||||
github.com/sagernet/nftables v0.3.0-mod.4
|
||||
github.com/sagernet/quic-go v0.61.0-sing-box-mod.13
|
||||
@@ -59,8 +58,8 @@ require (
|
||||
github.com/sagernet/sing-usbip v0.0.0-20260817040617-28bd42667eca
|
||||
github.com/sagernet/sing-vmess v0.2.9-0.20261108133243-b01463cef941
|
||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.5.0.20261019070639-79c1732442a9
|
||||
github.com/sagernet/wireguard-go v0.0.8-0.20261022215841-e4d85ef2ed38
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.5.0.20261022105140-481f8d5be5e6
|
||||
github.com/sagernet/wireguard-go v0.0.8-0.20261022215849-fdf0ad046586
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/stretchr/testify v1.12.0
|
||||
@@ -169,6 +168,7 @@ require (
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20261103043047-3aac4ed44c5c // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20261103043047-3aac4ed44c5c // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20261103043047-3aac4ed44c5c // indirect
|
||||
github.com/sagernet/gvisor v0.0.0-20260727.0-sing-box-mod.1 // indirect
|
||||
github.com/smallstep/pkcs7 v0.1.1 // indirect
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
github.com/tailscale/certstore v0.1.1-0.20260409135935-3638fb84b77d // indirect
|
||||
|
||||
@@ -346,10 +346,10 @@ github.com/sagernet/sing-vmess v0.2.9-0.20261108133243-b01463cef941 h1:QiLfQ/yZw
|
||||
github.com/sagernet/sing-vmess v0.2.9-0.20261108133243-b01463cef941/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/go.mod h1:NjhsCEWedJm7eFLyhuBgIEzwfhRmytrUoiLluxs5Sk8=
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.5.0.20261019070639-79c1732442a9 h1:Phb4IDqGdP2Wg8VDComdDy2uMg1ZN3gs0kpJHp6C8O8=
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.5.0.20261019070639-79c1732442a9/go.mod h1:WLUSOPmTcf7VN9gLCe01qUSIvD+/cKC177neENyZPkI=
|
||||
github.com/sagernet/wireguard-go v0.0.8-0.20261022215841-e4d85ef2ed38 h1:VruOdZAjG+nQi//y9YYL8Pf18+SymIkzBoxNt5gUzuY=
|
||||
github.com/sagernet/wireguard-go v0.0.8-0.20261022215841-e4d85ef2ed38/go.mod h1:er10sELpmzLXq7S7Pbc1Zsbyapcr+/gxNAHKTo6fzVA=
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.5.0.20261022105140-481f8d5be5e6 h1:RexTvtia7PIj+gm6p3dEimeUw9RtqaJau+ubLc4k70U=
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.5.0.20261022105140-481f8d5be5e6/go.mod h1:Z8Eql5l0q6mQ+etunojfaZxNJVhEkpbKGS/nnx9ZQpE=
|
||||
github.com/sagernet/wireguard-go v0.0.8-0.20261022215849-fdf0ad046586 h1:lssrGZJRiO6s2ShbBjchpFsNml9cj/7G+aeEL57ZvVc=
|
||||
github.com/sagernet/wireguard-go v0.0.8-0.20261022215849-fdf0ad046586/go.mod h1:er10sELpmzLXq7S7Pbc1Zsbyapcr+/gxNAHKTo6fzVA=
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA=
|
||||
github.com/smallstep/pkcs7 v0.1.1 h1:x+rPdt2W088V9Vkjho4KtoggyktZJlMduZAtRHm68LU=
|
||||
|
||||
@@ -16,9 +16,6 @@ import (
|
||||
|
||||
func registerOpenConnectEndpoint(registry *endpoint.Registry) {
|
||||
endpoint.Register[option.OpenConnectEndpointOptions](registry, C.TypeOpenConnect, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.OpenConnectEndpointOptions) (adapter.Endpoint, error) {
|
||||
if !options.System {
|
||||
return nil, E.New(`OpenConnect is not included in this build, rebuild with -tags with_openconnect,with_gvisor for system:false`)
|
||||
}
|
||||
return nil, E.New(`OpenConnect is not included in this build, rebuild with -tags with_openconnect`)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -16,15 +16,9 @@ import (
|
||||
|
||||
func registerOpenVPNEndpoints(registry *endpoint.Registry) {
|
||||
endpoint.Register[option.OpenVPNClientEndpointOptions](registry, C.TypeOpenVPNClient, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.OpenVPNClientEndpointOptions) (adapter.Endpoint, error) {
|
||||
if !options.System {
|
||||
return nil, E.New(`OpenVPN is not included in this build, rebuild with -tags with_openvpn,with_gvisor for system:false`)
|
||||
}
|
||||
return nil, E.New(`OpenVPN is not included in this build, rebuild with -tags with_openvpn`)
|
||||
})
|
||||
endpoint.Register[option.OpenVPNServerEndpointOptions](registry, C.TypeOpenVPNServer, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.OpenVPNServerEndpointOptions) (adapter.Endpoint, error) {
|
||||
if !options.System {
|
||||
return nil, E.New(`OpenVPN is not included in this build, rebuild with -tags with_openvpn,with_gvisor for system:false`)
|
||||
}
|
||||
return nil, E.New(`OpenVPN is not included in this build, rebuild with -tags with_openvpn`)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-box/service/oomkiller"
|
||||
openconnecttransport "github.com/sagernet/sing-box/transport/openconnect"
|
||||
"github.com/sagernet/sing-openconnect"
|
||||
"github.com/sagernet/sing-tun"
|
||||
@@ -48,6 +49,7 @@ type Endpoint struct {
|
||||
cancelLoop context.CancelFunc
|
||||
dnsRouter adapter.DNSRouter
|
||||
client *openconnect.Client
|
||||
deviceOptions *openconnecttransport.DeviceOptions
|
||||
device openconnecttransport.Device
|
||||
onDemand bool
|
||||
server string
|
||||
@@ -121,9 +123,6 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
if success {
|
||||
return
|
||||
}
|
||||
if openConnectEndpoint.device != nil {
|
||||
_ = openConnectEndpoint.device.Close()
|
||||
}
|
||||
cancelLoop()
|
||||
}()
|
||||
server := options.Server
|
||||
@@ -160,7 +159,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
udpTimeout = time.Duration(options.UDPTimeout)
|
||||
}
|
||||
networkManager := service.FromContext[adapter.NetworkManager](ctx)
|
||||
device, err := openconnecttransport.NewDevice(openconnecttransport.DeviceOptions{
|
||||
openConnectEndpoint.deviceOptions = &openconnecttransport.DeviceOptions{
|
||||
Context: ctx,
|
||||
Logger: logger,
|
||||
System: options.System,
|
||||
@@ -176,12 +175,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
Configuration: openconnecttransport.Configuration{
|
||||
MTU: openconnecttransport.DefaultMTU,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
openConnectEndpoint.device = device
|
||||
device.SetPacketWriter(openConnectEndpoint.writePacketBuffers)
|
||||
clientOptions, err := openConnectEndpoint.buildClientOptions(options, outboundDialer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -425,11 +419,19 @@ func (e *Endpoint) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
e.notifyStatusUpdated()
|
||||
return nil
|
||||
})
|
||||
scope.Add(e.device.Close)
|
||||
scope.Add(func() error {
|
||||
e.cancelLoop()
|
||||
return nil
|
||||
})
|
||||
e.deviceOptions.MemoryPressure = oomkiller.MemoryPressure(e.loopContext)
|
||||
device, err := openconnecttransport.NewDevice(*e.deviceOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(device.Close)
|
||||
device.SetPacketWriter(e.writePacketBuffers)
|
||||
e.device = device
|
||||
e.deviceOptions = nil
|
||||
case adapter.StartStatePostStart:
|
||||
var loopGroup sync.WaitGroup
|
||||
scope.Add(func() error {
|
||||
|
||||
+12
-10
@@ -17,6 +17,7 @@ import (
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-box/service/oomkiller"
|
||||
ovpntransport "github.com/sagernet/sing-box/transport/openvpn"
|
||||
ovpn "github.com/sagernet/sing-openvpn"
|
||||
"github.com/sagernet/sing-tun"
|
||||
@@ -50,6 +51,7 @@ type ClientEndpoint struct {
|
||||
outboundDialer N.Dialer
|
||||
queryOptions adapter.DNSQueryOptions
|
||||
client *ovpn.Client
|
||||
deviceOptions *ovpntransport.DeviceOptions
|
||||
device ovpntransport.Device
|
||||
onDemand bool
|
||||
stateAccess sync.Mutex
|
||||
@@ -92,9 +94,6 @@ func NewClientEndpoint(ctx context.Context, router adapter.Router, logger log.Co
|
||||
if success {
|
||||
return
|
||||
}
|
||||
if clientEndpoint.device != nil {
|
||||
_ = clientEndpoint.device.Close()
|
||||
}
|
||||
cancelLoop()
|
||||
}()
|
||||
clientOptions, err := clientEndpoint.buildClientOptions(options)
|
||||
@@ -123,7 +122,7 @@ func NewClientEndpoint(ctx context.Context, router adapter.Router, logger log.Co
|
||||
if options.UDPTimeout != 0 {
|
||||
udpTimeout = time.Duration(options.UDPTimeout)
|
||||
}
|
||||
device, err := ovpntransport.NewDevice(ovpntransport.DeviceOptions{
|
||||
clientEndpoint.deviceOptions = &ovpntransport.DeviceOptions{
|
||||
Context: ctx,
|
||||
Logger: logger,
|
||||
System: options.System,
|
||||
@@ -140,12 +139,7 @@ func NewClientEndpoint(ctx context.Context, router adapter.Router, logger log.Co
|
||||
MTU: options.MTU,
|
||||
Address: clientOptions.Tunnel.LocalAddress,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clientEndpoint.device = device
|
||||
device.SetPacketWriter(clientEndpoint.writePacketBuffers)
|
||||
client, err := ovpn.NewClient(clientOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -604,11 +598,19 @@ func (c *ClientEndpoint) Start(stage adapter.StartStage, scope *adapter.Scope) e
|
||||
c.notifyStatusUpdated()
|
||||
return nil
|
||||
})
|
||||
scope.Add(c.device.Close)
|
||||
scope.Add(func() error {
|
||||
c.cancelLoop()
|
||||
return nil
|
||||
})
|
||||
c.deviceOptions.MemoryPressure = oomkiller.MemoryPressure(c.ctx)
|
||||
device, err := ovpntransport.NewDevice(*c.deviceOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(device.Close)
|
||||
device.SetPacketWriter(c.writePacketBuffers)
|
||||
c.device = device
|
||||
c.deviceOptions = nil
|
||||
case adapter.StartStatePostStart:
|
||||
var loopGroup sync.WaitGroup
|
||||
scope.Add(func() error {
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-box/service/oomkiller"
|
||||
ovpntransport "github.com/sagernet/sing-box/transport/openvpn"
|
||||
ovpn "github.com/sagernet/sing-openvpn"
|
||||
"github.com/sagernet/sing-tun"
|
||||
@@ -42,6 +43,7 @@ type ServerEndpoint struct {
|
||||
dnsRouter adapter.DNSRouter
|
||||
listener *listener.Listener
|
||||
server *ovpn.Server
|
||||
deviceOptions *ovpntransport.DeviceOptions
|
||||
device ovpntransport.Device
|
||||
localAddresses []netip.Prefix
|
||||
started atomic.Bool
|
||||
@@ -100,7 +102,7 @@ func NewServerEndpoint(ctx context.Context, router adapter.Router, logger log.Co
|
||||
if options.UDPTimeout != 0 {
|
||||
udpTimeout = time.Duration(options.UDPTimeout)
|
||||
}
|
||||
device, err := ovpntransport.NewDevice(ovpntransport.DeviceOptions{
|
||||
serverEndpoint.deviceOptions = &ovpntransport.DeviceOptions{
|
||||
Context: ctx,
|
||||
Logger: logger,
|
||||
System: options.System,
|
||||
@@ -118,13 +120,7 @@ func NewServerEndpoint(ctx context.Context, router adapter.Router, logger log.Co
|
||||
Address: options.Address,
|
||||
Topology: options.Topology,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
cancelLoop()
|
||||
return nil, err
|
||||
}
|
||||
serverEndpoint.device = device
|
||||
device.SetPacketWriter(serverEndpoint.writePacketBuffersByDestination)
|
||||
return serverEndpoint, nil
|
||||
}
|
||||
|
||||
@@ -161,11 +157,19 @@ func validateServerTopology(topology string) error {
|
||||
|
||||
func (s *ServerEndpoint) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage == adapter.StartStateInitialize {
|
||||
scope.Add(s.device.Close)
|
||||
scope.Add(func() error {
|
||||
s.cancelLoop()
|
||||
return nil
|
||||
})
|
||||
s.deviceOptions.MemoryPressure = oomkiller.MemoryPressure(s.ctx)
|
||||
device, err := ovpntransport.NewDevice(*s.deviceOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(device.Close)
|
||||
device.SetPacketWriter(s.writePacketBuffersByDestination)
|
||||
s.device = device
|
||||
s.deviceOptions = nil
|
||||
return nil
|
||||
}
|
||||
if stage != adapter.StartStateStart {
|
||||
@@ -214,7 +218,6 @@ func (s *ServerEndpoint) Start(stage adapter.StartStage, scope *adapter.Scope) e
|
||||
Control: listenConfig.Control,
|
||||
InterfaceFinder: networkManager.InterfaceFinder(),
|
||||
InterfaceMonitor: networkManager.InterfaceMonitor(),
|
||||
ExcludeInterface: s.options.Name,
|
||||
IsExempt: func() bool {
|
||||
return networkManager.AutoRedirectOutputMark() != 0
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor
|
||||
//go:build with_tailscale
|
||||
|
||||
package tailscale
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor
|
||||
//go:build with_tailscale
|
||||
|
||||
package tailscale
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor
|
||||
//go:build with_tailscale
|
||||
|
||||
package tailscale
|
||||
|
||||
|
||||
+31
-138
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor
|
||||
//go:build with_tailscale
|
||||
|
||||
package tailscale
|
||||
|
||||
@@ -19,11 +19,6 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/adapters/gonet"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/transport/icmp"
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/adapter/endpoint"
|
||||
"github.com/sagernet/sing-box/common/dialer"
|
||||
@@ -34,6 +29,7 @@ import (
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-box/protocol/tailscale/tailssh"
|
||||
R "github.com/sagernet/sing-box/route/rule"
|
||||
"github.com/sagernet/sing-box/service/oomkiller"
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
@@ -96,7 +92,7 @@ type Endpoint struct {
|
||||
platformInterface adapter.PlatformInterface
|
||||
detour string
|
||||
server *tsnet.Server
|
||||
stack *stack.Stack
|
||||
stack *tun.Go
|
||||
returnAccess sync.Mutex
|
||||
returnPath tun.Return
|
||||
wgEngine wgengine.ExportedUserspaceEngine
|
||||
@@ -117,9 +113,6 @@ type Endpoint struct {
|
||||
relayServerPort *uint16
|
||||
relayServerStaticEndpoints []netip.AddrPort
|
||||
|
||||
udpTimeout time.Duration
|
||||
icmpTimeout time.Duration
|
||||
|
||||
sshServerInstance *tailssh.Server
|
||||
sshServerOptions *option.TailscaleSSHServerOptions
|
||||
taildrop *taildropManager
|
||||
@@ -173,12 +166,6 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
if options.AdvertiseExitNode && options.ExitNode != "" {
|
||||
return nil, E.New("cannot advertise an exit node and use an exit node at the same time.")
|
||||
}
|
||||
var udpTimeout time.Duration
|
||||
if options.UDPTimeout != 0 {
|
||||
udpTimeout = time.Duration(options.UDPTimeout)
|
||||
} else {
|
||||
udpTimeout = C.UDPTimeout
|
||||
}
|
||||
outboundDialer, err := dialer.NewWithOptions(dialer.Options{
|
||||
Context: ctx,
|
||||
Options: options.DialerOptions,
|
||||
@@ -197,7 +184,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
}
|
||||
taildropDirectory = filemanager.BasePath(ctx, os.ExpandEnv(taildropDirectory))
|
||||
taildropDirectory, _ = filepath.Abs(taildropDirectory)
|
||||
return &Endpoint{
|
||||
tailscaleEndpoint := &Endpoint{
|
||||
Adapter: endpoint.NewAdapter(C.TypeTailscale, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, nil),
|
||||
ctx: ctx,
|
||||
router: router,
|
||||
@@ -249,14 +236,14 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
relayServerStaticEndpoints: options.RelayServerStaticEndpoints,
|
||||
sshServerOptions: options.SSHServer,
|
||||
taildrop: newTaildropManager(ctx, logger, tag, taildropDirectory, platformInterface),
|
||||
udpTimeout: udpTimeout,
|
||||
icmpTimeout: C.ICMPTimeout,
|
||||
systemInterface: options.SystemInterface,
|
||||
systemInterfaceName: options.SystemInterfaceName,
|
||||
systemInterfaceMTU: options.SystemInterfaceMTU,
|
||||
keyAuth: options.AuthKey != "",
|
||||
onDemand: options.OnDemand,
|
||||
}, nil
|
||||
}
|
||||
tailscaleEndpoint.server.NetstackHandler = tailscaleEndpoint
|
||||
return tailscaleEndpoint, nil
|
||||
}
|
||||
|
||||
func (t *Endpoint) References() []string {
|
||||
@@ -269,6 +256,7 @@ func (t *Endpoint) References() []string {
|
||||
func (t *Endpoint) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
t.server.NetstackMemoryPressure = oomkiller.MemoryPressure(t.ctx)
|
||||
mkdirErr := filemanager.MkdirAll(t.ctx, t.server.Dir, 0o700)
|
||||
if mkdirErr != nil {
|
||||
return E.Cause(mkdirErr, "create state directory")
|
||||
@@ -473,18 +461,6 @@ func (t *Endpoint) postStart(scope *adapter.Scope) error {
|
||||
return nil
|
||||
})
|
||||
}
|
||||
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
|
||||
})
|
||||
scope.Add(func() error {
|
||||
fallbackTCPCloser()
|
||||
return nil
|
||||
})
|
||||
localBackend := t.server.ExportLocalBackend()
|
||||
t.localBackend.Store(localBackend)
|
||||
scope.Add(func() error {
|
||||
@@ -507,55 +483,7 @@ func (t *Endpoint) postStart(scope *adapter.Scope) error {
|
||||
wgEngine.SetOnReconfigListener(t.onReconfig)
|
||||
t.wgEngine = wgEngine
|
||||
|
||||
ipStack := t.server.ExportNetstack().ExportIPStack()
|
||||
gErr := ipStack.SetSpoofing(tun.DefaultNIC, true)
|
||||
if gErr != nil {
|
||||
return gonet.TranslateNetstackError(gErr)
|
||||
}
|
||||
gErr = ipStack.SetPromiscuousMode(tun.DefaultNIC, true)
|
||||
if gErr != nil {
|
||||
return gonet.TranslateNetstackError(gErr)
|
||||
}
|
||||
icmpForwarder := tun.NewICMPForwarder(ipStack, t, t.logger)
|
||||
scope.Add(icmpForwarder.Close)
|
||||
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber4, icmpForwarder.HandlePacket)
|
||||
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber6, icmpForwarder.HandlePacket)
|
||||
t.stack = ipStack
|
||||
netstack := t.server.ExportNetstack()
|
||||
if netstack != nil {
|
||||
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.NewUnbindPacketConnWithAddr(conn, destination)
|
||||
t.NewPacketConnectionEx(ctx, packetConn, source, destination, nil)
|
||||
}, true
|
||||
}
|
||||
}
|
||||
t.stack = t.server.ExportNetstack().ExportIPStack()
|
||||
|
||||
sshEnabled := t.sshServerOptions != nil && t.sshServerOptions.Enabled
|
||||
if sshEnabled {
|
||||
@@ -959,46 +887,27 @@ func (t *Endpoint) DialContext(ctx context.Context, network string, destination
|
||||
if t.systemDialer != nil {
|
||||
return t.systemDialer.DialContext(ctx, network, destination)
|
||||
}
|
||||
addr4, addr6 := t.server.TailscaleIPs()
|
||||
remoteAddr := tcpip.FullAddress{
|
||||
NIC: 1,
|
||||
Port: destination.Port,
|
||||
Addr: addressFromAddr(destination.Addr),
|
||||
address4, address6 := t.server.TailscaleIPs()
|
||||
local := address4
|
||||
if destination.IsIPv6() {
|
||||
local = address6
|
||||
}
|
||||
var localAddr tcpip.FullAddress
|
||||
var networkProtocol tcpip.NetworkProtocolNumber
|
||||
if destination.IsIPv4() {
|
||||
if !addr4.IsValid() {
|
||||
return nil, E.New("missing Tailscale IPv4 address")
|
||||
}
|
||||
networkProtocol = header.IPv4ProtocolNumber
|
||||
localAddr = tcpip.FullAddress{
|
||||
NIC: 1,
|
||||
Addr: addressFromAddr(addr4),
|
||||
}
|
||||
} else {
|
||||
if !addr6.IsValid() {
|
||||
return nil, E.New("missing Tailscale IPv6 address")
|
||||
}
|
||||
networkProtocol = header.IPv6ProtocolNumber
|
||||
localAddr = tcpip.FullAddress{
|
||||
NIC: 1,
|
||||
Addr: addressFromAddr(addr6),
|
||||
}
|
||||
if !local.IsValid() {
|
||||
return nil, E.New("missing Tailscale address for ", destination)
|
||||
}
|
||||
switch N.NetworkName(network) {
|
||||
case N.NetworkTCP:
|
||||
tcpConn, err := gonet.DialTCPWithBind(ctx, t.stack, localAddr, remoteAddr, networkProtocol)
|
||||
conn, err := t.stack.DialTCP(ctx, local, destination.AddrPort())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tcpConn, nil
|
||||
return conn, nil
|
||||
case N.NetworkUDP:
|
||||
udpConn, err := gonet.DialUDP(t.stack, &localAddr, &remoteAddr, networkProtocol)
|
||||
conn, err := t.stack.DialUDP(netip.AddrPortFrom(local, 0), destination.AddrPort())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return udpConn, nil
|
||||
return conn, nil
|
||||
default:
|
||||
return nil, E.Extend(N.ErrUnknownNetwork, network)
|
||||
}
|
||||
@@ -1015,29 +924,19 @@ func (t *Endpoint) listenPacketWithAddress(ctx context.Context, destination M.So
|
||||
if t.systemDialer != nil {
|
||||
return t.systemDialer.ListenPacket(ctx, destination)
|
||||
}
|
||||
addr4, addr6 := t.server.TailscaleIPs()
|
||||
bind := tcpip.FullAddress{
|
||||
NIC: 1,
|
||||
address4, address6 := t.server.TailscaleIPs()
|
||||
local := address4
|
||||
if destination.IsIPv6() {
|
||||
local = address6
|
||||
}
|
||||
var networkProtocol tcpip.NetworkProtocolNumber
|
||||
if destination.IsIPv4() {
|
||||
if !addr4.IsValid() {
|
||||
return nil, E.New("missing Tailscale IPv4 address")
|
||||
}
|
||||
networkProtocol = header.IPv4ProtocolNumber
|
||||
bind.Addr = addressFromAddr(addr4)
|
||||
} else {
|
||||
if !addr6.IsValid() {
|
||||
return nil, E.New("missing Tailscale IPv6 address")
|
||||
}
|
||||
networkProtocol = header.IPv6ProtocolNumber
|
||||
bind.Addr = addressFromAddr(addr6)
|
||||
if !local.IsValid() {
|
||||
return nil, E.New("missing Tailscale address for ", destination)
|
||||
}
|
||||
udpConn, err := gonet.DialUDP(t.stack, &bind, nil, networkProtocol)
|
||||
conn, err := t.stack.ListenUDP(netip.AddrPortFrom(local, 0))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return udpConn, nil
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (t *Endpoint) ListenPacketWithDestination(ctx context.Context, destination M.Socksaddr) (net.PacketConn, netip.Addr, error) {
|
||||
@@ -1078,7 +977,8 @@ func (t *Endpoint) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
|
||||
return packetConn, nil
|
||||
}
|
||||
|
||||
func (t *Endpoint) NewConnectionEx(ctx context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
|
||||
func (t *Endpoint) NewConnectionEx(_ context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
|
||||
ctx := log.ContextWithNewID(t.ctx)
|
||||
var metadata adapter.InboundContext
|
||||
metadata.Inbound = t.Tag()
|
||||
metadata.InboundType = t.Type()
|
||||
@@ -1101,7 +1001,8 @@ func (t *Endpoint) NewConnectionEx(ctx context.Context, conn net.Conn, source M.
|
||||
t.router.RouteConnectionEx(ctx, conn, metadata, onClose)
|
||||
}
|
||||
|
||||
func (t *Endpoint) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
|
||||
func (t *Endpoint) NewPacketConnectionEx(_ context.Context, conn N.PacketConn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
|
||||
ctx := log.ContextWithNewID(t.ctx)
|
||||
var metadata adapter.InboundContext
|
||||
metadata.Inbound = t.Tag()
|
||||
metadata.InboundType = t.Type()
|
||||
@@ -1184,14 +1085,6 @@ func (t *Endpoint) onReconfig(cfg *wgcfg.Config, routerCfg *router.Config, dnsCf
|
||||
}
|
||||
}
|
||||
|
||||
func addressFromAddr(destination netip.Addr) tcpip.Address {
|
||||
if destination.Is6() {
|
||||
return tcpip.AddrFrom16(destination.As16())
|
||||
} else {
|
||||
return tcpip.AddrFrom4(destination.As4())
|
||||
}
|
||||
}
|
||||
|
||||
type endpointDialer struct {
|
||||
N.Dialer
|
||||
logger logger.ContextLogger
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor && tvos
|
||||
//go:build with_tailscale && tvos
|
||||
|
||||
package tailscale
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor
|
||||
//go:build with_tailscale
|
||||
|
||||
package tailscale
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor
|
||||
//go:build with_tailscale
|
||||
|
||||
package tailscale
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor
|
||||
//go:build with_tailscale
|
||||
|
||||
package tailscale
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor
|
||||
//go:build with_tailscale
|
||||
|
||||
package tailscale
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor
|
||||
//go:build with_tailscale
|
||||
|
||||
package tailscale
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor
|
||||
//go:build with_tailscale
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor
|
||||
//go:build with_tailscale
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor && !windows
|
||||
//go:build with_tailscale && !windows
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor && windows
|
||||
//go:build with_tailscale && windows
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor
|
||||
//go:build with_tailscale
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor && android
|
||||
//go:build with_tailscale && android
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor && ios
|
||||
//go:build with_tailscale && ios
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor && !windows
|
||||
//go:build with_tailscale && !windows
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor && unix && !android && !ios
|
||||
//go:build with_tailscale && unix && !android && !ios
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor && windows
|
||||
//go:build with_tailscale && windows
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor && linux
|
||||
//go:build with_tailscale && linux
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor && !windows && !linux
|
||||
//go:build with_tailscale && !windows && !linux
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor
|
||||
//go:build with_tailscale
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor && android
|
||||
//go:build with_tailscale && android
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor && !windows && !android
|
||||
//go:build with_tailscale && !windows && !android
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor && windows
|
||||
//go:build with_tailscale && windows
|
||||
|
||||
package tailssh
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor && !windows
|
||||
//go:build with_tailscale && !windows
|
||||
|
||||
package tailscale
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor && windows
|
||||
//go:build with_tailscale && windows
|
||||
|
||||
package tailscale
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-box/service/oomkiller"
|
||||
"github.com/sagernet/sing-box/transport/wireguard"
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common"
|
||||
@@ -97,7 +98,6 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
Logger: logger,
|
||||
InterfaceFinder: networkManager.InterfaceFinder(),
|
||||
InterfaceMonitor: networkManager.InterfaceMonitor(),
|
||||
ExcludeInterface: options.Name,
|
||||
IsExempt: func() bool {
|
||||
return networkManager.AutoRedirectOutputMark() != 0
|
||||
},
|
||||
@@ -141,6 +141,10 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
func (w *Endpoint) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
err := w.endpoint.Initialize(oomkiller.MemoryPressure(w.ctx))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(w.endpoint.Close)
|
||||
case adapter.StartStateStart:
|
||||
return w.endpoint.Start(false)
|
||||
|
||||
@@ -1 +1 @@
|
||||
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_usbip,with_openvpn,with_openconnect,badlinkname,tfogo_checklinkname0
|
||||
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_usbip,with_openvpn,with_openconnect,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_cloudflared,with_usbip,with_openvpn,with_openconnect,badlinkname,tfogo_checklinkname0
|
||||
with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_cloudflared,with_usbip,with_openvpn,with_openconnect,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_cloudflared,with_naive_outbound,with_purego,with_usbip,with_openvpn,with_openconnect,badlinkname,tfogo_checklinkname0
|
||||
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,with_usbip,with_openvpn,with_openconnect,badlinkname,tfogo_checklinkname0
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build with_gvisor
|
||||
//go:build with_tailscale
|
||||
|
||||
package derp
|
||||
|
||||
|
||||
@@ -49,6 +49,14 @@ func NewService(ctx context.Context, logger log.ContextLogger, tag string, optio
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func MemoryPressure(ctx context.Context) func() tun.MemoryPressure {
|
||||
oomKiller := service.FromContext[*Service](ctx)
|
||||
if oomKiller == nil {
|
||||
return nil
|
||||
}
|
||||
return oomKiller.MemoryPressure
|
||||
}
|
||||
|
||||
func (s *Service) MemoryPressure() tun.MemoryPressure {
|
||||
return tun.MemoryPressure(s.pressure.Load())
|
||||
}
|
||||
|
||||
@@ -149,9 +149,6 @@ func TestOpenConnectEndpointUDPNATDataPlane(t *testing.T) {
|
||||
|
||||
func testEndpointUDPNATDataPlane(t *testing.T, newDevice func(context.Context, tun.Handler) (endpointUDPNATDevice, error)) {
|
||||
t.Helper()
|
||||
if !tun.WithGVisor {
|
||||
t.Skip("requires gVisor")
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
handler := &endpointUDPNATHandler{packets: make(chan endpointUDPNATPacket, 4)}
|
||||
@@ -182,8 +179,8 @@ func testEndpointUDPNATDataPlane(t *testing.T, newDevice func(context.Context, t
|
||||
require.Equal(t, M.SocksaddrFromNetIP(firstDestination), firstPacket.destination)
|
||||
require.Equal(t, []byte("request-one"), firstPacket.payload)
|
||||
|
||||
require.NoError(t, firstPacket.session.conn.WritePacket(buf.As([]byte("blocked")), M.SocksaddrFromNetIP(secondDestination)))
|
||||
require.NoError(t, firstPacket.session.conn.WritePacket(buf.As([]byte("allowed-one")), M.SocksaddrFromNetIP(firstDestination)))
|
||||
require.NoError(t, firstPacket.session.conn.WritePacket(endpointUDPPacketBuffer(firstPacket.session.conn, "blocked"), M.SocksaddrFromNetIP(secondDestination)))
|
||||
require.NoError(t, firstPacket.session.conn.WritePacket(endpointUDPPacketBuffer(firstPacket.session.conn, "allowed-one"), M.SocksaddrFromNetIP(firstDestination)))
|
||||
require.Equal(t, []byte("allowed-one"), waitEndpointUDPResponse(t, outboundPackets))
|
||||
|
||||
writeEndpointUDPPacket(t, device, source, secondDestination, []byte("request-two"))
|
||||
@@ -197,7 +194,7 @@ func testEndpointUDPNATDataPlane(t *testing.T, newDevice func(context.Context, t
|
||||
t.Fatal("first UDP NAT session was not evicted at max size")
|
||||
}
|
||||
|
||||
require.NoError(t, secondPacket.session.conn.WritePacket(buf.As([]byte("allowed-two")), M.SocksaddrFromNetIP(secondDestination)))
|
||||
require.NoError(t, secondPacket.session.conn.WritePacket(endpointUDPPacketBuffer(secondPacket.session.conn, "allowed-two"), M.SocksaddrFromNetIP(secondDestination)))
|
||||
require.Equal(t, []byte("allowed-two"), waitEndpointUDPResponse(t, outboundPackets))
|
||||
}
|
||||
|
||||
@@ -225,6 +222,14 @@ func writeEndpointUDPPacket(t *testing.T, device endpointUDPNATDevice, source ne
|
||||
packetBuffer.Release()
|
||||
}
|
||||
|
||||
func endpointUDPPacketBuffer(conn N.PacketConn, payload string) *buf.Buffer {
|
||||
headroom := N.CalculateFrontHeadroom(conn)
|
||||
buffer := buf.NewSize(headroom + len(payload))
|
||||
buffer.Resize(headroom, 0)
|
||||
buffer.WriteString(payload)
|
||||
return buffer
|
||||
}
|
||||
|
||||
func endpointUDPPayload(packet []byte) ([]byte, bool) {
|
||||
if len(packet) < header.IPv4MinimumSize {
|
||||
return nil, false
|
||||
|
||||
+51
-49
@@ -11,15 +11,15 @@ require (
|
||||
github.com/docker/go-connections v0.5.0
|
||||
github.com/gofrs/uuid/v5 v5.5.1
|
||||
github.com/opencontainers/image-spec v1.1.0
|
||||
github.com/sagernet/quic-go v0.61.0-sing-box-mod.4
|
||||
github.com/sagernet/sing v0.9.0-beta.2
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260729104525-103eb5fe5eb6
|
||||
github.com/sagernet/sing-quic v0.7.0-beta.2
|
||||
github.com/sagernet/quic-go v0.61.0-sing-box-mod.7
|
||||
github.com/sagernet/sing v0.9.5-0.20260914135810-80bfa92a0607
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260903200517-e060dda5b1f1
|
||||
github.com/sagernet/sing-quic v0.7.1-0.20260904135313-497364e8ee3e
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1
|
||||
github.com/sagernet/sing-tun v0.8.12-0.20260810013717-909ab10ad507
|
||||
github.com/sagernet/sing-tun v0.9.4-0.20260916041232-89d2e01a748a
|
||||
github.com/spyzhov/ajson v0.9.4
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/stretchr/testify v1.12.0
|
||||
go.uber.org/goleak v1.3.0
|
||||
golang.org/x/net v0.57.0
|
||||
)
|
||||
@@ -36,7 +36,6 @@ require (
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
||||
github.com/anthropics/anthropic-sdk-go v1.26.0 // indirect
|
||||
github.com/anytls/sing-anytls v0.0.11 // indirect
|
||||
github.com/axiomhq/hyperloglog v0.0.0-20240319100328-84253e514e02 // indirect
|
||||
github.com/caddyserver/certmagic v0.25.3-0.20260421143802-60d9d8b415d6 // indirect
|
||||
github.com/caddyserver/zerossl v0.1.5 // indirect
|
||||
@@ -49,7 +48,6 @@ require (
|
||||
github.com/cretz/bine v0.2.0 // indirect
|
||||
github.com/database64128/netx-go v0.1.1 // indirect
|
||||
github.com/database64128/tfo-go/v2 v2.3.2 // 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/dgryski/go-camellia v0.0.0-20191119043421-69a8a13fb23d // indirect
|
||||
github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc // indirect
|
||||
@@ -115,57 +113,57 @@ require (
|
||||
github.com/pires/go-proxyproto v0.8.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/sftp v1.13.10 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/quic-go/qpack v0.6.0 // indirect
|
||||
github.com/safchain/ethtool v0.3.0 // indirect
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect
|
||||
github.com/sagernet/bbolt v0.0.0-20260823094646-e24805439c9c // indirect
|
||||
github.com/sagernet/cors v1.2.1 // indirect
|
||||
github.com/sagernet/cronet-go v0.0.0-20260807162344-ec9a39c5ba3b // indirect
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20260807162344-ec9a39c5ba3b // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260807161529-8d42107dcdfc // indirect
|
||||
github.com/sagernet/cronet-go v0.0.0-20260912104727-0d28acc44093 // indirect
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20260912104727-0d28acc44093 // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260912104006-c10c03c318db // indirect
|
||||
github.com/sagernet/fswatch v0.1.2 // indirect
|
||||
github.com/sagernet/gliderssh v0.3.4-0.20260531100337-2194faca5648 // indirect
|
||||
github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237 // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20260814022025-64455d367bbf // indirect
|
||||
github.com/sagernet/nftables v0.3.0-mod.4 // indirect
|
||||
github.com/sagernet/sing-anytls v0.0.0-20260904135308-cec2d74334be // indirect
|
||||
github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3 // indirect
|
||||
github.com/sagernet/sing-mux v0.3.5 // indirect
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260810065514-53aa8058f8df // indirect
|
||||
github.com/sagernet/sing-mux v0.3.7-0.20260905054442-91d1502591ce // indirect
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260903200519-8b89c968949d // indirect
|
||||
github.com/sagernet/sing-shadowtls v0.2.1 // indirect
|
||||
github.com/sagernet/sing-snell v0.0.0-20260727093646-7cb813e07b73 // indirect
|
||||
github.com/sagernet/sing-usbip v0.0.0-20260616101517-efb91521eddb // indirect
|
||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 // indirect
|
||||
github.com/sagernet/sing-snell v0.0.0-20260904135315-bc5a12ac736f // indirect
|
||||
github.com/sagernet/sing-usbip v0.0.0-20260817040617-28bd42667eca // indirect
|
||||
github.com/sagernet/sing-vmess v0.2.8 // indirect
|
||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1 // indirect
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.2 // indirect
|
||||
github.com/sagernet/wireguard-go v0.0.5-0.20260810121456-c6c8a831ef70 // indirect
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.5.0.20260916041743-66c96c36515b // indirect
|
||||
github.com/sagernet/wireguard-go v0.0.6 // indirect
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect
|
||||
github.com/smallstep/pkcs7 v0.1.1 // indirect
|
||||
github.com/tailscale/certstore v0.1.1-0.20260409135935-3638fb84b77d // indirect
|
||||
@@ -215,3 +213,7 @@ require (
|
||||
lukechampine.com/blake3 v1.3.0 // indirect
|
||||
zombiezen.com/go/capnproto2 v2.18.2+incompatible // indirect
|
||||
)
|
||||
|
||||
replace github.com/sagernet/sing-tun => ../../sing-tun
|
||||
|
||||
replace github.com/sagernet/tailscale => ../../tailscale
|
||||
+90
-96
@@ -26,8 +26,6 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFI
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/anthropics/anthropic-sdk-go v1.26.0 h1:oUTzFaUpAevfuELAP1sjL6CQJ9HHAfT7CoSYSac11PY=
|
||||
github.com/anthropics/anthropic-sdk-go v1.26.0/go.mod h1:qUKmaW+uuPB64iy1l+4kOSvaLqPXnHTTBKH6RVZ7q5Q=
|
||||
github.com/anytls/sing-anytls v0.0.11 h1:w8e9Uj1oP3m4zxkyZDewPk0EcQbvVxb7Nn+rapEx4fc=
|
||||
github.com/anytls/sing-anytls v0.0.11/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8=
|
||||
github.com/axiomhq/hyperloglog v0.0.0-20240319100328-84253e514e02 h1:bXAPYSbdYbS5VTy92NIUbeDI1qyggi+JYh5op9IFlcQ=
|
||||
github.com/axiomhq/hyperloglog v0.0.0-20240319100328-84253e514e02/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c=
|
||||
github.com/caddyserver/certmagic v0.25.3-0.20260421143802-60d9d8b415d6 h1:LYSB6VgWzKtNrcxElw3c97BP40Oc7bizKxA9K1Vi/5k=
|
||||
@@ -248,8 +246,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
github.com/pkg/sftp v1.13.10 h1:+5FbKNTe5Z9aspU88DPIKJ9z2KZoaGCu6Sr6kKR/5mU=
|
||||
github.com/pkg/sftp v1.13.10/go.mod h1:bJ1a7uDhrX/4OII+agvy28lzRvQrmIQuaHrcI1HbeGA=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||
@@ -257,116 +253,114 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0=
|
||||
github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs=
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0=
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
|
||||
github.com/sagernet/bbolt v0.0.0-20260823094646-e24805439c9c h1:JdEDkgiwsDxiZb4+dQYgVOU/lND+jZxFmN5y/q49EXk=
|
||||
github.com/sagernet/bbolt v0.0.0-20260823094646-e24805439c9c/go.mod h1:7/qFPFH5fqK5XQeY8EA1Qpaly08Av77p38Zt50ieQww=
|
||||
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/cronet-go v0.0.0-20260807162344-ec9a39c5ba3b h1:SfX10lRxbq9ixHm4OZ4/7q+TSpK4Gh0lEVrPaIAB/K0=
|
||||
github.com/sagernet/cronet-go v0.0.0-20260807162344-ec9a39c5ba3b/go.mod h1:T/mwtrpC4JlWfScw73CmSBvHzIvc7BatQ1MhRr+cYNw=
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20260807162344-ec9a39c5ba3b h1:ilEtBdfFgdHmCY3q/Gzp3wRDILYAT8wOh+jVAEAT77U=
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20260807162344-ec9a39c5ba3b/go.mod h1:Mr2MlNGQYovxvSPGo0+HEgXJ+uITwvPMtp7kdZO8T9w=
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260807161529-8d42107dcdfc h1:JxjIRahHFgA766NTMNoQH5FHcSjo3OVdQbqMuqqvOSQ=
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260807161529-8d42107dcdfc h1:U1M7GkzYchNnahyGiSGD1xAHJXoCiae3E8DDPWaeliA=
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260807161529-8d42107dcdfc h1:Vtm7UuE69wKPNUakYjlxscX16LkQTEX1Uh6qf2YZj3Y=
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260807161529-8d42107dcdfc h1:w48m0+ic4Y4pmW9ZIAo7o70fq/ioL1pgIKCggvvZiOU=
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260807161529-8d42107dcdfc h1:1XkXOj47J9kPTBYZXIPraLG8V3vtQ2p6kI+EuLkNQVs=
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260807161529-8d42107dcdfc h1:++dHyER9VY0KIfN18i0J2uQcp/DMySqVsUtSEso6mcU=
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
|
||||
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260807161529-8d42107dcdfc h1:Jd84+nEjqapOYqxbbRaYD9WsqV/+UacrPngpzT3JOW4=
|
||||
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260807161529-8d42107dcdfc h1:2q/pUYTulaxitrk+Uuwu+nnPeJCwoWCI8YB0b5JU5Pg=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260807161529-8d42107dcdfc h1:KuR8ZjycdnaHpdlwER2BJcyQxFV89+Ci1MC7hQuDQtM=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo=
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260807161529-8d42107dcdfc h1:5oWj5iZn7tg9wOC4VMltItUE87FDxubwICgtjSp+HAM=
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260807161529-8d42107dcdfc h1:EZBIqNjit9xGM1w9xKcQVzU3gtyNdEcgXPfmeVuTinM=
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260807161529-8d42107dcdfc h1:yOIHOVXOlmbvcs1Gm2xfcr84+mvAVN0zdXycfLgr3DE=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260807161529-8d42107dcdfc h1:4uVapCorUiSKJ2xTi8BNLOTq878kFv3l+6+aDeYpuiE=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260807161529-8d42107dcdfc h1:fm2GA6JTp48rigyUtuzgu/G9WbMZ+o5QBylks1Noss0=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260807161529-8d42107dcdfc h1:kWx/l/TCx2hdUKnNn2uyKZAGkCeqm+vkhr84wZJkSgU=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260807161529-8d42107dcdfc h1:XnHUep8+amHCWW3WWCD6/QAZYAXkcLUeCZqs0SnXp7M=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260807161529-8d42107dcdfc h1:F7rgwvKytTxeU3G3RpZlH0o77J6OmbZpxaUkTWk1+cE=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260807161529-8d42107dcdfc h1:lpq6aztgg4Luspo4V4SresrCg7+bXlpZ45EfAwpWabg=
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:Wt5uFdU3tnmm8YzobYewwdF7Mt6SucRQg6xeTNWC3Tk=
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260807161529-8d42107dcdfc h1:o66baLwgg/aI14jCX6lrQ+1EPkn7RS4cFWJQRKXYXqM=
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:lyIF6wKBLwWa5ZXaAKbAoewewl+yCHo2iYev39Mbj4E=
|
||||
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260807161529-8d42107dcdfc h1:7tSY8HPMvf/piEi0TywA/dQWyp1lAJH9U/qyn4+DKY8=
|
||||
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:H46PnSTTZNcZokLLiDeMDaHiS1l14PH3tzWi0eykjD8=
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260807161529-8d42107dcdfc h1:zgHBT1uv5UQ/GHVMn4j6NXelH7ukIo0IQQLsntV+VfA=
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:RBhSUDAKWq7fswtV4nQUQhuaTLcX3ettR7teA7/yf2w=
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260807161529-8d42107dcdfc h1:HNzghnPzq2RK5TXjl5QIVPm44FKzw6pds1GQINAYD80=
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:wRzoIOGG4xbpp3Gh3triLKwMwYriScXzFtunLYhY4w0=
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260807161529-8d42107dcdfc h1:xAaqyzbYqGPJbKCa6onmX7Bs2HXM1mvbEdMtdAiXplA=
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:LNiZXmWil1OPwKCheqQjtakZlJuKGFz+iv2eGF76Hhs=
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260807161529-8d42107dcdfc h1:dHay8gOPaH4kwcTnxQeAEZaIw88Y0V6Gmef3HkdX31U=
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:YFDGKTkpkJGc5+hnX/RYosZyTWg9h+68VB55fYRRLYc=
|
||||
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260807161529-8d42107dcdfc h1:NLAel/XTGYWExz5gpFzlsX+BZba3/6Wgz1xwOzux9r0=
|
||||
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260807161529-8d42107dcdfc h1:/k71v3Hs2m6mpDTWVm2W6spZNd+do9U+1jBYTOIPj3g=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260807161529-8d42107dcdfc h1:HUB2CvXtgggtQNW5ix670s9Qd+vCiy5aFKEFJO5/UL8=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc=
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260807161529-8d42107dcdfc h1:rWdo0pRYdrGvZ0turVxLqsXsizj+AS/nivMHX0RHtLw=
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260807161529-8d42107dcdfc h1:+3Fe+RdrbyEGyi66Kt8BromMTFGVw6+8ZTEqKF4kCaU=
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260807161529-8d42107dcdfc/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
|
||||
github.com/sagernet/cronet-go v0.0.0-20260912104727-0d28acc44093 h1:CsvsLVIli53L6nzgEpyRjjWnRRhTds4D3eh5sEnF5Sw=
|
||||
github.com/sagernet/cronet-go v0.0.0-20260912104727-0d28acc44093/go.mod h1:T/mwtrpC4JlWfScw73CmSBvHzIvc7BatQ1MhRr+cYNw=
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20260912104727-0d28acc44093 h1:1lRUqrLcBz0Q0r/xvyiXS5hZwH5pOq6Lwb4dqbSqJfs=
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20260912104727-0d28acc44093/go.mod h1:bvm9T9FdwHYYfWdZkLoZ4Qr9Dce0TTQ7ngXlbGZnnJk=
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260912104006-c10c03c318db h1:o0NCKT9gZsOLJK5s5wXW5A5EaFCnF5En6SApmHwUMJo=
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260912104006-c10c03c318db/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260912104006-c10c03c318db h1:75fzfzaz/j1mKsqNE01KTMMP3i/9FgmPlwO2BIV8TpU=
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260912104006-c10c03c318db/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260912104006-c10c03c318db h1:tz6Tm3qqxPKp9QMFDUxbVzu5NgYQZq2hY9CGQ+sTmII=
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260912104006-c10c03c318db/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260912104006-c10c03c318db h1:OO+rUNHeZja1m0n/bBfkWtK2NQkNN9iROP0CRqw9aL8=
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260912104006-c10c03c318db/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260912104006-c10c03c318db h1:78W68WJdZjQDhkp4tcFkLcXBH4W8jlCBK1eFcBKKZwI=
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260912104006-c10c03c318db/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260912104006-c10c03c318db h1:qVLzw+rWqzD82/CUwvxfSohUj6aSD9zRAX7WtKiSNeQ=
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260912104006-c10c03c318db/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
|
||||
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260912104006-c10c03c318db h1:EoaFEVn+GVZw2jKXgK+73BdpUZKJ85PGUdbAyxy72pk=
|
||||
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260912104006-c10c03c318db/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260912104006-c10c03c318db h1:rtv8UspnSr157Hp9k6Pj0IV224GvANVx+XTTd2/CjdY=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260912104006-c10c03c318db/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260912104006-c10c03c318db h1:TwBUmUKDuQzA5nIshSzVE0tCKK1GpEfy54E1h3o62t8=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260912104006-c10c03c318db/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo=
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260912104006-c10c03c318db h1:T2yA2pXtVKeZniYbp8bfcNTigauAl3EO3AO1UwVXoGE=
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260912104006-c10c03c318db/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260912104006-c10c03c318db h1:w5BfjtEy9mjMiXtmKfB2uBGeRG4pwbuQ6ouTflNnWyU=
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260912104006-c10c03c318db/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260912104006-c10c03c318db h1:yNdO+HC5OkgKgwqVYd49FRVt5A2jfxsyrSKrf2uM0aM=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260912104006-c10c03c318db/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260912104006-c10c03c318db h1:jJ1WycEj07LsIhtZdgXSiDa9qMkDUvBtr/B8WQm5utQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260912104006-c10c03c318db/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260912104006-c10c03c318db h1:HPBv0BqbHC8ktpn1rSMeoREDPumyFFpJHZsUCwzwLqY=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260912104006-c10c03c318db/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260912104006-c10c03c318db h1:7mJdu1gjC45rEkiIGtdCuEs3v1Oj2IXBnSh9uIgZEmE=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260912104006-c10c03c318db/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260912104006-c10c03c318db h1:YCBQCFTjlkRkkCXV+ScjN/URW9Mx58f6Dv34a8JRtGw=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260912104006-c10c03c318db/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260912104006-c10c03c318db h1:RIp7sKxgUGMidhmi7oVhX8DgnG6UjKk7kvxWvWfKvbY=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260912104006-c10c03c318db/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260912104006-c10c03c318db h1:lElglqZOqg3g7/L8uzJKS6yPNgIxbEu4/vVTzlYE7W8=
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260912104006-c10c03c318db/go.mod h1:Wt5uFdU3tnmm8YzobYewwdF7Mt6SucRQg6xeTNWC3Tk=
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260912104006-c10c03c318db h1:4HvprIkwKcrPYuyQaH5tdIeh5KVBgkauL6o0VqpCkSo=
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260912104006-c10c03c318db/go.mod h1:lyIF6wKBLwWa5ZXaAKbAoewewl+yCHo2iYev39Mbj4E=
|
||||
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260912104006-c10c03c318db h1:rWrNWeyy563mTk3KZas3ore7JPq7M+l8r0XV9lAjc0c=
|
||||
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260912104006-c10c03c318db/go.mod h1:H46PnSTTZNcZokLLiDeMDaHiS1l14PH3tzWi0eykjD8=
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260912104006-c10c03c318db h1:YADxQVD/X9yyV3i/xS3T/lWhpVLslIIl+e+srwpT9p0=
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260912104006-c10c03c318db/go.mod h1:RBhSUDAKWq7fswtV4nQUQhuaTLcX3ettR7teA7/yf2w=
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260912104006-c10c03c318db h1:2hgFBooF0jPOGXKcuJgMA4h1aSOULyAI6OgubZBoD7g=
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260912104006-c10c03c318db/go.mod h1:wRzoIOGG4xbpp3Gh3triLKwMwYriScXzFtunLYhY4w0=
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260912104006-c10c03c318db h1:fFv7izOOsC/HQCDAwTtPjIlayo8znNlAnPqppDb08Jo=
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260912104006-c10c03c318db/go.mod h1:LNiZXmWil1OPwKCheqQjtakZlJuKGFz+iv2eGF76Hhs=
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260912104006-c10c03c318db h1:meCf6CbZqWpV5ITTjawLJzZfFrx6thSgs7a9PZyqdTM=
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260912104006-c10c03c318db/go.mod h1:YFDGKTkpkJGc5+hnX/RYosZyTWg9h+68VB55fYRRLYc=
|
||||
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260912104006-c10c03c318db h1:7bOFA2F/WApDRUamwGM5OThrY5H3+UZpW0yQLlukE8Y=
|
||||
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260912104006-c10c03c318db/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260912104006-c10c03c318db h1:9HjQtfjpo5PTr5AMBWgyTVnWI/zQOTDVQ1agftOOoGo=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260912104006-c10c03c318db/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260912104006-c10c03c318db h1:9OUQzCcoCvleQVLb3xW3AGB+eKGxPmldK1gg61xh7T8=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260912104006-c10c03c318db/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc=
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260912104006-c10c03c318db h1:fKs7KaruaDhStaiYpaqMQXDCmAc4YmNLI/pBkPYvwH8=
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260912104006-c10c03c318db/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260912104006-c10c03c318db h1:K7/F1mWxmf5yUDxSSk+6pRk+yfCoWsqIgt2LsjRpP8w=
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260912104006-c10c03c318db/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
|
||||
github.com/sagernet/fswatch v0.1.2 h1:/TT7k4mkce1qFPxamLO842WjqBgbTBiXP2mlUjp9PFk=
|
||||
github.com/sagernet/fswatch v0.1.2/go.mod h1:5BpGmpUQVd3Mc5r313HRpvADHRg3/rKn5QbwFteB880=
|
||||
github.com/sagernet/gliderssh v0.3.4-0.20260531100337-2194faca5648 h1:IWVjKBARzVjdmH0VUaeTBOBli1qkwKmTG4XfbkpSS20=
|
||||
github.com/sagernet/gliderssh v0.3.4-0.20260531100337-2194faca5648/go.mod h1:FmW0l0t/PzGIdJMr3iXOL+KuxvJTt6XAfF4GxbMlfZc=
|
||||
github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237 h1:SUPFNB+vSP4RBPrSEgNII+HkfqC8hKMpYLodom4o4EU=
|
||||
github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237/go.mod h1:QkkPEJLw59/tfxgapHta14UL5qMUah5NXhO0Kw2Kan4=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/netlink v0.0.0-20260814022025-64455d367bbf h1:b/3rm+KvxzuYRcnMdLq/hmcqX6/2B8k24l6SDHL2Piw=
|
||||
github.com/sagernet/netlink v0.0.0-20260814022025-64455d367bbf/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/nftables v0.3.0-mod.4 h1:vnOtcDYeSXv2e5RoRuGH0lrpttQFJ8iC4ICS2nhlDSo=
|
||||
github.com/sagernet/nftables v0.3.0-mod.4/go.mod h1:8kslHG4VvYNihcco+i6uxIX7qbT8A56T0y5q7U44ZaQ=
|
||||
github.com/sagernet/quic-go v0.61.0-sing-box-mod.4 h1:XoFf8KoBEsamWo3ePlcmS/xs8B7KDurJQfI2U7q/H1c=
|
||||
github.com/sagernet/quic-go v0.61.0-sing-box-mod.4/go.mod h1:hmLC8GJPp+BrpBgrgJnacvI4fZGIhasuy1ROJJ8GR4E=
|
||||
github.com/sagernet/sing v0.9.0-beta.2 h1:JZ6bF5cEobx1FjptNvSLfKXP66nU1U21AuEDnebg8u8=
|
||||
github.com/sagernet/sing v0.9.0-beta.2/go.mod h1:K3Owt3xPhHugvlnlPPxZJ/exXdaJfEPOTNorGk4AXjo=
|
||||
github.com/sagernet/quic-go v0.61.0-sing-box-mod.7 h1:sW2O+DoNF+my1PGlSZ3zG2N+fdxLR3DC0l4sXCM0lBE=
|
||||
github.com/sagernet/quic-go v0.61.0-sing-box-mod.7/go.mod h1:hmLC8GJPp+BrpBgrgJnacvI4fZGIhasuy1ROJJ8GR4E=
|
||||
github.com/sagernet/sing v0.9.5-0.20260914135810-80bfa92a0607 h1:YzA14QltKgRqFKEZYRP1JBL2meuf3Mx3DiDK/U5+/PA=
|
||||
github.com/sagernet/sing v0.9.5-0.20260914135810-80bfa92a0607/go.mod h1:K3Owt3xPhHugvlnlPPxZJ/exXdaJfEPOTNorGk4AXjo=
|
||||
github.com/sagernet/sing-anytls v0.0.0-20260904135308-cec2d74334be h1:0uMXu8kcJU0XLc2vfjGH6q6khmECCc5WYpD9dqlu1Xg=
|
||||
github.com/sagernet/sing-anytls v0.0.0-20260904135308-cec2d74334be/go.mod h1:VRKLnj0ObEsN228h+zuzf91p+6sjtYE8SBaLPVsBy5o=
|
||||
github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3 h1:3y6++yIa8XlDhxPkpR4p+7RUHVY2KTP9CPIGnWmOlO8=
|
||||
github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3/go.mod h1:XEqEDYRCAYLaoPjZ1ifVWJg5iWAJHL2gOAXe/PM28Cg=
|
||||
github.com/sagernet/sing-mux v0.3.5 h1:RHnhVEc+SFqkrK4xMygYjDwwLhzp2Bj3lztSukONfhI=
|
||||
github.com/sagernet/sing-mux v0.3.5/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk=
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260810065514-53aa8058f8df h1:ogyC7KPTWueN7kXFhKSdHeS5/t/zBjQgAOpWjqnrMos=
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260810065514-53aa8058f8df/go.mod h1:4AKZLVcvY3r54UaK2Gbnm7aN8pOwdLz+y4EP0QFZ5Eg=
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260729104525-103eb5fe5eb6 h1:ZAvhkor0prJ8KEX9EmTEH+gJ1WlA3ffjS8GZT6KKq9c=
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260729104525-103eb5fe5eb6/go.mod h1:PWX7WygD8jpwfqfaGNySXpJYTn0SOwjBI1BKHHC2+Bw=
|
||||
github.com/sagernet/sing-quic v0.7.0-beta.2 h1:qfMz4IyGIj6WhqhrR5ZU+d4Cqppi6RM6BpGXG6phfy8=
|
||||
github.com/sagernet/sing-quic v0.7.0-beta.2/go.mod h1:Z+ZpYBLJ7WkPPrGSCYFxna4Dos2XrywEy6YH6SY5L6Q=
|
||||
github.com/sagernet/sing-mux v0.3.7-0.20260905054442-91d1502591ce h1:ay1pGbzMF4e7iggj+uESNhwMNPbZZajDghcdC4P92Dc=
|
||||
github.com/sagernet/sing-mux v0.3.7-0.20260905054442-91d1502591ce/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk=
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260903200519-8b89c968949d h1:Jt/Tb0boIr/xRr4sWr2vC/rrVlYNoumZITLEQpqZ8UE=
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260903200519-8b89c968949d/go.mod h1:4AKZLVcvY3r54UaK2Gbnm7aN8pOwdLz+y4EP0QFZ5Eg=
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260903200517-e060dda5b1f1 h1:Zn7+pNY5mX1e4DO8oKhTHz5sxqUKNdCWKbfZUtM26Qg=
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260903200517-e060dda5b1f1/go.mod h1:PWX7WygD8jpwfqfaGNySXpJYTn0SOwjBI1BKHHC2+Bw=
|
||||
github.com/sagernet/sing-quic v0.7.1-0.20260904135313-497364e8ee3e h1:2r0FRN0DBSfggWYtdH/69uW91kqEOByBWw/5hiCq6qU=
|
||||
github.com/sagernet/sing-quic v0.7.1-0.20260904135313-497364e8ee3e/go.mod h1:rJFeVxbEej2iuyeCJ3drKW+p5rOgtLIW3XhZ6ty7Fig=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1 h1:ZiHZdnEnP+YS73NMsxiZmIFCwNd0M4k7PkGCKNXhbaM=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
|
||||
github.com/sagernet/sing-snell v0.0.0-20260727093646-7cb813e07b73 h1:Iyhoka9XutVbIhkhjn6s2Ez2AEuBG5i4KbkQKqRMsug=
|
||||
github.com/sagernet/sing-snell v0.0.0-20260727093646-7cb813e07b73/go.mod h1:et8Lws4f5QbOrY65DmjevHGup3mijJkhswkto6cwciM=
|
||||
github.com/sagernet/sing-tun v0.8.12-0.20260810013717-909ab10ad507 h1:YF57rLEryUvX0OJWpVTebZ9IMpvzRcozhJPcn58lQ9c=
|
||||
github.com/sagernet/sing-tun v0.8.12-0.20260810013717-909ab10ad507/go.mod h1:3EgPst7agntRO7D6GOsiZ1l9FoqdLeuWmKT5TnWkmf0=
|
||||
github.com/sagernet/sing-usbip v0.0.0-20260616101517-efb91521eddb h1:KEMbfexD4DvrQGYWwx6r+AwH9Veh8z6cnBZmtCS2G+0=
|
||||
github.com/sagernet/sing-usbip v0.0.0-20260616101517-efb91521eddb/go.mod h1:D4CnJX3MNAAANhbQUxfIRgBdnvlTEaV7h6ojedcs+pw=
|
||||
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-snell v0.0.0-20260904135315-bc5a12ac736f h1:tbTCI+iis5sTmua7a6Q7vebcSRURok/LGgnEafnQAsc=
|
||||
github.com/sagernet/sing-snell v0.0.0-20260904135315-bc5a12ac736f/go.mod h1:et8Lws4f5QbOrY65DmjevHGup3mijJkhswkto6cwciM=
|
||||
github.com/sagernet/sing-usbip v0.0.0-20260817040617-28bd42667eca h1:5wA+IE0Fq1CGVLOgSpm0gKKZ03HzugcJ2JyhmDqeX6A=
|
||||
github.com/sagernet/sing-usbip v0.0.0-20260817040617-28bd42667eca/go.mod h1:ADAZZU85MnM91XNhd2TdZRTaIbA7RjTZuQ1KCHcUbNg=
|
||||
github.com/sagernet/sing-vmess v0.2.8 h1:xd5nnDOMlC76RgrLksS4jlk3eMt3c3CvQY3NsjWPWeI=
|
||||
github.com/sagernet/sing-vmess v0.2.8/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/go.mod h1:NjhsCEWedJm7eFLyhuBgIEzwfhRmytrUoiLluxs5Sk8=
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.2 h1:JXYUrqxvIYGVVvTz0xzYR6DufhLBfnV5wh5lwhbdJVM=
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.2/go.mod h1:WLUSOPmTcf7VN9gLCe01qUSIvD+/cKC177neENyZPkI=
|
||||
github.com/sagernet/wireguard-go v0.0.5-0.20260810121456-c6c8a831ef70 h1:WTVgbkDDGnZqxIUnBsE9QyJz2dtSaeoh9mFwxmQqfgI=
|
||||
github.com/sagernet/wireguard-go v0.0.5-0.20260810121456-c6c8a831ef70/go.mod h1:er10sELpmzLXq7S7Pbc1Zsbyapcr+/gxNAHKTo6fzVA=
|
||||
github.com/sagernet/wireguard-go v0.0.6 h1:zAjWSzufYThDsyLHxPLyyR+XdpBMlFDWD7WxJAvynSw=
|
||||
github.com/sagernet/wireguard-go v0.0.6/go.mod h1:er10sELpmzLXq7S7Pbc1Zsbyapcr+/gxNAHKTo6fzVA=
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
@@ -377,8 +371,8 @@ github.com/spyzhov/ajson v0.9.4 h1:MVibcTCgO7DY4IlskdqIlCmDOsUOZ9P7oKj8ifdcf84=
|
||||
github.com/spyzhov/ajson v0.9.4/go.mod h1:a6oSw0MMb7Z5aD2tPoPO+jq11ETKgXUr2XktHdT8Wt8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/stretchr/testify v1.12.0 h1:K6Mr6jO9JICuend/5xzTM03ydSV3vdNRYAdPSukj8uI=
|
||||
github.com/stretchr/testify v1.12.0/go.mod h1:bOYBZb5qJ00vPzWfIqBUZPaxK8jWiXc6d3ErP4Ca9Gw=
|
||||
github.com/tailscale/certstore v0.1.1-0.20260409135935-3638fb84b77d h1:JcGKBZAL7ePLwOhUdN8qGQZlP5GueEiIZwY7R62pejE=
|
||||
github.com/tailscale/certstore v0.1.1-0.20260409135935-3638fb84b77d/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4=
|
||||
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4=
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -21,6 +22,7 @@ import (
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json/badjson"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
@@ -176,6 +178,8 @@ func TestOpenConnectDockerInterop(t *testing.T) {
|
||||
}
|
||||
|
||||
func openConnectInstanceOptions(server string, certificateAuthorityPath string, username string, password string) option.Options {
|
||||
hosts := new(badjson.TypedMap[string, badoption.Listable[netip.Addr]])
|
||||
hosts.Put("localhost", []netip.Addr{netip.MustParseAddr("127.0.0.1")})
|
||||
endpointOptions := option.OpenConnectEndpointOptions{
|
||||
Server: server,
|
||||
Flavor: "anyconnect",
|
||||
@@ -191,6 +195,9 @@ func openConnectInstanceOptions(server string, certificateAuthorityPath string,
|
||||
},
|
||||
}
|
||||
return option.Options{
|
||||
DNS: &option.DNSOptions{RawDNSOptions: option.RawDNSOptions{
|
||||
Servers: []option.DNSServerOptions{{Type: C.DNSTypeHosts, Options: &option.HostsDNSServerOptions{Predefined: hosts}}},
|
||||
}},
|
||||
Endpoints: []option.Endpoint{
|
||||
{
|
||||
Type: C.TypeOpenConnect,
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
//go:build with_wireguard
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestWireGuardEndpointDataPlane(t *testing.T) {
|
||||
for _, system := range []bool{false, true} {
|
||||
t.Run(fmt.Sprintf("system=%v", system), func(test *testing.T) {
|
||||
serverKey, err := ecdh.X25519().GenerateKey(rand.Reader)
|
||||
require.NoError(test, err)
|
||||
clientKey, err := ecdh.X25519().GenerateKey(rand.Reader)
|
||||
require.NoError(test, err)
|
||||
portReservation, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)})
|
||||
require.NoError(test, err)
|
||||
serverPort := uint16(portReservation.LocalAddr().(*net.UDPAddr).Port)
|
||||
require.NoError(test, portReservation.Close())
|
||||
serverAddresses := []netip.Prefix{netip.MustParsePrefix("198.18.17.1/32"), netip.MustParsePrefix("fd17::1/128")}
|
||||
clientAddresses := []netip.Prefix{netip.MustParsePrefix("198.18.17.2/32"), netip.MustParsePrefix("fd17::2/128")}
|
||||
instance := startInstance(test, option.Options{
|
||||
Endpoints: []option.Endpoint{
|
||||
{
|
||||
Type: C.TypeWireGuard,
|
||||
Tag: "server",
|
||||
Options: &option.WireGuardEndpointOptions{
|
||||
MTU: 1280, Address: serverAddresses, Workers: 2,
|
||||
PrivateKey: base64.StdEncoding.EncodeToString(serverKey.Bytes()),
|
||||
ListenPort: serverPort,
|
||||
Peers: []option.WireGuardPeer{{
|
||||
PublicKey: base64.StdEncoding.EncodeToString(clientKey.PublicKey().Bytes()),
|
||||
AllowedIPs: clientAddresses,
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: C.TypeWireGuard,
|
||||
Tag: "client",
|
||||
Options: &option.WireGuardEndpointOptions{
|
||||
System: system, MTU: 1280, Address: clientAddresses, Workers: 2,
|
||||
PrivateKey: base64.StdEncoding.EncodeToString(clientKey.Bytes()),
|
||||
Peers: []option.WireGuardPeer{{
|
||||
Address: "127.0.0.1", Port: serverPort,
|
||||
PublicKey: base64.StdEncoding.EncodeToString(serverKey.PublicKey().Bytes()),
|
||||
AllowedIPs: serverAddresses,
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
Outbounds: []option.Outbound{{Type: C.TypeDirect, Tag: "direct", Options: &option.DirectOutboundOptions{}}},
|
||||
Route: &option.RouteOptions{Final: "direct"},
|
||||
})
|
||||
endpoint, loaded := instance.Endpoint().Get("client")
|
||||
require.True(test, loaded)
|
||||
for index, address := range serverAddresses {
|
||||
for _, network := range []string{"tcp", "udp", "packet"} {
|
||||
test.Run(fmt.Sprintf("ipv6=%v/%s", address.Addr().Is6(), network), func(subtest *testing.T) {
|
||||
subtest.Parallel()
|
||||
loopback := netip.MustParseAddr("127.0.0.1")
|
||||
if index == 1 {
|
||||
loopback = netip.IPv6Loopback()
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(subtest.Context(), 3*time.Second)
|
||||
defer cancel()
|
||||
if network == "tcp" {
|
||||
listener, listenErr := net.ListenTCP("tcp", net.TCPAddrFromAddrPort(netip.AddrPortFrom(loopback, 0)))
|
||||
require.NoError(subtest, listenErr)
|
||||
defer listener.Close()
|
||||
listener.SetDeadline(time.Now().Add(3 * time.Second))
|
||||
destination := M.SocksaddrFrom(address.Addr(), uint16(listener.Addr().(*net.TCPAddr).Port))
|
||||
client, dialErr := endpoint.DialContext(ctx, "tcp", destination)
|
||||
require.NoError(subtest, dialErr)
|
||||
defer client.Close()
|
||||
server, acceptErr := listener.Accept()
|
||||
require.NoError(subtest, acceptErr)
|
||||
defer server.Close()
|
||||
client.SetDeadline(time.Now().Add(3 * time.Second))
|
||||
server.SetDeadline(time.Now().Add(3 * time.Second))
|
||||
payload := bytes.Repeat([]byte("wireguard-encrypted-tcp"), 8192)
|
||||
for _, pair := range [][2]net.Conn{{client, server}, {server, client}} {
|
||||
result := make(chan error, 1)
|
||||
go func() {
|
||||
_, writeErr := pair[0].Write(payload)
|
||||
result <- writeErr
|
||||
}()
|
||||
received := make([]byte, len(payload))
|
||||
_, readErr := io.ReadFull(pair[1], received)
|
||||
require.NoError(subtest, readErr)
|
||||
require.Equal(subtest, payload, received)
|
||||
require.NoError(subtest, <-result)
|
||||
}
|
||||
return
|
||||
}
|
||||
server, listenErr := net.ListenUDP("udp", net.UDPAddrFromAddrPort(netip.AddrPortFrom(loopback, 0)))
|
||||
require.NoError(subtest, listenErr)
|
||||
defer server.Close()
|
||||
server.SetDeadline(time.Now().Add(3 * time.Second))
|
||||
destination := M.SocksaddrFrom(address.Addr(), uint16(server.LocalAddr().(*net.UDPAddr).Port))
|
||||
var send func([]byte) (int, error)
|
||||
var receive func([]byte) (int, error)
|
||||
if network == "udp" {
|
||||
client, dialErr := endpoint.DialContext(ctx, "udp", destination)
|
||||
require.NoError(subtest, dialErr)
|
||||
defer client.Close()
|
||||
client.SetDeadline(time.Now().Add(3 * time.Second))
|
||||
send, receive = client.Write, client.Read
|
||||
} else {
|
||||
client, dialErr := endpoint.ListenPacket(ctx, destination)
|
||||
require.NoError(subtest, dialErr)
|
||||
defer client.Close()
|
||||
client.SetDeadline(time.Now().Add(3 * time.Second))
|
||||
send = func(payload []byte) (int, error) { return client.WriteTo(payload, destination.UDPAddr()) }
|
||||
receive = func(payload []byte) (int, error) {
|
||||
count, source, readErr := client.ReadFrom(payload)
|
||||
if readErr == nil {
|
||||
require.Equal(subtest, destination.String(), source.String())
|
||||
}
|
||||
return count, readErr
|
||||
}
|
||||
}
|
||||
for _, size := range []int{64, 4096} {
|
||||
payload := bytes.Repeat([]byte{0x65}, size)
|
||||
request := payload
|
||||
if system && size > 1200 {
|
||||
request = request[:1200]
|
||||
}
|
||||
_, writeErr := send(request)
|
||||
require.NoError(subtest, writeErr)
|
||||
received := make([]byte, 65535)
|
||||
count, source, readErr := server.ReadFromUDP(received)
|
||||
require.NoError(subtest, readErr)
|
||||
require.Equal(subtest, request, received[:count])
|
||||
_, writeErr = server.WriteToUDP(payload, source)
|
||||
require.NoError(subtest, writeErr)
|
||||
count, readErr = receive(received)
|
||||
require.NoError(subtest, readErr)
|
||||
require.Equal(subtest, payload, received[:count])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -37,20 +37,20 @@ type Device interface {
|
||||
}
|
||||
|
||||
type DeviceOptions struct {
|
||||
Context context.Context
|
||||
Logger logger.ContextLogger
|
||||
System bool
|
||||
Handler tun.Handler
|
||||
UDPTimeout time.Duration
|
||||
ICMPTimeout time.Duration
|
||||
UDPMapping tun.NATMapping
|
||||
UDPFiltering tun.NATFiltering
|
||||
UDPNATMax uint32
|
||||
InterfaceFinder control.InterfaceFinder
|
||||
ExcludeInterface []string
|
||||
Name string
|
||||
MTU uint32
|
||||
Configuration Configuration
|
||||
Context context.Context
|
||||
Logger logger.ContextLogger
|
||||
System bool
|
||||
Handler tun.Handler
|
||||
UDPTimeout time.Duration
|
||||
ICMPTimeout time.Duration
|
||||
UDPMapping tun.NATMapping
|
||||
UDPFiltering tun.NATFiltering
|
||||
UDPNATMax uint32
|
||||
InterfaceFinder control.InterfaceFinder
|
||||
MemoryPressure func() tun.MemoryPressure
|
||||
Name string
|
||||
MTU uint32
|
||||
Configuration Configuration
|
||||
}
|
||||
|
||||
type Configuration struct {
|
||||
@@ -86,12 +86,26 @@ func NewDevice(options DeviceOptions) (Device, error) {
|
||||
if !options.System {
|
||||
return newStackDevice(options)
|
||||
}
|
||||
if !tun.WithGVisor {
|
||||
return newSystemDevice(options)
|
||||
}
|
||||
return newSystemStackDevice(options)
|
||||
}
|
||||
|
||||
func newStack(options DeviceOptions, memoryTun *tun.MemoryTun) (*tun.Go, error) {
|
||||
return tun.NewGo(tun.StackOptions{
|
||||
Context: options.Context,
|
||||
Tun: memoryTun,
|
||||
TunOptions: tun.Options{MTU: options.MTU},
|
||||
UDPTimeout: options.UDPTimeout,
|
||||
ICMPTimeout: options.ICMPTimeout,
|
||||
UDPMapping: options.UDPMapping,
|
||||
UDPFiltering: options.UDPFiltering,
|
||||
UDPNATMax: options.UDPNATMax,
|
||||
Handler: options.Handler,
|
||||
Logger: options.Logger,
|
||||
InterfaceFinder: options.InterfaceFinder,
|
||||
MemoryPressure: options.MemoryPressure,
|
||||
})
|
||||
}
|
||||
|
||||
type baseDevice struct {
|
||||
packetWriter PacketWriter
|
||||
returnState atomic.Pointer[returnPathState]
|
||||
|
||||
@@ -1,27 +1,13 @@
|
||||
//go:build with_gvisor
|
||||
|
||||
package openconnect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/netip"
|
||||
"slices"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/buffer"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/adapters/gonet"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/network/ipv4"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/network/ipv6"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
"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/common/interrupt"
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
@@ -32,17 +18,13 @@ var _ Device = (*stackDevice)(nil)
|
||||
|
||||
type stackDevice struct {
|
||||
baseDevice
|
||||
stateAccess sync.RWMutex
|
||||
options DeviceOptions
|
||||
stack *stack.Stack
|
||||
endpoint *stackEndpoint
|
||||
inet4Address netip.Addr
|
||||
inet6Address netip.Addr
|
||||
inet4UDP interrupt.Group
|
||||
inet6UDP interrupt.Group
|
||||
udpForwarder *tun.UDPForwarder
|
||||
icmpForwarder *tun.ICMPForwarder
|
||||
closeOnce sync.Once
|
||||
stateAccess sync.RWMutex
|
||||
options DeviceOptions
|
||||
stack *tun.Go
|
||||
memoryTun *tun.MemoryTun
|
||||
inet4Address netip.Addr
|
||||
inet6Address netip.Addr
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
func newStackDevice(options DeviceOptions) (*stackDevice, error) {
|
||||
@@ -52,51 +34,23 @@ func newStackDevice(options DeviceOptions) (*stackDevice, error) {
|
||||
device := &stackDevice{
|
||||
options: options,
|
||||
}
|
||||
endpoint := &stackEndpoint{
|
||||
device: device,
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
endpoint.mtu.Store(options.MTU)
|
||||
ipStack, err := tun.NewGVisorStackWithOptions(endpoint, stack.NICOptions{}, true)
|
||||
device.inet4Address, device.inet6Address = firstAddresses(options.Configuration.Addresses)
|
||||
device.memoryTun = tun.NewMemoryTun(tun.MemoryTunOptions{
|
||||
MTU: int(options.MTU),
|
||||
Headroom: PacketHeadroom,
|
||||
RearSpace: systemDevicePacketRearSpace,
|
||||
Outbound: device.writeOutbound,
|
||||
})
|
||||
var err error
|
||||
device.stack, err = newStack(options, device.memoryTun)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
device.stack = ipStack
|
||||
device.endpoint = endpoint
|
||||
err = device.updateAddresses(nil, options.Configuration.Addresses)
|
||||
if err != nil {
|
||||
ipStack.Close()
|
||||
return nil, err
|
||||
}
|
||||
if options.Handler != nil {
|
||||
ipStack.SetTransportProtocolHandler(tcp.ProtocolNumber, tun.NewTCPForwarder(options.Context, ipStack, options.Handler).HandlePacket)
|
||||
udpForwarder := tun.NewUDPForwarder(options.Context, ipStack, options.Handler, tun.UDPNatOptions{
|
||||
Timeout: options.UDPTimeout,
|
||||
Shared: true,
|
||||
Mapping: options.UDPMapping,
|
||||
Filtering: options.UDPFiltering,
|
||||
MaxSize: options.UDPNATMax,
|
||||
InterfaceFinder: options.InterfaceFinder,
|
||||
ExcludeInterface: options.ExcludeInterface,
|
||||
})
|
||||
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, udpForwarder.HandlePacket)
|
||||
device.udpForwarder = udpForwarder
|
||||
icmpForwarder := tun.NewICMPForwarder(ipStack, options.Handler, options.Logger)
|
||||
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber4, icmpForwarder.HandlePacket)
|
||||
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber6, icmpForwarder.HandlePacket)
|
||||
device.icmpForwarder = icmpForwarder
|
||||
}
|
||||
return device, nil
|
||||
}
|
||||
|
||||
func (d *stackDevice) Start() error {
|
||||
if d.udpForwarder != nil {
|
||||
err := d.udpForwarder.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return d.stack.Start()
|
||||
}
|
||||
|
||||
func (d *stackDevice) UpdateConfiguration(configuration Configuration) error {
|
||||
@@ -104,51 +58,10 @@ func (d *stackDevice) UpdateConfiguration(configuration Configuration) error {
|
||||
defer d.stateAccess.Unlock()
|
||||
if configuration.MTU != 0 {
|
||||
d.options.MTU = configuration.MTU
|
||||
d.endpoint.mtu.Store(configuration.MTU)
|
||||
d.memoryTun.UpdateMTU(int(configuration.MTU))
|
||||
}
|
||||
previousAddresses := d.options.Configuration.Addresses
|
||||
d.options.Configuration = configuration
|
||||
return d.updateAddresses(previousAddresses, configuration.Addresses)
|
||||
}
|
||||
|
||||
func (d *stackDevice) updateAddresses(previousAddresses []netip.Prefix, addresses []netip.Prefix) error {
|
||||
for _, prefix := range previousAddresses {
|
||||
if slices.Contains(addresses, prefix) {
|
||||
continue
|
||||
}
|
||||
gErr := d.stack.RemoveAddress(tun.DefaultNIC, tun.AddressFromAddr(prefix.Addr()))
|
||||
if gErr != nil {
|
||||
return E.New("remove local address ", prefix, ": ", gErr.String())
|
||||
}
|
||||
}
|
||||
for _, prefix := range addresses {
|
||||
if slices.Contains(previousAddresses, prefix) {
|
||||
continue
|
||||
}
|
||||
protocolAddress := tcpip.ProtocolAddress{
|
||||
AddressWithPrefix: tcpip.AddressWithPrefix{
|
||||
Address: tun.AddressFromAddr(prefix.Addr()),
|
||||
PrefixLen: prefix.Bits(),
|
||||
},
|
||||
}
|
||||
if prefix.Addr().Is4() {
|
||||
protocolAddress.Protocol = ipv4.ProtocolNumber
|
||||
} else {
|
||||
protocolAddress.Protocol = ipv6.ProtocolNumber
|
||||
}
|
||||
gErr := d.stack.AddProtocolAddress(tun.DefaultNIC, protocolAddress, stack.AddressProperties{})
|
||||
if gErr != nil {
|
||||
return E.New("add local address ", prefix, ": ", gErr.String())
|
||||
}
|
||||
}
|
||||
inet4Address, inet6Address := firstAddresses(addresses)
|
||||
if d.inet4Address != inet4Address {
|
||||
d.inet4UDP.Interrupt(true)
|
||||
}
|
||||
if d.inet6Address != inet6Address {
|
||||
d.inet6UDP.Interrupt(true)
|
||||
}
|
||||
d.inet4Address, d.inet6Address = inet4Address, inet6Address
|
||||
d.inet4Address, d.inet6Address = firstAddresses(configuration.Addresses)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -157,92 +70,60 @@ func (d *stackDevice) WriteInboundBuffers(packetBuffers []*buf.Buffer) error {
|
||||
}
|
||||
|
||||
func (d *stackDevice) writeBuffers(packetBuffers []*buf.Buffer) error {
|
||||
networkProtocols := make([]tcpip.NetworkProtocolNumber, 0, len(packetBuffers))
|
||||
stackPacketBuffers := make([]*stack.PacketBuffer, 0, len(packetBuffers))
|
||||
var packetErr error
|
||||
for _, packetBuffer := range packetBuffers {
|
||||
packet := packetBuffer.Bytes()
|
||||
var networkProtocol tcpip.NetworkProtocolNumber
|
||||
switch header.IPVersion(packet) {
|
||||
case header.IPv4Version:
|
||||
networkProtocol = header.IPv4ProtocolNumber
|
||||
case header.IPv6Version:
|
||||
networkProtocol = header.IPv6ProtocolNumber
|
||||
default:
|
||||
if packetErr == nil {
|
||||
packetErr = E.New("invalid IP packet")
|
||||
}
|
||||
continue
|
||||
}
|
||||
networkProtocols = append(networkProtocols, networkProtocol)
|
||||
stackPacketBuffers = append(stackPacketBuffers, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Payload: buffer.MakeWithData(packet),
|
||||
}))
|
||||
}
|
||||
d.endpoint.deliverNetworkPackets(networkProtocols, stackPacketBuffers)
|
||||
for _, packetBuffer := range stackPacketBuffers {
|
||||
packetBuffer.DecRef()
|
||||
}
|
||||
return packetErr
|
||||
_, err := d.memoryTun.WritePackets(common.Map(packetBuffers, (*buf.Buffer).Bytes))
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *stackDevice) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
address := tcpip.FullAddress{
|
||||
NIC: tun.DefaultNIC,
|
||||
Port: destination.Port,
|
||||
Addr: tun.AddressFromAddr(destination.Addr),
|
||||
bind, err := d.bindAddress(destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch N.NetworkName(network) {
|
||||
case N.NetworkTCP:
|
||||
d.stateAccess.RLock()
|
||||
bind, networkProtocol, _, err := d.bindAddressLocked(destination)
|
||||
d.stateAccess.RUnlock()
|
||||
var tcpConn *tun.GoConn
|
||||
tcpConn, err = d.stack.DialTCP(ctx, bind, destination.AddrPort())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gonet.DialTCPWithBind(ctx, d.stack, bind, address, networkProtocol)
|
||||
return tcpConn, nil
|
||||
case N.NetworkUDP:
|
||||
d.stateAccess.RLock()
|
||||
defer d.stateAccess.RUnlock()
|
||||
bind, networkProtocol, udpGroup, err := d.bindAddressLocked(destination)
|
||||
var udpConn *tun.GoUDPConn
|
||||
udpConn, err = d.stack.DialUDP(netip.AddrPortFrom(bind, 0), destination.AddrPort())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
udpConn, err := gonet.DialUDP(d.stack, &bind, &address, networkProtocol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return udpGroup.NewConn(udpConn, false), nil
|
||||
return udpConn, nil
|
||||
default:
|
||||
return nil, E.Extend(N.ErrUnknownNetwork, network)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *stackDevice) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
d.stateAccess.RLock()
|
||||
defer d.stateAccess.RUnlock()
|
||||
bind, networkProtocol, udpGroup, err := d.bindAddressLocked(destination)
|
||||
bind, err := d.bindAddress(destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
udpConn, err := gonet.DialUDP(d.stack, &bind, nil, networkProtocol)
|
||||
udpConn, err := d.stack.ListenUDP(netip.AddrPortFrom(bind, 0))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return udpGroup.NewPacketConn(udpConn, false), nil
|
||||
return udpConn, nil
|
||||
}
|
||||
|
||||
func (d *stackDevice) bindAddressLocked(destination M.Socksaddr) (tcpip.FullAddress, tcpip.NetworkProtocolNumber, *interrupt.Group, error) {
|
||||
func (d *stackDevice) bindAddress(destination M.Socksaddr) (netip.Addr, error) {
|
||||
d.stateAccess.RLock()
|
||||
defer d.stateAccess.RUnlock()
|
||||
if destination.IsIPv4() {
|
||||
if !d.inet4Address.IsValid() {
|
||||
return tcpip.FullAddress{}, 0, nil, E.New("missing IPv4 local address")
|
||||
return netip.Addr{}, E.New("missing IPv4 local address")
|
||||
}
|
||||
return tcpip.FullAddress{NIC: tun.DefaultNIC, Addr: tun.AddressFromAddr(d.inet4Address)}, header.IPv4ProtocolNumber, &d.inet4UDP, nil
|
||||
return d.inet4Address, nil
|
||||
}
|
||||
if !d.inet6Address.IsValid() {
|
||||
return tcpip.FullAddress{}, 0, nil, E.New("missing IPv6 local address")
|
||||
return netip.Addr{}, E.New("missing IPv6 local address")
|
||||
}
|
||||
return tcpip.FullAddress{NIC: tun.DefaultNIC, Addr: tun.AddressFromAddr(d.inet6Address)}, header.IPv6ProtocolNumber, &d.inet6UDP, nil
|
||||
return d.inet6Address, nil
|
||||
}
|
||||
|
||||
func (d *stackDevice) PortAddresses() (netip.Addr, netip.Addr) {
|
||||
@@ -258,115 +139,9 @@ func (d *stackDevice) PortMTU() uint32 {
|
||||
}
|
||||
|
||||
func (d *stackDevice) Close() error {
|
||||
var err error
|
||||
d.closeOnce.Do(func() {
|
||||
close(d.endpoint.done)
|
||||
if d.udpForwarder != nil {
|
||||
d.udpForwarder.Close()
|
||||
}
|
||||
if d.icmpForwarder != nil {
|
||||
d.icmpForwarder.Close()
|
||||
}
|
||||
d.stack.Close()
|
||||
for _, endpoint := range d.stack.CleanupEndpoints() {
|
||||
endpoint.Abort()
|
||||
}
|
||||
d.stack.Wait()
|
||||
err = E.Errors(d.stack.Close(), d.memoryTun.Close())
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
type stackEndpoint struct {
|
||||
device *stackDevice
|
||||
mtu atomic.Uint32
|
||||
done chan struct{}
|
||||
dispatcherAccess sync.RWMutex
|
||||
dispatcher stack.NetworkDispatcher
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) MTU() uint32 {
|
||||
return e.mtu.Load()
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) SetMTU(mtu uint32) {
|
||||
e.mtu.Store(mtu)
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) MaxHeaderLength() uint16 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) LinkAddress() tcpip.LinkAddress {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) SetLinkAddress(addr tcpip.LinkAddress) {
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) Capabilities() stack.LinkEndpointCapabilities {
|
||||
return stack.CapabilityRXChecksumOffload
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||
e.dispatcherAccess.Lock()
|
||||
defer e.dispatcherAccess.Unlock()
|
||||
e.dispatcher = dispatcher
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) IsAttached() bool {
|
||||
e.dispatcherAccess.RLock()
|
||||
defer e.dispatcherAccess.RUnlock()
|
||||
return e.dispatcher != nil
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) deliverNetworkPackets(networkProtocols []tcpip.NetworkProtocolNumber, packetBuffers []*stack.PacketBuffer) {
|
||||
e.dispatcherAccess.RLock()
|
||||
defer e.dispatcherAccess.RUnlock()
|
||||
if e.dispatcher == nil {
|
||||
return
|
||||
}
|
||||
for i, packetBuffer := range packetBuffers {
|
||||
e.dispatcher.DeliverNetworkPacket(networkProtocols[i], packetBuffer)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) Wait() {
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) ARPHardwareType() header.ARPHardwareType {
|
||||
return header.ARPHardwareNone
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) AddHeader(packetBuffer *stack.PacketBuffer) {
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) ParseHeader(packetBuffer *stack.PacketBuffer) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) WritePackets(list stack.PacketBufferList) (int, tcpip.Error) {
|
||||
packetBuffers := make([]*buf.Buffer, 0, list.Len())
|
||||
for _, packetBuffer := range list.AsSlice() {
|
||||
packetSlices := packetBuffer.AsSlices()
|
||||
packetLength := 0
|
||||
for _, packetSlice := range packetSlices {
|
||||
packetLength += len(packetSlice)
|
||||
}
|
||||
outboundBuffer := buf.NewSize(PacketHeadroom + packetLength + systemDevicePacketRearSpace)
|
||||
outboundBuffer.Resize(PacketHeadroom, 0)
|
||||
for _, packetSlice := range packetSlices {
|
||||
_, _ = outboundBuffer.Write(packetSlice)
|
||||
}
|
||||
packetBuffers = append(packetBuffers, outboundBuffer)
|
||||
}
|
||||
err := e.device.writeOutbound(packetBuffers)
|
||||
if err != nil {
|
||||
return 0, &tcpip.ErrClosedForSend{}
|
||||
}
|
||||
return list.Len(), nil
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) Close() {
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) SetOnCloseAction(action func()) {
|
||||
return err
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
//go:build !with_gvisor
|
||||
|
||||
package openconnect
|
||||
|
||||
import E "github.com/sagernet/sing/common/exceptions"
|
||||
|
||||
func newStackDevice(options DeviceOptions) (Device, error) {
|
||||
return nil, E.New("system:false requires the with_gvisor build tag")
|
||||
}
|
||||
|
||||
func newSystemStackDevice(options DeviceOptions) (Device, error) {
|
||||
return nil, E.New("system stack requires the with_gvisor build tag")
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
//go:build with_gvisor
|
||||
|
||||
package openconnect
|
||||
|
||||
import (
|
||||
@@ -22,11 +20,7 @@ func newSystemStackDevice(options DeviceOptions) (*systemStackDevice, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stackOptions := options
|
||||
stackOptions.System = false
|
||||
stackOptions.Name = system.options.Name
|
||||
stackOptions.ExcludeInterface = []string{system.options.Name}
|
||||
stackDevice, err := newStackDevice(stackOptions)
|
||||
stackDevice, err := newStackDevice(options)
|
||||
if err != nil {
|
||||
system.Close()
|
||||
return nil, err
|
||||
|
||||
+31
-17
@@ -36,20 +36,20 @@ type Device interface {
|
||||
}
|
||||
|
||||
type DeviceOptions struct {
|
||||
Context context.Context
|
||||
Logger logger.ContextLogger
|
||||
System bool
|
||||
Handler tun.Handler
|
||||
UDPTimeout time.Duration
|
||||
ICMPTimeout time.Duration
|
||||
UDPMapping tun.NATMapping
|
||||
UDPFiltering tun.NATFiltering
|
||||
UDPNATMax uint32
|
||||
InterfaceFinder control.InterfaceFinder
|
||||
ExcludeInterface []string
|
||||
Name string
|
||||
MTU uint32
|
||||
Configuration Configuration
|
||||
Context context.Context
|
||||
Logger logger.ContextLogger
|
||||
System bool
|
||||
Handler tun.Handler
|
||||
UDPTimeout time.Duration
|
||||
ICMPTimeout time.Duration
|
||||
UDPMapping tun.NATMapping
|
||||
UDPFiltering tun.NATFiltering
|
||||
UDPNATMax uint32
|
||||
InterfaceFinder control.InterfaceFinder
|
||||
MemoryPressure func() tun.MemoryPressure
|
||||
Name string
|
||||
MTU uint32
|
||||
Configuration Configuration
|
||||
}
|
||||
|
||||
type Configuration struct {
|
||||
@@ -85,12 +85,26 @@ func NewDevice(options DeviceOptions) (Device, error) {
|
||||
if !options.System {
|
||||
return newStackDevice(options)
|
||||
}
|
||||
if !tun.WithGVisor {
|
||||
return newSystemDevice(options)
|
||||
}
|
||||
return newSystemStackDevice(options)
|
||||
}
|
||||
|
||||
func newStack(options DeviceOptions, memoryTun *tun.MemoryTun) (*tun.Go, error) {
|
||||
return tun.NewGo(tun.StackOptions{
|
||||
Context: options.Context,
|
||||
Tun: memoryTun,
|
||||
TunOptions: tun.Options{MTU: options.MTU},
|
||||
UDPTimeout: options.UDPTimeout,
|
||||
ICMPTimeout: options.ICMPTimeout,
|
||||
UDPMapping: options.UDPMapping,
|
||||
UDPFiltering: options.UDPFiltering,
|
||||
UDPNATMax: options.UDPNATMax,
|
||||
Handler: options.Handler,
|
||||
Logger: options.Logger,
|
||||
InterfaceFinder: options.InterfaceFinder,
|
||||
MemoryPressure: options.MemoryPressure,
|
||||
})
|
||||
}
|
||||
|
||||
type baseDevice struct {
|
||||
packetWriter PacketWriter
|
||||
returnState atomic.Pointer[returnPathState]
|
||||
|
||||
@@ -1,27 +1,13 @@
|
||||
//go:build with_gvisor
|
||||
|
||||
package openvpn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/netip"
|
||||
"slices"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/buffer"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/adapters/gonet"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/network/ipv4"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/network/ipv6"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
"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/common/interrupt"
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
@@ -34,14 +20,10 @@ type stackDevice struct {
|
||||
baseDevice
|
||||
stateAccess sync.RWMutex
|
||||
options DeviceOptions
|
||||
stack *stack.Stack
|
||||
endpoint *stackEndpoint
|
||||
stack *tun.Go
|
||||
memoryTun *tun.MemoryTun
|
||||
inet4Address netip.Addr
|
||||
inet6Address netip.Addr
|
||||
inet4UDP interrupt.Group
|
||||
inet6UDP interrupt.Group
|
||||
udpForwarder *tun.UDPForwarder
|
||||
icmpForwarder *tun.ICMPForwarder
|
||||
logRouteOptions bool
|
||||
closeOnce sync.Once
|
||||
}
|
||||
@@ -54,107 +36,38 @@ func newStackDevice(options DeviceOptions) (*stackDevice, error) {
|
||||
options: options,
|
||||
logRouteOptions: true,
|
||||
}
|
||||
endpoint := &stackEndpoint{
|
||||
device: device,
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
endpoint.mtu.Store(options.MTU)
|
||||
ipStack, err := tun.NewGVisorStackWithOptions(endpoint, stack.NICOptions{}, true)
|
||||
device.inet4Address, device.inet6Address = firstAddresses(options.Configuration.Address)
|
||||
device.memoryTun = tun.NewMemoryTun(tun.MemoryTunOptions{
|
||||
MTU: int(options.MTU),
|
||||
Headroom: PacketHeadroom,
|
||||
RearSpace: systemDevicePacketRearSpace,
|
||||
Outbound: device.writeOutbound,
|
||||
})
|
||||
var err error
|
||||
device.stack, err = newStack(options, device.memoryTun)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
device.stack = ipStack
|
||||
device.endpoint = endpoint
|
||||
err = device.updateAddresses(nil, options.Configuration.Address)
|
||||
if err != nil {
|
||||
ipStack.Close()
|
||||
return nil, err
|
||||
}
|
||||
if options.Handler != nil {
|
||||
ipStack.SetTransportProtocolHandler(tcp.ProtocolNumber, tun.NewTCPForwarder(options.Context, ipStack, options.Handler).HandlePacket)
|
||||
udpForwarder := tun.NewUDPForwarder(options.Context, ipStack, options.Handler, tun.UDPNatOptions{
|
||||
Timeout: options.UDPTimeout,
|
||||
Shared: true,
|
||||
Mapping: options.UDPMapping,
|
||||
Filtering: options.UDPFiltering,
|
||||
MaxSize: options.UDPNATMax,
|
||||
InterfaceFinder: options.InterfaceFinder,
|
||||
ExcludeInterface: options.ExcludeInterface,
|
||||
})
|
||||
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, udpForwarder.HandlePacket)
|
||||
device.udpForwarder = udpForwarder
|
||||
icmpForwarder := tun.NewICMPForwarder(ipStack, options.Handler, options.Logger)
|
||||
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber4, icmpForwarder.HandlePacket)
|
||||
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber6, icmpForwarder.HandlePacket)
|
||||
device.icmpForwarder = icmpForwarder
|
||||
}
|
||||
return device, nil
|
||||
}
|
||||
|
||||
func (d *stackDevice) Start() error {
|
||||
if d.udpForwarder != nil {
|
||||
err := d.udpForwarder.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return d.stack.Start()
|
||||
}
|
||||
|
||||
func (d *stackDevice) UpdateConfiguration(configuration Configuration) error {
|
||||
d.stateAccess.Lock()
|
||||
defer d.stateAccess.Unlock()
|
||||
if d.logRouteOptions && hasRouteOptions(configuration.Routes) {
|
||||
d.options.Logger.Debug("route gateway and metric options are not representable by the gVisor stack device; routes are installed by prefix")
|
||||
d.options.Logger.Debug("route gateway and metric options are not representable by the stack device; routes are installed by prefix")
|
||||
d.logRouteOptions = false
|
||||
}
|
||||
if configuration.MTU != 0 {
|
||||
d.options.MTU = configuration.MTU
|
||||
d.endpoint.mtu.Store(configuration.MTU)
|
||||
d.memoryTun.UpdateMTU(int(configuration.MTU))
|
||||
}
|
||||
previousAddresses := d.options.Configuration.Address
|
||||
d.options.Configuration = configuration
|
||||
return d.updateAddresses(previousAddresses, configuration.Address)
|
||||
}
|
||||
|
||||
func (d *stackDevice) updateAddresses(previousAddresses []netip.Prefix, addresses []netip.Prefix) error {
|
||||
for _, prefix := range previousAddresses {
|
||||
if slices.Contains(addresses, prefix) {
|
||||
continue
|
||||
}
|
||||
gErr := d.stack.RemoveAddress(tun.DefaultNIC, tun.AddressFromAddr(prefix.Addr()))
|
||||
if gErr != nil {
|
||||
return E.New("remove local address ", prefix, ": ", gErr.String())
|
||||
}
|
||||
}
|
||||
for _, prefix := range addresses {
|
||||
if slices.Contains(previousAddresses, prefix) {
|
||||
continue
|
||||
}
|
||||
protocolAddress := tcpip.ProtocolAddress{
|
||||
AddressWithPrefix: tcpip.AddressWithPrefix{
|
||||
Address: tun.AddressFromAddr(prefix.Addr()),
|
||||
PrefixLen: prefix.Bits(),
|
||||
},
|
||||
}
|
||||
if prefix.Addr().Is4() {
|
||||
protocolAddress.Protocol = ipv4.ProtocolNumber
|
||||
} else {
|
||||
protocolAddress.Protocol = ipv6.ProtocolNumber
|
||||
}
|
||||
gErr := d.stack.AddProtocolAddress(tun.DefaultNIC, protocolAddress, stack.AddressProperties{})
|
||||
if gErr != nil {
|
||||
return E.New("add local address ", prefix, ": ", gErr.String())
|
||||
}
|
||||
}
|
||||
inet4Address, inet6Address := firstAddresses(addresses)
|
||||
if d.inet4Address != inet4Address {
|
||||
d.inet4UDP.Interrupt(true)
|
||||
}
|
||||
if d.inet6Address != inet6Address {
|
||||
d.inet6UDP.Interrupt(true)
|
||||
}
|
||||
d.inet4Address, d.inet6Address = inet4Address, inet6Address
|
||||
d.inet4Address, d.inet6Address = firstAddresses(configuration.Address)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -163,95 +76,63 @@ func (d *stackDevice) WriteInboundBuffers(packetBuffers []*buf.Buffer) error {
|
||||
}
|
||||
|
||||
func (d *stackDevice) writeBuffers(packetBuffers []*buf.Buffer) error {
|
||||
networkProtocols := make([]tcpip.NetworkProtocolNumber, 0, len(packetBuffers))
|
||||
stackPacketBuffers := make([]*stack.PacketBuffer, 0, len(packetBuffers))
|
||||
var packetErr error
|
||||
for _, packetBuffer := range packetBuffers {
|
||||
packet := packetBuffer.Bytes()
|
||||
var networkProtocol tcpip.NetworkProtocolNumber
|
||||
switch header.IPVersion(packet) {
|
||||
case header.IPv4Version:
|
||||
networkProtocol = header.IPv4ProtocolNumber
|
||||
case header.IPv6Version:
|
||||
networkProtocol = header.IPv6ProtocolNumber
|
||||
default:
|
||||
if packetErr == nil {
|
||||
packetErr = E.New("invalid IP packet")
|
||||
}
|
||||
continue
|
||||
}
|
||||
networkProtocols = append(networkProtocols, networkProtocol)
|
||||
stackPacketBuffers = append(stackPacketBuffers, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Payload: buffer.MakeWithData(packet),
|
||||
}))
|
||||
}
|
||||
d.endpoint.deliverNetworkPackets(networkProtocols, stackPacketBuffers)
|
||||
for _, packetBuffer := range stackPacketBuffers {
|
||||
packetBuffer.DecRef()
|
||||
}
|
||||
return packetErr
|
||||
_, err := d.memoryTun.WritePackets(common.Map(packetBuffers, (*buf.Buffer).Bytes))
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *stackDevice) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
address := tcpip.FullAddress{
|
||||
NIC: tun.DefaultNIC,
|
||||
Port: destination.Port,
|
||||
Addr: tun.AddressFromAddr(destination.Addr),
|
||||
bind, err := d.bindAddress(destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch N.NetworkName(network) {
|
||||
case N.NetworkTCP:
|
||||
d.stateAccess.RLock()
|
||||
bind, networkProtocol, _, err := d.bindAddressLocked(destination)
|
||||
d.stateAccess.RUnlock()
|
||||
var tcpConn *tun.GoConn
|
||||
tcpConn, err = d.stack.DialTCP(ctx, bind, destination.AddrPort())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gonet.DialTCPWithBind(ctx, d.stack, bind, address, networkProtocol)
|
||||
return tcpConn, nil
|
||||
case N.NetworkUDP:
|
||||
d.stateAccess.RLock()
|
||||
defer d.stateAccess.RUnlock()
|
||||
bind, networkProtocol, udpGroup, err := d.bindAddressLocked(destination)
|
||||
var udpConn *tun.GoUDPConn
|
||||
udpConn, err = d.stack.DialUDP(netip.AddrPortFrom(bind, 0), destination.AddrPort())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
udpConn, err := gonet.DialUDP(d.stack, &bind, &address, networkProtocol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return udpGroup.NewConn(udpConn, false), nil
|
||||
return udpConn, nil
|
||||
default:
|
||||
return nil, E.Extend(N.ErrUnknownNetwork, network)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *stackDevice) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
d.stateAccess.RLock()
|
||||
defer d.stateAccess.RUnlock()
|
||||
bind, networkProtocol, udpGroup, err := d.bindAddressLocked(destination)
|
||||
bind, err := d.bindAddress(destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
udpConn, err := gonet.DialUDP(d.stack, &bind, nil, networkProtocol)
|
||||
udpConn, err := d.stack.ListenUDP(netip.AddrPortFrom(bind, 0))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return udpGroup.NewPacketConn(udpConn, false), nil
|
||||
return udpConn, nil
|
||||
}
|
||||
|
||||
func (d *stackDevice) bindAddressLocked(destination M.Socksaddr) (tcpip.FullAddress, tcpip.NetworkProtocolNumber, *interrupt.Group, error) {
|
||||
func (d *stackDevice) bindAddress(destination M.Socksaddr) (netip.Addr, error) {
|
||||
d.stateAccess.RLock()
|
||||
defer d.stateAccess.RUnlock()
|
||||
if destination.IsIPv4() {
|
||||
if !d.inet4Address.IsValid() {
|
||||
return tcpip.FullAddress{}, 0, nil, E.New("missing IPv4 local address")
|
||||
return netip.Addr{}, E.New("missing IPv4 local address")
|
||||
}
|
||||
return tcpip.FullAddress{NIC: tun.DefaultNIC, Addr: tun.AddressFromAddr(d.inet4Address)}, header.IPv4ProtocolNumber, &d.inet4UDP, nil
|
||||
return d.inet4Address, nil
|
||||
}
|
||||
if d.options.Configuration.BlockIPv6 {
|
||||
return tcpip.FullAddress{}, 0, nil, E.New("IPv6 blocked by pushed block-ipv6")
|
||||
return netip.Addr{}, E.New("IPv6 blocked by pushed block-ipv6")
|
||||
}
|
||||
if !d.inet6Address.IsValid() {
|
||||
return tcpip.FullAddress{}, 0, nil, E.New("missing IPv6 local address")
|
||||
return netip.Addr{}, E.New("missing IPv6 local address")
|
||||
}
|
||||
return tcpip.FullAddress{NIC: tun.DefaultNIC, Addr: tun.AddressFromAddr(d.inet6Address)}, header.IPv6ProtocolNumber, &d.inet6UDP, nil
|
||||
return d.inet6Address, nil
|
||||
}
|
||||
|
||||
func (d *stackDevice) PortAddresses() (netip.Addr, netip.Addr) {
|
||||
@@ -267,115 +148,9 @@ func (d *stackDevice) PortMTU() uint32 {
|
||||
}
|
||||
|
||||
func (d *stackDevice) Close() error {
|
||||
var err error
|
||||
d.closeOnce.Do(func() {
|
||||
close(d.endpoint.done)
|
||||
if d.udpForwarder != nil {
|
||||
d.udpForwarder.Close()
|
||||
}
|
||||
if d.icmpForwarder != nil {
|
||||
d.icmpForwarder.Close()
|
||||
}
|
||||
d.stack.Close()
|
||||
for _, endpoint := range d.stack.CleanupEndpoints() {
|
||||
endpoint.Abort()
|
||||
}
|
||||
d.stack.Wait()
|
||||
err = E.Errors(d.stack.Close(), d.memoryTun.Close())
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
type stackEndpoint struct {
|
||||
device *stackDevice
|
||||
mtu atomic.Uint32
|
||||
done chan struct{}
|
||||
dispatcherAccess sync.RWMutex
|
||||
dispatcher stack.NetworkDispatcher
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) MTU() uint32 {
|
||||
return e.mtu.Load()
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) SetMTU(mtu uint32) {
|
||||
e.mtu.Store(mtu)
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) MaxHeaderLength() uint16 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) LinkAddress() tcpip.LinkAddress {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) SetLinkAddress(addr tcpip.LinkAddress) {
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) Capabilities() stack.LinkEndpointCapabilities {
|
||||
return stack.CapabilityRXChecksumOffload
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||
e.dispatcherAccess.Lock()
|
||||
defer e.dispatcherAccess.Unlock()
|
||||
e.dispatcher = dispatcher
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) IsAttached() bool {
|
||||
e.dispatcherAccess.RLock()
|
||||
defer e.dispatcherAccess.RUnlock()
|
||||
return e.dispatcher != nil
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) deliverNetworkPackets(networkProtocols []tcpip.NetworkProtocolNumber, packetBuffers []*stack.PacketBuffer) {
|
||||
e.dispatcherAccess.RLock()
|
||||
defer e.dispatcherAccess.RUnlock()
|
||||
if e.dispatcher == nil {
|
||||
return
|
||||
}
|
||||
for i, packetBuffer := range packetBuffers {
|
||||
e.dispatcher.DeliverNetworkPacket(networkProtocols[i], packetBuffer)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) Wait() {
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) ARPHardwareType() header.ARPHardwareType {
|
||||
return header.ARPHardwareNone
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) AddHeader(packetBuffer *stack.PacketBuffer) {
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) ParseHeader(packetBuffer *stack.PacketBuffer) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) WritePackets(list stack.PacketBufferList) (int, tcpip.Error) {
|
||||
packetBuffers := make([]*buf.Buffer, 0, list.Len())
|
||||
for _, packetBuffer := range list.AsSlice() {
|
||||
packetSlices := packetBuffer.AsSlices()
|
||||
packetLength := 0
|
||||
for _, packetSlice := range packetSlices {
|
||||
packetLength += len(packetSlice)
|
||||
}
|
||||
outboundBuffer := buf.NewSize(PacketHeadroom + packetLength + systemDevicePacketRearSpace)
|
||||
outboundBuffer.Resize(PacketHeadroom, 0)
|
||||
for _, packetSlice := range packetSlices {
|
||||
_, _ = outboundBuffer.Write(packetSlice)
|
||||
}
|
||||
packetBuffers = append(packetBuffers, outboundBuffer)
|
||||
}
|
||||
err := e.device.writeOutbound(packetBuffers)
|
||||
if err != nil {
|
||||
return 0, &tcpip.ErrClosedForSend{}
|
||||
}
|
||||
return list.Len(), nil
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) Close() {
|
||||
}
|
||||
|
||||
func (e *stackEndpoint) SetOnCloseAction(action func()) {
|
||||
return err
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
//go:build !with_gvisor
|
||||
|
||||
package openvpn
|
||||
|
||||
import E "github.com/sagernet/sing/common/exceptions"
|
||||
|
||||
func newStackDevice(options DeviceOptions) (Device, error) {
|
||||
return nil, E.New("system:false requires the with_gvisor build tag")
|
||||
}
|
||||
|
||||
func newSystemStackDevice(options DeviceOptions) (Device, error) {
|
||||
return nil, E.New("system stack requires the with_gvisor build tag")
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
//go:build with_gvisor
|
||||
|
||||
package openvpn
|
||||
|
||||
import (
|
||||
@@ -22,11 +20,7 @@ func newSystemStackDevice(options DeviceOptions) (*systemStackDevice, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stackOptions := options
|
||||
stackOptions.System = false
|
||||
stackOptions.Name = system.options.Name
|
||||
stackOptions.ExcludeInterface = []string{system.options.Name}
|
||||
stackDevice, err := newStackDevice(stackOptions)
|
||||
stackDevice, err := newStackDevice(options)
|
||||
if err != nil {
|
||||
system.Close()
|
||||
return nil, err
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
@@ -32,8 +33,8 @@ type DeviceOptions struct {
|
||||
UDPMapping tun.NATMapping
|
||||
UDPFiltering tun.NATFiltering
|
||||
UDPNATMax uint32
|
||||
NetworkMonitor tun.NetworkUpdateMonitor
|
||||
InterfaceFinder control.InterfaceFinder
|
||||
MemoryPressure func() tun.MemoryPressure
|
||||
CreateDialer func(interfaceName string) N.Dialer
|
||||
Name string
|
||||
MTU uint32
|
||||
@@ -44,9 +45,29 @@ type DeviceOptions struct {
|
||||
func NewDevice(options DeviceOptions) (Device, error) {
|
||||
if !options.System {
|
||||
return newStackDevice(options)
|
||||
} else if !tun.WithGVisor {
|
||||
return newSystemDevice(options)
|
||||
} else {
|
||||
return newSystemStackDevice(options)
|
||||
}
|
||||
return newSystemStackDevice(options)
|
||||
}
|
||||
|
||||
func newStack(options DeviceOptions, memoryTun *tun.MemoryTun) (*tun.Go, error) {
|
||||
return tun.NewGo(tun.StackOptions{
|
||||
Context: options.Context,
|
||||
Tun: memoryTun,
|
||||
TunOptions: tun.Options{MTU: options.MTU},
|
||||
UDPTimeout: options.UDPTimeout,
|
||||
ICMPTimeout: options.ICMPTimeout,
|
||||
UDPMapping: options.UDPMapping,
|
||||
UDPFiltering: options.UDPFiltering,
|
||||
UDPNATMax: options.UDPNATMax,
|
||||
Handler: options.Handler,
|
||||
Logger: options.Logger,
|
||||
InterfaceFinder: options.InterfaceFinder,
|
||||
MemoryPressure: options.MemoryPressure,
|
||||
})
|
||||
}
|
||||
|
||||
func deviceAddresses(addresses []netip.Prefix) (netip.Addr, netip.Addr) {
|
||||
inet4Prefix := common.Find(addresses, func(it netip.Prefix) bool { return it.Addr().Is4() })
|
||||
inet6Prefix := common.Find(addresses, func(it netip.Prefix) bool { return it.Addr().Is6() })
|
||||
return inet4Prefix.Addr(), inet6Prefix.Addr()
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
//go:build with_gvisor
|
||||
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
@@ -8,22 +6,13 @@ import (
|
||||
"net/netip"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/buffer"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/adapters/gonet"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/network/ipv4"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/network/ipv6"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
"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-tun"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/wireguard-go/conn"
|
||||
"github.com/sagernet/wireguard-go/device"
|
||||
wgTun "github.com/sagernet/wireguard-go/tun"
|
||||
)
|
||||
@@ -31,105 +20,49 @@ import (
|
||||
var _ Device = (*stackDevice)(nil)
|
||||
|
||||
type stackDevice struct {
|
||||
stack *stack.Stack
|
||||
mtu uint32
|
||||
events chan wgTun.Event
|
||||
outbound chan *stack.PacketBuffer
|
||||
packetOutbound chan *buf.Buffer
|
||||
done chan struct{}
|
||||
closeOnce sync.Once
|
||||
dispatcher stack.NetworkDispatcher
|
||||
inet4Address netip.Addr
|
||||
inet6Address netip.Addr
|
||||
icmpForwarder *tun.ICMPForwarder
|
||||
udpForwarder *tun.UDPForwarder
|
||||
stack *tun.Go
|
||||
memoryTun *tun.MemoryTun
|
||||
mtu uint32
|
||||
events chan wgTun.Event
|
||||
closeOnce sync.Once
|
||||
inet4Address netip.Addr
|
||||
inet6Address netip.Addr
|
||||
}
|
||||
|
||||
func newStackDevice(options DeviceOptions) (*stackDevice, error) {
|
||||
tunDevice := &stackDevice{
|
||||
mtu: options.MTU,
|
||||
events: make(chan wgTun.Event, 1),
|
||||
outbound: make(chan *stack.PacketBuffer, 256),
|
||||
packetOutbound: make(chan *buf.Buffer, 256),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
ipStack, err := tun.NewGVisorStackWithOptions((*wireEndpoint)(tunDevice), stack.NICOptions{}, true)
|
||||
memoryTun := tun.NewMemoryTun(tun.MemoryTunOptions{MTU: int(options.MTU)})
|
||||
stack, err := newStack(options, memoryTun)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, prefix := range options.Address {
|
||||
addr := tun.AddressFromAddr(prefix.Addr())
|
||||
protoAddr := tcpip.ProtocolAddress{
|
||||
AddressWithPrefix: tcpip.AddressWithPrefix{
|
||||
Address: addr,
|
||||
PrefixLen: prefix.Bits(),
|
||||
},
|
||||
}
|
||||
if prefix.Addr().Is4() {
|
||||
tunDevice.inet4Address = prefix.Addr()
|
||||
protoAddr.Protocol = ipv4.ProtocolNumber
|
||||
} else {
|
||||
tunDevice.inet6Address = prefix.Addr()
|
||||
protoAddr.Protocol = ipv6.ProtocolNumber
|
||||
}
|
||||
gErr := ipStack.AddProtocolAddress(tun.DefaultNIC, protoAddr, stack.AddressProperties{})
|
||||
if gErr != nil {
|
||||
return nil, E.New("parse local address ", protoAddr.AddressWithPrefix, ": ", gErr.String())
|
||||
}
|
||||
}
|
||||
tunDevice.stack = ipStack
|
||||
if options.Handler != nil {
|
||||
ipStack.SetTransportProtocolHandler(tcp.ProtocolNumber, tun.NewTCPForwarder(options.Context, ipStack, options.Handler).HandlePacket)
|
||||
udpForwarder := tun.NewUDPForwarder(options.Context, ipStack, options.Handler, tun.UDPNatOptions{
|
||||
Timeout: options.UDPTimeout,
|
||||
Shared: true,
|
||||
Mapping: options.UDPMapping,
|
||||
Filtering: options.UDPFiltering,
|
||||
MaxSize: options.UDPNATMax,
|
||||
InterfaceFinder: options.InterfaceFinder,
|
||||
})
|
||||
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, udpForwarder.HandlePacket)
|
||||
tunDevice.udpForwarder = udpForwarder
|
||||
icmpForwarder := tun.NewICMPForwarder(ipStack, options.Handler, options.Logger)
|
||||
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber4, icmpForwarder.HandlePacket)
|
||||
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber6, icmpForwarder.HandlePacket)
|
||||
tunDevice.icmpForwarder = icmpForwarder
|
||||
}
|
||||
return tunDevice, nil
|
||||
inet4Address, inet6Address := deviceAddresses(options.Address)
|
||||
return &stackDevice{
|
||||
stack: stack,
|
||||
memoryTun: memoryTun,
|
||||
mtu: options.MTU,
|
||||
events: make(chan wgTun.Event, 1),
|
||||
inet4Address: inet4Address,
|
||||
inet6Address: inet6Address,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *stackDevice) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
addr := tcpip.FullAddress{
|
||||
NIC: tun.DefaultNIC,
|
||||
Port: destination.Port,
|
||||
Addr: tun.AddressFromAddr(destination.Addr),
|
||||
}
|
||||
bind := tcpip.FullAddress{
|
||||
NIC: tun.DefaultNIC,
|
||||
}
|
||||
var networkProtocol tcpip.NetworkProtocolNumber
|
||||
if destination.IsIPv4() {
|
||||
if !w.inet4Address.IsValid() {
|
||||
return nil, E.New("missing IPv4 local address")
|
||||
}
|
||||
networkProtocol = header.IPv4ProtocolNumber
|
||||
bind.Addr = tun.AddressFromAddr(w.inet4Address)
|
||||
} else {
|
||||
if !w.inet6Address.IsValid() {
|
||||
return nil, E.New("missing IPv6 local address")
|
||||
}
|
||||
networkProtocol = header.IPv6ProtocolNumber
|
||||
bind.Addr = tun.AddressFromAddr(w.inet6Address)
|
||||
bind, err := w.bindAddress(destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch N.NetworkName(network) {
|
||||
case N.NetworkTCP:
|
||||
tcpConn, err := DialTCPWithBind(ctx, w.stack, bind, addr, networkProtocol)
|
||||
var tcpConn *tun.GoConn
|
||||
tcpConn, err = w.stack.DialTCP(ctx, bind, destination.AddrPort())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tcpConn.SetKeepAliveConfig(net.KeepAliveConfig{Enable: true, Idle: 15 * time.Second, Interval: 15 * time.Second})
|
||||
return tcpConn, nil
|
||||
case N.NetworkUDP:
|
||||
udpConn, err := gonet.DialUDP(w.stack, &bind, &addr, networkProtocol)
|
||||
var udpConn *tun.GoUDPConn
|
||||
udpConn, err = w.stack.DialUDP(netip.AddrPortFrom(bind, 0), destination.AddrPort())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -140,30 +73,30 @@ func (w *stackDevice) DialContext(ctx context.Context, network string, destinati
|
||||
}
|
||||
|
||||
func (w *stackDevice) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
bind := tcpip.FullAddress{
|
||||
NIC: tun.DefaultNIC,
|
||||
bind, err := w.bindAddress(destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var networkProtocol tcpip.NetworkProtocolNumber
|
||||
if destination.IsIPv4() {
|
||||
if !w.inet4Address.IsValid() {
|
||||
return nil, E.New("missing IPv4 local address")
|
||||
}
|
||||
networkProtocol = header.IPv4ProtocolNumber
|
||||
bind.Addr = tun.AddressFromAddr(w.inet4Address)
|
||||
} else {
|
||||
if !w.inet6Address.IsValid() {
|
||||
return nil, E.New("missing IPv6 local address")
|
||||
}
|
||||
networkProtocol = header.IPv6ProtocolNumber
|
||||
bind.Addr = tun.AddressFromAddr(w.inet6Address)
|
||||
}
|
||||
udpConn, err := gonet.DialUDP(w.stack, &bind, nil, networkProtocol)
|
||||
udpConn, err := w.stack.ListenUDP(netip.AddrPortFrom(bind, 0))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return udpConn, nil
|
||||
}
|
||||
|
||||
func (w *stackDevice) bindAddress(destination M.Socksaddr) (netip.Addr, error) {
|
||||
if destination.IsIPv4() {
|
||||
if !w.inet4Address.IsValid() {
|
||||
return netip.Addr{}, E.New("missing IPv4 local address")
|
||||
}
|
||||
return w.inet4Address, nil
|
||||
}
|
||||
if !w.inet6Address.IsValid() {
|
||||
return netip.Addr{}, E.New("missing IPv6 local address")
|
||||
}
|
||||
return w.inet6Address, nil
|
||||
}
|
||||
|
||||
func (w *stackDevice) Inet4Address() netip.Addr {
|
||||
return w.inet4Address
|
||||
}
|
||||
@@ -176,11 +109,9 @@ func (w *stackDevice) SetDevice(device *device.Device) {
|
||||
}
|
||||
|
||||
func (w *stackDevice) Start() error {
|
||||
if w.udpForwarder != nil {
|
||||
err := w.udpForwarder.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err := w.stack.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.events <- wgTun.EventUp
|
||||
return nil
|
||||
@@ -190,52 +121,16 @@ func (w *stackDevice) File() *os.File {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *stackDevice) Read(bufs [][]byte, sizes []int, offset int) (count int, err error) {
|
||||
select {
|
||||
case packet, ok := <-w.outbound:
|
||||
if !ok {
|
||||
return 0, os.ErrClosed
|
||||
}
|
||||
defer packet.DecRef()
|
||||
var copyN int
|
||||
/*rangeIterate(packet.Data().AsRange(), func(view *buffer.View) {
|
||||
copyN += copy(bufs[0][offset+copyN:], view.AsSlice())
|
||||
})*/
|
||||
for _, view := range packet.AsSlices() {
|
||||
copyN += copy(bufs[0][offset+copyN:], view)
|
||||
}
|
||||
sizes[0] = copyN
|
||||
return 1, nil
|
||||
case packet := <-w.packetOutbound:
|
||||
defer packet.Release()
|
||||
sizes[0] = copy(bufs[0][offset:], packet.Bytes())
|
||||
return 1, nil
|
||||
case <-w.done:
|
||||
return 0, os.ErrClosed
|
||||
}
|
||||
func (w *stackDevice) Read(bufs [][]byte, sizes []int, offset int) (int, error) {
|
||||
return w.memoryTun.ReadPackets(bufs, sizes, offset)
|
||||
}
|
||||
|
||||
func (w *stackDevice) Write(bufs [][]byte, offset int) (count int, err error) {
|
||||
for _, b := range bufs {
|
||||
b = b[offset:]
|
||||
if len(b) == 0 {
|
||||
continue
|
||||
}
|
||||
var networkProtocol tcpip.NetworkProtocolNumber
|
||||
switch header.IPVersion(b) {
|
||||
case header.IPv4Version:
|
||||
networkProtocol = header.IPv4ProtocolNumber
|
||||
case header.IPv6Version:
|
||||
networkProtocol = header.IPv6ProtocolNumber
|
||||
}
|
||||
packetBuffer := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Payload: buffer.MakeWithData(b),
|
||||
})
|
||||
w.dispatcher.DeliverNetworkPacket(networkProtocol, packetBuffer)
|
||||
packetBuffer.DecRef()
|
||||
count++
|
||||
func (w *stackDevice) Write(bufs [][]byte, offset int) (int, error) {
|
||||
packets := make([][]byte, 0, len(bufs))
|
||||
for _, packet := range bufs {
|
||||
packets = append(packets, packet[offset:])
|
||||
}
|
||||
return
|
||||
return w.memoryTun.WritePackets(packets)
|
||||
}
|
||||
|
||||
func (w *stackDevice) Flush() error {
|
||||
@@ -255,90 +150,14 @@ func (w *stackDevice) Events() <-chan wgTun.Event {
|
||||
}
|
||||
|
||||
func (w *stackDevice) Close() error {
|
||||
var err error
|
||||
w.closeOnce.Do(func() {
|
||||
close(w.done)
|
||||
close(w.events)
|
||||
if w.icmpForwarder != nil {
|
||||
w.icmpForwarder.Close()
|
||||
}
|
||||
if w.udpForwarder != nil {
|
||||
_ = w.udpForwarder.Close()
|
||||
}
|
||||
w.stack.Close()
|
||||
for _, endpoint := range w.stack.CleanupEndpoints() {
|
||||
endpoint.Abort()
|
||||
}
|
||||
w.stack.Wait()
|
||||
err = E.Errors(w.stack.Close(), w.memoryTun.Close())
|
||||
})
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *stackDevice) BatchSize() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
var _ stack.LinkEndpoint = (*wireEndpoint)(nil)
|
||||
|
||||
type wireEndpoint stackDevice
|
||||
|
||||
func (ep *wireEndpoint) MTU() uint32 {
|
||||
return ep.mtu
|
||||
}
|
||||
|
||||
func (ep *wireEndpoint) SetMTU(mtu uint32) {
|
||||
}
|
||||
|
||||
func (ep *wireEndpoint) MaxHeaderLength() uint16 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (ep *wireEndpoint) LinkAddress() tcpip.LinkAddress {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (ep *wireEndpoint) SetLinkAddress(addr tcpip.LinkAddress) {
|
||||
}
|
||||
|
||||
func (ep *wireEndpoint) Capabilities() stack.LinkEndpointCapabilities {
|
||||
return stack.CapabilityRXChecksumOffload
|
||||
}
|
||||
|
||||
func (ep *wireEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||
ep.dispatcher = dispatcher
|
||||
}
|
||||
|
||||
func (ep *wireEndpoint) IsAttached() bool {
|
||||
return ep.dispatcher != nil
|
||||
}
|
||||
|
||||
func (ep *wireEndpoint) Wait() {
|
||||
}
|
||||
|
||||
func (ep *wireEndpoint) ARPHardwareType() header.ARPHardwareType {
|
||||
return header.ARPHardwareNone
|
||||
}
|
||||
|
||||
func (ep *wireEndpoint) AddHeader(buffer *stack.PacketBuffer) {
|
||||
}
|
||||
|
||||
func (ep *wireEndpoint) ParseHeader(ptr *stack.PacketBuffer) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (ep *wireEndpoint) WritePackets(list stack.PacketBufferList) (int, tcpip.Error) {
|
||||
for _, packetBuffer := range list.AsSlice() {
|
||||
packetBuffer.IncRef()
|
||||
select {
|
||||
case <-ep.done:
|
||||
return 0, &tcpip.ErrClosedForSend{}
|
||||
case ep.outbound <- packetBuffer:
|
||||
}
|
||||
}
|
||||
return list.Len(), nil
|
||||
}
|
||||
|
||||
func (ep *wireEndpoint) Close() {
|
||||
}
|
||||
|
||||
func (ep *wireEndpoint) SetOnCloseAction(f func()) {
|
||||
return conn.IdealBatchSize
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
//go:build with_gvisor
|
||||
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/adapters/gonet"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/transport/tcp"
|
||||
"github.com/sagernet/gvisor/pkg/waiter"
|
||||
"github.com/sagernet/sing-tun"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
)
|
||||
|
||||
func DialTCPWithBind(ctx context.Context, s *stack.Stack, localAddr, remoteAddr tcpip.FullAddress, network tcpip.NetworkProtocolNumber) (*gonet.TCPConn, error) {
|
||||
// Create TCP endpoint, then connect.
|
||||
var wq waiter.Queue
|
||||
ep, err := s.NewEndpoint(tcp.ProtocolNumber, network, &wq)
|
||||
if err != nil {
|
||||
return nil, errors.New(err.String())
|
||||
}
|
||||
|
||||
// Create wait queue entry that notifies a channel.
|
||||
//
|
||||
// We do this unconditionally as Connect will always return an error.
|
||||
waitEntry, notifyCh := waiter.NewChannelEntry(waiter.WritableEvents)
|
||||
wq.EventRegister(&waitEntry)
|
||||
defer wq.EventUnregister(&waitEntry)
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
// Bind before connect if requested.
|
||||
if localAddr != (tcpip.FullAddress{}) {
|
||||
if err = ep.Bind(localAddr); err != nil {
|
||||
return nil, fmt.Errorf("ep.Bind(%+v) = %s", localAddr, err)
|
||||
}
|
||||
}
|
||||
|
||||
err = ep.Connect(remoteAddr)
|
||||
if _, ok := err.(*tcpip.ErrConnectStarted); ok {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
ep.Close()
|
||||
return nil, ctx.Err()
|
||||
case <-notifyCh:
|
||||
}
|
||||
|
||||
err = ep.LastError()
|
||||
}
|
||||
if err != nil {
|
||||
ep.Close()
|
||||
return nil, &net.OpError{
|
||||
Op: "connect",
|
||||
Net: "tcp",
|
||||
Addr: M.SocksaddrFromNetIP(netip.AddrPortFrom(tun.AddrFromAddress(remoteAddr.Addr), remoteAddr.Port)).TCPAddr(),
|
||||
Err: errors.New(err.String()),
|
||||
}
|
||||
}
|
||||
|
||||
// sing-box added: set keepalive
|
||||
ep.SocketOptions().SetKeepAlive(true)
|
||||
keepAliveIdle := tcpip.KeepaliveIdleOption(15 * time.Second)
|
||||
ep.SetSockOpt(&keepAliveIdle)
|
||||
keepAliveInterval := tcpip.KeepaliveIntervalOption(15 * time.Second)
|
||||
ep.SetSockOpt(&keepAliveInterval)
|
||||
|
||||
return gonet.NewTCPConn(&wq, ep), nil
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
//go:build !with_gvisor
|
||||
|
||||
package wireguard
|
||||
|
||||
import "github.com/sagernet/sing-tun"
|
||||
|
||||
func newStackDevice(options DeviceOptions) (Device, error) {
|
||||
return nil, tun.ErrGVisorNotIncluded
|
||||
}
|
||||
|
||||
func newSystemStackDevice(options DeviceOptions) (Device, error) {
|
||||
return nil, tun.ErrGVisorNotIncluded
|
||||
}
|
||||
@@ -35,22 +35,7 @@ func newSystemDevice(options DeviceOptions) (*systemDevice, error) {
|
||||
if options.Name == "" {
|
||||
options.Name = tun.CalculateInterfaceName("wg")
|
||||
}
|
||||
var inet4Address netip.Addr
|
||||
var inet6Address netip.Addr
|
||||
if len(options.Address) > 0 {
|
||||
if prefix := common.Find(options.Address, func(it netip.Prefix) bool {
|
||||
return it.Addr().Is4()
|
||||
}); prefix.IsValid() {
|
||||
inet4Address = prefix.Addr()
|
||||
}
|
||||
}
|
||||
if len(options.Address) > 0 {
|
||||
if prefix := common.Find(options.Address, func(it netip.Prefix) bool {
|
||||
return it.Addr().Is6()
|
||||
}); prefix.IsValid() {
|
||||
inet6Address = prefix.Addr()
|
||||
}
|
||||
}
|
||||
inet4Address, inet6Address := deviceAddresses(options.Address)
|
||||
return &systemDevice{
|
||||
options: options,
|
||||
dialer: options.CreateDialer(options.Name),
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
//go:build with_gvisor
|
||||
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/buffer"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/network/ipv4"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/network/ipv6"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
"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-tun"
|
||||
"github.com/sagernet/sing-tun/gtcpip/header"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/wireguard-go/device"
|
||||
)
|
||||
@@ -24,12 +16,10 @@ var _ Device = (*systemStackDevice)(nil)
|
||||
|
||||
type systemStackDevice struct {
|
||||
*systemDevice
|
||||
stack *stack.Stack
|
||||
endpoint *deviceEndpoint
|
||||
icmpForwarder *tun.ICMPForwarder
|
||||
udpForwarder *tun.UDPForwarder
|
||||
writeBufs [][]byte
|
||||
closeOnce sync.Once
|
||||
stack *tun.Go
|
||||
memoryTun *tun.MemoryTun
|
||||
device atomic.Pointer[device.Device]
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
func newSystemStackDevice(options DeviceOptions) (*systemStackDevice, error) {
|
||||
@@ -37,212 +27,98 @@ func newSystemStackDevice(options DeviceOptions) (*systemStackDevice, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
endpoint := &deviceEndpoint{
|
||||
mtu: options.MTU,
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
ipStack, err := tun.NewGVisorStackWithOptions(endpoint, stack.NICOptions{}, true)
|
||||
stackDevice := &systemStackDevice{systemDevice: system}
|
||||
stackDevice.memoryTun = tun.NewMemoryTun(tun.MemoryTunOptions{MTU: int(options.MTU), Outbound: stackDevice.inputPackets})
|
||||
stackDevice.stack, err = newStack(options, stackDevice.memoryTun)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, prefix := range options.Address {
|
||||
addr := tun.AddressFromAddr(prefix.Addr())
|
||||
protoAddr := tcpip.ProtocolAddress{
|
||||
AddressWithPrefix: tcpip.AddressWithPrefix{
|
||||
Address: addr,
|
||||
PrefixLen: prefix.Bits(),
|
||||
},
|
||||
}
|
||||
if prefix.Addr().Is4() {
|
||||
protoAddr.Protocol = ipv4.ProtocolNumber
|
||||
} else {
|
||||
protoAddr.Protocol = ipv6.ProtocolNumber
|
||||
}
|
||||
gErr := ipStack.AddProtocolAddress(tun.DefaultNIC, protoAddr, stack.AddressProperties{})
|
||||
if gErr != nil {
|
||||
return nil, E.New("parse local address ", protoAddr.AddressWithPrefix, ": ", gErr.String())
|
||||
}
|
||||
}
|
||||
stackDevice := &systemStackDevice{
|
||||
systemDevice: system,
|
||||
stack: ipStack,
|
||||
endpoint: endpoint,
|
||||
}
|
||||
if options.Handler != nil {
|
||||
ipStack.SetTransportProtocolHandler(tcp.ProtocolNumber, tun.NewTCPForwarder(options.Context, ipStack, options.Handler).HandlePacket)
|
||||
udpForwarder := tun.NewUDPForwarder(options.Context, ipStack, options.Handler, tun.UDPNatOptions{
|
||||
Timeout: options.UDPTimeout,
|
||||
Shared: true,
|
||||
Mapping: options.UDPMapping,
|
||||
Filtering: options.UDPFiltering,
|
||||
MaxSize: options.UDPNATMax,
|
||||
InterfaceFinder: options.InterfaceFinder,
|
||||
ExcludeInterface: []string{options.Name},
|
||||
})
|
||||
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, udpForwarder.HandlePacket)
|
||||
stackDevice.udpForwarder = udpForwarder
|
||||
icmpForwarder := tun.NewICMPForwarder(ipStack, options.Handler, options.Logger)
|
||||
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber4, icmpForwarder.HandlePacket)
|
||||
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber6, icmpForwarder.HandlePacket)
|
||||
stackDevice.icmpForwarder = icmpForwarder
|
||||
}
|
||||
return stackDevice, nil
|
||||
}
|
||||
|
||||
func (w *systemStackDevice) SetDevice(device *device.Device) {
|
||||
w.endpoint.device = device
|
||||
w.device.Store(device)
|
||||
}
|
||||
|
||||
func (w *systemStackDevice) Start() error {
|
||||
if w.udpForwarder != nil {
|
||||
err := w.udpForwarder.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err := w.stack.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err := w.systemDevice.Start()
|
||||
if err != nil && w.udpForwarder != nil {
|
||||
_ = w.udpForwarder.Close()
|
||||
err = w.systemDevice.Start()
|
||||
if err != nil {
|
||||
w.stack.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *systemStackDevice) Write(bufs [][]byte, offset int) (count int, err error) {
|
||||
if w.batchDevice != nil {
|
||||
w.writeBufs = w.writeBufs[:0]
|
||||
for _, packet := range bufs {
|
||||
if !w.writeStack(packet[offset:]) {
|
||||
w.writeBufs = append(w.writeBufs, packet)
|
||||
}
|
||||
}
|
||||
if len(w.writeBufs) > 0 {
|
||||
return w.batchDevice.BatchWrite(w.writeBufs, offset)
|
||||
}
|
||||
} else {
|
||||
for _, packet := range bufs {
|
||||
if !w.writeStack(packet[offset:]) {
|
||||
if tun.PacketOffset > 0 {
|
||||
clear(packet[offset-tun.PacketOffset : offset])
|
||||
tun.PacketFillHeader(packet[offset-tun.PacketOffset:], tun.PacketIPVersion(packet[offset:]))
|
||||
}
|
||||
_, err = w.device.Write(packet[offset-tun.PacketOffset:])
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
func (w *systemStackDevice) Write(bufs [][]byte, offset int) (int, error) {
|
||||
stackPackets := make([][]byte, 0, len(bufs))
|
||||
systemPackets := make([][]byte, 0, len(bufs))
|
||||
for _, packet := range bufs {
|
||||
if w.isLocalDestination(packet[offset:]) {
|
||||
systemPackets = append(systemPackets, packet)
|
||||
} else {
|
||||
stackPackets = append(stackPackets, packet[offset:])
|
||||
}
|
||||
}
|
||||
// WireGuard will not read count
|
||||
return
|
||||
if len(stackPackets) > 0 {
|
||||
_, err := w.memoryTun.WritePackets(stackPackets)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
if len(systemPackets) > 0 {
|
||||
return w.systemDevice.Write(systemPackets, offset)
|
||||
}
|
||||
return len(bufs), nil
|
||||
}
|
||||
|
||||
func (w *systemStackDevice) isLocalDestination(packet []byte) bool {
|
||||
var destination netip.Addr
|
||||
switch header.IPVersion(packet) {
|
||||
case header.IPv4Version:
|
||||
destination = header.IPv4(packet).DestinationAddr()
|
||||
case header.IPv6Version:
|
||||
destination = header.IPv6(packet).DestinationAddr()
|
||||
default:
|
||||
return true
|
||||
}
|
||||
for _, prefix := range w.options.Address {
|
||||
if prefix.Contains(destination) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (w *systemStackDevice) inputPackets(packets []*buf.Buffer) error {
|
||||
defer buf.ReleaseMulti(packets)
|
||||
wgDevice := w.device.Load()
|
||||
if wgDevice == nil {
|
||||
return nil
|
||||
}
|
||||
references := make([]*device.InputPacketRef, 0, len(packets))
|
||||
for _, packet := range packets {
|
||||
var destination []byte
|
||||
switch header.IPVersion(packet.Bytes()) {
|
||||
case header.IPv4Version:
|
||||
destination = header.IPv4(packet.Bytes()).DestinationAddressSlice()
|
||||
case header.IPv6Version:
|
||||
destination = header.IPv6(packet.Bytes()).DestinationAddressSlice()
|
||||
default:
|
||||
continue
|
||||
}
|
||||
references = append(references, &device.InputPacketRef{Destination: destination, PacketSlices: [][]byte{packet.Bytes()}})
|
||||
}
|
||||
wgDevice.InputPackets(references)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *systemStackDevice) Close() error {
|
||||
var err error
|
||||
w.closeOnce.Do(func() {
|
||||
close(w.endpoint.done)
|
||||
if w.icmpForwarder != nil {
|
||||
w.icmpForwarder.Close()
|
||||
}
|
||||
if w.udpForwarder != nil {
|
||||
_ = w.udpForwarder.Close()
|
||||
}
|
||||
w.stack.Close()
|
||||
for _, endpoint := range w.stack.CleanupEndpoints() {
|
||||
endpoint.Abort()
|
||||
}
|
||||
w.stack.Wait()
|
||||
err = w.systemDevice.Close()
|
||||
err = E.Errors(w.stack.Close(), w.memoryTun.Close(), w.systemDevice.Close())
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *systemStackDevice) writeStack(packet []byte) bool {
|
||||
var (
|
||||
networkProtocol tcpip.NetworkProtocolNumber
|
||||
destination netip.Addr
|
||||
)
|
||||
switch header.IPVersion(packet) {
|
||||
case header.IPv4Version:
|
||||
networkProtocol = header.IPv4ProtocolNumber
|
||||
destination = netip.AddrFrom4(header.IPv4(packet).DestinationAddress().As4())
|
||||
case header.IPv6Version:
|
||||
networkProtocol = header.IPv6ProtocolNumber
|
||||
destination = netip.AddrFrom16(header.IPv6(packet).DestinationAddress().As16())
|
||||
}
|
||||
for _, prefix := range w.options.Address {
|
||||
if prefix.Contains(destination) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
packetBuffer := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Payload: buffer.MakeWithData(packet),
|
||||
})
|
||||
w.endpoint.dispatcher.DeliverNetworkPacket(networkProtocol, packetBuffer)
|
||||
packetBuffer.DecRef()
|
||||
return true
|
||||
}
|
||||
|
||||
type deviceEndpoint struct {
|
||||
mtu uint32
|
||||
done chan struct{}
|
||||
device *device.Device
|
||||
dispatcher stack.NetworkDispatcher
|
||||
}
|
||||
|
||||
func (ep *deviceEndpoint) MTU() uint32 {
|
||||
return ep.mtu
|
||||
}
|
||||
|
||||
func (ep *deviceEndpoint) SetMTU(mtu uint32) {
|
||||
}
|
||||
|
||||
func (ep *deviceEndpoint) MaxHeaderLength() uint16 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (ep *deviceEndpoint) LinkAddress() tcpip.LinkAddress {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (ep *deviceEndpoint) SetLinkAddress(addr tcpip.LinkAddress) {
|
||||
}
|
||||
|
||||
func (ep *deviceEndpoint) Capabilities() stack.LinkEndpointCapabilities {
|
||||
return stack.CapabilityRXChecksumOffload
|
||||
}
|
||||
|
||||
func (ep *deviceEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||
ep.dispatcher = dispatcher
|
||||
}
|
||||
|
||||
func (ep *deviceEndpoint) IsAttached() bool {
|
||||
return ep.dispatcher != nil
|
||||
}
|
||||
|
||||
func (ep *deviceEndpoint) Wait() {
|
||||
}
|
||||
|
||||
func (ep *deviceEndpoint) ARPHardwareType() header.ARPHardwareType {
|
||||
return header.ARPHardwareNone
|
||||
}
|
||||
|
||||
func (ep *deviceEndpoint) AddHeader(buffer *stack.PacketBuffer) {
|
||||
}
|
||||
|
||||
func (ep *deviceEndpoint) ParseHeader(ptr *stack.PacketBuffer) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (ep *deviceEndpoint) WritePackets(list stack.PacketBufferList) (int, tcpip.Error) {
|
||||
for _, packetBuffer := range list.AsSlice() {
|
||||
destination := packetBuffer.Network().DestinationAddress()
|
||||
ep.device.InputPacket(destination.AsSlice(), packetBuffer.AsSlices())
|
||||
}
|
||||
return list.Len(), nil
|
||||
}
|
||||
|
||||
func (ep *deviceEndpoint) Close() {
|
||||
}
|
||||
|
||||
func (ep *deviceEndpoint) SetOnCloseAction(f func()) {
|
||||
}
|
||||
@@ -106,6 +106,16 @@ func NewEndpoint(options EndpointOptions) (*Endpoint, error) {
|
||||
if options.MTU == 0 {
|
||||
options.MTU = 1408
|
||||
}
|
||||
return &Endpoint{
|
||||
options: options,
|
||||
peers: peers,
|
||||
ipcConf: ipcConf,
|
||||
allowedAddress: allowedAddresses,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *Endpoint) Initialize(memoryPressure func() tun.MemoryPressure) error {
|
||||
options := e.options
|
||||
deviceOptions := DeviceOptions{
|
||||
Context: options.Context,
|
||||
Logger: options.Logger,
|
||||
@@ -117,24 +127,20 @@ func NewEndpoint(options EndpointOptions) (*Endpoint, error) {
|
||||
UDPFiltering: options.UDPFiltering,
|
||||
UDPNATMax: options.UDPNATMax,
|
||||
InterfaceFinder: options.InterfaceFinder,
|
||||
MemoryPressure: memoryPressure,
|
||||
CreateDialer: options.CreateDialer,
|
||||
Name: options.Name,
|
||||
MTU: options.MTU,
|
||||
Address: options.Address,
|
||||
AllowedAddress: allowedAddresses,
|
||||
AllowedAddress: e.allowedAddress,
|
||||
}
|
||||
tunDevice, err := NewDevice(deviceOptions)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "create WireGuard device")
|
||||
return E.Cause(err, "create WireGuard device")
|
||||
}
|
||||
return &Endpoint{
|
||||
options: options,
|
||||
peers: peers,
|
||||
ipcConf: ipcConf,
|
||||
allowedAddress: allowedAddresses,
|
||||
tunDevice: tunDevice,
|
||||
returnDevice: &returnDeviceWrapper{Device: tunDevice},
|
||||
}, nil
|
||||
e.tunDevice = tunDevice
|
||||
e.returnDevice = &returnDeviceWrapper{Device: tunDevice}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Endpoint) Start(postStart bool) error {
|
||||
@@ -343,7 +349,7 @@ func (e *Endpoint) Close() error {
|
||||
if wgDevice != nil {
|
||||
return nil
|
||||
}
|
||||
return e.tunDevice.Close()
|
||||
return common.Close(e.tunDevice)
|
||||
}
|
||||
|
||||
func (e *Endpoint) Lookup(address netip.Addr) *device.Peer {
|
||||
|
||||
Reference in new issue
Block a user