From 8d88c6532fd58fb346598afe8c71b3cf548fcd66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 9 Jan 2026 22:51:57 +0800 Subject: [PATCH] Add dial option `bind_address_no_port` --- common/dialer/default.go | 6 ++++++ docs/configuration/shared/dial.md | 16 +++++++++++++++- docs/configuration/shared/dial.zh.md | 16 +++++++++++++++- go.mod | 2 +- go.sum | 4 ++-- option/outbound.go | 1 + 6 files changed, 40 insertions(+), 5 deletions(-) diff --git a/common/dialer/default.go b/common/dialer/default.go index d38ad4871..3ab2e05a0 100644 --- a/common/dialer/default.go +++ b/common/dialer/default.go @@ -137,6 +137,12 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial dialer.Control = control.Append(dialer.Control, control.ProtectPath(options.ProtectPath)) listener.Control = control.Append(listener.Control, control.ProtectPath(options.ProtectPath)) } + if options.BindAddressNoPort { + if !C.IsLinux { + return nil, E.New("`bind_address_no_port` is only supported on Linux") + } + dialer.Control = control.Append(dialer.Control, control.BindAddressNoPort()) + } if options.ConnectTimeout != 0 { dialer.Timeout = time.Duration(options.ConnectTimeout) } else { diff --git a/docs/configuration/shared/dial.md b/docs/configuration/shared/dial.md index 3907dcb2a..306952fc4 100644 --- a/docs/configuration/shared/dial.md +++ b/docs/configuration/shared/dial.md @@ -6,7 +6,8 @@ icon: material/new-box :material-plus: [disable_tcp_keep_alive](#disable_tcp_keep_alive) :material-plus: [tcp_keep_alive](#tcp_keep_alive) - :material-plus: [tcp_keep_alive_interval](#tcp_keep_alive_interval) + :material-plus: [tcp_keep_alive_interval](#tcp_keep_alive_interval) + :material-plus: [bind_address_no_port](#bind_address_no_port) !!! quote "Changes in sing-box 1.12.0" @@ -29,6 +30,7 @@ icon: material/new-box "bind_interface": "", "inet4_bind_address": "", "inet6_bind_address": "", + "bind_address_no_port": false, "routing_mark": 0, "reuse_addr": false, "netns": "", @@ -76,6 +78,18 @@ The IPv4 address to bind to. The IPv6 address to bind to. +#### bind_address_no_port + +!!! question "Since sing-box 1.13.0" + +!!! quote "" + + Only supported on Linux. + +Do not reserve a port when binding to a source address. + +This allows reusing the same source port for multiple connections if the full 4-tuple (source IP, source port, destination IP, destination port) remains unique. + #### routing_mark !!! quote "" diff --git a/docs/configuration/shared/dial.zh.md b/docs/configuration/shared/dial.zh.md index 23cea5097..493093517 100644 --- a/docs/configuration/shared/dial.zh.md +++ b/docs/configuration/shared/dial.zh.md @@ -6,7 +6,8 @@ icon: material/new-box :material-plus: [disable_tcp_keep_alive](#disable_tcp_keep_alive) :material-plus: [tcp_keep_alive](#tcp_keep_alive) - :material-plus: [tcp_keep_alive_interval](#tcp_keep_alive_interval) + :material-plus: [tcp_keep_alive_interval](#tcp_keep_alive_interval) + :material-plus: [bind_address_no_port](#bind_address_no_port) !!! quote "sing-box 1.12.0 中的更改" @@ -29,6 +30,7 @@ icon: material/new-box "bind_interface": "", "inet4_bind_address": "", "inet6_bind_address": "", + "bind_address_no_port": false, "routing_mark": 0, "reuse_addr": false, "netns": "", @@ -76,6 +78,18 @@ icon: material/new-box 要绑定的 IPv6 地址。 +#### bind_address_no_port + +!!! question "自 sing-box 1.13.0 起" + +!!! quote "" + + 仅支持 Linux。 + +绑定到源地址时不保留端口。 + +这允许在完整的四元组(源 IP、源端口、目标 IP、目标端口)保持唯一的情况下,为多个连接复用同一源端口。 + #### routing_mark !!! quote "" diff --git a/go.mod b/go.mod index 08e873af5..7ba33b250 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/sagernet/gomobile v0.1.11 github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1 github.com/sagernet/quic-go v0.58.0-sing-box-mod.1 - github.com/sagernet/sing v0.8.0-beta.9 + github.com/sagernet/sing v0.8.0-beta.9.0.20260109141034-50e1ed36c6f6 github.com/sagernet/sing-mux v0.3.4 github.com/sagernet/sing-quic v0.6.0-beta.8 github.com/sagernet/sing-shadowsocks v0.2.8 diff --git a/go.sum b/go.sum index 7f6c3ed93..68913f00c 100644 --- a/go.sum +++ b/go.sum @@ -208,8 +208,8 @@ github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNen github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= github.com/sagernet/quic-go v0.58.0-sing-box-mod.1 h1:E9yZrU0ZxSiW5RrGUnFZeI02EIMdAAv0RxdoxXCqZyk= github.com/sagernet/quic-go v0.58.0-sing-box-mod.1/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4= -github.com/sagernet/sing v0.8.0-beta.9 h1:LTFjTYiEr6A5NZ04tbrjWLb0T7unSmEJX2ksJkfI1lY= -github.com/sagernet/sing v0.8.0-beta.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing v0.8.0-beta.9.0.20260109141034-50e1ed36c6f6 h1:TgmW2IKThK+3wWhoB/UKjwdW2NUyWqCyXZoCYTMizv8= +github.com/sagernet/sing v0.8.0-beta.9.0.20260109141034-50e1ed36c6f6/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-mux v0.3.4 h1:ZQplKl8MNXutjzbMVtWvWG31fohhgOfCuUZR4dVQ8+s= github.com/sagernet/sing-mux v0.3.4/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk= github.com/sagernet/sing-quic v0.6.0-beta.8 h1:Y0P8WTqWpfg80rLFsDfF22QumM+HEAjRQ2o+8Dv+vDs= diff --git a/option/outbound.go b/option/outbound.go index b5c52fa2d..2ed7cf2eb 100644 --- a/option/outbound.go +++ b/option/outbound.go @@ -69,6 +69,7 @@ type DialerOptions struct { BindInterface string `json:"bind_interface,omitempty"` Inet4BindAddress *badoption.Addr `json:"inet4_bind_address,omitempty"` Inet6BindAddress *badoption.Addr `json:"inet6_bind_address,omitempty"` + BindAddressNoPort bool `json:"bind_address_no_port,omitempty"` ProtectPath string `json:"protect_path,omitempty"` RoutingMark FwMark `json:"routing_mark,omitempty"` ReuseAddr bool `json:"reuse_addr,omitempty"`