tun_linux.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. //go:build linux && !android && !e2e_testing
  2. // +build linux,!android,!e2e_testing
  3. package overlay
  4. import (
  5. "fmt"
  6. "io"
  7. "net"
  8. "net/netip"
  9. "os"
  10. "time"
  11. "unsafe"
  12. "github.com/sirupsen/logrus"
  13. "github.com/slackhq/nebula/config"
  14. "github.com/slackhq/nebula/routing"
  15. "github.com/slackhq/nebula/util"
  16. "github.com/vishvananda/netlink"
  17. "golang.org/x/sys/unix"
  18. wgtun "golang.zx2c4.com/wireguard/tun"
  19. )
  20. type tun struct {
  21. deviceIndex int
  22. ioctlFd uintptr
  23. useSystemRoutes bool
  24. useSystemRoutesBufferSize int
  25. }
  26. func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, multiqueue bool) (*wgTun, error) {
  27. deviceName := c.GetString("tun.dev", "")
  28. mtu := c.GetInt("tun.mtu", DefaultMTU)
  29. // Create WireGuard TUN device
  30. tunDevice, err := wgtun.CreateTUN(deviceName, mtu)
  31. if err != nil {
  32. return nil, fmt.Errorf("failed to create TUN device: %w", err)
  33. }
  34. // Get the actual device name
  35. actualName, err := tunDevice.Name()
  36. if err != nil {
  37. tunDevice.Close()
  38. return nil, fmt.Errorf("failed to get TUN device name: %w", err)
  39. }
  40. t := &wgTun{
  41. tunDevice: tunDevice,
  42. vpnNetworks: vpnNetworks,
  43. MaxMTU: mtu,
  44. DefaultMTU: mtu,
  45. l: l,
  46. }
  47. // Create Linux-specific route manager
  48. routeManager := &tun{
  49. useSystemRoutes: c.GetBool("tun.use_system_route_table", false),
  50. useSystemRoutesBufferSize: c.GetInt("tun.use_system_route_table_buffer_size", 0),
  51. }
  52. t.routeManager = routeManager
  53. err = t.reload(c, true)
  54. if err != nil {
  55. tunDevice.Close()
  56. return nil, err
  57. }
  58. c.RegisterReloadCallback(func(c *config.C) {
  59. err := t.reload(c, false)
  60. if err != nil {
  61. util.LogWithContextIfNeeded("failed to reload tun device", err, t.l)
  62. }
  63. })
  64. l.WithField("name", actualName).Info("Created WireGuard TUN device")
  65. return t, nil
  66. }
  67. func newTunFromFd(c *config.C, l *logrus.Logger, deviceFd int, vpnNetworks []netip.Prefix) (*wgTun, error) {
  68. // Create TUN device from file descriptor
  69. file := os.NewFile(uintptr(deviceFd), "/dev/net/tun")
  70. mtu := c.GetInt("tun.mtu", DefaultMTU)
  71. tunDevice, err := wgtun.CreateTUNFromFile(file, mtu)
  72. if err != nil {
  73. return nil, fmt.Errorf("failed to create TUN device from fd: %w", err)
  74. }
  75. t := &wgTun{
  76. tunDevice: tunDevice,
  77. vpnNetworks: vpnNetworks,
  78. MaxMTU: mtu,
  79. DefaultMTU: mtu,
  80. l: l,
  81. }
  82. // Create Linux-specific route manager
  83. routeManager := &tun{
  84. useSystemRoutes: c.GetBool("tun.use_system_route_table", false),
  85. useSystemRoutesBufferSize: c.GetInt("tun.use_system_route_table_buffer_size", 0),
  86. }
  87. t.routeManager = routeManager
  88. err = t.reload(c, true)
  89. if err != nil {
  90. tunDevice.Close()
  91. return nil, err
  92. }
  93. c.RegisterReloadCallback(func(c *config.C) {
  94. err := t.reload(c, false)
  95. if err != nil {
  96. util.LogWithContextIfNeeded("failed to reload tun device", err, t.l)
  97. }
  98. })
  99. return t, nil
  100. }
  101. func (rm *tun) Activate(t *wgTun) error {
  102. name, err := t.tunDevice.Name()
  103. if err != nil {
  104. return fmt.Errorf("failed to get device name: %w", err)
  105. }
  106. if t.routeManager.useSystemRoutes {
  107. t.watchRoutes()
  108. }
  109. // Get the netlink device
  110. link, err := netlink.LinkByName(name)
  111. if err != nil {
  112. return fmt.Errorf("failed to get tun device link: %s", err)
  113. }
  114. rm.deviceIndex = link.Attrs().Index
  115. // Open socket for ioctl operations
  116. s, err := unix.Socket(
  117. unix.AF_INET,
  118. unix.SOCK_DGRAM,
  119. unix.IPPROTO_IP,
  120. )
  121. if err != nil {
  122. return err
  123. }
  124. rm.ioctlFd = uintptr(s)
  125. // Set the MTU
  126. rm.SetMTU(t, t.MaxMTU)
  127. // Set the transmit queue length
  128. txQueueLen := 500 // default
  129. devName := deviceBytes(name)
  130. ifrq := ifreqQLEN{Name: devName, Value: int32(txQueueLen)}
  131. if err = ioctl(t.routeManager.ioctlFd, unix.SIOCSIFTXQLEN, uintptr(unsafe.Pointer(&ifrq))); err != nil {
  132. t.l.WithError(err).Error("Failed to set tun tx queue length")
  133. }
  134. // Disable IPv6 link-local address generation
  135. const modeNone = 1
  136. if err = netlink.LinkSetIP6AddrGenMode(link, modeNone); err != nil {
  137. t.l.WithError(err).Warn("Failed to disable link local address generation")
  138. }
  139. // Add IP addresses
  140. if err = t.routeManager.addIPs(t, link); err != nil {
  141. return err
  142. }
  143. // Bring up the interface
  144. if err = netlink.LinkSetUp(link); err != nil {
  145. return fmt.Errorf("failed to bring the tun device up: %s", err)
  146. }
  147. // Set route MTU
  148. for i := range t.vpnNetworks {
  149. if err = t.routeManager.SetDefaultRoute(t, t.vpnNetworks[i]); err != nil {
  150. return fmt.Errorf("failed to set default route MTU: %w", err)
  151. }
  152. }
  153. // Set the routes
  154. if err = t.routeManager.AddRoutes(t, false); err != nil {
  155. return err
  156. }
  157. return nil
  158. }
  159. func (rm *tun) SetMTU(t *wgTun, mtu int) {
  160. name, err := t.tunDevice.Name()
  161. if err != nil {
  162. t.l.WithError(err).Error("Failed to get device name for MTU set")
  163. return
  164. }
  165. link, err := netlink.LinkByName(name)
  166. if err != nil {
  167. t.l.WithError(err).Error("Failed to get link for MTU set")
  168. return
  169. }
  170. if err := netlink.LinkSetMTU(link, mtu); err != nil {
  171. t.l.WithError(err).Error("Failed to set tun mtu")
  172. }
  173. }
  174. func (rm *tun) SetDefaultRoute(t *wgTun, cidr netip.Prefix) error {
  175. dr := &net.IPNet{
  176. IP: cidr.Masked().Addr().AsSlice(),
  177. Mask: net.CIDRMask(cidr.Bits(), cidr.Addr().BitLen()),
  178. }
  179. nr := netlink.Route{
  180. LinkIndex: t.routeManager.deviceIndex,
  181. Dst: dr,
  182. MTU: t.DefaultMTU,
  183. AdvMSS: advMSS(Route{}, t.DefaultMTU, t.MaxMTU),
  184. Scope: unix.RT_SCOPE_LINK,
  185. Src: net.IP(cidr.Addr().AsSlice()),
  186. Protocol: unix.RTPROT_KERNEL,
  187. Table: unix.RT_TABLE_MAIN,
  188. Type: unix.RTN_UNICAST,
  189. }
  190. err := netlink.RouteReplace(&nr)
  191. if err != nil {
  192. t.l.WithError(err).WithField("cidr", cidr).Warn("Failed to set default route MTU, retrying")
  193. // Retry twice more
  194. for i := 0; i < 2; i++ {
  195. time.Sleep(100 * time.Millisecond)
  196. err = netlink.RouteReplace(&nr)
  197. if err == nil {
  198. break
  199. } else {
  200. t.l.WithError(err).WithField("cidr", cidr).WithField("mtu", t.DefaultMTU).Warn("Failed to set default route MTU, retrying")
  201. }
  202. }
  203. if err != nil {
  204. return fmt.Errorf("failed to set mtu %v on the default route %v; %v", t.DefaultMTU, dr, err)
  205. }
  206. }
  207. return nil
  208. }
  209. func (rm *tun) AddRoutes(t *wgTun, logErrors bool) error {
  210. routes := *t.Routes.Load()
  211. for _, r := range routes {
  212. if !r.Install {
  213. continue
  214. }
  215. dr := &net.IPNet{
  216. IP: r.Cidr.Masked().Addr().AsSlice(),
  217. Mask: net.CIDRMask(r.Cidr.Bits(), r.Cidr.Addr().BitLen()),
  218. }
  219. nr := netlink.Route{
  220. LinkIndex: t.routeManager.deviceIndex,
  221. Dst: dr,
  222. MTU: r.MTU,
  223. AdvMSS: advMSS(r, t.DefaultMTU, t.MaxMTU),
  224. Scope: unix.RT_SCOPE_LINK,
  225. }
  226. if r.Metric > 0 {
  227. nr.Priority = r.Metric
  228. }
  229. err := netlink.RouteReplace(&nr)
  230. if err != nil {
  231. retErr := util.NewContextualError("Failed to add route", map[string]any{"route": r}, err)
  232. if logErrors {
  233. retErr.Log(t.l)
  234. } else {
  235. return retErr
  236. }
  237. } else {
  238. t.l.WithField("route", r).Info("Added route")
  239. }
  240. }
  241. return nil
  242. }
  243. func (rm *tun) RemoveRoutes(t *wgTun, routes []Route) {
  244. for _, r := range routes {
  245. if !r.Install {
  246. continue
  247. }
  248. dr := &net.IPNet{
  249. IP: r.Cidr.Masked().Addr().AsSlice(),
  250. Mask: net.CIDRMask(r.Cidr.Bits(), r.Cidr.Addr().BitLen()),
  251. }
  252. nr := netlink.Route{
  253. LinkIndex: t.routeManager.deviceIndex,
  254. Dst: dr,
  255. MTU: r.MTU,
  256. AdvMSS: advMSS(r, t.DefaultMTU, t.MaxMTU),
  257. Scope: unix.RT_SCOPE_LINK,
  258. }
  259. if r.Metric > 0 {
  260. nr.Priority = r.Metric
  261. }
  262. err := netlink.RouteDel(&nr)
  263. if err != nil {
  264. t.l.WithError(err).WithField("route", r).Error("Failed to remove route")
  265. } else {
  266. t.l.WithField("route", r).Info("Removed route")
  267. }
  268. }
  269. }
  270. func (rm *tun) NewMultiQueueReader(t *wgTun) (io.ReadWriteCloser, error) {
  271. // For Linux with WireGuard TUN, we can reuse the same device
  272. // The vectorized I/O will handle batching
  273. return &wgTunReader{
  274. parent: t,
  275. tunDevice: t.tunDevice,
  276. offset: 0,
  277. l: t.l,
  278. }, nil
  279. }
  280. // Helper functions
  281. func deviceBytes(name string) [16]byte {
  282. var o [16]byte
  283. for i, c := range name {
  284. if i >= 16 {
  285. break
  286. }
  287. o[i] = byte(c)
  288. }
  289. return o
  290. }
  291. func advMSS(r Route, defaultMTU, maxMTU int) int {
  292. mtu := r.MTU
  293. if r.MTU == 0 {
  294. mtu = defaultMTU
  295. }
  296. // We only need to set advmss if the route MTU does not match the device MTU
  297. if mtu != maxMTU {
  298. return mtu - 40
  299. }
  300. return 0
  301. }
  302. type ifreqQLEN struct {
  303. Name [16]byte
  304. Value int32
  305. pad [8]byte
  306. }
  307. func hasNetlinkAddr(al []*netlink.Addr, x netlink.Addr) bool {
  308. for i := range al {
  309. if al[i].Equal(x) {
  310. return true
  311. }
  312. }
  313. return false
  314. }
  315. func (rm *tun) addIPs(t *wgTun, link netlink.Link) error {
  316. newAddrs := make([]*netlink.Addr, len(t.vpnNetworks))
  317. for i := range t.vpnNetworks {
  318. newAddrs[i] = &netlink.Addr{
  319. IPNet: &net.IPNet{
  320. IP: t.vpnNetworks[i].Addr().AsSlice(),
  321. Mask: net.CIDRMask(t.vpnNetworks[i].Bits(), t.vpnNetworks[i].Addr().BitLen()),
  322. },
  323. Label: t.vpnNetworks[i].Addr().Zone(),
  324. }
  325. }
  326. // Add all new addresses
  327. for i := range newAddrs {
  328. if err := netlink.AddrReplace(link, newAddrs[i]); err != nil {
  329. return err
  330. }
  331. }
  332. // Iterate over remainder, remove whoever shouldn't be there
  333. al, err := netlink.AddrList(link, netlink.FAMILY_ALL)
  334. if err != nil {
  335. return fmt.Errorf("failed to get tun address list: %s", err)
  336. }
  337. for i := range al {
  338. if hasNetlinkAddr(newAddrs, al[i]) {
  339. continue
  340. }
  341. err = netlink.AddrDel(link, &al[i])
  342. if err != nil {
  343. t.l.WithError(err).Error("failed to remove address from tun address list")
  344. } else {
  345. t.l.WithField("removed", al[i].String()).Info("removed address not listed in cert(s)")
  346. }
  347. }
  348. return nil
  349. }
  350. // watchRoutes monitors system route changes
  351. func (t *wgTun) watchRoutes() {
  352. rch := make(chan netlink.RouteUpdate)
  353. doneChan := make(chan struct{})
  354. netlinkOptions := netlink.RouteSubscribeOptions{
  355. ReceiveBufferSize: t.routeManager.useSystemRoutesBufferSize,
  356. ReceiveBufferForceSize: t.routeManager.useSystemRoutesBufferSize != 0,
  357. ErrorCallback: func(e error) { t.l.WithError(e).Errorf("netlink error") },
  358. }
  359. if err := netlink.RouteSubscribeWithOptions(rch, doneChan, netlinkOptions); err != nil {
  360. t.l.WithError(err).Errorf("failed to subscribe to system route changes")
  361. return
  362. }
  363. t.routeChan = doneChan
  364. go func() {
  365. for {
  366. select {
  367. case r, ok := <-rch:
  368. if ok {
  369. t.updateRoutes(r)
  370. } else {
  371. return
  372. }
  373. case <-doneChan:
  374. return
  375. }
  376. }
  377. }()
  378. }
  379. func (t *wgTun) updateRoutes(r netlink.RouteUpdate) {
  380. gateways := t.getGatewaysFromRoute(&r.Route, t.routeManager.deviceIndex)
  381. if len(gateways) == 0 {
  382. t.l.WithField("route", r).Debug("Ignoring route update, no gateways")
  383. return
  384. }
  385. if r.Dst == nil {
  386. t.l.WithField("route", r).Debug("Ignoring route update, no destination address")
  387. return
  388. }
  389. dstAddr, ok := netip.AddrFromSlice(r.Dst.IP)
  390. if !ok {
  391. t.l.WithField("route", r).Debug("Ignoring route update, invalid destination address")
  392. return
  393. }
  394. ones, _ := r.Dst.Mask.Size()
  395. dst := netip.PrefixFrom(dstAddr, ones)
  396. newTree := t.routeTree.Load().Clone()
  397. if r.Type == unix.RTM_NEWROUTE {
  398. t.l.WithField("destination", dst).WithField("via", gateways).Info("Adding route")
  399. newTree.Insert(dst, gateways)
  400. } else {
  401. t.l.WithField("destination", dst).WithField("via", gateways).Info("Removing route")
  402. newTree.Delete(dst)
  403. }
  404. t.routeTree.Store(newTree)
  405. }
  406. func (t *wgTun) getGatewaysFromRoute(r *netlink.Route, deviceIndex int) routing.Gateways {
  407. var gateways routing.Gateways
  408. name, err := t.tunDevice.Name()
  409. if err != nil {
  410. t.l.Error("Ignoring route update: failed to get device name")
  411. return gateways
  412. }
  413. link, err := netlink.LinkByName(name)
  414. if err != nil {
  415. t.l.WithField("DeviceName", name).Error("Ignoring route update: failed to get link by name")
  416. return gateways
  417. }
  418. // If this route is relevant to our interface and there is a gateway then add it
  419. if r.LinkIndex == link.Attrs().Index && len(r.Gw) > 0 {
  420. gwAddr, ok := netip.AddrFromSlice(r.Gw)
  421. if !ok {
  422. t.l.WithField("route", r).Debug("Ignoring route update, invalid gateway address")
  423. } else {
  424. gwAddr = gwAddr.Unmap()
  425. if !t.isGatewayInVpnNetworks(gwAddr) {
  426. t.l.WithField("route", r).Debug("Ignoring route update, not in our network")
  427. } else {
  428. gateways = append(gateways, routing.NewGateway(gwAddr, 1))
  429. }
  430. }
  431. }
  432. for _, p := range r.MultiPath {
  433. if p.LinkIndex == link.Attrs().Index && len(p.Gw) > 0 {
  434. gwAddr, ok := netip.AddrFromSlice(p.Gw)
  435. if !ok {
  436. t.l.WithField("route", r).Debug("Ignoring multipath route update, invalid gateway address")
  437. } else {
  438. gwAddr = gwAddr.Unmap()
  439. if !t.isGatewayInVpnNetworks(gwAddr) {
  440. t.l.WithField("route", r).Debug("Ignoring route update, not in our network")
  441. } else {
  442. gateways = append(gateways, routing.NewGateway(gwAddr, p.Hops+1))
  443. }
  444. }
  445. }
  446. }
  447. routing.CalculateBucketsForGateways(gateways)
  448. return gateways
  449. }
  450. func (t *wgTun) isGatewayInVpnNetworks(gwAddr netip.Addr) bool {
  451. for i := range t.vpnNetworks {
  452. if t.vpnNetworks[i].Contains(gwAddr) {
  453. return true
  454. }
  455. }
  456. return false
  457. }
  458. func ioctl(a1, a2, a3 uintptr) error {
  459. _, _, errno := unix.Syscall(unix.SYS_IOCTL, a1, a2, a3)
  460. if errno != 0 {
  461. return errno
  462. }
  463. return nil
  464. }