tun_linux_route_test.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. //go:build linux && !android && !e2e_testing
  2. package overlay
  3. import (
  4. "net"
  5. "net/netip"
  6. "os"
  7. "testing"
  8. "github.com/DefinedNet/netlink"
  9. "github.com/slackhq/nebula/config"
  10. "github.com/slackhq/nebula/test"
  11. "github.com/stretchr/testify/assert"
  12. "github.com/stretchr/testify/require"
  13. "golang.org/x/sys/unix"
  14. )
  15. // An unsafe_route with the same destination and metric as a lan's route must not replace it. Ours waits behind theirs
  16. // and takes over when the lan goes away. Run as root, or unprivileged with `unshare -rn`.
  17. func TestTunRouteLeavesAnotherDevicesRoute(t *testing.T) {
  18. if os.Geteuid() != 0 {
  19. t.Skip("creating links and adding routes needs root")
  20. }
  21. lan := &netlink.Veth{LinkAttrs: netlink.LinkAttrs{Name: "nebrt0"}, PeerName: "nebrt1"}
  22. require.NoError(t, netlink.LinkAdd(lan))
  23. t.Cleanup(func() { _ = netlink.LinkDel(lan) })
  24. peer, err := netlink.LinkByName("nebrt1")
  25. require.NoError(t, err)
  26. require.NoError(t, netlink.LinkSetUp(lan))
  27. require.NoError(t, netlink.LinkSetUp(peer))
  28. lanAddrs := []*netlink.Addr{
  29. {IPNet: &net.IPNet{IP: net.ParseIP("198.51.100.5"), Mask: net.CIDRMask(24, 32)}},
  30. {IPNet: &net.IPNet{IP: net.ParseIP("2001:db8:1::5"), Mask: net.CIDRMask(64, 128)}, Flags: unix.IFA_F_NODAD},
  31. }
  32. for _, a := range lanAddrs {
  33. require.NoError(t, netlink.AddrAdd(lan, a))
  34. }
  35. l := test.NewLogger()
  36. c := config.NewC(l)
  37. // The kernel puts a v4 lan route at metric 0, our default, and a v6 one at 256
  38. require.NoError(t, c.LoadString(`
  39. tun:
  40. dev: nebrt2
  41. unsafe_routes:
  42. - route: 198.51.100.0/24
  43. via: 10.250.0.2
  44. - route: 2001:db8:1::/64
  45. via: fd00:250::2
  46. metric: 256
  47. `))
  48. tn, err := newTun(c, l, []netip.Prefix{netip.MustParsePrefix("10.250.0.1/24"), netip.MustParsePrefix("fd00:250::1/64")}, false)
  49. require.NoError(t, err)
  50. t.Cleanup(func() { _ = tn.Close() })
  51. require.NoError(t, tn.Activate())
  52. via := func(dst string) int {
  53. routes, err := netlink.RouteGet(net.ParseIP(dst))
  54. require.NoError(t, err)
  55. require.NotEmpty(t, routes)
  56. return routes[0].LinkIndex
  57. }
  58. devices := func(dst string) []int {
  59. _, n, err := net.ParseCIDR(dst)
  60. require.NoError(t, err)
  61. routes, err := netlink.RouteListFiltered(netlink.FAMILY_ALL, &netlink.Route{Dst: n}, netlink.RT_FILTER_DST)
  62. require.NoError(t, err)
  63. var out []int
  64. for _, r := range routes {
  65. out = append(out, r.LinkIndex)
  66. }
  67. return out
  68. }
  69. for _, dst := range []string{"198.51.100.0/24", "2001:db8:1::/64"} {
  70. assert.ElementsMatch(t, []int{lan.Index, tn.deviceIndex}, devices(dst), dst)
  71. }
  72. assert.Equal(t, lan.Index, via("198.51.100.9"))
  73. assert.Equal(t, lan.Index, via("2001:db8:1::9"))
  74. // Leaving the lan
  75. for _, a := range lanAddrs {
  76. require.NoError(t, netlink.AddrDel(lan, a))
  77. }
  78. assert.Equal(t, tn.deviceIndex, via("198.51.100.9"))
  79. assert.Equal(t, tn.deviceIndex, via("2001:db8:1::9"))
  80. // Dropping the unsafe_routes removes only ours
  81. for _, a := range lanAddrs {
  82. require.NoError(t, netlink.AddrAdd(lan, a))
  83. }
  84. require.NoError(t, c.ReloadConfigString("tun:\n dev: nebrt2\n"))
  85. for _, dst := range []string{"198.51.100.0/24", "2001:db8:1::/64"} {
  86. assert.Equal(t, []int{lan.Index}, devices(dst), dst)
  87. }
  88. }
  89. // The route for our own vpn network is replaced to set its mtu, which must not take a lan's route for the same network
  90. func TestTunVpnNetworkLeavesAnotherDevicesRoute(t *testing.T) {
  91. if os.Geteuid() != 0 {
  92. t.Skip("creating links and adding routes needs root")
  93. }
  94. lan := &netlink.Veth{LinkAttrs: netlink.LinkAttrs{Name: "nebrt0"}, PeerName: "nebrt1"}
  95. require.NoError(t, netlink.LinkAdd(lan))
  96. t.Cleanup(func() { _ = netlink.LinkDel(lan) })
  97. require.NoError(t, netlink.LinkSetUp(lan))
  98. require.NoError(t, netlink.AddrAdd(lan, &netlink.Addr{IPNet: &net.IPNet{IP: net.ParseIP("10.250.0.5"), Mask: net.CIDRMask(24, 32)}}))
  99. l := test.NewLogger()
  100. c := config.NewC(l)
  101. require.NoError(t, c.LoadString("tun:\n dev: nebrt2\n"))
  102. tn, err := newTun(c, l, []netip.Prefix{netip.MustParsePrefix("10.250.0.1/24")}, false)
  103. require.NoError(t, err)
  104. t.Cleanup(func() { _ = tn.Close() })
  105. require.NoError(t, tn.Activate())
  106. _, n, err := net.ParseCIDR("10.250.0.0/24")
  107. require.NoError(t, err)
  108. routes, err := netlink.RouteListFiltered(netlink.FAMILY_V4, &netlink.Route{Dst: n}, netlink.RT_FILTER_DST)
  109. require.NoError(t, err)
  110. var devices []int
  111. for _, r := range routes {
  112. devices = append(devices, r.LinkIndex)
  113. if r.LinkIndex == tn.deviceIndex {
  114. assert.Equal(t, tn.DefaultMTU, r.MTU, "ours still carries the mtu")
  115. }
  116. }
  117. assert.ElementsMatch(t, []int{lan.Index, tn.deviceIndex}, devices)
  118. }