gateway.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. package logic
  2. import (
  3. "errors"
  4. "fmt"
  5. "net"
  6. "slices"
  7. "sort"
  8. "time"
  9. "github.com/google/uuid"
  10. "github.com/gravitl/netmaker/database"
  11. "github.com/gravitl/netmaker/logger"
  12. "github.com/gravitl/netmaker/models"
  13. "github.com/gravitl/netmaker/servercfg"
  14. "golang.org/x/exp/slog"
  15. )
  16. var (
  17. IPv4Network = "0.0.0.0/0"
  18. IPv6Network = "::/0"
  19. )
  20. // IsInternetGw - checks if node is acting as internet gw
  21. func IsInternetGw(node models.Node) bool {
  22. return node.IsInternetGateway
  23. }
  24. // GetInternetGateways - gets all the nodes that are internet gateways
  25. func GetInternetGateways() ([]models.Node, error) {
  26. nodes, err := GetAllNodes()
  27. if err != nil {
  28. return nil, err
  29. }
  30. igs := make([]models.Node, 0)
  31. for _, node := range nodes {
  32. if node.IsInternetGateway {
  33. igs = append(igs, node)
  34. }
  35. }
  36. return igs, nil
  37. }
  38. // GetAllIngresses - gets all the nodes that are ingresses
  39. func GetAllIngresses() ([]models.Node, error) {
  40. nodes, err := GetAllNodes()
  41. if err != nil {
  42. return nil, err
  43. }
  44. ingresses := make([]models.Node, 0)
  45. for _, node := range nodes {
  46. if node.IsIngressGateway {
  47. ingresses = append(ingresses, node)
  48. }
  49. }
  50. return ingresses, nil
  51. }
  52. // GetAllEgresses - gets all the nodes that are egresses
  53. func GetAllEgresses() ([]models.Node, error) {
  54. nodes, err := GetAllNodes()
  55. if err != nil {
  56. return nil, err
  57. }
  58. egresses := make([]models.Node, 0)
  59. for _, node := range nodes {
  60. if node.EgressDetails.IsEgressGateway {
  61. egresses = append(egresses, node)
  62. }
  63. }
  64. return egresses, nil
  65. }
  66. // CreateEgressGateway - creates an egress gateway
  67. func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, error) {
  68. node, err := GetNodeByID(gateway.NodeID)
  69. if err != nil {
  70. return models.Node{}, err
  71. }
  72. host, err := GetHost(node.HostID.String())
  73. if err != nil {
  74. return models.Node{}, err
  75. }
  76. if host.OS != "linux" { // support for other OS to be added
  77. return models.Node{}, errors.New(host.OS + " is unsupported for egress gateways")
  78. }
  79. if host.FirewallInUse == models.FIREWALL_NONE {
  80. return models.Node{}, errors.New("please install iptables or nftables on the device")
  81. }
  82. if len(gateway.RangesWithMetric) == 0 && len(gateway.Ranges) > 0 {
  83. for _, rangeI := range gateway.Ranges {
  84. gateway.RangesWithMetric = append(gateway.RangesWithMetric, models.EgressRangeMetric{
  85. Network: rangeI,
  86. RouteMetric: 256,
  87. })
  88. }
  89. }
  90. for i := len(gateway.Ranges) - 1; i >= 0; i-- {
  91. // check if internet gateway IPv4
  92. if gateway.Ranges[i] == "0.0.0.0/0" || gateway.Ranges[i] == "::/0" {
  93. // remove inet range
  94. gateway.Ranges = append(gateway.Ranges[:i], gateway.Ranges[i+1:]...)
  95. continue
  96. }
  97. normalized, err := NormalizeCIDR(gateway.Ranges[i])
  98. if err != nil {
  99. return models.Node{}, err
  100. }
  101. gateway.Ranges[i] = normalized
  102. }
  103. rangesWithMetric := []string{}
  104. for i := len(gateway.RangesWithMetric) - 1; i >= 0; i-- {
  105. if gateway.RangesWithMetric[i].Network == "0.0.0.0/0" || gateway.RangesWithMetric[i].Network == "::/0" {
  106. // remove inet range
  107. gateway.RangesWithMetric = append(gateway.RangesWithMetric[:i], gateway.RangesWithMetric[i+1:]...)
  108. continue
  109. }
  110. normalized, err := NormalizeCIDR(gateway.RangesWithMetric[i].Network)
  111. if err != nil {
  112. return models.Node{}, err
  113. }
  114. gateway.RangesWithMetric[i].Network = normalized
  115. rangesWithMetric = append(rangesWithMetric, gateway.RangesWithMetric[i].Network)
  116. if gateway.RangesWithMetric[i].RouteMetric <= 0 || gateway.RangesWithMetric[i].RouteMetric > 999 {
  117. gateway.RangesWithMetric[i].RouteMetric = 256
  118. }
  119. }
  120. sort.Strings(gateway.Ranges)
  121. sort.Strings(rangesWithMetric)
  122. if !slices.Equal(gateway.Ranges, rangesWithMetric) {
  123. return models.Node{}, errors.New("invalid ranges")
  124. }
  125. if gateway.NatEnabled == "" {
  126. gateway.NatEnabled = "yes"
  127. }
  128. err = ValidateEgressGateway(gateway)
  129. if err != nil {
  130. return models.Node{}, err
  131. }
  132. if gateway.Ranges == nil {
  133. gateway.Ranges = make([]string, 0)
  134. }
  135. node.EgressDetails.IsEgressGateway = true
  136. node.EgressDetails.EgressGatewayRanges = gateway.Ranges
  137. node.EgressDetails.EgressGatewayNatEnabled = models.ParseBool(gateway.NatEnabled)
  138. node.EgressDetails.EgressGatewayRequest = gateway // store entire request for use when preserving the egress gateway
  139. node.SetLastModified()
  140. if err = UpsertNode(&node); err != nil {
  141. return models.Node{}, err
  142. }
  143. return node, nil
  144. }
  145. // ValidateEgressGateway - validates the egress gateway model
  146. func ValidateEgressGateway(gateway models.EgressGatewayRequest) error {
  147. return nil
  148. }
  149. // DeleteEgressGateway - deletes egress from node
  150. func DeleteEgressGateway(network, nodeid string) (models.Node, error) {
  151. node, err := GetNodeByID(nodeid)
  152. if err != nil {
  153. return models.Node{}, err
  154. }
  155. node.EgressDetails.IsEgressGateway = false
  156. node.EgressDetails.EgressGatewayRanges = []string{}
  157. node.EgressDetails.EgressGatewayRequest = models.EgressGatewayRequest{} // remove preserved request as the egress gateway is gone
  158. node.SetLastModified()
  159. if err = UpsertNode(&node); err != nil {
  160. return models.Node{}, err
  161. }
  162. return node, nil
  163. }
  164. // CreateIngressGateway - creates an ingress gateway
  165. func CreateIngressGateway(netid string, nodeid string, ingress models.IngressRequest) (models.Node, error) {
  166. node, err := GetNodeByID(nodeid)
  167. if err != nil {
  168. return models.Node{}, err
  169. }
  170. if node.IsRelayed {
  171. return models.Node{}, errors.New("gateway cannot be created on a relayed node")
  172. }
  173. host, err := GetHost(node.HostID.String())
  174. if err != nil {
  175. return models.Node{}, err
  176. }
  177. if host.OS != "linux" {
  178. return models.Node{}, errors.New("gateway can only be created on linux based node")
  179. }
  180. network, err := GetParentNetwork(netid)
  181. if err != nil {
  182. return models.Node{}, err
  183. }
  184. node.IsIngressGateway = true
  185. node.IsGw = true
  186. node.IsInternetGateway = ingress.IsInternetGateway
  187. node.IngressGatewayRange = network.AddressRange
  188. node.IngressGatewayRange6 = network.AddressRange6
  189. node.IngressDNS = ingress.ExtclientDNS
  190. if node.IsInternetGateway && node.IngressDNS == "" {
  191. node.IngressDNS = "1.1.1.1"
  192. }
  193. node.IngressPersistentKeepalive = 20
  194. if ingress.PersistentKeepalive != 0 {
  195. node.IngressPersistentKeepalive = ingress.PersistentKeepalive
  196. }
  197. node.IngressMTU = 1420
  198. if ingress.MTU != 0 {
  199. node.IngressMTU = ingress.MTU
  200. }
  201. if servercfg.IsPro {
  202. if _, exists := FailOverExists(node.Network); exists {
  203. ResetFailedOverPeer(&node)
  204. }
  205. }
  206. node.SetLastModified()
  207. node.Metadata = ingress.Metadata
  208. if node.Metadata == "" {
  209. node.Metadata = "This host can be used for remote access"
  210. }
  211. if node.Tags == nil {
  212. node.Tags = make(map[models.TagID]struct{})
  213. }
  214. node.Tags[models.TagID(fmt.Sprintf("%s.%s", netid, models.GwTagName))] = struct{}{}
  215. err = UpsertNode(&node)
  216. if err != nil {
  217. return models.Node{}, err
  218. }
  219. err = SetNetworkNodesLastModified(netid)
  220. return node, err
  221. }
  222. // GetIngressGwUsers - lists the users having to access to ingressGW
  223. func GetIngressGwUsers(node models.Node) (models.IngressGwUsers, error) {
  224. gwUsers := models.IngressGwUsers{
  225. NodeID: node.ID.String(),
  226. Network: node.Network,
  227. }
  228. users, err := GetUsers()
  229. if err != nil {
  230. return gwUsers, err
  231. }
  232. for _, user := range users {
  233. if !user.IsAdmin && !user.IsSuperAdmin {
  234. gwUsers.Users = append(gwUsers.Users, user)
  235. }
  236. }
  237. return gwUsers, nil
  238. }
  239. // DeleteIngressGateway - deletes an ingress gateway
  240. func DeleteIngressGateway(nodeid string) (models.Node, []models.ExtClient, error) {
  241. removedClients := []models.ExtClient{}
  242. node, err := GetNodeByID(nodeid)
  243. if err != nil {
  244. return models.Node{}, removedClients, err
  245. }
  246. clients, err := GetExtClientsByID(nodeid, node.Network)
  247. if err != nil && !database.IsEmptyRecord(err) {
  248. return models.Node{}, removedClients, err
  249. }
  250. removedClients = clients
  251. // delete ext clients belonging to ingress gateway
  252. if err = DeleteGatewayExtClients(node.ID.String(), node.Network); err != nil {
  253. return models.Node{}, removedClients, err
  254. }
  255. logger.Log(3, "deleting ingress gateway")
  256. node.LastModified = time.Now().UTC()
  257. node.IsIngressGateway = false
  258. delete(node.Tags, models.TagID(fmt.Sprintf("%s.%s", node.Network, models.GwTagName)))
  259. node.IngressGatewayRange = ""
  260. node.Metadata = ""
  261. err = UpsertNode(&node)
  262. if err != nil {
  263. return models.Node{}, removedClients, err
  264. }
  265. err = SetNetworkNodesLastModified(node.Network)
  266. return node, removedClients, err
  267. }
  268. // DeleteGatewayExtClients - deletes ext clients based on gateway (mac) of ingress node and network
  269. func DeleteGatewayExtClients(gatewayID string, networkName string) error {
  270. currentExtClients, err := GetNetworkExtClients(networkName)
  271. if database.IsEmptyRecord(err) {
  272. return nil
  273. }
  274. if err != nil {
  275. return err
  276. }
  277. for _, extClient := range currentExtClients {
  278. if extClient.IngressGatewayID == gatewayID {
  279. if err = DeleteExtClient(networkName, extClient.ClientID); err != nil {
  280. logger.Log(1, "failed to remove ext client", extClient.ClientID)
  281. continue
  282. }
  283. }
  284. }
  285. return nil
  286. }
  287. // IsUserAllowedAccessToExtClient - checks if user has permission to access extclient
  288. func IsUserAllowedAccessToExtClient(username string, client models.ExtClient) bool {
  289. if username == MasterUser {
  290. return true
  291. }
  292. user, err := GetUser(username)
  293. if err != nil {
  294. return false
  295. }
  296. if user.UserName != client.OwnerID {
  297. return false
  298. }
  299. return true
  300. }
  301. func ValidateInetGwReq(inetNode models.Node, req models.InetNodeReq, update bool) error {
  302. inetHost, err := GetHost(inetNode.HostID.String())
  303. if err != nil {
  304. return err
  305. }
  306. if inetHost.FirewallInUse == models.FIREWALL_NONE {
  307. return errors.New("iptables or nftables needs to be installed")
  308. }
  309. if inetNode.InternetGwID != "" {
  310. return fmt.Errorf("node %s is using a internet gateway already", inetHost.Name)
  311. }
  312. if inetNode.IsRelayed {
  313. return fmt.Errorf("node %s is being relayed", inetHost.Name)
  314. }
  315. for _, clientNodeID := range req.InetNodeClientIDs {
  316. clientNode, err := GetNodeByID(clientNodeID)
  317. if err != nil {
  318. return err
  319. }
  320. if clientNode.IsFailOver {
  321. return errors.New("failover node cannot be set to use internet gateway")
  322. }
  323. clientHost, err := GetHost(clientNode.HostID.String())
  324. if err != nil {
  325. return err
  326. }
  327. if clientHost.IsDefault {
  328. return errors.New("default host cannot be set to use internet gateway")
  329. }
  330. if clientHost.OS != models.OS_Types.Linux && clientHost.OS != models.OS_Types.Windows {
  331. return errors.New("can only attach linux or windows machine to a internet gateway")
  332. }
  333. if clientNode.IsInternetGateway {
  334. return fmt.Errorf("node %s acting as internet gateway cannot use another internet gateway", clientHost.Name)
  335. }
  336. if update {
  337. if clientNode.InternetGwID != "" && clientNode.InternetGwID != inetNode.ID.String() {
  338. return fmt.Errorf("node %s is already using a internet gateway", clientHost.Name)
  339. }
  340. } else {
  341. if clientNode.InternetGwID != "" {
  342. return fmt.Errorf("node %s is already using a internet gateway", clientHost.Name)
  343. }
  344. }
  345. if clientNode.FailedOverBy != uuid.Nil {
  346. ResetFailedOverPeer(&clientNode)
  347. }
  348. if clientNode.IsRelayed && clientNode.RelayedBy != inetNode.ID.String() {
  349. return fmt.Errorf("node %s is being relayed", clientHost.Name)
  350. }
  351. for _, nodeID := range clientHost.Nodes {
  352. node, err := GetNodeByID(nodeID)
  353. if err != nil {
  354. continue
  355. }
  356. if node.InternetGwID != "" && node.InternetGwID != inetNode.ID.String() {
  357. return errors.New("nodes on same host cannot use different internet gateway")
  358. }
  359. }
  360. }
  361. return nil
  362. }
  363. // SetInternetGw - sets the node as internet gw based on flag bool
  364. func SetInternetGw(node *models.Node, req models.InetNodeReq) {
  365. node.IsInternetGateway = true
  366. node.InetNodeReq = req
  367. for _, clientNodeID := range req.InetNodeClientIDs {
  368. clientNode, err := GetNodeByID(clientNodeID)
  369. if err != nil {
  370. continue
  371. }
  372. clientNode.InternetGwID = node.ID.String()
  373. UpsertNode(&clientNode)
  374. }
  375. }
  376. func UnsetInternetGw(node *models.Node) {
  377. nodes, err := GetNetworkNodes(node.Network)
  378. if err != nil {
  379. slog.Error("failed to get network nodes", "network", node.Network, "error", err)
  380. return
  381. }
  382. for _, clientNode := range nodes {
  383. if node.ID.String() == clientNode.InternetGwID {
  384. clientNode.InternetGwID = ""
  385. UpsertNode(&clientNode)
  386. }
  387. }
  388. node.IsInternetGateway = false
  389. node.InetNodeReq = models.InetNodeReq{}
  390. }
  391. func SetDefaultGwForRelayedUpdate(relayed, relay models.Node, peerUpdate models.HostPeerUpdate) models.HostPeerUpdate {
  392. if relay.InternetGwID != "" {
  393. relayedHost, err := GetHost(relayed.HostID.String())
  394. if err != nil {
  395. return peerUpdate
  396. }
  397. peerUpdate.ChangeDefaultGw = true
  398. peerUpdate.DefaultGwIp = relay.Address.IP
  399. if peerUpdate.DefaultGwIp == nil || relayedHost.EndpointIP == nil {
  400. peerUpdate.DefaultGwIp = relay.Address6.IP
  401. }
  402. }
  403. return peerUpdate
  404. }
  405. func SetDefaultGw(node models.Node, peerUpdate models.HostPeerUpdate) models.HostPeerUpdate {
  406. if node.InternetGwID != "" {
  407. inetNode, err := GetNodeByID(node.InternetGwID)
  408. if err != nil {
  409. return peerUpdate
  410. }
  411. host, err := GetHost(node.HostID.String())
  412. if err != nil {
  413. return peerUpdate
  414. }
  415. peerUpdate.ChangeDefaultGw = true
  416. peerUpdate.DefaultGwIp = inetNode.Address.IP
  417. if peerUpdate.DefaultGwIp == nil || host.EndpointIP == nil {
  418. peerUpdate.DefaultGwIp = inetNode.Address6.IP
  419. }
  420. }
  421. return peerUpdate
  422. }
  423. // GetAllowedIpForInetNodeClient - get inet cidr for node using a inet gw
  424. func GetAllowedIpForInetNodeClient(node, peer *models.Node) []net.IPNet {
  425. var allowedips = []net.IPNet{}
  426. if peer.Address.IP != nil {
  427. _, ipnet, _ := net.ParseCIDR(IPv4Network)
  428. allowedips = append(allowedips, *ipnet)
  429. }
  430. if peer.Address6.IP != nil {
  431. _, ipnet, _ := net.ParseCIDR(IPv6Network)
  432. allowedips = append(allowedips, *ipnet)
  433. }
  434. return allowedips
  435. }