route.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. package overlay
  2. import (
  3. "fmt"
  4. "log/slog"
  5. "math"
  6. "net"
  7. "net/netip"
  8. "runtime"
  9. "strconv"
  10. "github.com/gaissmai/bart"
  11. "github.com/slackhq/nebula/config"
  12. "github.com/slackhq/nebula/routing"
  13. )
  14. type Route struct {
  15. MTU int
  16. Metric int
  17. Cidr netip.Prefix
  18. Via routing.Gateways
  19. Install bool
  20. }
  21. // Equal determines if a route that could be installed in the system route table is equal to another
  22. // Via is ignored since that is only consumed within nebula itself
  23. func (r Route) Equal(t Route) bool {
  24. if r.Cidr != t.Cidr {
  25. return false
  26. }
  27. if r.Metric != t.Metric {
  28. return false
  29. }
  30. if r.MTU != t.MTU {
  31. return false
  32. }
  33. if r.Install != t.Install {
  34. return false
  35. }
  36. return true
  37. }
  38. func (r Route) String() string {
  39. s := r.Cidr.String()
  40. if r.Metric != 0 {
  41. s += fmt.Sprintf(" metric: %v", r.Metric)
  42. }
  43. return s
  44. }
  45. func makeRouteTree(l *slog.Logger, routes []Route, allowMTU bool) (*bart.Table[routing.Gateways], error) {
  46. routeTree := new(bart.Table[routing.Gateways])
  47. seen := make(map[netip.Prefix]bool, len(routes))
  48. for _, r := range routes {
  49. if seen[r.Cidr] {
  50. l.Warn("route is listed more than once, only the last entry's via is used", "route", r)
  51. }
  52. seen[r.Cidr] = true
  53. if !allowMTU && r.MTU > 0 {
  54. l.Warn("route MTU is not supported on this platform",
  55. "goos", runtime.GOOS,
  56. "route", r,
  57. )
  58. }
  59. gateways := r.Via
  60. if len(gateways) > 0 {
  61. routing.CalculateBucketsForGateways(gateways)
  62. routeTree.Insert(r.Cidr, gateways)
  63. }
  64. }
  65. return routeTree, nil
  66. }
  67. func parseRoutes(c *config.C, networks []netip.Prefix) ([]Route, error) {
  68. var err error
  69. r := c.Get("tun.routes")
  70. if r == nil {
  71. return []Route{}, nil
  72. }
  73. rawRoutes, ok := r.([]any)
  74. if !ok {
  75. return nil, fmt.Errorf("tun.routes is not an array")
  76. }
  77. if len(rawRoutes) < 1 {
  78. return []Route{}, nil
  79. }
  80. routes := make([]Route, len(rawRoutes))
  81. for i, r := range rawRoutes {
  82. m, ok := r.(map[string]any)
  83. if !ok {
  84. return nil, fmt.Errorf("entry %v in tun.routes is invalid", i+1)
  85. }
  86. rMtu, ok := m["mtu"]
  87. if !ok {
  88. return nil, fmt.Errorf("entry %v.mtu in tun.routes is not present", i+1)
  89. }
  90. mtu, ok := rMtu.(int)
  91. if !ok {
  92. s, ok := rMtu.(string)
  93. if !ok {
  94. return nil, fmt.Errorf("entry %v.mtu in tun.routes is not an integer: %v", i+1, rMtu)
  95. }
  96. mtu, err = strconv.Atoi(s)
  97. if err != nil {
  98. return nil, fmt.Errorf("entry %v.mtu in tun.routes is not an integer: %v", i+1, err)
  99. }
  100. }
  101. if mtu < 500 {
  102. return nil, fmt.Errorf("entry %v.mtu in tun.routes is below 500: %v", i+1, mtu)
  103. }
  104. rRoute, ok := m["route"]
  105. if !ok {
  106. return nil, fmt.Errorf("entry %v.route in tun.routes is not present", i+1)
  107. }
  108. r := Route{
  109. Install: true,
  110. MTU: mtu,
  111. }
  112. r.Cidr, err = netip.ParsePrefix(fmt.Sprintf("%v", rRoute))
  113. if err != nil {
  114. return nil, fmt.Errorf("entry %v.route in tun.routes failed to parse: %v", i+1, err)
  115. }
  116. found := false
  117. for _, network := range networks {
  118. if network.Contains(r.Cidr.Addr()) && r.Cidr.Bits() >= network.Bits() {
  119. found = true
  120. break
  121. }
  122. }
  123. if !found {
  124. return nil, fmt.Errorf(
  125. "entry %v.route in tun.routes is not contained within the configured vpn networks; route: %v, networks: %v",
  126. i+1,
  127. r.Cidr.String(),
  128. networks,
  129. )
  130. }
  131. routes[i] = r
  132. }
  133. return routes, nil
  134. }
  135. func parseUnsafeRoutes(c *config.C, networks []netip.Prefix) ([]Route, error) {
  136. var err error
  137. r := c.Get("tun.unsafe_routes")
  138. if r == nil {
  139. return []Route{}, nil
  140. }
  141. rawRoutes, ok := r.([]any)
  142. if !ok {
  143. return nil, fmt.Errorf("tun.unsafe_routes is not an array")
  144. }
  145. if len(rawRoutes) < 1 {
  146. return []Route{}, nil
  147. }
  148. routes := make([]Route, len(rawRoutes))
  149. for i, r := range rawRoutes {
  150. m, ok := r.(map[string]any)
  151. if !ok {
  152. return nil, fmt.Errorf("entry %v in tun.unsafe_routes is invalid", i+1)
  153. }
  154. var mtu int
  155. if rMtu, ok := m["mtu"]; ok {
  156. mtu, ok = rMtu.(int)
  157. if !ok {
  158. s, ok := rMtu.(string)
  159. if !ok {
  160. return nil, fmt.Errorf("entry %v.mtu in tun.unsafe_routes is not an integer: %v", i+1, rMtu)
  161. }
  162. mtu, err = strconv.Atoi(s)
  163. if err != nil {
  164. return nil, fmt.Errorf("entry %v.mtu in tun.unsafe_routes is not an integer: %v", i+1, err)
  165. }
  166. }
  167. if mtu != 0 && mtu < 500 {
  168. return nil, fmt.Errorf("entry %v.mtu in tun.unsafe_routes is below 500: %v", i+1, mtu)
  169. }
  170. }
  171. rMetric, ok := m["metric"]
  172. if !ok {
  173. rMetric = 0
  174. }
  175. metric, ok := rMetric.(int)
  176. if !ok {
  177. s, ok := rMetric.(string)
  178. if !ok {
  179. return nil, fmt.Errorf("entry %v.metric in tun.unsafe_routes is not an integer: %v", i+1, rMetric)
  180. }
  181. n, err := strconv.ParseInt(s, 10, 32)
  182. if err != nil {
  183. return nil, fmt.Errorf("entry %v.metric in tun.unsafe_routes is not an integer: %v", i+1, err)
  184. }
  185. metric = int(n)
  186. }
  187. if metric < 0 || metric > math.MaxInt32 {
  188. return nil, fmt.Errorf("entry %v.metric in tun.unsafe_routes is not in range (0-%d) : %v", i+1, math.MaxInt32, metric)
  189. }
  190. rVia, ok := m["via"]
  191. if !ok {
  192. return nil, fmt.Errorf("entry %v.via in tun.unsafe_routes is not present", i+1)
  193. }
  194. var gateways routing.Gateways
  195. switch via := rVia.(type) {
  196. case string:
  197. viaIp, err := netip.ParseAddr(via)
  198. if err != nil {
  199. return nil, fmt.Errorf("entry %v.via in tun.unsafe_routes failed to parse address: %v", i+1, err)
  200. }
  201. gateways = routing.Gateways{routing.NewGateway(viaIp, 1)}
  202. case []any:
  203. gateways = make(routing.Gateways, len(via))
  204. for ig, v := range via {
  205. gatewayMap, ok := v.(map[string]any)
  206. if !ok {
  207. return nil, fmt.Errorf("entry %v in tun.unsafe_routes[%v].via is invalid", i+1, ig+1)
  208. }
  209. rGateway, ok := gatewayMap["gateway"]
  210. if !ok {
  211. return nil, fmt.Errorf("entry .gateway in tun.unsafe_routes[%v].via[%v] is not present", i+1, ig+1)
  212. }
  213. parsedGateway, ok := rGateway.(string)
  214. if !ok {
  215. return nil, fmt.Errorf("entry .gateway in tun.unsafe_routes[%v].via[%v] is not a string", i+1, ig+1)
  216. }
  217. gatewayIp, err := netip.ParseAddr(parsedGateway)
  218. if err != nil {
  219. return nil, fmt.Errorf("entry .gateway in tun.unsafe_routes[%v].via[%v] failed to parse address: %v", i+1, ig+1, err)
  220. }
  221. rGatewayWeight, ok := gatewayMap["weight"]
  222. if !ok {
  223. rGatewayWeight = 1
  224. }
  225. gatewayWeight, ok := rGatewayWeight.(int)
  226. if !ok {
  227. s, ok := rGatewayWeight.(string)
  228. if !ok {
  229. return nil, fmt.Errorf("entry .weight in tun.unsafe_routes[%v].via[%v] is not an integer", i+1, ig+1)
  230. }
  231. w, err := strconv.ParseInt(s, 10, 32)
  232. if err != nil {
  233. return nil, fmt.Errorf("entry .weight in tun.unsafe_routes[%v].via[%v] is not an integer", i+1, ig+1)
  234. }
  235. gatewayWeight = int(w)
  236. }
  237. if gatewayWeight < 1 || gatewayWeight > math.MaxInt32 {
  238. return nil, fmt.Errorf("entry .weight in tun.unsafe_routes[%v].via[%v] is not in range (1-%d) : %v", i+1, ig+1, math.MaxInt32, gatewayWeight)
  239. }
  240. gateways[ig] = routing.NewGateway(gatewayIp, gatewayWeight)
  241. }
  242. default:
  243. return nil, fmt.Errorf("entry %v.via in tun.unsafe_routes is not a string or list of gateways: found %T", i+1, rVia)
  244. }
  245. rRoute, ok := m["route"]
  246. if !ok {
  247. return nil, fmt.Errorf("entry %v.route in tun.unsafe_routes is not present", i+1)
  248. }
  249. install := true
  250. rInstall, ok := m["install"]
  251. if ok {
  252. install, err = strconv.ParseBool(fmt.Sprintf("%v", rInstall))
  253. if err != nil {
  254. return nil, fmt.Errorf("entry %v.install in tun.unsafe_routes is not a boolean: %v", i+1, err)
  255. }
  256. }
  257. r := Route{
  258. Via: gateways,
  259. MTU: mtu,
  260. Metric: metric,
  261. Install: install,
  262. }
  263. r.Cidr, err = netip.ParsePrefix(fmt.Sprintf("%v", rRoute))
  264. if err != nil {
  265. return nil, fmt.Errorf("entry %v.route in tun.unsafe_routes failed to parse: %v", i+1, err)
  266. }
  267. for _, network := range networks {
  268. if network.Contains(r.Cidr.Addr()) {
  269. return nil, fmt.Errorf(
  270. "entry %v.route in tun.unsafe_routes is contained within the configured vpn networks; route: %v, network: %v",
  271. i+1,
  272. r.Cidr.String(),
  273. network.String(),
  274. )
  275. }
  276. }
  277. routes[i] = r
  278. }
  279. return routes, nil
  280. }
  281. func ipWithin(o *net.IPNet, i *net.IPNet) bool {
  282. // Make sure o contains the lowest form of i
  283. if !o.Contains(i.IP.Mask(i.Mask)) {
  284. return false
  285. }
  286. // Find the max ip in i
  287. ip4 := i.IP.To4()
  288. if ip4 == nil {
  289. return false
  290. }
  291. last := make(net.IP, len(ip4))
  292. copy(last, ip4)
  293. for x := range ip4 {
  294. last[x] |= ^i.Mask[x]
  295. }
  296. // Make sure o contains the max
  297. if !o.Contains(last) {
  298. return false
  299. }
  300. return true
  301. }