dialer.go 5.6 KB

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