github.com/slackhq/nebula@v1.9.0/overlay/tun_darwin.go (about)

     1  //go:build !ios && !e2e_testing
     2  // +build !ios,!e2e_testing
     3  
     4  package overlay
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"net"
    11  	"os"
    12  	"sync/atomic"
    13  	"syscall"
    14  	"unsafe"
    15  
    16  	"github.com/sirupsen/logrus"
    17  	"github.com/slackhq/nebula/cidr"
    18  	"github.com/slackhq/nebula/config"
    19  	"github.com/slackhq/nebula/iputil"
    20  	"github.com/slackhq/nebula/util"
    21  	netroute "golang.org/x/net/route"
    22  	"golang.org/x/sys/unix"
    23  )
    24  
    25  type tun struct {
    26  	io.ReadWriteCloser
    27  	Device     string
    28  	cidr       *net.IPNet
    29  	DefaultMTU int
    30  	Routes     atomic.Pointer[[]Route]
    31  	routeTree  atomic.Pointer[cidr.Tree4[iputil.VpnIp]]
    32  	linkAddr   *netroute.LinkAddr
    33  	l          *logrus.Logger
    34  
    35  	// cache out buffer since we need to prepend 4 bytes for tun metadata
    36  	out []byte
    37  }
    38  
    39  type sockaddrCtl struct {
    40  	scLen      uint8
    41  	scFamily   uint8
    42  	ssSysaddr  uint16
    43  	scID       uint32
    44  	scUnit     uint32
    45  	scReserved [5]uint32
    46  }
    47  
    48  type ifReq struct {
    49  	Name  [16]byte
    50  	Flags uint16
    51  	pad   [8]byte
    52  }
    53  
    54  var sockaddrCtlSize uintptr = 32
    55  
    56  const (
    57  	_SYSPROTO_CONTROL = 2              //define SYSPROTO_CONTROL 2 /* kernel control protocol */
    58  	_AF_SYS_CONTROL   = 2              //#define AF_SYS_CONTROL 2 /* corresponding sub address type */
    59  	_PF_SYSTEM        = unix.AF_SYSTEM //#define PF_SYSTEM AF_SYSTEM
    60  	_CTLIOCGINFO      = 3227799043     //#define CTLIOCGINFO     _IOWR('N', 3, struct ctl_info)
    61  	utunControlName   = "com.apple.net.utun_control"
    62  )
    63  
    64  type ifreqAddr struct {
    65  	Name [16]byte
    66  	Addr unix.RawSockaddrInet4
    67  	pad  [8]byte
    68  }
    69  
    70  type ifreqMTU struct {
    71  	Name [16]byte
    72  	MTU  int32
    73  	pad  [8]byte
    74  }
    75  
    76  func newTun(c *config.C, l *logrus.Logger, cidr *net.IPNet, _ bool) (*tun, error) {
    77  	name := c.GetString("tun.dev", "")
    78  	ifIndex := -1
    79  	if name != "" && name != "utun" {
    80  		_, err := fmt.Sscanf(name, "utun%d", &ifIndex)
    81  		if err != nil || ifIndex < 0 {
    82  			// NOTE: we don't make this error so we don't break existing
    83  			// configs that set a name before it was used.
    84  			l.Warn("interface name must be utun[0-9]+ on Darwin, ignoring")
    85  			ifIndex = -1
    86  		}
    87  	}
    88  
    89  	fd, err := unix.Socket(_PF_SYSTEM, unix.SOCK_DGRAM, _SYSPROTO_CONTROL)
    90  	if err != nil {
    91  		return nil, fmt.Errorf("system socket: %v", err)
    92  	}
    93  
    94  	var ctlInfo = &struct {
    95  		ctlID   uint32
    96  		ctlName [96]byte
    97  	}{}
    98  
    99  	copy(ctlInfo.ctlName[:], utunControlName)
   100  
   101  	err = ioctl(uintptr(fd), uintptr(_CTLIOCGINFO), uintptr(unsafe.Pointer(ctlInfo)))
   102  	if err != nil {
   103  		return nil, fmt.Errorf("CTLIOCGINFO: %v", err)
   104  	}
   105  
   106  	sc := sockaddrCtl{
   107  		scLen:     uint8(sockaddrCtlSize),
   108  		scFamily:  unix.AF_SYSTEM,
   109  		ssSysaddr: _AF_SYS_CONTROL,
   110  		scID:      ctlInfo.ctlID,
   111  		scUnit:    uint32(ifIndex) + 1,
   112  	}
   113  
   114  	_, _, errno := unix.RawSyscall(
   115  		unix.SYS_CONNECT,
   116  		uintptr(fd),
   117  		uintptr(unsafe.Pointer(&sc)),
   118  		sockaddrCtlSize,
   119  	)
   120  	if errno != 0 {
   121  		return nil, fmt.Errorf("SYS_CONNECT: %v", errno)
   122  	}
   123  
   124  	var ifName struct {
   125  		name [16]byte
   126  	}
   127  	ifNameSize := uintptr(len(ifName.name))
   128  	_, _, errno = syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd),
   129  		2, // SYSPROTO_CONTROL
   130  		2, // UTUN_OPT_IFNAME
   131  		uintptr(unsafe.Pointer(&ifName)),
   132  		uintptr(unsafe.Pointer(&ifNameSize)), 0)
   133  	if errno != 0 {
   134  		return nil, fmt.Errorf("SYS_GETSOCKOPT: %v", errno)
   135  	}
   136  	name = string(ifName.name[:ifNameSize-1])
   137  
   138  	err = syscall.SetNonblock(fd, true)
   139  	if err != nil {
   140  		return nil, fmt.Errorf("SetNonblock: %v", err)
   141  	}
   142  
   143  	file := os.NewFile(uintptr(fd), "")
   144  
   145  	t := &tun{
   146  		ReadWriteCloser: file,
   147  		Device:          name,
   148  		cidr:            cidr,
   149  		DefaultMTU:      c.GetInt("tun.mtu", DefaultMTU),
   150  		l:               l,
   151  	}
   152  
   153  	err = t.reload(c, true)
   154  	if err != nil {
   155  		return nil, err
   156  	}
   157  
   158  	c.RegisterReloadCallback(func(c *config.C) {
   159  		err := t.reload(c, false)
   160  		if err != nil {
   161  			util.LogWithContextIfNeeded("failed to reload tun device", err, t.l)
   162  		}
   163  	})
   164  
   165  	return t, nil
   166  }
   167  
   168  func (t *tun) deviceBytes() (o [16]byte) {
   169  	for i, c := range t.Device {
   170  		o[i] = byte(c)
   171  	}
   172  	return
   173  }
   174  
   175  func newTunFromFd(_ *config.C, _ *logrus.Logger, _ int, _ *net.IPNet) (*tun, error) {
   176  	return nil, fmt.Errorf("newTunFromFd not supported in Darwin")
   177  }
   178  
   179  func (t *tun) Close() error {
   180  	if t.ReadWriteCloser != nil {
   181  		return t.ReadWriteCloser.Close()
   182  	}
   183  	return nil
   184  }
   185  
   186  func (t *tun) Activate() error {
   187  	devName := t.deviceBytes()
   188  
   189  	var addr, mask [4]byte
   190  
   191  	copy(addr[:], t.cidr.IP.To4())
   192  	copy(mask[:], t.cidr.Mask)
   193  
   194  	s, err := unix.Socket(
   195  		unix.AF_INET,
   196  		unix.SOCK_DGRAM,
   197  		unix.IPPROTO_IP,
   198  	)
   199  	if err != nil {
   200  		return err
   201  	}
   202  	defer unix.Close(s)
   203  
   204  	fd := uintptr(s)
   205  
   206  	ifra := ifreqAddr{
   207  		Name: devName,
   208  		Addr: unix.RawSockaddrInet4{
   209  			Family: unix.AF_INET,
   210  			Addr:   addr,
   211  		},
   212  	}
   213  
   214  	// Set the device ip address
   215  	if err = ioctl(fd, unix.SIOCSIFADDR, uintptr(unsafe.Pointer(&ifra))); err != nil {
   216  		return fmt.Errorf("failed to set tun address: %s", err)
   217  	}
   218  
   219  	// Set the device network
   220  	ifra.Addr.Addr = mask
   221  	if err = ioctl(fd, unix.SIOCSIFNETMASK, uintptr(unsafe.Pointer(&ifra))); err != nil {
   222  		return fmt.Errorf("failed to set tun netmask: %s", err)
   223  	}
   224  
   225  	// Set the device name
   226  	ifrf := ifReq{Name: devName}
   227  	if err = ioctl(fd, unix.SIOCGIFFLAGS, uintptr(unsafe.Pointer(&ifrf))); err != nil {
   228  		return fmt.Errorf("failed to set tun device name: %s", err)
   229  	}
   230  
   231  	// Set the MTU on the device
   232  	ifm := ifreqMTU{Name: devName, MTU: int32(t.DefaultMTU)}
   233  	if err = ioctl(fd, unix.SIOCSIFMTU, uintptr(unsafe.Pointer(&ifm))); err != nil {
   234  		return fmt.Errorf("failed to set tun mtu: %v", err)
   235  	}
   236  
   237  	/*
   238  		// Set the transmit queue length
   239  		ifrq := ifreqQLEN{Name: devName, Value: int32(t.TXQueueLen)}
   240  		if err = ioctl(fd, unix.SIOCSIFTXQLEN, uintptr(unsafe.Pointer(&ifrq))); err != nil {
   241  			// If we can't set the queue length nebula will still work but it may lead to packet loss
   242  			l.WithError(err).Error("Failed to set tun tx queue length")
   243  		}
   244  	*/
   245  
   246  	// Bring up the interface
   247  	ifrf.Flags = ifrf.Flags | unix.IFF_UP
   248  	if err = ioctl(fd, unix.SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifrf))); err != nil {
   249  		return fmt.Errorf("failed to bring the tun device up: %s", err)
   250  	}
   251  
   252  	routeSock, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
   253  	if err != nil {
   254  		return fmt.Errorf("unable to create AF_ROUTE socket: %v", err)
   255  	}
   256  	defer func() {
   257  		unix.Shutdown(routeSock, unix.SHUT_RDWR)
   258  		err := unix.Close(routeSock)
   259  		if err != nil {
   260  			t.l.WithError(err).Error("failed to close AF_ROUTE socket")
   261  		}
   262  	}()
   263  
   264  	routeAddr := &netroute.Inet4Addr{}
   265  	maskAddr := &netroute.Inet4Addr{}
   266  	linkAddr, err := getLinkAddr(t.Device)
   267  	if err != nil {
   268  		return err
   269  	}
   270  	if linkAddr == nil {
   271  		return fmt.Errorf("unable to discover link_addr for tun interface")
   272  	}
   273  	t.linkAddr = linkAddr
   274  
   275  	copy(routeAddr.IP[:], addr[:])
   276  	copy(maskAddr.IP[:], mask[:])
   277  	err = addRoute(routeSock, routeAddr, maskAddr, linkAddr)
   278  	if err != nil {
   279  		if errors.Is(err, unix.EEXIST) {
   280  			err = fmt.Errorf("unable to add tun route, identical route already exists: %s", t.cidr)
   281  		}
   282  		return err
   283  	}
   284  
   285  	// Run the interface
   286  	ifrf.Flags = ifrf.Flags | unix.IFF_UP | unix.IFF_RUNNING
   287  	if err = ioctl(fd, unix.SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifrf))); err != nil {
   288  		return fmt.Errorf("failed to run tun device: %s", err)
   289  	}
   290  
   291  	// Unsafe path routes
   292  	return t.addRoutes(false)
   293  }
   294  
   295  func (t *tun) reload(c *config.C, initial bool) error {
   296  	change, routes, err := getAllRoutesFromConfig(c, t.cidr, initial)
   297  	if err != nil {
   298  		return err
   299  	}
   300  
   301  	if !initial && !change {
   302  		return nil
   303  	}
   304  
   305  	routeTree, err := makeRouteTree(t.l, routes, false)
   306  	if err != nil {
   307  		return err
   308  	}
   309  
   310  	// Teach nebula how to handle the routes before establishing them in the system table
   311  	oldRoutes := t.Routes.Swap(&routes)
   312  	t.routeTree.Store(routeTree)
   313  
   314  	if !initial {
   315  		// Remove first, if the system removes a wanted route hopefully it will be re-added next
   316  		err := t.removeRoutes(findRemovedRoutes(routes, *oldRoutes))
   317  		if err != nil {
   318  			util.LogWithContextIfNeeded("Failed to remove routes", err, t.l)
   319  		}
   320  
   321  		// Ensure any routes we actually want are installed
   322  		err = t.addRoutes(true)
   323  		if err != nil {
   324  			// Catch any stray logs
   325  			util.LogWithContextIfNeeded("Failed to add routes", err, t.l)
   326  		}
   327  	}
   328  
   329  	return nil
   330  }
   331  
   332  func (t *tun) RouteFor(ip iputil.VpnIp) iputil.VpnIp {
   333  	ok, r := t.routeTree.Load().MostSpecificContains(ip)
   334  	if ok {
   335  		return r
   336  	}
   337  
   338  	return 0
   339  }
   340  
   341  // Get the LinkAddr for the interface of the given name
   342  // TODO: Is there an easier way to fetch this when we create the interface?
   343  // Maybe SIOCGIFINDEX? but this doesn't appear to exist in the darwin headers.
   344  func getLinkAddr(name string) (*netroute.LinkAddr, error) {
   345  	rib, err := netroute.FetchRIB(unix.AF_UNSPEC, unix.NET_RT_IFLIST, 0)
   346  	if err != nil {
   347  		return nil, err
   348  	}
   349  	msgs, err := netroute.ParseRIB(unix.NET_RT_IFLIST, rib)
   350  	if err != nil {
   351  		return nil, err
   352  	}
   353  
   354  	for _, m := range msgs {
   355  		switch m := m.(type) {
   356  		case *netroute.InterfaceMessage:
   357  			if m.Name == name {
   358  				sa, ok := m.Addrs[unix.RTAX_IFP].(*netroute.LinkAddr)
   359  				if ok {
   360  					return sa, nil
   361  				}
   362  			}
   363  		}
   364  	}
   365  
   366  	return nil, nil
   367  }
   368  
   369  func (t *tun) addRoutes(logErrors bool) error {
   370  	routeSock, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
   371  	if err != nil {
   372  		return fmt.Errorf("unable to create AF_ROUTE socket: %v", err)
   373  	}
   374  
   375  	defer func() {
   376  		unix.Shutdown(routeSock, unix.SHUT_RDWR)
   377  		err := unix.Close(routeSock)
   378  		if err != nil {
   379  			t.l.WithError(err).Error("failed to close AF_ROUTE socket")
   380  		}
   381  	}()
   382  
   383  	routeAddr := &netroute.Inet4Addr{}
   384  	maskAddr := &netroute.Inet4Addr{}
   385  	routes := *t.Routes.Load()
   386  	for _, r := range routes {
   387  		if r.Via == nil || !r.Install {
   388  			// We don't allow route MTUs so only install routes with a via
   389  			continue
   390  		}
   391  
   392  		copy(routeAddr.IP[:], r.Cidr.IP.To4())
   393  		copy(maskAddr.IP[:], net.IP(r.Cidr.Mask).To4())
   394  
   395  		err := addRoute(routeSock, routeAddr, maskAddr, t.linkAddr)
   396  		if err != nil {
   397  			if errors.Is(err, unix.EEXIST) {
   398  				t.l.WithField("route", r.Cidr).
   399  					Warnf("unable to add unsafe_route, identical route already exists")
   400  			} else {
   401  				retErr := util.NewContextualError("Failed to add route", map[string]interface{}{"route": r}, err)
   402  				if logErrors {
   403  					retErr.Log(t.l)
   404  				} else {
   405  					return retErr
   406  				}
   407  			}
   408  		} else {
   409  			t.l.WithField("route", r).Info("Added route")
   410  		}
   411  	}
   412  
   413  	return nil
   414  }
   415  
   416  func (t *tun) removeRoutes(routes []Route) error {
   417  	routeSock, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
   418  	if err != nil {
   419  		return fmt.Errorf("unable to create AF_ROUTE socket: %v", err)
   420  	}
   421  
   422  	defer func() {
   423  		unix.Shutdown(routeSock, unix.SHUT_RDWR)
   424  		err := unix.Close(routeSock)
   425  		if err != nil {
   426  			t.l.WithError(err).Error("failed to close AF_ROUTE socket")
   427  		}
   428  	}()
   429  
   430  	routeAddr := &netroute.Inet4Addr{}
   431  	maskAddr := &netroute.Inet4Addr{}
   432  
   433  	for _, r := range routes {
   434  		if !r.Install {
   435  			continue
   436  		}
   437  
   438  		copy(routeAddr.IP[:], r.Cidr.IP.To4())
   439  		copy(maskAddr.IP[:], net.IP(r.Cidr.Mask).To4())
   440  
   441  		err := delRoute(routeSock, routeAddr, maskAddr, t.linkAddr)
   442  		if err != nil {
   443  			t.l.WithError(err).WithField("route", r).Error("Failed to remove route")
   444  		} else {
   445  			t.l.WithField("route", r).Info("Removed route")
   446  		}
   447  	}
   448  	return nil
   449  }
   450  
   451  func addRoute(sock int, addr, mask *netroute.Inet4Addr, link *netroute.LinkAddr) error {
   452  	r := netroute.RouteMessage{
   453  		Version: unix.RTM_VERSION,
   454  		Type:    unix.RTM_ADD,
   455  		Flags:   unix.RTF_UP,
   456  		Seq:     1,
   457  		Addrs: []netroute.Addr{
   458  			unix.RTAX_DST:     addr,
   459  			unix.RTAX_GATEWAY: link,
   460  			unix.RTAX_NETMASK: mask,
   461  		},
   462  	}
   463  
   464  	data, err := r.Marshal()
   465  	if err != nil {
   466  		return fmt.Errorf("failed to create route.RouteMessage: %w", err)
   467  	}
   468  	_, err = unix.Write(sock, data[:])
   469  	if err != nil {
   470  		return fmt.Errorf("failed to write route.RouteMessage to socket: %w", err)
   471  	}
   472  
   473  	return nil
   474  }
   475  
   476  func delRoute(sock int, addr, mask *netroute.Inet4Addr, link *netroute.LinkAddr) error {
   477  	r := netroute.RouteMessage{
   478  		Version: unix.RTM_VERSION,
   479  		Type:    unix.RTM_DELETE,
   480  		Seq:     1,
   481  		Addrs: []netroute.Addr{
   482  			unix.RTAX_DST:     addr,
   483  			unix.RTAX_GATEWAY: link,
   484  			unix.RTAX_NETMASK: mask,
   485  		},
   486  	}
   487  
   488  	data, err := r.Marshal()
   489  	if err != nil {
   490  		return fmt.Errorf("failed to create route.RouteMessage: %w", err)
   491  	}
   492  	_, err = unix.Write(sock, data[:])
   493  	if err != nil {
   494  		return fmt.Errorf("failed to write route.RouteMessage to socket: %w", err)
   495  	}
   496  
   497  	return nil
   498  }
   499  
   500  func (t *tun) Read(to []byte) (int, error) {
   501  
   502  	buf := make([]byte, len(to)+4)
   503  
   504  	n, err := t.ReadWriteCloser.Read(buf)
   505  
   506  	copy(to, buf[4:])
   507  	return n - 4, err
   508  }
   509  
   510  // Write is only valid for single threaded use
   511  func (t *tun) Write(from []byte) (int, error) {
   512  	buf := t.out
   513  	if cap(buf) < len(from)+4 {
   514  		buf = make([]byte, len(from)+4)
   515  		t.out = buf
   516  	}
   517  	buf = buf[:len(from)+4]
   518  
   519  	if len(from) == 0 {
   520  		return 0, syscall.EIO
   521  	}
   522  
   523  	// Determine the IP Family for the NULL L2 Header
   524  	ipVer := from[0] >> 4
   525  	if ipVer == 4 {
   526  		buf[3] = syscall.AF_INET
   527  	} else if ipVer == 6 {
   528  		buf[3] = syscall.AF_INET6
   529  	} else {
   530  		return 0, fmt.Errorf("unable to determine IP version from packet")
   531  	}
   532  
   533  	copy(buf[4:], from)
   534  
   535  	n, err := t.ReadWriteCloser.Write(buf)
   536  	return n - 4, err
   537  }
   538  
   539  func (t *tun) Cidr() *net.IPNet {
   540  	return t.cidr
   541  }
   542  
   543  func (t *tun) Name() string {
   544  	return t.Device
   545  }
   546  
   547  func (t *tun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
   548  	return nil, fmt.Errorf("TODO: multiqueue not implemented for darwin")
   549  }