Skip to content

Commit

Permalink
Merge pull request #609 from XTLS/fix/dialer
Browse files Browse the repository at this point in the history
Move `DomainStrategy` & `DialerProxy` to `DialSystem`
  • Loading branch information
badO1a5A90 committed Sep 7, 2021
2 parents 0403e6d + 86a8fb5 commit 64892fb
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 117 deletions.
3 changes: 1 addition & 2 deletions app/dns/server.go
Expand Up @@ -22,7 +22,6 @@ import (
"github.com/xtls/xray-core/features"
"github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet"
)

// Server is a DNS rely server.
Expand Down Expand Up @@ -307,7 +306,7 @@ func (s *Server) queryIPTimeout(idx int, client Client, domain string, option dn
Tag: s.tag,
})
}
ctx = internet.ContextWithLookupDomain(ctx, domain)

ips, err := client.QueryIP(ctx, domain, option)
cancel()

Expand Down
3 changes: 1 addition & 2 deletions app/dns/udpns.go
Expand Up @@ -2,7 +2,6 @@ package dns

import (
"context"
"github.com/xtls/xray-core/transport/internet"
"strings"
"sync"
"sync/atomic"
Expand Down Expand Up @@ -192,7 +191,7 @@ func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, option
if inbound := session.InboundFromContext(ctx); inbound != nil {
udpCtx = session.ContextWithInbound(udpCtx, inbound)
}
udpCtx = internet.ContextWithLookupDomain(udpCtx, internet.LookupDomainFromContext(ctx))

udpCtx = session.ContextWithContent(udpCtx, &session.Content{
Protocol: "dns",
})
Expand Down
95 changes: 95 additions & 0 deletions transport/internet/dialer.go
Expand Up @@ -3,8 +3,15 @@ package internet
import (
"context"

"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/pipe"
)

// Dialer is the interface for dialing outbound connections.
Expand Down Expand Up @@ -62,11 +69,99 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *MemoryStrea
return nil, newError("unknown network ", dest.Network)
}

var (
dnsClient dns.Client
obm outbound.Manager
)

func lookupIP(domain string, strategy DomainStrategy, localAddr net.Address) ([]net.IP, error) {
if dnsClient == nil {
return nil, nil
}

var option = dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
}

switch {
case strategy == DomainStrategy_USE_IP4 || (localAddr != nil && localAddr.Family().IsIPv4()):
option = dns.IPOption{
IPv4Enable: true,
IPv6Enable: false,
FakeEnable: false,
}
case strategy == DomainStrategy_USE_IP6 || (localAddr != nil && localAddr.Family().IsIPv6()):
option = dns.IPOption{
IPv4Enable: false,
IPv6Enable: true,
FakeEnable: false,
}
case strategy == DomainStrategy_AS_IS:
return nil, nil
}

return dnsClient.LookupIP(domain, option)
}

func canLookupIP(ctx context.Context, dst net.Destination, sockopt *SocketConfig) bool {
if dst.Address.Family().IsIP() || dnsClient == nil {
return false
}
return sockopt.DomainStrategy != DomainStrategy_AS_IS
}

func redirect(ctx context.Context, dst net.Destination, obt string) net.Conn {
newError("redirecting request " + dst.String() + " to " + obt).WriteToLog(session.ExportIDToError(ctx))
h := obm.GetHandler(obt)
ctx = session.ContextWithOutbound(ctx, &session.Outbound{dst, nil})
if h != nil {
ur, uw := pipe.New(pipe.OptionsFromContext(ctx)...)
dr, dw := pipe.New(pipe.OptionsFromContext(ctx)...)

go h.Dispatch(ctx, &transport.Link{ur, dw})
nc := cnc.NewConnection(
cnc.ConnectionInputMulti(uw),
cnc.ConnectionOutputMulti(dr),
cnc.ConnectionOnClose(common.ChainedClosable{uw, dw}),
)
return nc
}
return nil
}

// DialSystem calls system dialer to create a network connection.
func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) {
var src net.Address
if outbound := session.OutboundFromContext(ctx); outbound != nil {
src = outbound.Gateway
}
if sockopt == nil {
return effectiveSystemDialer.Dial(ctx, src, dest, sockopt)
}

if canLookupIP(ctx, dest, sockopt) {
ips, err := lookupIP(dest.Address.String(), sockopt.DomainStrategy, src)
if err == nil && len(ips) > 0 {
dest.Address = net.IPAddress(ips[dice.Roll(len(ips))])
newError("replace destination with " + dest.String()).AtInfo().WriteToLog()
} else if err != nil {
newError("failed to resolve ip").Base(err).AtWarning().WriteToLog()
}
}

if obm != nil && len(sockopt.DialerProxy) > 0 {
nc := redirect(ctx, dest, sockopt.DialerProxy)
if nc != nil {
return nc, nil
}
}

return effectiveSystemDialer.Dial(ctx, src, dest, sockopt)
}

func InitSystemDialer(dc dns.Client, om outbound.Manager) {
dnsClient = dc
obm = om
}
95 changes: 0 additions & 95 deletions transport/internet/system_dialer.go
Expand Up @@ -5,29 +5,18 @@ import (
"syscall"
"time"

"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/dice"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/features/dns"
"github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/pipe"
)

var (
effectiveSystemDialer SystemDialer = &DefaultSystemDialer{}
)

// InitSystemDialer: It's private method and you are NOT supposed to use this function.
func InitSystemDialer(dc dns.Client, om outbound.Manager) {
effectiveSystemDialer.Init(dc, om)
}

type SystemDialer interface {
Dial(ctx context.Context, source net.Address, destination net.Destination, sockopt *SocketConfig) (net.Conn, error)
Init(dc dns.Client, om outbound.Manager)
}

type DefaultSystemDialer struct {
Expand Down Expand Up @@ -58,85 +47,8 @@ func hasBindAddr(sockopt *SocketConfig) bool {
return sockopt != nil && len(sockopt.BindAddress) > 0 && sockopt.BindPort > 0
}

func (d *DefaultSystemDialer) lookupIP(domain string, strategy DomainStrategy, localAddr net.Address) ([]net.IP, error) {
if d.dns == nil {
return nil, nil
}

var option = dns.IPOption{
IPv4Enable: true,
IPv6Enable: true,
FakeEnable: false,
}

switch {
case strategy == DomainStrategy_USE_IP4 || (localAddr != nil && localAddr.Family().IsIPv4()):
option = dns.IPOption{
IPv4Enable: true,
IPv6Enable: false,
FakeEnable: false,
}
case strategy == DomainStrategy_USE_IP6 || (localAddr != nil && localAddr.Family().IsIPv6()):
option = dns.IPOption{
IPv4Enable: false,
IPv6Enable: true,
FakeEnable: false,
}
case strategy == DomainStrategy_AS_IS:
return nil, nil
}

return d.dns.LookupIP(domain, option)
}

func (d *DefaultSystemDialer) canLookupIP(ctx context.Context, dst net.Destination, sockopt *SocketConfig) bool {
if sockopt == nil || dst.Address.Family().IsIP() || d.dns == nil {
return false
}
if dst.Address.Domain() == LookupDomainFromContext(ctx) {
newError("infinite loop detected").AtError().WriteToLog(session.ExportIDToError(ctx))
return false
}
return sockopt.DomainStrategy != DomainStrategy_AS_IS
}

func (d *DefaultSystemDialer) redirect(ctx context.Context, dst net.Destination, obt string) net.Conn {
newError("redirecting request " + dst.String() + " to " + obt).WriteToLog(session.ExportIDToError(ctx))
h := d.obm.GetHandler(obt)
ctx = session.ContextWithOutbound(ctx, &session.Outbound{dst, nil})
if h != nil {
ur, uw := pipe.New(pipe.OptionsFromContext(ctx)...)
dr, dw := pipe.New(pipe.OptionsFromContext(ctx)...)

go h.Dispatch(ctx, &transport.Link{ur, dw})
nc := cnc.NewConnection(
cnc.ConnectionInputMulti(uw),
cnc.ConnectionOutputMulti(dr),
cnc.ConnectionOnClose(common.ChainedClosable{uw, dw}),
)
return nc
}
return nil
}

func (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) {
newError("dialing to " + dest.String()).AtDebug().WriteToLog()
if d.obm != nil && sockopt != nil && len(sockopt.DialerProxy) > 0 {
nc := d.redirect(ctx, dest, sockopt.DialerProxy)
if nc != nil {
return nc, nil
}
}

if d.canLookupIP(ctx, dest, sockopt) {
ips, err := d.lookupIP(dest.Address.String(), sockopt.DomainStrategy, src)
if err == nil && len(ips) > 0 {
dest.Address = net.IPAddress(ips[dice.Roll(len(ips))])
newError("replace destination with " + dest.String()).AtInfo().WriteToLog()
} else if err != nil {
newError("failed to resolve ip").Base(err).AtWarning().WriteToLog()
}
}

if dest.Network == net.Network_UDP && !hasBindAddr(sockopt) {
srcAddr := resolveSrcAddr(net.Network_UDP, src)
Expand Down Expand Up @@ -192,11 +104,6 @@ func (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest ne
return dialer.DialContext(ctx, dest.Network.SystemString(), dest.NetAddr())
}

func (d *DefaultSystemDialer) Init(dc dns.Client, om outbound.Manager) {
d.dns = dc
d.obm = om
}

type PacketConnWrapper struct {
conn net.PacketConn
dest net.Addr
Expand Down Expand Up @@ -257,8 +164,6 @@ func WithAdapter(dialer SystemDialerAdapter) SystemDialer {
}
}

func (v *SimpleSystemDialer) Init(_ dns.Client, _ outbound.Manager) {}

func (v *SimpleSystemDialer) Dial(ctx context.Context, src net.Address, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) {
return v.adapter.Dial(dest.Network.SystemString(), dest.NetAddr())
}
Expand Down
18 changes: 0 additions & 18 deletions transport/internet/system_dialer_context.go

This file was deleted.

0 comments on commit 64892fb

Please sign in to comment.