tun_ios.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. //go:build ios && !e2e_testing
  2. // +build ios,!e2e_testing
  3. package overlay
  4. import (
  5. "errors"
  6. "fmt"
  7. "io"
  8. "net/netip"
  9. "os"
  10. "sync"
  11. "sync/atomic"
  12. "syscall"
  13. "github.com/gaissmai/bart"
  14. "github.com/sirupsen/logrus"
  15. "github.com/slackhq/nebula/config"
  16. "github.com/slackhq/nebula/routing"
  17. "github.com/slackhq/nebula/util"
  18. )
  19. type tun struct {
  20. io.ReadWriteCloser
  21. vpnNetworks []netip.Prefix
  22. Routes atomic.Pointer[[]Route]
  23. routeTree atomic.Pointer[bart.Table[routing.Gateways]]
  24. l *logrus.Logger
  25. }
  26. func newTun(_ *config.C, _ *logrus.Logger, _ []netip.Prefix, _ bool) (*tun, error) {
  27. return nil, fmt.Errorf("newTun not supported in iOS")
  28. }
  29. func newTunFromFd(c *config.C, l *logrus.Logger, deviceFd int, vpnNetworks []netip.Prefix) (*tun, error) {
  30. file := os.NewFile(uintptr(deviceFd), "/dev/tun")
  31. t := &tun{
  32. vpnNetworks: vpnNetworks,
  33. ReadWriteCloser: &tunReadCloser{f: file},
  34. l: l,
  35. }
  36. err := t.reload(c, true)
  37. if err != nil {
  38. return nil, err
  39. }
  40. c.RegisterReloadCallback(func(c *config.C) {
  41. err := t.reload(c, false)
  42. if err != nil {
  43. util.LogWithContextIfNeeded("failed to reload tun device", err, t.l)
  44. }
  45. })
  46. return t, nil
  47. }
  48. func (t *tun) Activate() error {
  49. return nil
  50. }
  51. func (t *tun) reload(c *config.C, initial bool) error {
  52. change, routes, err := getAllRoutesFromConfig(c, t.vpnNetworks, initial)
  53. if err != nil {
  54. return err
  55. }
  56. if !initial && !change {
  57. return nil
  58. }
  59. routeTree, err := makeRouteTree(t.l, routes, false)
  60. if err != nil {
  61. return err
  62. }
  63. // Teach nebula how to handle the routes
  64. t.Routes.Store(&routes)
  65. t.routeTree.Store(routeTree)
  66. return nil
  67. }
  68. func (t *tun) RoutesFor(ip netip.Addr) routing.Gateways {
  69. r, _ := t.routeTree.Load().Lookup(ip)
  70. return r
  71. }
  72. // The following is hoisted up from water, we do this so we can inject our own fd on iOS
  73. type tunReadCloser struct {
  74. f io.ReadWriteCloser
  75. rMu sync.Mutex
  76. rBuf []byte
  77. wMu sync.Mutex
  78. wBuf []byte
  79. }
  80. func (tr *tunReadCloser) Read(to []byte) (int, error) {
  81. tr.rMu.Lock()
  82. defer tr.rMu.Unlock()
  83. if cap(tr.rBuf) < len(to)+4 {
  84. tr.rBuf = make([]byte, len(to)+4)
  85. }
  86. tr.rBuf = tr.rBuf[:len(to)+4]
  87. n, err := tr.f.Read(tr.rBuf)
  88. copy(to, tr.rBuf[4:])
  89. return n - 4, err
  90. }
  91. func (tr *tunReadCloser) Write(from []byte) (int, error) {
  92. if len(from) == 0 {
  93. return 0, syscall.EIO
  94. }
  95. tr.wMu.Lock()
  96. defer tr.wMu.Unlock()
  97. if cap(tr.wBuf) < len(from)+4 {
  98. tr.wBuf = make([]byte, len(from)+4)
  99. }
  100. tr.wBuf = tr.wBuf[:len(from)+4]
  101. // Determine the IP Family for the NULL L2 Header
  102. ipVer := from[0] >> 4
  103. if ipVer == 4 {
  104. tr.wBuf[3] = syscall.AF_INET
  105. } else if ipVer == 6 {
  106. tr.wBuf[3] = syscall.AF_INET6
  107. } else {
  108. return 0, errors.New("unable to determine IP version from packet")
  109. }
  110. copy(tr.wBuf[4:], from)
  111. n, err := tr.f.Write(tr.wBuf)
  112. return n - 4, err
  113. }
  114. func (tr *tunReadCloser) Close() error {
  115. return tr.f.Close()
  116. }
  117. func (t *tun) Networks() []netip.Prefix {
  118. return t.vpnNetworks
  119. }
  120. func (t *tun) Name() string {
  121. return "iOS"
  122. }
  123. func (t *tun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
  124. return nil, fmt.Errorf("TODO: multiqueue not implemented for ios")
  125. }