dialer.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. package internet
  2. import (
  3. "context"
  4. "github.com/xtls/xray-core/common"
  5. "github.com/xtls/xray-core/common/dice"
  6. "github.com/xtls/xray-core/common/net"
  7. "github.com/xtls/xray-core/common/net/cnc"
  8. "github.com/xtls/xray-core/common/session"
  9. "github.com/xtls/xray-core/features/dns"
  10. "github.com/xtls/xray-core/features/outbound"
  11. "github.com/xtls/xray-core/transport"
  12. "github.com/xtls/xray-core/transport/internet/stat"
  13. "github.com/xtls/xray-core/transport/pipe"
  14. )
  15. // Dialer is the interface for dialing outbound connections.
  16. type Dialer interface {
  17. // Dial dials a system connection to the given destination.
  18. Dial(ctx context.Context, destination net.Destination) (stat.Connection, error)
  19. // Address returns the address used by this Dialer. Maybe nil if not known.
  20. Address() net.Address
  21. }
  22. // dialFunc is an interface to dial network connection to a specific destination.
  23. type dialFunc func(ctx context.Context, dest net.Destination, streamSettings *MemoryStreamConfig) (stat.Connection, error)
  24. var transportDialerCache = make(map[string]dialFunc)
  25. // RegisterTransportDialer registers a Dialer with given name.
  26. func RegisterTransportDialer(protocol string, dialer dialFunc) error {
  27. if _, found := transportDialerCache[protocol]; found {
  28. return newError(protocol, " dialer already registered").AtError()
  29. }
  30. transportDialerCache[protocol] = dialer
  31. return nil
  32. }
  33. // Dial dials a internet connection towards the given destination.
  34. func Dial(ctx context.Context, dest net.Destination, streamSettings *MemoryStreamConfig) (stat.Connection, error) {
  35. if dest.Network == net.Network_TCP {
  36. if streamSettings == nil {
  37. s, err := ToMemoryStreamConfig(nil)
  38. if err != nil {
  39. return nil, newError("failed to create default stream settings").Base(err)
  40. }
  41. streamSettings = s
  42. }
  43. protocol := streamSettings.ProtocolName
  44. dialer := transportDialerCache[protocol]
  45. if dialer == nil {
  46. return nil, newError(protocol, " dialer not registered").AtError()
  47. }
  48. return dialer(ctx, dest, streamSettings)
  49. }
  50. if dest.Network == net.Network_UDP {
  51. udpDialer := transportDialerCache["udp"]
  52. if udpDialer == nil {
  53. return nil, newError("UDP dialer not registered").AtError()
  54. }
  55. return udpDialer(ctx, dest, streamSettings)
  56. }
  57. return nil, newError("unknown network ", dest.Network)
  58. }
  59. var (
  60. dnsClient dns.Client
  61. obm outbound.Manager
  62. )
  63. func lookupIP(domain string, strategy DomainStrategy, localAddr net.Address) ([]net.IP, error) {
  64. if dnsClient == nil {
  65. return nil, nil
  66. }
  67. option := dns.IPOption{
  68. IPv4Enable: true,
  69. IPv6Enable: true,
  70. FakeEnable: false,
  71. }
  72. switch {
  73. case strategy == DomainStrategy_USE_IP4 || (localAddr != nil && localAddr.Family().IsIPv4()):
  74. option = dns.IPOption{
  75. IPv4Enable: true,
  76. IPv6Enable: false,
  77. FakeEnable: false,
  78. }
  79. case strategy == DomainStrategy_USE_IP6 || (localAddr != nil && localAddr.Family().IsIPv6()):
  80. option = dns.IPOption{
  81. IPv4Enable: false,
  82. IPv6Enable: true,
  83. FakeEnable: false,
  84. }
  85. case strategy == DomainStrategy_AS_IS:
  86. return nil, nil
  87. }
  88. return dnsClient.LookupIP(domain, option)
  89. }
  90. func canLookupIP(ctx context.Context, dst net.Destination, sockopt *SocketConfig) bool {
  91. if dst.Address.Family().IsIP() || dnsClient == nil {
  92. return false
  93. }
  94. return sockopt.DomainStrategy != DomainStrategy_AS_IS
  95. }
  96. func redirect(ctx context.Context, dst net.Destination, obt string) net.Conn {
  97. newError("redirecting request " + dst.String() + " to " + obt).WriteToLog(session.ExportIDToError(ctx))
  98. h := obm.GetHandler(obt)
  99. ctx = session.ContextWithOutbound(ctx, &session.Outbound{Target: dst, Gateway: nil})
  100. if h != nil {
  101. ur, uw := pipe.New(pipe.OptionsFromContext(ctx)...)
  102. dr, dw := pipe.New(pipe.OptionsFromContext(ctx)...)
  103. go h.Dispatch(ctx, &transport.Link{Reader: ur, Writer: dw})
  104. nc := cnc.NewConnection(
  105. cnc.ConnectionInputMulti(uw),
  106. cnc.ConnectionOutputMulti(dr),
  107. cnc.ConnectionOnClose(common.ChainedClosable{uw, dw}),
  108. )
  109. return nc
  110. }
  111. return nil
  112. }
  113. // DialSystem calls system dialer to create a network connection.
  114. func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) {
  115. var src net.Address
  116. if outbound := session.OutboundFromContext(ctx); outbound != nil {
  117. src = outbound.Gateway
  118. }
  119. if sockopt == nil {
  120. return effectiveSystemDialer.Dial(ctx, src, dest, sockopt)
  121. }
  122. if canLookupIP(ctx, dest, sockopt) {
  123. ips, err := lookupIP(dest.Address.String(), sockopt.DomainStrategy, src)
  124. if err == nil && len(ips) > 0 {
  125. dest.Address = net.IPAddress(ips[dice.Roll(len(ips))])
  126. newError("replace destination with " + dest.String()).AtInfo().WriteToLog()
  127. } else if err != nil {
  128. newError("failed to resolve ip").Base(err).AtWarning().WriteToLog()
  129. }
  130. }
  131. if obm != nil && len(sockopt.DialerProxy) > 0 {
  132. nc := redirect(ctx, dest, sockopt.DialerProxy)
  133. if nc != nil {
  134. return nc, nil
  135. }
  136. }
  137. return effectiveSystemDialer.Dial(ctx, src, dest, sockopt)
  138. }
  139. func InitSystemDialer(dc dns.Client, om outbound.Manager) {
  140. dnsClient = dc
  141. obm = om
  142. }