route.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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. )
  13. type Route struct {
  14. MTU int
  15. Metric int
  16. Cidr netip.Prefix
  17. Via netip.Addr
  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[netip.Addr], error) {
  45. routeTree := new(bart.Table[netip.Addr])
  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. if r.Via.IsValid() {
  51. routeTree.Insert(r.Cidr, r.Via)
  52. }
  53. }
  54. return routeTree, nil
  55. }
  56. func parseRoutes(c *config.C, networks []netip.Prefix) ([]Route, error) {
  57. var err error
  58. r := c.Get("tun.routes")
  59. if r == nil {
  60. return []Route{}, nil
  61. }
  62. rawRoutes, ok := r.([]interface{})
  63. if !ok {
  64. return nil, fmt.Errorf("tun.routes is not an array")
  65. }
  66. if len(rawRoutes) < 1 {
  67. return []Route{}, nil
  68. }
  69. routes := make([]Route, len(rawRoutes))
  70. for i, r := range rawRoutes {
  71. m, ok := r.(map[interface{}]interface{})
  72. if !ok {
  73. return nil, fmt.Errorf("entry %v in tun.routes is invalid", i+1)
  74. }
  75. rMtu, ok := m["mtu"]
  76. if !ok {
  77. return nil, fmt.Errorf("entry %v.mtu in tun.routes is not present", i+1)
  78. }
  79. mtu, ok := rMtu.(int)
  80. if !ok {
  81. mtu, err = strconv.Atoi(rMtu.(string))
  82. if err != nil {
  83. return nil, fmt.Errorf("entry %v.mtu in tun.routes is not an integer: %v", i+1, err)
  84. }
  85. }
  86. if mtu < 500 {
  87. return nil, fmt.Errorf("entry %v.mtu in tun.routes is below 500: %v", i+1, mtu)
  88. }
  89. rRoute, ok := m["route"]
  90. if !ok {
  91. return nil, fmt.Errorf("entry %v.route in tun.routes is not present", i+1)
  92. }
  93. r := Route{
  94. Install: true,
  95. MTU: mtu,
  96. }
  97. r.Cidr, err = netip.ParsePrefix(fmt.Sprintf("%v", rRoute))
  98. if err != nil {
  99. return nil, fmt.Errorf("entry %v.route in tun.routes failed to parse: %v", i+1, err)
  100. }
  101. found := false
  102. for _, network := range networks {
  103. if network.Contains(r.Cidr.Addr()) && r.Cidr.Bits() >= network.Bits() {
  104. found = true
  105. break
  106. }
  107. }
  108. if !found {
  109. return nil, fmt.Errorf(
  110. "entry %v.route in tun.routes is not contained within the configured vpn networks; route: %v, networks: %v",
  111. i+1,
  112. r.Cidr.String(),
  113. networks,
  114. )
  115. }
  116. routes[i] = r
  117. }
  118. return routes, nil
  119. }
  120. func parseUnsafeRoutes(c *config.C, networks []netip.Prefix) ([]Route, error) {
  121. var err error
  122. r := c.Get("tun.unsafe_routes")
  123. if r == nil {
  124. return []Route{}, nil
  125. }
  126. rawRoutes, ok := r.([]interface{})
  127. if !ok {
  128. return nil, fmt.Errorf("tun.unsafe_routes is not an array")
  129. }
  130. if len(rawRoutes) < 1 {
  131. return []Route{}, nil
  132. }
  133. routes := make([]Route, len(rawRoutes))
  134. for i, r := range rawRoutes {
  135. m, ok := r.(map[interface{}]interface{})
  136. if !ok {
  137. return nil, fmt.Errorf("entry %v in tun.unsafe_routes is invalid", i+1)
  138. }
  139. var mtu int
  140. if rMtu, ok := m["mtu"]; ok {
  141. mtu, ok = rMtu.(int)
  142. if !ok {
  143. mtu, err = strconv.Atoi(rMtu.(string))
  144. if err != nil {
  145. return nil, fmt.Errorf("entry %v.mtu in tun.unsafe_routes is not an integer: %v", i+1, err)
  146. }
  147. }
  148. if mtu != 0 && mtu < 500 {
  149. return nil, fmt.Errorf("entry %v.mtu in tun.unsafe_routes is below 500: %v", i+1, mtu)
  150. }
  151. }
  152. rMetric, ok := m["metric"]
  153. if !ok {
  154. rMetric = 0
  155. }
  156. metric, ok := rMetric.(int)
  157. if !ok {
  158. _, err = strconv.ParseInt(rMetric.(string), 10, 32)
  159. if err != nil {
  160. return nil, fmt.Errorf("entry %v.metric in tun.unsafe_routes is not an integer: %v", i+1, err)
  161. }
  162. }
  163. if metric < 0 || metric > math.MaxInt32 {
  164. return nil, fmt.Errorf("entry %v.metric in tun.unsafe_routes is not in range (0-%d) : %v", i+1, math.MaxInt32, metric)
  165. }
  166. rVia, ok := m["via"]
  167. if !ok {
  168. return nil, fmt.Errorf("entry %v.via in tun.unsafe_routes is not present", i+1)
  169. }
  170. via, ok := rVia.(string)
  171. if !ok {
  172. return nil, fmt.Errorf("entry %v.via in tun.unsafe_routes is not a string: found %T", i+1, rVia)
  173. }
  174. viaVpnIp, err := netip.ParseAddr(via)
  175. if err != nil {
  176. return nil, fmt.Errorf("entry %v.via in tun.unsafe_routes failed to parse address: %v", i+1, err)
  177. }
  178. rRoute, ok := m["route"]
  179. if !ok {
  180. return nil, fmt.Errorf("entry %v.route in tun.unsafe_routes is not present", i+1)
  181. }
  182. install := true
  183. rInstall, ok := m["install"]
  184. if ok {
  185. install, err = strconv.ParseBool(fmt.Sprintf("%v", rInstall))
  186. if err != nil {
  187. return nil, fmt.Errorf("entry %v.install in tun.unsafe_routes is not a boolean: %v", i+1, err)
  188. }
  189. }
  190. r := Route{
  191. Via: viaVpnIp,
  192. MTU: mtu,
  193. Metric: metric,
  194. Install: install,
  195. }
  196. r.Cidr, err = netip.ParsePrefix(fmt.Sprintf("%v", rRoute))
  197. if err != nil {
  198. return nil, fmt.Errorf("entry %v.route in tun.unsafe_routes failed to parse: %v", i+1, err)
  199. }
  200. for _, network := range networks {
  201. if network.Contains(r.Cidr.Addr()) {
  202. return nil, fmt.Errorf(
  203. "entry %v.route in tun.unsafe_routes is contained within the configured vpn networks; route: %v, network: %v",
  204. i+1,
  205. r.Cidr.String(),
  206. network.String(),
  207. )
  208. }
  209. }
  210. routes[i] = r
  211. }
  212. return routes, nil
  213. }
  214. func ipWithin(o *net.IPNet, i *net.IPNet) bool {
  215. // Make sure o contains the lowest form of i
  216. if !o.Contains(i.IP.Mask(i.Mask)) {
  217. return false
  218. }
  219. // Find the max ip in i
  220. ip4 := i.IP.To4()
  221. if ip4 == nil {
  222. return false
  223. }
  224. last := make(net.IP, len(ip4))
  225. copy(last, ip4)
  226. for x := range ip4 {
  227. last[x] |= ^i.Mask[x]
  228. }
  229. // Make sure o contains the max
  230. if !o.Contains(last) {
  231. return false
  232. }
  233. return true
  234. }