diff --git a/common/dialer/default.go b/common/dialer/default.go index a5642174..53fc6dc7 100644 --- a/common/dialer/default.go +++ b/common/dialer/default.go @@ -3,6 +3,7 @@ package dialer import ( "context" "net" + "net/netip" "time" "github.com/sagernet/sing-box/adapter" @@ -54,6 +55,7 @@ var warnTFOOnUnsupportedPlatform = warning.New( type DefaultDialer struct { tfo.Dialer net.ListenConfig + bindUDPAddr string } func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDialer { @@ -108,7 +110,15 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia if options.TCPFastOpen { warnTFOOnUnsupportedPlatform.Check() } - return &DefaultDialer{tfo.Dialer{Dialer: dialer, DisableTFO: !options.TCPFastOpen}, listener} + var bindUDPAddr string + bindAddress := netip.Addr(options.BindAddress) + if bindAddress.IsValid() { + dialer.LocalAddr = &net.TCPAddr{ + IP: bindAddress.AsSlice(), + } + bindUDPAddr = M.SocksaddrFrom(bindAddress, 0).String() + } + return &DefaultDialer{tfo.Dialer{Dialer: dialer, DisableTFO: !options.TCPFastOpen}, listener, bindUDPAddr} } func (d *DefaultDialer) DialContext(ctx context.Context, network string, address M.Socksaddr) (net.Conn, error) { @@ -116,7 +126,7 @@ func (d *DefaultDialer) DialContext(ctx context.Context, network string, address } func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - return d.ListenConfig.ListenPacket(ctx, N.NetworkUDP, "") + return d.ListenConfig.ListenPacket(ctx, N.NetworkUDP, d.bindUDPAddr) } func (d *DefaultDialer) Upstream() any { diff --git a/docs/changelog.md b/docs/changelog.md index 301c54f6..6bccde21 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,6 +1,7 @@ #### 2022/08/22 * Add strategy setting for each [DNS server](/configuration/dns/server) +* Add bind address to outbound options #### 2022/08/21 diff --git a/docs/configuration/outbound/direct.md b/docs/configuration/outbound/direct.md index 24d20d4a..eda9bc03 100644 --- a/docs/configuration/outbound/direct.md +++ b/docs/configuration/outbound/direct.md @@ -14,6 +14,7 @@ "detour": "upstream-out", "bind_interface": "en0", + "bind_address": "0.0.0.0", "routing_mark": 1234, "reuse_addr": false, "connect_timeout": "5s", @@ -47,6 +48,10 @@ Other dial fields will be ignored when enabled. The network interface to bind to. +#### bind_address + +The address to bind to. + #### routing_mark !!! error "" diff --git a/docs/configuration/outbound/http.md b/docs/configuration/outbound/http.md index b7e2a931..b7087013 100644 --- a/docs/configuration/outbound/http.md +++ b/docs/configuration/outbound/http.md @@ -17,6 +17,7 @@ "detour": "upstream-out", "bind_interface": "en0", + "bind_address": "0.0.0.0", "routing_mark": 1234, "reuse_addr": false, "connect_timeout": "5s", @@ -66,6 +67,10 @@ Other dial fields will be ignored when enabled. The network interface to bind to. +#### bind_address + +The address to bind to. + #### routing_mark !!! error "" diff --git a/docs/configuration/outbound/hysteria.md b/docs/configuration/outbound/hysteria.md index 3bbddc18..c69bd4ea 100644 --- a/docs/configuration/outbound/hysteria.md +++ b/docs/configuration/outbound/hysteria.md @@ -25,6 +25,7 @@ "detour": "upstream-out", "bind_interface": "en0", + "bind_address": "0.0.0.0", "routing_mark": 1234, "reuse_addr": false, "connect_timeout": "5s", @@ -134,6 +135,10 @@ Other dial fields will be ignored when enabled. The network interface to bind to. +#### bind_address + +The address to bind to. + #### routing_mark !!! error "" diff --git a/docs/configuration/outbound/shadowsocks.md b/docs/configuration/outbound/shadowsocks.md index 2cbc2d5b..6a0ff3f3 100644 --- a/docs/configuration/outbound/shadowsocks.md +++ b/docs/configuration/outbound/shadowsocks.md @@ -17,6 +17,7 @@ "detour": "upstream-out", "bind_interface": "en0", + "bind_address": "0.0.0.0", "routing_mark": 1234, "reuse_addr": false, "connect_timeout": "5s", @@ -106,6 +107,10 @@ Other dial fields will be ignored when enabled. The network interface to bind to. +#### bind_address + +The address to bind to. + #### routing_mark !!! error "" diff --git a/docs/configuration/outbound/socks.md b/docs/configuration/outbound/socks.md index e23a1c98..5416ab89 100644 --- a/docs/configuration/outbound/socks.md +++ b/docs/configuration/outbound/socks.md @@ -19,6 +19,7 @@ "detour": "upstream-out", "bind_interface": "en0", + "bind_address": "0.0.0.0", "routing_mark": 1234, "reuse_addr": false, "connect_timeout": "5s", @@ -82,6 +83,10 @@ Other dial fields will be ignored when enabled. The network interface to bind to. +#### bind_address + +The address to bind to. + #### routing_mark !!! error "" diff --git a/docs/configuration/outbound/ssh.md b/docs/configuration/outbound/ssh.md index e6b3c8eb..8adcdb50 100644 --- a/docs/configuration/outbound/ssh.md +++ b/docs/configuration/outbound/ssh.md @@ -19,6 +19,7 @@ "detour": "upstream-out", "bind_interface": "en0", + "bind_address": "0.0.0.0", "routing_mark": 1234, "reuse_addr": false, "connect_timeout": "5s", @@ -82,6 +83,10 @@ Other dial fields will be ignored when enabled. The network interface to bind to. +#### bind_address + +The address to bind to. + #### routing_mark !!! error "" diff --git a/docs/configuration/outbound/tor.md b/docs/configuration/outbound/tor.md index a899fbd6..028ff068 100644 --- a/docs/configuration/outbound/tor.md +++ b/docs/configuration/outbound/tor.md @@ -16,6 +16,7 @@ "detour": "upstream-out", "bind_interface": "en0", + "bind_address": "0.0.0.0", "routing_mark": 1234, "reuse_addr": false, "connect_timeout": "5s", @@ -69,6 +70,10 @@ Other dial fields will be ignored when enabled. The network interface to bind to. +#### bind_address + +The address to bind to. + #### routing_mark !!! error "" diff --git a/docs/configuration/outbound/trojan.md b/docs/configuration/outbound/trojan.md index fbee069e..71c28f4e 100644 --- a/docs/configuration/outbound/trojan.md +++ b/docs/configuration/outbound/trojan.md @@ -16,6 +16,7 @@ "detour": "upstream-out", "bind_interface": "en0", + "bind_address": "0.0.0.0", "routing_mark": 1234, "reuse_addr": false, "connect_timeout": "5s", @@ -75,6 +76,10 @@ Other dial fields will be ignored when enabled. The network interface to bind to. +#### bind_address + +The address to bind to. + #### routing_mark !!! error "" diff --git a/docs/configuration/outbound/vmess.md b/docs/configuration/outbound/vmess.md index 1596fcc1..66f26b9b 100644 --- a/docs/configuration/outbound/vmess.md +++ b/docs/configuration/outbound/vmess.md @@ -20,6 +20,7 @@ "detour": "upstream-out", "bind_interface": "en0", + "bind_address": "0.0.0.0", "routing_mark": 1234, "reuse_addr": false, "connect_timeout": "5s", @@ -109,6 +110,10 @@ Other dial fields will be ignored when enabled. The network interface to bind to. +#### bind_address + +The address to bind to. + #### routing_mark !!! error "" diff --git a/docs/configuration/outbound/wireguard.md b/docs/configuration/outbound/wireguard.md index 59bf38ac..a00113ff 100644 --- a/docs/configuration/outbound/wireguard.md +++ b/docs/configuration/outbound/wireguard.md @@ -21,6 +21,7 @@ "detour": "upstream-out", "bind_interface": "en0", + "bind_address": "0.0.0.0", "routing_mark": 1234, "reuse_addr": false, "connect_timeout": "5s", @@ -101,6 +102,10 @@ Other dial fields will be ignored when enabled. The network interface to bind to. +#### bind_address + +The address to bind to. + #### routing_mark !!! error "" diff --git a/option/outbound.go b/option/outbound.go index ac4547ca..24629b2b 100644 --- a/option/outbound.go +++ b/option/outbound.go @@ -100,13 +100,14 @@ func (h *Outbound) UnmarshalJSON(bytes []byte) error { } type DialerOptions struct { - Detour string `json:"detour,omitempty"` - BindInterface string `json:"bind_interface,omitempty"` - ProtectPath string `json:"protect_path,omitempty"` - RoutingMark int `json:"routing_mark,omitempty"` - ReuseAddr bool `json:"reuse_addr,omitempty"` - ConnectTimeout Duration `json:"connect_timeout,omitempty"` - TCPFastOpen bool `json:"tcp_fast_open,omitempty"` + Detour string `json:"detour,omitempty"` + BindInterface string `json:"bind_interface,omitempty"` + BindAddress ListenAddress `json:"bind_address,omitempty"` + ProtectPath string `json:"protect_path,omitempty"` + RoutingMark int `json:"routing_mark,omitempty"` + ReuseAddr bool `json:"reuse_addr,omitempty"` + ConnectTimeout Duration `json:"connect_timeout,omitempty"` + TCPFastOpen bool `json:"tcp_fast_open,omitempty"` } type OutboundDialerOptions struct {