Skip to content

Commit

Permalink
Add DestIpAddress() in Dialer interface
Browse files Browse the repository at this point in the history
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
  • Loading branch information
yuhan6665 committed Dec 18, 2023
1 parent 5a5e615 commit d60281d
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 3 deletions.
4 changes: 4 additions & 0 deletions app/proxyman/outbound/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@ func (h *Handler) Address() net.Address {
return h.senderSettings.Via.AsAddress()
}

func (h *Handler) DestIpAddress() net.IP {
return internet.DestIpAddress()
}

// Dial implements internet.Dialer.
func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connection, error) {
if h.senderSettings != nil {
Expand Down
73 changes: 70 additions & 3 deletions proxy/wireguard/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ package wireguard

import (
"context"
"fmt"
"net/netip"
"strings"
"sync"

"github.com/xtls/xray-core/common"
Expand All @@ -49,7 +51,6 @@ type Handler struct {
policyManager policy.Manager
dns dns.Client
// cached configuration
ipc string
endpoints []netip.Addr
hasIPv4, hasIPv6 bool
wgLock sync.Mutex
Expand All @@ -69,7 +70,6 @@ func New(ctx context.Context, conf *DeviceConfig) (*Handler, error) {
conf: conf,
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
dns: d,
ipc: createIPCRequest(conf),
endpoints: endpoints,
hasIPv4: hasIPv4,
hasIPv6: hasIPv6,
Expand Down Expand Up @@ -247,9 +247,76 @@ func (h *Handler) makeVirtualTun(bind *netBindClient) (Tunnel, error) {
bind.dnsOption.IPv4Enable = h.hasIPv4
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()
return nil, err
}
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 changes: 8 additions & 0 deletions transport/internet/dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ type Dialer interface {

// Address returns the address used by this Dialer. Maybe nil if not known.
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.
Expand Down Expand Up @@ -68,6 +71,11 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *MemoryStrea
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 (
dnsClient dns.Client
obm outbound.Manager
Expand Down
9 changes: 9 additions & 0 deletions transport/internet/system_dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ var effectiveSystemDialer SystemDialer = &DefaultSystemDialer{}

type SystemDialer interface {
Dial(ctx context.Context, source net.Address, destination net.Destination, sockopt *SocketConfig) (net.Conn, error)
DestIpAddress() net.IP
}

type DefaultSystemDialer struct {
Expand Down Expand Up @@ -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())
}

func (d *DefaultSystemDialer) DestIpAddress() net.IP {
return nil
}

type PacketConnWrapper struct {
Conn net.PacketConn
Dest net.Addr
Expand Down Expand Up @@ -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())
}

func (d *SimpleSystemDialer) DestIpAddress() net.IP {
return nil
}

// UseAlternativeSystemDialer replaces the current system dialer with a given one.
// Caller must ensure there is no race condition.
//
Expand Down

0 comments on commit d60281d

Please sign in to comment.