tun_openbsd.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. //go:build !e2e_testing
  2. package overlay
  3. import (
  4. "errors"
  5. "fmt"
  6. "log/slog"
  7. "net/netip"
  8. "os"
  9. "sync/atomic"
  10. "syscall"
  11. "unsafe"
  12. "github.com/gaissmai/bart"
  13. "github.com/slackhq/nebula/config"
  14. "github.com/slackhq/nebula/overlay/tio"
  15. "github.com/slackhq/nebula/routing"
  16. "github.com/slackhq/nebula/util"
  17. netroute "golang.org/x/net/route"
  18. "golang.org/x/sys/unix"
  19. )
  20. const (
  21. SIOCAIFADDR_IN6 = 0x8080691a
  22. )
  23. type ifreqAlias4 struct {
  24. Name [unix.IFNAMSIZ]byte
  25. Addr unix.RawSockaddrInet4
  26. DstAddr unix.RawSockaddrInet4
  27. MaskAddr unix.RawSockaddrInet4
  28. }
  29. type ifreqAlias6 struct {
  30. Name [unix.IFNAMSIZ]byte
  31. Addr unix.RawSockaddrInet6
  32. DstAddr unix.RawSockaddrInet6
  33. PrefixMask unix.RawSockaddrInet6
  34. Flags uint32
  35. Lifetime [2]uint32
  36. }
  37. type ifreq struct {
  38. Name [unix.IFNAMSIZ]byte
  39. data int
  40. }
  41. type tun struct {
  42. Device string
  43. vpnNetworks []netip.Prefix
  44. MTU int
  45. Routes atomic.Pointer[[]Route]
  46. routeTree atomic.Pointer[bart.Table[routing.Gateways]]
  47. l *slog.Logger
  48. f *os.File
  49. fd int
  50. }
  51. func newTunFromFd(_ *config.C, _ *slog.Logger, _ int, _ []netip.Prefix) (*tun, error) {
  52. return nil, fmt.Errorf("newTunFromFd not supported in openbsd")
  53. }
  54. func newTun(c *config.C, l *slog.Logger, vpnNetworks []netip.Prefix, _ bool) (*tun, error) {
  55. fd, deviceName, err := openTun(l, c.GetString("tun.dev", ""))
  56. if err != nil {
  57. return nil, err
  58. }
  59. err = unix.SetNonblock(fd, true)
  60. if err != nil {
  61. l.Warn("Failed to set the tun device as nonblocking", "error", err)
  62. }
  63. t := &tun{
  64. f: os.NewFile(uintptr(fd), ""),
  65. fd: fd,
  66. Device: deviceName,
  67. vpnNetworks: vpnNetworks,
  68. MTU: getMTU(l, c),
  69. l: l,
  70. }
  71. err = t.reload(c, true, nil)
  72. if err != nil {
  73. return nil, err
  74. }
  75. c.RegisterReloadCallback(func(c *config.C, r *config.Reload) {
  76. r.RestartRequiredIfChanged("tun.mtu")
  77. if tunDevNeedsRestart(c.GetString("tun.dev", ""), t.Device) {
  78. r.RestartRequiredIfChanged("tun.dev")
  79. }
  80. err := t.reload(c, false, r)
  81. if err != nil {
  82. util.LogWithContextIfNeeded("failed to reload tun device", err, t.l)
  83. r.Failed()
  84. }
  85. })
  86. return t, nil
  87. }
  88. func (t *tun) Close() error {
  89. if t.f != nil {
  90. if err := t.f.Close(); err != nil {
  91. return fmt.Errorf("error closing tun file: %w", err)
  92. }
  93. // t.f.Close should have handled it for us but let's be extra sure
  94. _ = unix.Close(t.fd)
  95. }
  96. return nil
  97. }
  98. // tunWritev and tunReadv are linkname'd to x/sys/unix's libc-routed writev/readv stubs so the
  99. // calls go through libc's pinned trampoline. OpenBSD's pinsyscall protection rejects a raw
  100. // syscall.Syscall(SYS_WRITEV/SYS_READV, ...) because it doesn't originate from a libc-pinned
  101. // address, so we can't use the syscall.Syscall pattern that freebsd / netbsd use. We pull the
  102. // low-level stubs instead of calling unix.Writev/unix.Readv because those take [][]byte and rebuild
  103. // the []Iovec every call, which heap-allocates the header; linkname'ing the stubs lets us hand them
  104. // our own stack-allocated iovecs. See golang/go#78049.
  105. //go:linkname tunWritev golang.org/x/sys/unix.writev
  106. //go:noescape
  107. func tunWritev(fd int, iovecs []unix.Iovec) (n int, err error)
  108. //go:linkname tunReadv golang.org/x/sys/unix.readv
  109. //go:noescape
  110. func tunReadv(fd int, iovecs []unix.Iovec) (n int, err error)
  111. // Read pulls one IP packet off the tun device, scattering the 4 byte protocol header away from
  112. // the packet so the payload lands directly in to.
  113. func (t *tun) Read(to []byte) (int, error) {
  114. var head [4]byte
  115. rc, err := t.f.SyscallConn()
  116. if err != nil {
  117. return 0, err
  118. }
  119. var n int
  120. var callErr error
  121. err = rc.Read(func(fd uintptr) bool {
  122. iovecs := []unix.Iovec{
  123. {Base: &head[0], Len: 4},
  124. {Base: &to[0], Len: uint64(len(to))},
  125. }
  126. n, callErr = tunReadv(int(fd), iovecs)
  127. if errno, ok := callErr.(syscall.Errno); ok && errno.Temporary() {
  128. return false
  129. }
  130. return true
  131. })
  132. if err != nil {
  133. return 0, err
  134. }
  135. if callErr != nil {
  136. return 0, callErr
  137. }
  138. if n < 4 {
  139. return 0, nil
  140. }
  141. return n - 4, nil
  142. }
  143. // Write pushes one IP packet onto the tun device.
  144. func (t *tun) Write(from []byte) (int, error) {
  145. if len(from) == 0 {
  146. return 0, syscall.EIO
  147. }
  148. ipVer := from[0] >> 4
  149. var head [4]byte
  150. switch ipVer {
  151. case 4:
  152. head[3] = syscall.AF_INET
  153. case 6:
  154. head[3] = syscall.AF_INET6
  155. default:
  156. return 0, fmt.Errorf("unable to determine IP version from packet")
  157. }
  158. // Grab rc as a local so the compiler can devirtualize the call and keep the closure on the stack.
  159. rc, err := t.f.SyscallConn()
  160. if err != nil {
  161. return 0, err
  162. }
  163. var n int
  164. var callErr error
  165. err = rc.Write(func(fd uintptr) bool {
  166. iovecs := []unix.Iovec{
  167. {Base: &head[0], Len: 4},
  168. {Base: &from[0], Len: uint64(len(from))},
  169. }
  170. n, callErr = tunWritev(int(fd), iovecs)
  171. // Type-assert to syscall.Errno so the EAGAIN/EWOULDBLOCK/EINTR check doesn't box the errno
  172. // constants into error interfaces on every call.
  173. if errno, ok := callErr.(syscall.Errno); ok && errno.Temporary() {
  174. return false
  175. }
  176. return true
  177. })
  178. if err != nil {
  179. return 0, err
  180. }
  181. if callErr != nil {
  182. return 0, callErr
  183. }
  184. return n - 4, nil
  185. }
  186. func (t *tun) addIp(cidr netip.Prefix) error {
  187. if cidr.Addr().Is4() {
  188. var req ifreqAlias4
  189. req.Name = t.deviceBytes()
  190. req.Addr = unix.RawSockaddrInet4{
  191. Len: unix.SizeofSockaddrInet4,
  192. Family: unix.AF_INET,
  193. Addr: cidr.Addr().As4(),
  194. }
  195. req.DstAddr = unix.RawSockaddrInet4{
  196. Len: unix.SizeofSockaddrInet4,
  197. Family: unix.AF_INET,
  198. Addr: cidr.Addr().As4(),
  199. }
  200. req.MaskAddr = unix.RawSockaddrInet4{
  201. Len: unix.SizeofSockaddrInet4,
  202. Family: unix.AF_INET,
  203. Addr: prefixToMask(cidr).As4(),
  204. }
  205. s, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP)
  206. if err != nil {
  207. return err
  208. }
  209. defer syscall.Close(s)
  210. if err := ioctl(uintptr(s), unix.SIOCAIFADDR, uintptr(unsafe.Pointer(&req))); err != nil {
  211. return fmt.Errorf("failed to set tun address %s: %s", cidr.Addr(), err)
  212. }
  213. err = addRoute(cidr, t.vpnNetworks)
  214. if err != nil {
  215. return fmt.Errorf("failed to set route for vpn network %v: %w", cidr, err)
  216. }
  217. return nil
  218. }
  219. if cidr.Addr().Is6() {
  220. var req ifreqAlias6
  221. req.Name = t.deviceBytes()
  222. req.Addr = unix.RawSockaddrInet6{
  223. Len: unix.SizeofSockaddrInet6,
  224. Family: unix.AF_INET6,
  225. Addr: cidr.Addr().As16(),
  226. }
  227. req.PrefixMask = unix.RawSockaddrInet6{
  228. Len: unix.SizeofSockaddrInet6,
  229. Family: unix.AF_INET6,
  230. Addr: prefixToMask(cidr).As16(),
  231. }
  232. req.Lifetime[0] = 0xffffffff
  233. req.Lifetime[1] = 0xffffffff
  234. s, err := unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, unix.IPPROTO_IP)
  235. if err != nil {
  236. return err
  237. }
  238. defer syscall.Close(s)
  239. if err := ioctl(uintptr(s), SIOCAIFADDR_IN6, uintptr(unsafe.Pointer(&req))); err != nil {
  240. return fmt.Errorf("failed to set tun address %s: %s", cidr.Addr().String(), err)
  241. }
  242. return nil
  243. }
  244. return fmt.Errorf("unknown address type %v", cidr)
  245. }
  246. func (t *tun) Activate() error {
  247. err := t.doIoctlByName(unix.SIOCSIFMTU, uint32(t.MTU))
  248. if err != nil {
  249. return fmt.Errorf("failed to set tun mtu: %w", err)
  250. }
  251. for i := range t.vpnNetworks {
  252. err = t.addIp(t.vpnNetworks[i])
  253. if err != nil {
  254. return err
  255. }
  256. }
  257. return t.addRoutes(false, nil)
  258. }
  259. func (t *tun) doIoctlByName(ctl uintptr, value uint32) error {
  260. s, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP)
  261. if err != nil {
  262. return err
  263. }
  264. defer syscall.Close(s)
  265. ir := ifreq{Name: t.deviceBytes(), data: int(value)}
  266. err = ioctl(uintptr(s), ctl, uintptr(unsafe.Pointer(&ir)))
  267. return err
  268. }
  269. func (t *tun) reload(c *config.C, initial bool, r *config.Reload) error {
  270. change, routes, err := getAllRoutesFromConfig(t.l, c, t.vpnNetworks, initial)
  271. if err != nil {
  272. return err
  273. }
  274. if !initial && !change {
  275. return nil
  276. }
  277. routeTree, err := makeRouteTree(t.l, routes, false)
  278. if err != nil {
  279. return err
  280. }
  281. // Teach nebula how to handle the routes before establishing them in the system table
  282. oldRoutes := t.Routes.Swap(&routes)
  283. t.routeTree.Store(routeTree)
  284. if !initial {
  285. // Remove first, if the system removes a wanted route hopefully it will be re-added next
  286. err := t.removeRoutes(findRemovedRoutes(routes, *oldRoutes), r)
  287. if err != nil {
  288. util.LogWithContextIfNeeded("Failed to remove routes", err, t.l)
  289. r.Failed()
  290. }
  291. // Ensure any routes we actually want are installed
  292. err = t.addRoutes(true, r)
  293. if err != nil {
  294. // Catch any stray logs
  295. util.LogWithContextIfNeeded("Failed to add routes", err, t.l)
  296. r.Failed()
  297. }
  298. }
  299. return nil
  300. }
  301. func (t *tun) RoutesFor(ip netip.Addr) routing.Gateways {
  302. r, _ := t.routeTree.Load().Lookup(ip)
  303. return r
  304. }
  305. func (t *tun) Networks() []netip.Prefix {
  306. return t.vpnNetworks
  307. }
  308. func (t *tun) Name() string {
  309. return t.Device
  310. }
  311. func (t *tun) Queues(int) ([]tio.Queue, error) {
  312. return []tio.Queue{tio.NewSingleQueue(t, defaultBatchBufSize)}, nil
  313. }
  314. func (t *tun) addRoutes(logErrors bool, rl *config.Reload) error {
  315. routes := *t.Routes.Load()
  316. for _, r := range routes {
  317. if len(r.Via) == 0 || !r.Install {
  318. // We don't allow route MTUs so only install routes with a via
  319. continue
  320. }
  321. err := addRoute(r.Cidr, t.vpnNetworks)
  322. if err != nil {
  323. retErr := util.NewContextualError("Failed to add route", map[string]any{"route": r}, err)
  324. if logErrors {
  325. retErr.Log(t.l)
  326. rl.Failed()
  327. } else {
  328. return retErr
  329. }
  330. } else {
  331. t.l.Info("Added route", "route", r)
  332. }
  333. }
  334. return nil
  335. }
  336. func (t *tun) removeRoutes(routes []Route, rl *config.Reload) error {
  337. for _, r := range routes {
  338. if len(r.Via) == 0 || !r.Install {
  339. // addRoutes never installs these
  340. continue
  341. }
  342. err := delRoute(r.Cidr, t.vpnNetworks)
  343. if errors.Is(err, unix.ESRCH) {
  344. // Already gone, which is what we wanted
  345. t.l.Info("Route was already removed", "route", r)
  346. } else if err != nil {
  347. t.l.Error("Failed to remove route", "error", err, "route", r)
  348. rl.Failed()
  349. } else {
  350. t.l.Info("Removed route", "route", r)
  351. }
  352. }
  353. return nil
  354. }
  355. func (t *tun) deviceBytes() (o [16]byte) {
  356. for i, c := range t.Device {
  357. o[i] = byte(c)
  358. }
  359. return
  360. }
  361. func addRoute(prefix netip.Prefix, gateways []netip.Prefix) error {
  362. sock, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
  363. if err != nil {
  364. return fmt.Errorf("unable to create AF_ROUTE socket: %v", err)
  365. }
  366. defer unix.Close(sock)
  367. route := &netroute.RouteMessage{
  368. Version: unix.RTM_VERSION,
  369. Type: unix.RTM_ADD,
  370. Flags: unix.RTF_UP | unix.RTF_GATEWAY,
  371. Seq: 1,
  372. }
  373. if prefix.Addr().Is4() {
  374. gw, err := selectGateway(prefix, gateways)
  375. if err != nil {
  376. return err
  377. }
  378. route.Addrs = []netroute.Addr{
  379. unix.RTAX_DST: &netroute.Inet4Addr{IP: prefix.Masked().Addr().As4()},
  380. unix.RTAX_NETMASK: &netroute.Inet4Addr{IP: prefixToMask(prefix).As4()},
  381. unix.RTAX_GATEWAY: &netroute.Inet4Addr{IP: gw.Addr().As4()},
  382. }
  383. } else {
  384. gw, err := selectGateway(prefix, gateways)
  385. if err != nil {
  386. return err
  387. }
  388. route.Addrs = []netroute.Addr{
  389. unix.RTAX_DST: &netroute.Inet6Addr{IP: prefix.Masked().Addr().As16()},
  390. unix.RTAX_NETMASK: &netroute.Inet6Addr{IP: prefixToMask(prefix).As16()},
  391. unix.RTAX_GATEWAY: &netroute.Inet6Addr{IP: gw.Addr().As16()},
  392. }
  393. }
  394. data, err := route.Marshal()
  395. if err != nil {
  396. return fmt.Errorf("failed to create route.RouteMessage: %w", err)
  397. }
  398. _, err = unix.Write(sock, data[:])
  399. if err != nil {
  400. if errors.Is(err, unix.EEXIST) {
  401. // Try to do a change
  402. route.Type = unix.RTM_CHANGE
  403. data, err = route.Marshal()
  404. if err != nil {
  405. return fmt.Errorf("failed to create route.RouteMessage for change: %w", err)
  406. }
  407. _, err = unix.Write(sock, data[:])
  408. return err
  409. }
  410. return fmt.Errorf("failed to write route.RouteMessage to socket: %w", err)
  411. }
  412. return nil
  413. }
  414. func delRoute(prefix netip.Prefix, gateways []netip.Prefix) error {
  415. sock, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
  416. if err != nil {
  417. return fmt.Errorf("unable to create AF_ROUTE socket: %v", err)
  418. }
  419. defer unix.Close(sock)
  420. route := netroute.RouteMessage{
  421. Version: unix.RTM_VERSION,
  422. Type: unix.RTM_DELETE,
  423. Seq: 1,
  424. }
  425. if prefix.Addr().Is4() {
  426. gw, err := selectGateway(prefix, gateways)
  427. if err != nil {
  428. return err
  429. }
  430. route.Addrs = []netroute.Addr{
  431. unix.RTAX_DST: &netroute.Inet4Addr{IP: prefix.Masked().Addr().As4()},
  432. unix.RTAX_NETMASK: &netroute.Inet4Addr{IP: prefixToMask(prefix).As4()},
  433. unix.RTAX_GATEWAY: &netroute.Inet4Addr{IP: gw.Addr().As4()},
  434. }
  435. } else {
  436. gw, err := selectGateway(prefix, gateways)
  437. if err != nil {
  438. return err
  439. }
  440. route.Addrs = []netroute.Addr{
  441. unix.RTAX_DST: &netroute.Inet6Addr{IP: prefix.Masked().Addr().As16()},
  442. unix.RTAX_NETMASK: &netroute.Inet6Addr{IP: prefixToMask(prefix).As16()},
  443. unix.RTAX_GATEWAY: &netroute.Inet6Addr{IP: gw.Addr().As16()},
  444. }
  445. }
  446. data, err := route.Marshal()
  447. if err != nil {
  448. return fmt.Errorf("failed to create route.RouteMessage: %w", err)
  449. }
  450. _, err = unix.Write(sock, data[:])
  451. if err != nil {
  452. return fmt.Errorf("failed to write route.RouteMessage to socket: %w", err)
  453. }
  454. return nil
  455. }