Browse Source

Split bind_address

世界 3 years ago
parent
commit
7f84936050
2 changed files with 52 additions and 22 deletions
  1. 50 21
      common/dialer/default.go
  2. 2 1
      option/outbound.go

+ 50 - 21
common/dialer/default.go

@@ -3,7 +3,6 @@ package dialer
 import (
 	"context"
 	"net"
-	"net/netip"
 	"time"
 
 	"github.com/sagernet/sing-box/adapter"
@@ -54,10 +53,13 @@ var warnTFOOnUnsupportedPlatform = warning.New(
 )
 
 type DefaultDialer struct {
-	dialer      tfo.Dialer
-	udpDialer   net.Dialer
+	dialer4     tfo.Dialer
+	dialer6     tfo.Dialer
+	udpDialer4  net.Dialer
+	udpDialer6  net.Dialer
 	udpListener net.ListenConfig
-	bindUDPAddr string
+	udpAddr4    string
+	udpAddr6    string
 }
 
 func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDialer {
@@ -120,22 +122,37 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
 		dialer.Control = control.Append(dialer.Control, control.DisableUDPFragment())
 		listener.Control = control.Append(listener.Control, control.DisableUDPFragment())
 	}
-	var bindUDPAddr string
-	udpDialer := dialer
-	var bindAddress netip.Addr
-	if options.BindAddress != nil {
-		bindAddress = options.BindAddress.Build()
+	var (
+		dialer4    = dialer
+		udpDialer4 = dialer
+		udpAddr4   string
+	)
+	if options.Inet4BindAddress != nil {
+		bindAddr := options.Inet4BindAddress.Build()
+		dialer4.LocalAddr = &net.TCPAddr{IP: bindAddr.AsSlice()}
+		udpDialer4.LocalAddr = &net.UDPAddr{IP: bindAddr.AsSlice()}
+		udpAddr4 = M.SocksaddrFrom(bindAddr, 0).String()
 	}
-	if bindAddress.IsValid() {
-		dialer.LocalAddr = &net.TCPAddr{
-			IP: bindAddress.AsSlice(),
-		}
-		udpDialer.LocalAddr = &net.UDPAddr{
-			IP: bindAddress.AsSlice(),
-		}
-		bindUDPAddr = M.SocksaddrFrom(bindAddress, 0).String()
+	var (
+		dialer6    = dialer
+		udpDialer6 = dialer
+		udpAddr6   string
+	)
+	if options.Inet6BindAddress != nil {
+		bindAddr := options.Inet6BindAddress.Build()
+		dialer6.LocalAddr = &net.TCPAddr{IP: bindAddr.AsSlice()}
+		udpDialer6.LocalAddr = &net.UDPAddr{IP: bindAddr.AsSlice()}
+		udpAddr6 = M.SocksaddrFrom(bindAddr, 0).String()
+	}
+	return &DefaultDialer{
+		tfo.Dialer{Dialer: dialer4, DisableTFO: !options.TCPFastOpen},
+		tfo.Dialer{Dialer: dialer6, DisableTFO: !options.TCPFastOpen},
+		udpDialer4,
+		udpDialer6,
+		listener,
+		udpAddr4,
+		udpAddr6,
 	}
-	return &DefaultDialer{tfo.Dialer{Dialer: dialer, DisableTFO: !options.TCPFastOpen}, udpDialer, listener, bindUDPAddr}
 }
 
 func (d *DefaultDialer) DialContext(ctx context.Context, network string, address M.Socksaddr) (net.Conn, error) {
@@ -144,11 +161,23 @@ func (d *DefaultDialer) DialContext(ctx context.Context, network string, address
 	}
 	switch N.NetworkName(network) {
 	case N.NetworkUDP:
-		return d.udpDialer.DialContext(ctx, network, address.String())
+		if !address.IsIPv6() {
+			return d.udpDialer4.DialContext(ctx, network, address.String())
+		} else {
+			return d.udpDialer6.DialContext(ctx, network, address.String())
+		}
+	}
+	if !address.IsIPv6() {
+		return DialSlowContext(&d.dialer4, ctx, network, address)
+	} else {
+		return DialSlowContext(&d.dialer6, ctx, network, address)
 	}
-	return DialSlowContext(&d.dialer, ctx, network, address)
 }
 
 func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
-	return d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.bindUDPAddr)
+	if !destination.IsIPv6() {
+		return d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr4)
+	} else {
+		return d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr6)
+	}
 }

+ 2 - 1
option/outbound.go

@@ -122,7 +122,8 @@ func (h *Outbound) UnmarshalJSON(bytes []byte) error {
 type DialerOptions struct {
 	Detour             string         `json:"detour,omitempty"`
 	BindInterface      string         `json:"bind_interface,omitempty"`
-	BindAddress        *ListenAddress `json:"bind_address,omitempty"`
+	Inet4BindAddress   *ListenAddress `json:"inet4_bind_address,omitempty"`
+	Inet6BindAddress   *ListenAddress `json:"inet6_bind_address,omitempty"`
 	ProtectPath        string         `json:"protect_path,omitempty"`
 	RoutingMark        int            `json:"routing_mark,omitempty"`
 	ReuseAddr          bool           `json:"reuse_addr,omitempty"`