route.go 7.2 KB

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