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 }