route.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. package overlay
  2. import (
  3. "fmt"
  4. "math"
  5. "net"
  6. "net/netip"
  7. "runtime"
  8. "strconv"
  9. "github.com/gaissmai/bart"
  10. "github.com/sirupsen/logrus"
  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 *logrus.Logger, routes []Route, allowMTU bool) (*bart.Table[routing.Gateways], error) {
  46. routeTree := new(bart.Table[routing.Gateways])
  47. for _, r := range routes {
  48. if !allowMTU && r.MTU > 0 {
  49. l.WithField("route", r).Warnf("route MTU is not supported in %s", runtime.GOOS)
  50. }
  51. gateways := r.Via
  52. if len(gateways) > 0 {
  53. routing.CalculateBucketsForGateways(gateways)
  54. routeTree.Insert(r.Cidr, gateways)
  55. }
  56. }
  57. return routeTree, nil
  58. }
  59. func parseRoutes(c *config.C, networks []netip.Prefix) ([]Route, error) {
  60. var err error
  61. r := c.Get("tun.routes")
  62. if r == nil {
  63. return []Route{}, nil
  64. }
  65. rawRoutes, ok := r.([]any)
  66. if !ok {
  67. return nil, fmt.Errorf("tun.routes is not an array")
  68. }
  69. if len(rawRoutes) < 1 {
  70. return []Route{}, nil
  71. }
  72. routes := make([]Route, len(rawRoutes))
  73. for i, r := range rawRoutes {
  74. m, ok := r.(map[string]any)
  75. if !ok {
  76. return nil, fmt.Errorf("entry %v in tun.routes is invalid", i+1)
  77. }
  78. rMtu, ok := m["mtu"]
  79. if !ok {
  80. return nil, fmt.Errorf("entry %v.mtu in tun.routes is not present", i+1)
  81. }
  82. mtu, ok := rMtu.(int)
  83. if !ok {
  84. mtu, err = strconv.Atoi(rMtu.(string))
  85. if err != nil {
  86. return nil, fmt.Errorf("entry %v.mtu in tun.routes is not an integer: %v", i+1, err)
  87. }
  88. }
  89. if mtu < 500 {
  90. return nil, fmt.Errorf("entry %v.mtu in tun.routes is below 500: %v", i+1, mtu)
  91. }
  92. rRoute, ok := m["route"]
  93. if !ok {
  94. return nil, fmt.Errorf("entry %v.route in tun.routes is not present", i+1)
  95. }
  96. r := Route{
  97. Install: true,
  98. MTU: mtu,
  99. }
  100. r.Cidr, err = netip.ParsePrefix(fmt.Sprintf("%v", rRoute))
  101. if err != nil {
  102. return nil, fmt.Errorf("entry %v.route in tun.routes failed to parse: %v", i+1, err)
  103. }
  104. found := false
  105. for _, network := range networks {
  106. if network.Contains(r.Cidr.Addr()) && r.Cidr.Bits() >= network.Bits() {
  107. found = true
  108. break
  109. }
  110. }
  111. if !found {
  112. return nil, fmt.Errorf(
  113. "entry %v.route in tun.routes is not contained within the configured vpn networks; route: %v, networks: %v",
  114. i+1,
  115. r.Cidr.String(),
  116. networks,
  117. )
  118. }
  119. routes[i] = r
  120. }
  121. return routes, nil
  122. }
  123. func parseUnsafeRoutes(c *config.C, networks []netip.Prefix) ([]Route, error) {
  124. var err error
  125. r := c.Get("tun.unsafe_routes")
  126. if r == nil {
  127. return []Route{}, nil
  128. }
  129. rawRoutes, ok := r.([]any)
  130. if !ok {
  131. return nil, fmt.Errorf("tun.unsafe_routes is not an array")
  132. }
  133. if len(rawRoutes) < 1 {
  134. return []Route{}, nil
  135. }
  136. routes := make([]Route, len(rawRoutes))
  137. for i, r := range rawRoutes {
  138. m, ok := r.(map[string]any)
  139. if !ok {
  140. return nil, fmt.Errorf("entry %v in tun.unsafe_routes is invalid", i+1)
  141. }
  142. var mtu int
  143. if rMtu, ok := m["mtu"]; ok {
  144. mtu, ok = rMtu.(int)
  145. if !ok {
  146. mtu, err = strconv.Atoi(rMtu.(string))
  147. if err != nil {
  148. return nil, fmt.Errorf("entry %v.mtu in tun.unsafe_routes is not an integer: %v", i+1, err)
  149. }
  150. }
  151. if mtu != 0 && mtu < 500 {
  152. return nil, fmt.Errorf("entry %v.mtu in tun.unsafe_routes is below 500: %v", i+1, mtu)
  153. }
  154. }
  155. rMetric, ok := m["metric"]
  156. if !ok {
  157. rMetric = 0
  158. }
  159. metric, ok := rMetric.(int)
  160. if !ok {
  161. _, err = strconv.ParseInt(rMetric.(string), 10, 32)
  162. if err != nil {
  163. return nil, fmt.Errorf("entry %v.metric in tun.unsafe_routes is not an integer: %v", i+1, err)
  164. }
  165. }
  166. if metric < 0 || metric > math.MaxInt32 {
  167. return nil, fmt.Errorf("entry %v.metric in tun.unsafe_routes is not in range (0-%d) : %v", i+1, math.MaxInt32, metric)
  168. }
  169. rVia, ok := m["via"]
  170. if !ok {
  171. return nil, fmt.Errorf("entry %v.via in tun.unsafe_routes is not present", i+1)
  172. }
  173. var gateways routing.Gateways
  174. switch via := rVia.(type) {
  175. case string:
  176. viaIp, err := netip.ParseAddr(via)
  177. if err != nil {
  178. return nil, fmt.Errorf("entry %v.via in tun.unsafe_routes failed to parse address: %v", i+1, err)
  179. }
  180. gateways = routing.Gateways{routing.NewGateway(viaIp, 1)}
  181. case []interface{}:
  182. gateways = make(routing.Gateways, len(via))
  183. for ig, v := range via {
  184. gatewayMap, ok := v.(map[interface{}]interface{})
  185. if !ok {
  186. return nil, fmt.Errorf("entry %v in tun.unsafe_routes[%v].via is invalid", i+1, ig+1)
  187. }
  188. rGateway, ok := gatewayMap["gateway"]
  189. if !ok {
  190. return nil, fmt.Errorf("entry .gateway in tun.unsafe_routes[%v].via[%v] is not present", i+1, ig+1)
  191. }
  192. parsedGateway, ok := rGateway.(string)
  193. if !ok {
  194. return nil, fmt.Errorf("entry .gateway in tun.unsafe_routes[%v].via[%v] is not a string", i+1, ig+1)
  195. }
  196. gatewayIp, err := netip.ParseAddr(parsedGateway)
  197. if err != nil {
  198. return nil, fmt.Errorf("entry .gateway in tun.unsafe_routes[%v].via[%v] failed to parse address: %v", i+1, ig+1, err)
  199. }
  200. rGatewayWeight, ok := gatewayMap["weight"]
  201. if !ok {
  202. rGatewayWeight = 1
  203. }
  204. gatewayWeight, ok := rGatewayWeight.(int)
  205. if !ok {
  206. _, err = strconv.ParseInt(rGatewayWeight.(string), 10, 32)
  207. if err != nil {
  208. return nil, fmt.Errorf("entry .weight in tun.unsafe_routes[%v].via[%v] is not an integer", i+1, ig+1)
  209. }
  210. }
  211. if gatewayWeight < 1 || gatewayWeight > math.MaxInt32 {
  212. 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)
  213. }
  214. gateways[ig] = routing.NewGateway(gatewayIp, gatewayWeight)
  215. }
  216. default:
  217. return nil, fmt.Errorf("entry %v.via in tun.unsafe_routes is not a string or list of gateways: found %T", i+1, rVia)
  218. }
  219. rRoute, ok := m["route"]
  220. if !ok {
  221. return nil, fmt.Errorf("entry %v.route in tun.unsafe_routes is not present", i+1)
  222. }
  223. install := true
  224. rInstall, ok := m["install"]
  225. if ok {
  226. install, err = strconv.ParseBool(fmt.Sprintf("%v", rInstall))
  227. if err != nil {
  228. return nil, fmt.Errorf("entry %v.install in tun.unsafe_routes is not a boolean: %v", i+1, err)
  229. }
  230. }
  231. r := Route{
  232. Via: gateways,
  233. MTU: mtu,
  234. Metric: metric,
  235. Install: install,
  236. }
  237. r.Cidr, err = netip.ParsePrefix(fmt.Sprintf("%v", rRoute))
  238. if err != nil {
  239. return nil, fmt.Errorf("entry %v.route in tun.unsafe_routes failed to parse: %v", i+1, err)
  240. }
  241. for _, network := range networks {
  242. if network.Contains(r.Cidr.Addr()) {
  243. return nil, fmt.Errorf(
  244. "entry %v.route in tun.unsafe_routes is contained within the configured vpn networks; route: %v, network: %v",
  245. i+1,
  246. r.Cidr.String(),
  247. network.String(),
  248. )
  249. }
  250. }
  251. routes[i] = r
  252. }
  253. return routes, nil
  254. }
  255. func ipWithin(o *net.IPNet, i *net.IPNet) bool {
  256. // Make sure o contains the lowest form of i
  257. if !o.Contains(i.IP.Mask(i.Mask)) {
  258. return false
  259. }
  260. // Find the max ip in i
  261. ip4 := i.IP.To4()
  262. if ip4 == nil {
  263. return false
  264. }
  265. last := make(net.IP, len(ip4))
  266. copy(last, ip4)
  267. for x := range ip4 {
  268. last[x] |= ^i.Mask[x]
  269. }
  270. // Make sure o contains the max
  271. if !o.Contains(last) {
  272. return false
  273. }
  274. return true
  275. }