dialer.go 5.4 KB

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