1
0

service.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. package service
  2. import (
  3. "bytes"
  4. "context"
  5. "errors"
  6. "fmt"
  7. "log"
  8. "math"
  9. "net"
  10. "net/netip"
  11. "strings"
  12. "sync"
  13. "github.com/slackhq/nebula"
  14. "github.com/slackhq/nebula/overlay"
  15. "golang.org/x/sync/errgroup"
  16. "gvisor.dev/gvisor/pkg/buffer"
  17. "gvisor.dev/gvisor/pkg/tcpip"
  18. "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
  19. "gvisor.dev/gvisor/pkg/tcpip/header"
  20. "gvisor.dev/gvisor/pkg/tcpip/link/channel"
  21. "gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
  22. "gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
  23. "gvisor.dev/gvisor/pkg/tcpip/stack"
  24. "gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
  25. "gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
  26. "gvisor.dev/gvisor/pkg/tcpip/transport/udp"
  27. "gvisor.dev/gvisor/pkg/waiter"
  28. )
  29. const nicID = 1
  30. type Service struct {
  31. control *nebula.Control
  32. ipstack *stack.Stack
  33. // done is closed once the forwarding goroutines have exited and the
  34. // netstack is torn down, at which point err holds the first fatal error.
  35. done chan struct{}
  36. err error
  37. mu struct {
  38. sync.Mutex
  39. closed bool
  40. listeners map[uint16]*tcpListener
  41. }
  42. }
  43. func New(control *nebula.Control) (_ *Service, reterr error) {
  44. // Check this before Start so a failure doesn't leave a running nebula
  45. device, ok := control.Device().(*overlay.UserDevice)
  46. if !ok {
  47. return nil, errors.New("must be using user device")
  48. }
  49. err := control.Start()
  50. if err != nil {
  51. return nil, err
  52. }
  53. // Anything that fails after a successful Start must tear nebula back down
  54. defer func() {
  55. if reterr != nil {
  56. control.Stop()
  57. }
  58. }()
  59. ctx := control.Context()
  60. eg, ctx := errgroup.WithContext(ctx)
  61. s := Service{
  62. control: control,
  63. }
  64. s.mu.listeners = map[uint16]*tcpListener{}
  65. s.ipstack = stack.New(stack.Options{
  66. NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
  67. TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol, icmp.NewProtocol4, icmp.NewProtocol6},
  68. })
  69. // The teardown goroutine only owns the stack once New succeeds
  70. defer func() {
  71. if reterr != nil {
  72. s.ipstack.Destroy()
  73. }
  74. }()
  75. sackEnabledOpt := tcpip.TCPSACKEnabled(true) // TCP SACK is disabled by default
  76. tcpipErr := s.ipstack.SetTransportProtocolOption(tcp.ProtocolNumber, &sackEnabledOpt)
  77. if tcpipErr != nil {
  78. return nil, fmt.Errorf("could not enable TCP SACK: %v", tcpipErr)
  79. }
  80. linkEP := channel.New( /*size*/ 512 /*mtu*/, 1280, "")
  81. if tcpipProblem := s.ipstack.CreateNIC(nicID, linkEP); tcpipProblem != nil {
  82. return nil, fmt.Errorf("could not create netstack NIC: %v", tcpipProblem)
  83. }
  84. ipv4Subnet, _ := tcpip.NewSubnet(tcpip.AddrFrom4([4]byte{0x00, 0x00, 0x00, 0x00}), tcpip.MaskFrom(strings.Repeat("\x00", 4)))
  85. s.ipstack.SetRouteTable([]tcpip.Route{
  86. {
  87. Destination: ipv4Subnet,
  88. NIC: nicID,
  89. },
  90. })
  91. ipNet := device.Networks()
  92. pa := tcpip.ProtocolAddress{
  93. AddressWithPrefix: tcpip.AddrFromSlice(ipNet[0].Addr().AsSlice()).WithPrefix(),
  94. Protocol: ipv4.ProtocolNumber,
  95. }
  96. if err := s.ipstack.AddProtocolAddress(nicID, pa, stack.AddressProperties{
  97. PEB: stack.CanBePrimaryEndpoint, // zero value default
  98. ConfigType: stack.AddressConfigStatic, // zero value default
  99. }); err != nil {
  100. return nil, fmt.Errorf("error creating IP: %s", err)
  101. }
  102. const tcpReceiveBufferSize = 0
  103. const maxInFlightConnectionAttempts = 1024
  104. tcpFwd := tcp.NewForwarder(s.ipstack, tcpReceiveBufferSize, maxInFlightConnectionAttempts, s.tcpHandler)
  105. s.ipstack.SetTransportProtocolHandler(tcp.ProtocolNumber, tcpFwd.HandlePacket)
  106. reader, writer := device.Pipe()
  107. go func() {
  108. <-ctx.Done()
  109. reader.Close()
  110. writer.Close()
  111. }()
  112. // create Goroutines to forward packets between Nebula and Gvisor
  113. eg.Go(func() error {
  114. buf := make([]byte, header.IPv4MaximumHeaderSize+header.IPv4MaximumPayloadSize)
  115. for {
  116. // this will read exactly one packet
  117. n, err := reader.Read(buf)
  118. if err != nil {
  119. // An error after shutdown began is noise from the device pipes
  120. // closing, anything else is fatal and must stop nebula too
  121. if ctx.Err() != nil {
  122. return nil
  123. }
  124. s.control.Stop()
  125. return err
  126. }
  127. packetBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{
  128. Payload: buffer.MakeWithData(bytes.Clone(buf[:n])),
  129. })
  130. linkEP.InjectInbound(header.IPv4ProtocolNumber, packetBuf)
  131. if ctx.Err() != nil {
  132. return nil
  133. }
  134. }
  135. })
  136. eg.Go(func() error {
  137. for {
  138. packet := linkEP.ReadContext(ctx)
  139. if packet == nil {
  140. if ctx.Err() != nil {
  141. return nil
  142. }
  143. continue
  144. }
  145. bufView := packet.ToView()
  146. if _, err := bufView.WriteTo(writer); err != nil {
  147. // Same shutdown noise handling as the inbound reader
  148. if ctx.Err() != nil {
  149. return nil
  150. }
  151. s.control.Stop()
  152. return err
  153. }
  154. bufView.Release()
  155. }
  156. })
  157. // Add the nebula wait function to the group so a fatal reader error
  158. // propagates out through errgroup.Wait().
  159. eg.Go(func() error {
  160. return control.Wait()
  161. })
  162. // Tear down here rather than in Close so it also happens when nebula stops
  163. // on its own. The forwarding goroutines must exit before the stack they feed
  164. // is destroyed.
  165. s.done = make(chan struct{})
  166. go func() {
  167. s.err = eg.Wait()
  168. s.closeListeners()
  169. // Destroy aborts the endpoints that exist when it starts, then waits on
  170. // every endpoint, so a Dial registering in between would hold Wait until
  171. // its connect timed out. Without the NIC new dials fail route lookup.
  172. // RemoveNIC also closes linkEP.
  173. _ = s.ipstack.RemoveNIC(nicID)
  174. s.ipstack.Destroy()
  175. close(s.done)
  176. }()
  177. return &s, nil
  178. }
  179. func getProtocolNumber(addr netip.Addr) tcpip.NetworkProtocolNumber {
  180. if addr.Is6() {
  181. return ipv6.ProtocolNumber
  182. }
  183. return ipv4.ProtocolNumber
  184. }
  185. // DialContext dials the provided address.
  186. func (s *Service) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
  187. switch network {
  188. case "udp", "udp4", "udp6":
  189. addr, err := net.ResolveUDPAddr(network, address)
  190. if err != nil {
  191. return nil, err
  192. }
  193. fullAddr := tcpip.FullAddress{
  194. NIC: nicID,
  195. Addr: tcpip.AddrFromSlice(addr.IP),
  196. Port: uint16(addr.Port),
  197. }
  198. num := getProtocolNumber(addr.AddrPort().Addr())
  199. return gonet.DialUDP(s.ipstack, nil, &fullAddr, num)
  200. case "tcp", "tcp4", "tcp6":
  201. addr, err := net.ResolveTCPAddr(network, address)
  202. if err != nil {
  203. return nil, err
  204. }
  205. fullAddr := tcpip.FullAddress{
  206. NIC: nicID,
  207. Addr: tcpip.AddrFromSlice(addr.IP),
  208. Port: uint16(addr.Port),
  209. }
  210. num := getProtocolNumber(addr.AddrPort().Addr())
  211. return gonet.DialContextTCP(ctx, s.ipstack, fullAddr, num)
  212. default:
  213. return nil, fmt.Errorf("unknown network type: %s", network)
  214. }
  215. }
  216. // Dial dials the provided address
  217. func (s *Service) Dial(network, address string) (net.Conn, error) {
  218. return s.DialContext(context.Background(), network, address)
  219. }
  220. // Listen listens on the provided address. Currently only TCP with wildcard
  221. // addresses are supported.
  222. func (s *Service) Listen(network, address string) (net.Listener, error) {
  223. if network != "tcp" && network != "tcp4" {
  224. return nil, errors.New("only tcp is supported")
  225. }
  226. addr, err := net.ResolveTCPAddr(network, address)
  227. if err != nil {
  228. return nil, err
  229. }
  230. if addr.IP != nil && !bytes.Equal(addr.IP, []byte{0, 0, 0, 0}) {
  231. return nil, fmt.Errorf("only wildcard address supported, got %q %v", address, addr.IP)
  232. }
  233. if addr.Port == 0 {
  234. return nil, errors.New("specific port required, got 0")
  235. }
  236. if addr.Port < 0 || addr.Port >= math.MaxUint16 {
  237. return nil, fmt.Errorf("invalid port %d", addr.Port)
  238. }
  239. port := uint16(addr.Port)
  240. l := &tcpListener{
  241. port: port,
  242. s: s,
  243. addr: addr,
  244. accept: make(chan net.Conn),
  245. closed: make(chan struct{}),
  246. }
  247. s.mu.Lock()
  248. defer s.mu.Unlock()
  249. if s.mu.closed {
  250. return nil, net.ErrClosed
  251. }
  252. if _, ok := s.mu.listeners[port]; ok {
  253. return nil, fmt.Errorf("already listening on port %d", port)
  254. }
  255. s.mu.listeners[port] = l
  256. return l, nil
  257. }
  258. // Wait blocks until the service has fully stopped, either via Close or a fatal
  259. // error, and returns the first fatal error if there was one.
  260. func (s *Service) Wait() error {
  261. <-s.done
  262. return s.err
  263. }
  264. // Close closes all listeners and stops nebula. Use Wait to block until
  265. // shutdown has completed.
  266. func (s *Service) Close() error {
  267. s.closeListeners()
  268. s.control.Stop()
  269. return nil
  270. }
  271. // closeListeners unblocks pending Accept calls and rejects new listeners.
  272. func (s *Service) closeListeners() {
  273. // Every caller closes every listener rather than returning early once
  274. // closed is set, so none returns while another is still closing them.
  275. s.mu.Lock()
  276. s.mu.closed = true
  277. listeners := make([]*tcpListener, 0, len(s.mu.listeners))
  278. for _, l := range s.mu.listeners {
  279. listeners = append(listeners, l)
  280. }
  281. s.mu.Unlock()
  282. for _, l := range listeners {
  283. _ = l.Close()
  284. }
  285. }
  286. func (s *Service) tcpHandler(r *tcp.ForwarderRequest) {
  287. endpointID := r.ID()
  288. s.mu.Lock()
  289. l, ok := s.mu.listeners[endpointID.LocalPort]
  290. s.mu.Unlock()
  291. if !ok {
  292. r.Complete(true)
  293. return
  294. }
  295. var wq waiter.Queue
  296. ep, err := r.CreateEndpoint(&wq)
  297. if err != nil {
  298. log.Printf("got error creating endpoint %q", err)
  299. r.Complete(true)
  300. return
  301. }
  302. r.Complete(false)
  303. ep.SocketOptions().SetKeepAlive(true)
  304. // The handoff blocks until Accept is called, so it must not hold s.mu or a
  305. // listener nobody accepts from stalls every other port.
  306. conn := gonet.NewTCPConn(&wq, ep)
  307. select {
  308. case l.accept <- conn:
  309. case <-l.closed:
  310. _ = conn.Close()
  311. }
  312. }