Explorar o código

Add DestIpAddress() in Dialer interface

Android client prepares an IP before proxy connection is established. It is useful when connecting to wireguard (or quic) outbound with domain address. E.g. engage.cloudflareclient.com:2408
yuhan6665 hai 1 ano
pai
achega
d60281d0a5

+ 4 - 0
app/proxyman/outbound/handler.go

@@ -229,6 +229,10 @@ func (h *Handler) Address() net.Address {
 	return h.senderSettings.Via.AsAddress()
 	return h.senderSettings.Via.AsAddress()
 }
 }
 
 
+func (h *Handler) DestIpAddress() net.IP {
+	return internet.DestIpAddress()
+}
+
 // Dial implements internet.Dialer.
 // Dial implements internet.Dialer.
 func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connection, error) {
 func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connection, error) {
 	if h.senderSettings != nil {
 	if h.senderSettings != nil {

+ 70 - 3
proxy/wireguard/client.go

@@ -22,7 +22,9 @@ package wireguard
 
 
 import (
 import (
 	"context"
 	"context"
+	"fmt"
 	"net/netip"
 	"net/netip"
+	"strings"
 	"sync"
 	"sync"
 
 
 	"github.com/xtls/xray-core/common"
 	"github.com/xtls/xray-core/common"
@@ -49,7 +51,6 @@ type Handler struct {
 	policyManager policy.Manager
 	policyManager policy.Manager
 	dns           dns.Client
 	dns           dns.Client
 	// cached configuration
 	// cached configuration
-	ipc              string
 	endpoints        []netip.Addr
 	endpoints        []netip.Addr
 	hasIPv4, hasIPv6 bool
 	hasIPv4, hasIPv6 bool
 	wgLock           sync.Mutex
 	wgLock           sync.Mutex
@@ -69,7 +70,6 @@ func New(ctx context.Context, conf *DeviceConfig) (*Handler, error) {
 		conf:          conf,
 		conf:          conf,
 		policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
 		policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
 		dns:           d,
 		dns:           d,
-		ipc:           createIPCRequest(conf),
 		endpoints:     endpoints,
 		endpoints:     endpoints,
 		hasIPv4:       hasIPv4,
 		hasIPv4:       hasIPv4,
 		hasIPv6:       hasIPv6,
 		hasIPv6:       hasIPv6,
@@ -247,9 +247,76 @@ func (h *Handler) makeVirtualTun(bind *netBindClient) (Tunnel, error) {
 	bind.dnsOption.IPv4Enable = h.hasIPv4
 	bind.dnsOption.IPv4Enable = h.hasIPv4
 	bind.dnsOption.IPv6Enable = h.hasIPv6
 	bind.dnsOption.IPv6Enable = h.hasIPv6
 
 
-	if err = t.BuildDevice(h.ipc, bind); err != nil {
+	if err = t.BuildDevice(h.createIPCRequest(bind, h.conf), bind); err != nil {
 		_ = t.Close()
 		_ = t.Close()
 		return nil, err
 		return nil, err
 	}
 	}
 	return t, nil
 	return t, nil
 }
 }
+
+
+// serialize the config into an IPC request
+func (h *Handler) createIPCRequest(bind *netBindClient, conf *DeviceConfig) string {
+	var request strings.Builder
+
+	request.WriteString(fmt.Sprintf("private_key=%s\n", conf.SecretKey))
+
+	if !conf.IsClient {
+		// placeholder, we'll handle actual port listening on Xray
+		request.WriteString("listen_port=1337\n")
+	}
+
+	for _, peer := range conf.Peers {
+		if peer.PublicKey != "" {
+			request.WriteString(fmt.Sprintf("public_key=%s\n", peer.PublicKey))
+		}
+
+		if peer.PreSharedKey != "" {
+			request.WriteString(fmt.Sprintf("preshared_key=%s\n", peer.PreSharedKey))
+		}
+
+		split := strings.Split(peer.Endpoint, ":")
+		addr := net.ParseAddress(split[0])
+		if addr.Family().IsDomain() {
+			dialerIp := bind.dialer.DestIpAddress()
+			if dialerIp != nil {
+				addr = net.ParseAddress(dialerIp.String())
+				newError("createIPCRequest use dialer dest ip: ", addr).WriteToLog()
+			} else {
+				ips, err := h.dns.LookupIP(addr.Domain(), dns.IPOption{
+					IPv4Enable: h.hasIPv4 && h.conf.preferIP4(),
+					IPv6Enable: h.hasIPv6 && h.conf.preferIP6(),
+				})
+				{ // Resolve fallback
+					if (len(ips) == 0 || err != nil) && h.conf.hasFallback() {
+						ips, err = h.dns.LookupIP(addr.Domain(), dns.IPOption{
+							IPv4Enable: h.hasIPv4 && h.conf.fallbackIP4(),
+							IPv6Enable: h.hasIPv6 && h.conf.fallbackIP6(),
+						})
+					}
+				}
+				if err != nil {
+					newError("createIPCRequest failed to lookup DNS").Base(err).WriteToLog()
+				} else if len(ips) == 0 {
+					newError("createIPCRequest empty lookup DNS").WriteToLog()
+				} else {
+					addr = net.IPAddress(ips[dice.Roll(len(ips))])
+				}
+			}
+		}
+
+		if peer.Endpoint != "" {
+			request.WriteString(fmt.Sprintf("endpoint=%s:%s\n", addr, split[1]))
+		}
+
+		for _, ip := range peer.AllowedIps {
+			request.WriteString(fmt.Sprintf("allowed_ip=%s\n", ip))
+		}
+
+		if peer.KeepAlive != 0 {
+			request.WriteString(fmt.Sprintf("persistent_keepalive_interval=%d\n", peer.KeepAlive))
+		}
+	}
+
+	return request.String()[:request.Len()]
+}

+ 8 - 0
transport/internet/dialer.go

@@ -22,6 +22,9 @@ type Dialer interface {
 
 
 	// Address returns the address used by this Dialer. Maybe nil if not known.
 	// Address returns the address used by this Dialer. Maybe nil if not known.
 	Address() net.Address
 	Address() net.Address
+
+	// DestIpAddress returns the ip of proxy server. It is useful in case of Android client, which prepare an IP before proxy connection is established
+	DestIpAddress() net.IP
 }
 }
 
 
 // dialFunc is an interface to dial network connection to a specific destination.
 // dialFunc is an interface to dial network connection to a specific destination.
@@ -68,6 +71,11 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *MemoryStrea
 	return nil, newError("unknown network ", dest.Network)
 	return nil, newError("unknown network ", dest.Network)
 }
 }
 
 
+// DestIpAddress returns the ip of proxy server. It is useful in case of Android client, which prepare an IP before proxy connection is established
+func DestIpAddress() net.IP {
+	return effectiveSystemDialer.DestIpAddress()
+}
+
 var (
 var (
 	dnsClient dns.Client
 	dnsClient dns.Client
 	obm       outbound.Manager
 	obm       outbound.Manager

+ 9 - 0
transport/internet/system_dialer.go

@@ -16,6 +16,7 @@ var effectiveSystemDialer SystemDialer = &DefaultSystemDialer{}
 
 
 type SystemDialer interface {
 type SystemDialer interface {
 	Dial(ctx context.Context, source net.Address, destination net.Destination, sockopt *SocketConfig) (net.Conn, error)
 	Dial(ctx context.Context, source net.Address, destination net.Destination, sockopt *SocketConfig) (net.Conn, error)
+	DestIpAddress() net.IP
 }
 }
 
 
 type DefaultSystemDialer struct {
 type DefaultSystemDialer struct {
@@ -108,6 +109,10 @@ func (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest ne
 	return dialer.DialContext(ctx, dest.Network.SystemString(), dest.NetAddr())
 	return dialer.DialContext(ctx, dest.Network.SystemString(), dest.NetAddr())
 }
 }
 
 
+func (d *DefaultSystemDialer) DestIpAddress() net.IP {
+	return nil
+}
+
 type PacketConnWrapper struct {
 type PacketConnWrapper struct {
 	Conn net.PacketConn
 	Conn net.PacketConn
 	Dest net.Addr
 	Dest net.Addr
@@ -172,6 +177,10 @@ func (v *SimpleSystemDialer) Dial(ctx context.Context, src net.Address, dest net
 	return v.adapter.Dial(dest.Network.SystemString(), dest.NetAddr())
 	return v.adapter.Dial(dest.Network.SystemString(), dest.NetAddr())
 }
 }
 
 
+func (d *SimpleSystemDialer) DestIpAddress() net.IP {
+	return nil
+}
+
 // UseAlternativeSystemDialer replaces the current system dialer with a given one.
 // UseAlternativeSystemDialer replaces the current system dialer with a given one.
 // Caller must ensure there is no race condition.
 // Caller must ensure there is no race condition.
 //
 //