tun_darwin.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. //go:build darwin && !ios && !e2e_testing
  2. // +build darwin,!ios,!e2e_testing
  3. package overlay
  4. import (
  5. "errors"
  6. "fmt"
  7. "io"
  8. "net/netip"
  9. "unsafe"
  10. "github.com/sirupsen/logrus"
  11. "github.com/slackhq/nebula/config"
  12. "github.com/slackhq/nebula/util"
  13. netroute "golang.org/x/net/route"
  14. "golang.org/x/sys/unix"
  15. wgtun "golang.zx2c4.com/wireguard/tun"
  16. )
  17. type tun struct {
  18. linkAddr *netroute.LinkAddr
  19. }
  20. // ioctl structures for Darwin network configuration
  21. type ifReq struct {
  22. Name [unix.IFNAMSIZ]byte
  23. Flags uint16
  24. pad [8]byte
  25. }
  26. type ifreqMTU struct {
  27. Name [16]byte
  28. MTU int32
  29. pad [8]byte
  30. }
  31. type addrLifetime struct {
  32. Expire float64
  33. Preferred float64
  34. Vltime uint32
  35. Pltime uint32
  36. }
  37. type ifreqAlias4 struct {
  38. Name [unix.IFNAMSIZ]byte
  39. Addr unix.RawSockaddrInet4
  40. DstAddr unix.RawSockaddrInet4
  41. MaskAddr unix.RawSockaddrInet4
  42. }
  43. type ifreqAlias6 struct {
  44. Name [unix.IFNAMSIZ]byte
  45. Addr unix.RawSockaddrInet6
  46. DstAddr unix.RawSockaddrInet6
  47. PrefixMask unix.RawSockaddrInet6
  48. Flags uint32
  49. Lifetime addrLifetime
  50. }
  51. const (
  52. _SIOCAIFADDR_IN6 = 2155899162
  53. _IN6_IFF_NODAD = 0x0020
  54. )
  55. func newTunFromFd(_ *config.C, _ *logrus.Logger, _ int, _ []netip.Prefix) (*wgTun, error) {
  56. return nil, fmt.Errorf("newTunFromFd not supported on Darwin")
  57. }
  58. func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, _ bool) (*wgTun, error) {
  59. deviceName := c.GetString("tun.dev", "utun")
  60. mtu := c.GetInt("tun.mtu", DefaultMTU)
  61. // Create WireGuard TUN device
  62. tunDevice, err := wgtun.CreateTUN(deviceName, mtu)
  63. if err != nil {
  64. return nil, fmt.Errorf("failed to create TUN device: %w", err)
  65. }
  66. // Get the actual device name
  67. actualName, err := tunDevice.Name()
  68. if err != nil {
  69. tunDevice.Close()
  70. return nil, fmt.Errorf("failed to get TUN device name: %w", err)
  71. }
  72. t := &wgTun{
  73. tunDevice: tunDevice,
  74. vpnNetworks: vpnNetworks,
  75. MaxMTU: mtu,
  76. DefaultMTU: mtu,
  77. l: l,
  78. }
  79. // Create Darwin-specific route manager
  80. t.routeManager = &tun{}
  81. err = t.reload(c, true)
  82. if err != nil {
  83. tunDevice.Close()
  84. return nil, err
  85. }
  86. c.RegisterReloadCallback(func(c *config.C) {
  87. err := t.reload(c, false)
  88. if err != nil {
  89. util.LogWithContextIfNeeded("failed to reload tun device", err, t.l)
  90. }
  91. })
  92. l.WithField("name", actualName).Info("Created WireGuard TUN device")
  93. return t, nil
  94. }
  95. func (rm *tun) Activate(t *wgTun) error {
  96. name, err := t.tunDevice.Name()
  97. if err != nil {
  98. return fmt.Errorf("failed to get device name: %w", err)
  99. }
  100. // Set the MTU
  101. rm.SetMTU(t, t.MaxMTU)
  102. // Add IP addresses
  103. for _, network := range t.vpnNetworks {
  104. if err := rm.addIP(t, name, network); err != nil {
  105. return err
  106. }
  107. }
  108. // Bring up the interface using ioctl
  109. if err := rm.bringUpInterface(name); err != nil {
  110. return fmt.Errorf("failed to bring up interface: %w", err)
  111. }
  112. // Get the link address for routing
  113. linkAddr, err := getLinkAddr(name)
  114. if err != nil {
  115. return fmt.Errorf("failed to get link address: %w", err)
  116. }
  117. if linkAddr == nil {
  118. return fmt.Errorf("unable to discover link_addr for tun interface")
  119. }
  120. rm.linkAddr = linkAddr
  121. // Set the routes
  122. if err := rm.AddRoutes(t, false); err != nil {
  123. return err
  124. }
  125. return nil
  126. }
  127. func (rm *tun) bringUpInterface(name string) error {
  128. // Open a socket for ioctl
  129. fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
  130. if err != nil {
  131. return fmt.Errorf("failed to create socket: %w", err)
  132. }
  133. defer unix.Close(fd)
  134. // Get current flags
  135. var ifrf ifReq
  136. copy(ifrf.Name[:], name)
  137. if err := ioctl(uintptr(fd), unix.SIOCGIFFLAGS, uintptr(unsafe.Pointer(&ifrf))); err != nil {
  138. return fmt.Errorf("failed to get interface flags: %w", err)
  139. }
  140. // Set IFF_UP and IFF_RUNNING flags
  141. ifrf.Flags = ifrf.Flags | unix.IFF_UP | unix.IFF_RUNNING
  142. if err := ioctl(uintptr(fd), unix.SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifrf))); err != nil {
  143. return fmt.Errorf("failed to set interface flags: %w", err)
  144. }
  145. return nil
  146. }
  147. func (rm *tun) SetMTU(t *wgTun, mtu int) {
  148. name, err := t.tunDevice.Name()
  149. if err != nil {
  150. t.l.WithError(err).Error("Failed to get device name for MTU set")
  151. return
  152. }
  153. // Open a socket for ioctl
  154. fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
  155. if err != nil {
  156. t.l.WithError(err).Error("Failed to create socket for MTU set")
  157. return
  158. }
  159. defer unix.Close(fd)
  160. // Prepare the ioctl request
  161. var ifr ifreqMTU
  162. copy(ifr.Name[:], name)
  163. ifr.MTU = int32(mtu)
  164. // Set the MTU using ioctl
  165. if err := ioctl(uintptr(fd), unix.SIOCSIFMTU, uintptr(unsafe.Pointer(&ifr))); err != nil {
  166. t.l.WithError(err).Error("Failed to set tun mtu via ioctl")
  167. }
  168. }
  169. func (rm *tun) SetDefaultRoute(t *wgTun, cidr netip.Prefix) error {
  170. // On Darwin, routes are set via ifconfig and route commands
  171. return nil
  172. }
  173. func (rm *tun) AddRoutes(t *wgTun, logErrors bool) error {
  174. routes := *t.Routes.Load()
  175. for _, r := range routes {
  176. if !r.Install {
  177. continue
  178. }
  179. err := rm.addRoute(r.Cidr)
  180. if err != nil {
  181. if errors.Is(err, unix.EEXIST) {
  182. t.l.WithField("route", r.Cidr).
  183. Warnf("unable to add unsafe_route, identical route already exists")
  184. } else {
  185. retErr := util.NewContextualError("Failed to add route", map[string]any{"route": r}, err)
  186. if logErrors {
  187. retErr.Log(t.l)
  188. } else {
  189. return retErr
  190. }
  191. }
  192. } else {
  193. t.l.WithField("route", r).Info("Added route")
  194. }
  195. }
  196. return nil
  197. }
  198. func (rm *tun) RemoveRoutes(t *wgTun, routes []Route) {
  199. for _, r := range routes {
  200. if !r.Install {
  201. continue
  202. }
  203. err := rm.delRoute(r.Cidr)
  204. if err != nil {
  205. t.l.WithError(err).WithField("route", r).Error("Failed to remove route")
  206. } else {
  207. t.l.WithField("route", r).Info("Removed route")
  208. }
  209. }
  210. }
  211. func (rm *tun) NewMultiQueueReader(t *wgTun) (io.ReadWriteCloser, error) {
  212. // Darwin doesn't support multi-queue TUN devices in the same way as Linux
  213. // Return a reader that wraps the same device
  214. return &wgTunReader{
  215. parent: t,
  216. tunDevice: t.tunDevice,
  217. offset: 0,
  218. l: t.l,
  219. }, nil
  220. }
  221. func (rm *tun) addIP(t *wgTun, name string, network netip.Prefix) error {
  222. addr := network.Addr()
  223. if addr.Is4() {
  224. return rm.addIPv4(name, network)
  225. } else {
  226. return rm.addIPv6(name, network)
  227. }
  228. }
  229. func (rm *tun) addIPv4(name string, network netip.Prefix) error {
  230. // Open an IPv4 socket for ioctl
  231. s, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_IP)
  232. if err != nil {
  233. return fmt.Errorf("failed to create IPv4 socket: %w", err)
  234. }
  235. defer unix.Close(s)
  236. var ifr ifreqAlias4
  237. copy(ifr.Name[:], name)
  238. // Set the address
  239. ifr.Addr = unix.RawSockaddrInet4{
  240. Len: unix.SizeofSockaddrInet4,
  241. Family: unix.AF_INET,
  242. Addr: network.Addr().As4(),
  243. }
  244. // Set the destination address (same as address for point-to-point)
  245. ifr.DstAddr = unix.RawSockaddrInet4{
  246. Len: unix.SizeofSockaddrInet4,
  247. Family: unix.AF_INET,
  248. Addr: network.Addr().As4(),
  249. }
  250. // Set the netmask
  251. ifr.MaskAddr = unix.RawSockaddrInet4{
  252. Len: unix.SizeofSockaddrInet4,
  253. Family: unix.AF_INET,
  254. Addr: prefixToMask(network).As4(),
  255. }
  256. if err := ioctl(uintptr(s), unix.SIOCAIFADDR, uintptr(unsafe.Pointer(&ifr))); err != nil {
  257. return fmt.Errorf("failed to set IPv4 address via ioctl: %w", err)
  258. }
  259. return nil
  260. }
  261. func (rm *tun) addIPv6(name string, network netip.Prefix) error {
  262. // Open an IPv6 socket for ioctl
  263. s, err := unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, unix.IPPROTO_IP)
  264. if err != nil {
  265. return fmt.Errorf("failed to create IPv6 socket: %w", err)
  266. }
  267. defer unix.Close(s)
  268. var ifr ifreqAlias6
  269. copy(ifr.Name[:], name)
  270. // Set the address
  271. ifr.Addr = unix.RawSockaddrInet6{
  272. Len: unix.SizeofSockaddrInet6,
  273. Family: unix.AF_INET6,
  274. Addr: network.Addr().As16(),
  275. }
  276. // Set the prefix mask
  277. ifr.PrefixMask = unix.RawSockaddrInet6{
  278. Len: unix.SizeofSockaddrInet6,
  279. Family: unix.AF_INET6,
  280. Addr: prefixToMask(network).As16(),
  281. }
  282. // Set lifetime (never expires)
  283. ifr.Lifetime = addrLifetime{
  284. Vltime: 0xffffffff,
  285. Pltime: 0xffffffff,
  286. }
  287. // Set flags (no DAD - Duplicate Address Detection)
  288. ifr.Flags = _IN6_IFF_NODAD
  289. if err := ioctl(uintptr(s), _SIOCAIFADDR_IN6, uintptr(unsafe.Pointer(&ifr))); err != nil {
  290. return fmt.Errorf("failed to set IPv6 address via ioctl: %w", err)
  291. }
  292. return nil
  293. }
  294. func getLinkAddr(name string) (*netroute.LinkAddr, error) {
  295. rib, err := netroute.FetchRIB(unix.AF_UNSPEC, unix.NET_RT_IFLIST, 0)
  296. if err != nil {
  297. return nil, err
  298. }
  299. msgs, err := netroute.ParseRIB(unix.NET_RT_IFLIST, rib)
  300. if err != nil {
  301. return nil, err
  302. }
  303. for _, m := range msgs {
  304. switch m := m.(type) {
  305. case *netroute.InterfaceMessage:
  306. if m.Name == name {
  307. sa, ok := m.Addrs[unix.RTAX_IFP].(*netroute.LinkAddr)
  308. if ok {
  309. return sa, nil
  310. }
  311. }
  312. }
  313. }
  314. return nil, nil
  315. }
  316. func (rm *tun) addRoute(prefix netip.Prefix) error {
  317. sock, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
  318. if err != nil {
  319. return fmt.Errorf("unable to create AF_ROUTE socket: %v", err)
  320. }
  321. defer unix.Close(sock)
  322. route := &netroute.RouteMessage{
  323. Version: unix.RTM_VERSION,
  324. Type: unix.RTM_ADD,
  325. Flags: unix.RTF_UP,
  326. Seq: 1,
  327. }
  328. if prefix.Addr().Is4() {
  329. route.Addrs = []netroute.Addr{
  330. unix.RTAX_DST: &netroute.Inet4Addr{IP: prefix.Masked().Addr().As4()},
  331. unix.RTAX_NETMASK: &netroute.Inet4Addr{IP: prefixToMask(prefix).As4()},
  332. unix.RTAX_GATEWAY: rm.linkAddr,
  333. }
  334. } else {
  335. route.Addrs = []netroute.Addr{
  336. unix.RTAX_DST: &netroute.Inet6Addr{IP: prefix.Masked().Addr().As16()},
  337. unix.RTAX_NETMASK: &netroute.Inet6Addr{IP: prefixToMask(prefix).As16()},
  338. unix.RTAX_GATEWAY: rm.linkAddr,
  339. }
  340. }
  341. data, err := route.Marshal()
  342. if err != nil {
  343. return fmt.Errorf("failed to create route.RouteMessage: %w", err)
  344. }
  345. _, err = unix.Write(sock, data[:])
  346. if err != nil {
  347. return fmt.Errorf("failed to write route.RouteMessage to socket: %w", err)
  348. }
  349. return nil
  350. }
  351. func (rm *tun) delRoute(prefix netip.Prefix) error {
  352. sock, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
  353. if err != nil {
  354. return fmt.Errorf("unable to create AF_ROUTE socket: %v", err)
  355. }
  356. defer unix.Close(sock)
  357. route := netroute.RouteMessage{
  358. Version: unix.RTM_VERSION,
  359. Type: unix.RTM_DELETE,
  360. Seq: 1,
  361. }
  362. if prefix.Addr().Is4() {
  363. route.Addrs = []netroute.Addr{
  364. unix.RTAX_DST: &netroute.Inet4Addr{IP: prefix.Masked().Addr().As4()},
  365. unix.RTAX_NETMASK: &netroute.Inet4Addr{IP: prefixToMask(prefix).As4()},
  366. unix.RTAX_GATEWAY: rm.linkAddr,
  367. }
  368. } else {
  369. route.Addrs = []netroute.Addr{
  370. unix.RTAX_DST: &netroute.Inet6Addr{IP: prefix.Masked().Addr().As16()},
  371. unix.RTAX_NETMASK: &netroute.Inet6Addr{IP: prefixToMask(prefix).As16()},
  372. unix.RTAX_GATEWAY: rm.linkAddr,
  373. }
  374. }
  375. data, err := route.Marshal()
  376. if err != nil {
  377. return fmt.Errorf("failed to create route.RouteMessage: %w", err)
  378. }
  379. _, err = unix.Write(sock, data[:])
  380. if err != nil {
  381. return fmt.Errorf("failed to write route.RouteMessage to socket: %w", err)
  382. }
  383. return nil
  384. }
  385. func ioctl(a1, a2, a3 uintptr) error {
  386. _, _, errno := unix.Syscall(unix.SYS_IOCTL, a1, a2, a3)
  387. if errno != 0 {
  388. return errno
  389. }
  390. return nil
  391. }
  392. func prefixToMask(prefix netip.Prefix) netip.Addr {
  393. bits := prefix.Bits()
  394. if prefix.Addr().Is4() {
  395. // Create IPv4 netmask from prefix length
  396. mask := ^uint32(0) << (32 - bits)
  397. return netip.AddrFrom4([4]byte{
  398. byte(mask >> 24),
  399. byte(mask >> 16),
  400. byte(mask >> 8),
  401. byte(mask),
  402. })
  403. } else {
  404. // Create IPv6 netmask from prefix length
  405. var mask [16]byte
  406. for i := 0; i < bits/8; i++ {
  407. mask[i] = 0xff
  408. }
  409. if bits%8 != 0 {
  410. mask[bits/8] = ^byte(0) << (8 - bits%8)
  411. }
  412. return netip.AddrFrom16(mask)
  413. }
  414. }