stack_gvisor.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. package tun
  2. import (
  3. "context"
  4. "time"
  5. "github.com/xtls/xray-core/common/errors"
  6. "github.com/xtls/xray-core/common/net"
  7. "gvisor.dev/gvisor/pkg/tcpip"
  8. "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
  9. "gvisor.dev/gvisor/pkg/tcpip/header"
  10. "gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
  11. "gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
  12. "gvisor.dev/gvisor/pkg/tcpip/stack"
  13. "gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
  14. "gvisor.dev/gvisor/pkg/tcpip/transport/udp"
  15. "gvisor.dev/gvisor/pkg/waiter"
  16. )
  17. const (
  18. defaultNIC tcpip.NICID = 1
  19. tcpRXBufMinSize = tcp.MinBufferSize
  20. tcpRXBufDefSize = tcp.DefaultSendBufferSize
  21. tcpRXBufMaxSize = 8 << 20 // 8MiB
  22. tcpTXBufMinSize = tcp.MinBufferSize
  23. tcpTXBufDefSize = tcp.DefaultReceiveBufferSize
  24. tcpTXBufMaxSize = 6 << 20 // 6MiB
  25. )
  26. // stackGVisor is ip stack implemented by gVisor package
  27. type stackGVisor struct {
  28. ctx context.Context
  29. tun GVisorTun
  30. idleTimeout time.Duration
  31. handler *Handler
  32. stack *stack.Stack
  33. endpoint stack.LinkEndpoint
  34. }
  35. // GVisorTun implements a bridge to connect gVisor ip stack to tun interface
  36. type GVisorTun interface {
  37. newEndpoint() (stack.LinkEndpoint, error)
  38. }
  39. // NewStack builds new ip stack (using gVisor)
  40. func NewStack(ctx context.Context, options StackOptions, handler *Handler) (Stack, error) {
  41. gStack := &stackGVisor{
  42. ctx: ctx,
  43. tun: options.Tun.(GVisorTun),
  44. idleTimeout: options.IdleTimeout,
  45. handler: handler,
  46. }
  47. return gStack, nil
  48. }
  49. // Start is called by Handler to bring stack to life
  50. func (t *stackGVisor) Start() error {
  51. linkEndpoint, err := t.tun.newEndpoint()
  52. if err != nil {
  53. return err
  54. }
  55. ipStack, err := createStack(linkEndpoint)
  56. if err != nil {
  57. return err
  58. }
  59. tcpForwarder := tcp.NewForwarder(ipStack, 0, 65535, func(r *tcp.ForwarderRequest) {
  60. go func(r *tcp.ForwarderRequest) {
  61. var wq waiter.Queue
  62. var id = r.ID()
  63. // Perform a TCP three-way handshake.
  64. ep, err := r.CreateEndpoint(&wq)
  65. if err != nil {
  66. errors.LogError(t.ctx, err.String())
  67. r.Complete(true)
  68. return
  69. }
  70. options := ep.SocketOptions()
  71. options.SetKeepAlive(false)
  72. options.SetReuseAddress(true)
  73. options.SetReusePort(true)
  74. t.handler.HandleConnection(
  75. gonet.NewTCPConn(&wq, ep),
  76. // local address on the gVisor side is connection destination
  77. net.TCPDestination(net.IPAddress(id.LocalAddress.AsSlice()), net.Port(id.LocalPort)),
  78. )
  79. // close the socket
  80. ep.Close()
  81. // send connection complete upstream
  82. r.Complete(false)
  83. }(r)
  84. })
  85. ipStack.SetTransportProtocolHandler(tcp.ProtocolNumber, tcpForwarder.HandlePacket)
  86. // Use custom UDP packet handler instead of forwarder for FullCone NAT
  87. ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, func(id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool {
  88. t.handler.HandleUDPPacket(id, pkt, ipStack)
  89. return true
  90. })
  91. t.stack = ipStack
  92. t.endpoint = linkEndpoint
  93. return nil
  94. }
  95. // Close is called by Handler to shut down the stack
  96. func (t *stackGVisor) Close() error {
  97. if t.stack == nil {
  98. return nil
  99. }
  100. t.endpoint.Attach(nil)
  101. t.stack.Close()
  102. for _, endpoint := range t.stack.CleanupEndpoints() {
  103. endpoint.Abort()
  104. }
  105. return nil
  106. }
  107. // createStack configure gVisor ip stack
  108. func createStack(ep stack.LinkEndpoint) (*stack.Stack, error) {
  109. opts := stack.Options{
  110. NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
  111. TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol},
  112. HandleLocal: false,
  113. }
  114. gStack := stack.New(opts)
  115. err := gStack.CreateNIC(defaultNIC, ep)
  116. if err != nil {
  117. return nil, errors.New(err.String())
  118. }
  119. gStack.SetRouteTable([]tcpip.Route{
  120. {Destination: header.IPv4EmptySubnet, NIC: defaultNIC},
  121. {Destination: header.IPv6EmptySubnet, NIC: defaultNIC},
  122. })
  123. err = gStack.SetSpoofing(defaultNIC, true)
  124. if err != nil {
  125. return nil, errors.New(err.String())
  126. }
  127. err = gStack.SetPromiscuousMode(defaultNIC, true)
  128. if err != nil {
  129. return nil, errors.New(err.String())
  130. }
  131. cOpt := tcpip.CongestionControlOption("cubic")
  132. gStack.SetTransportProtocolOption(tcp.ProtocolNumber, &cOpt)
  133. sOpt := tcpip.TCPSACKEnabled(true)
  134. gStack.SetTransportProtocolOption(tcp.ProtocolNumber, &sOpt)
  135. mOpt := tcpip.TCPModerateReceiveBufferOption(true)
  136. gStack.SetTransportProtocolOption(tcp.ProtocolNumber, &mOpt)
  137. tcpRXBufOpt := tcpip.TCPReceiveBufferSizeRangeOption{
  138. Min: tcpRXBufMinSize,
  139. Default: tcpRXBufDefSize,
  140. Max: tcpRXBufMaxSize,
  141. }
  142. err = gStack.SetTransportProtocolOption(tcp.ProtocolNumber, &tcpRXBufOpt)
  143. if err != nil {
  144. return nil, errors.New(err.String())
  145. }
  146. tcpTXBufOpt := tcpip.TCPSendBufferSizeRangeOption{
  147. Min: tcpTXBufMinSize,
  148. Default: tcpTXBufDefSize,
  149. Max: tcpTXBufMaxSize,
  150. }
  151. err = gStack.SetTransportProtocolOption(tcp.ProtocolNumber, &tcpTXBufOpt)
  152. if err != nil {
  153. return nil, errors.New(err.String())
  154. }
  155. return gStack, nil
  156. }