egress.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. package logic
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "maps"
  7. "strings"
  8. "github.com/gravitl/netmaker/db"
  9. "github.com/gravitl/netmaker/models"
  10. "github.com/gravitl/netmaker/schema"
  11. "github.com/gravitl/netmaker/servercfg"
  12. )
  13. var ValidateEgressReq = validateEgressReq
  14. func validateEgressReq(e *schema.Egress) error {
  15. if e.Network == "" {
  16. return errors.New("network id is empty")
  17. }
  18. _, err := GetNetwork(e.Network)
  19. if err != nil {
  20. return errors.New("failed to get network " + err.Error())
  21. }
  22. if !servercfg.IsPro && len(e.Nodes) > 1 {
  23. return errors.New("can only set one routing node on CE")
  24. }
  25. if len(e.Nodes) > 0 {
  26. for k := range e.Nodes {
  27. _, err := GetNodeByID(k)
  28. if err != nil {
  29. return errors.New("invalid routing node " + err.Error())
  30. }
  31. }
  32. }
  33. return nil
  34. }
  35. func DoesUserHaveAccessToEgress(user *models.User, e *schema.Egress, acls []models.Acl) bool {
  36. if !e.Status {
  37. return false
  38. }
  39. for _, acl := range acls {
  40. if !acl.Enabled {
  41. continue
  42. }
  43. dstTags := ConvAclTagToValueMap(acl.Dst)
  44. _, all := dstTags["*"]
  45. if _, ok := dstTags[e.ID]; ok || all {
  46. // get all src tags
  47. for _, srcAcl := range acl.Src {
  48. if srcAcl.ID == models.UserAclID && srcAcl.Value == user.UserName {
  49. return true
  50. } else if srcAcl.ID == models.UserGroupAclID {
  51. // fetch all users in the group
  52. if _, ok := user.UserGroups[models.UserGroupID(srcAcl.Value)]; ok {
  53. return true
  54. }
  55. }
  56. }
  57. }
  58. }
  59. return false
  60. }
  61. func DoesNodeHaveAccessToEgress(node *models.Node, e *schema.Egress, acls []models.Acl) bool {
  62. nodeTags := maps.Clone(node.Tags)
  63. nodeTags[models.TagID(node.ID.String())] = struct{}{}
  64. nodeTags[models.TagID("*")] = struct{}{}
  65. for _, acl := range acls {
  66. if !acl.Enabled {
  67. continue
  68. }
  69. srcVal := ConvAclTagToValueMap(acl.Src)
  70. for _, dstI := range acl.Dst {
  71. if (dstI.ID == models.EgressID && dstI.Value == e.ID) || (dstI.ID == models.NodeTagID && dstI.Value == "*") {
  72. if dstI.ID == models.EgressID {
  73. e := schema.Egress{ID: dstI.Value}
  74. err := e.Get(db.WithContext(context.TODO()))
  75. if err != nil {
  76. continue
  77. }
  78. }
  79. if node.IsStatic {
  80. if _, ok := srcVal[node.StaticNode.ClientID]; ok {
  81. return true
  82. }
  83. } else {
  84. if _, ok := srcVal[node.ID.String()]; ok {
  85. return true
  86. }
  87. }
  88. for tagID := range nodeTags {
  89. if _, ok := srcVal[tagID.String()]; ok {
  90. return true
  91. }
  92. }
  93. }
  94. }
  95. }
  96. return false
  97. }
  98. func AddEgressInfoToPeerByAccess(node, targetNode *models.Node, eli []schema.Egress, acls []models.Acl, isDefaultPolicyActive bool) {
  99. req := models.EgressGatewayRequest{
  100. NodeID: targetNode.ID.String(),
  101. NetID: targetNode.Network,
  102. NatEnabled: "yes",
  103. }
  104. for _, e := range eli {
  105. if !e.Status || e.Network != targetNode.Network {
  106. continue
  107. }
  108. if !isDefaultPolicyActive {
  109. if !DoesNodeHaveAccessToEgress(node, &e, acls) {
  110. if node.IsRelayed && node.RelayedBy == targetNode.ID.String() {
  111. if !DoesNodeHaveAccessToEgress(targetNode, &e, acls) {
  112. continue
  113. }
  114. } else {
  115. continue
  116. }
  117. }
  118. }
  119. if metric, ok := e.Nodes[targetNode.ID.String()]; ok {
  120. m64, err := metric.(json.Number).Int64()
  121. if err != nil {
  122. m64 = 256
  123. }
  124. m := uint32(m64)
  125. if e.Range != "" {
  126. req.Ranges = append(req.Ranges, e.Range)
  127. } else {
  128. req.Ranges = append(req.Ranges, e.DomainAns...)
  129. }
  130. if e.Range != "" {
  131. req.Ranges = append(req.Ranges, e.Range)
  132. req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
  133. Network: e.Range,
  134. Nat: e.Nat,
  135. RouteMetric: m,
  136. })
  137. }
  138. if e.Domain != "" && len(e.DomainAns) > 0 {
  139. req.Ranges = append(req.Ranges, e.DomainAns...)
  140. for _, domainAnsI := range e.DomainAns {
  141. req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
  142. Network: domainAnsI,
  143. Nat: e.Nat,
  144. RouteMetric: m,
  145. })
  146. }
  147. }
  148. }
  149. for tagID := range targetNode.Tags {
  150. if metric, ok := e.Tags[tagID.String()]; ok {
  151. m64, err := metric.(json.Number).Int64()
  152. if err != nil {
  153. m64 = 256
  154. }
  155. m := uint32(m64)
  156. if e.Range != "" {
  157. req.Ranges = append(req.Ranges, e.Range)
  158. } else {
  159. req.Ranges = append(req.Ranges, e.DomainAns...)
  160. }
  161. if e.Range != "" {
  162. req.Ranges = append(req.Ranges, e.Range)
  163. req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
  164. Network: e.Range,
  165. Nat: e.Nat,
  166. RouteMetric: m,
  167. })
  168. }
  169. if e.Domain != "" && len(e.DomainAns) > 0 {
  170. req.Ranges = append(req.Ranges, e.DomainAns...)
  171. for _, domainAnsI := range e.DomainAns {
  172. req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
  173. Network: domainAnsI,
  174. Nat: e.Nat,
  175. RouteMetric: m,
  176. })
  177. }
  178. }
  179. break
  180. }
  181. }
  182. }
  183. if targetNode.Mutex != nil {
  184. targetNode.Mutex.Lock()
  185. }
  186. if len(req.Ranges) > 0 {
  187. targetNode.EgressDetails.IsEgressGateway = true
  188. targetNode.EgressDetails.EgressGatewayRanges = req.Ranges
  189. targetNode.EgressDetails.EgressGatewayRequest = req
  190. } else {
  191. targetNode.EgressDetails = models.EgressDetails{}
  192. }
  193. if targetNode.Mutex != nil {
  194. targetNode.Mutex.Unlock()
  195. }
  196. }
  197. func GetEgressDomainsByAccess(user *models.User, network models.NetworkID) (domains []string) {
  198. acls, _ := ListAclsByNetwork(network)
  199. eli, _ := (&schema.Egress{Network: network.String()}).ListByNetwork(db.WithContext(context.TODO()))
  200. defaultDevicePolicy, _ := GetDefaultPolicy(network, models.UserPolicy)
  201. isDefaultPolicyActive := defaultDevicePolicy.Enabled
  202. for _, e := range eli {
  203. if !e.Status || e.Network != network.String() {
  204. continue
  205. }
  206. if !isDefaultPolicyActive {
  207. if !DoesUserHaveAccessToEgress(user, &e, acls) {
  208. continue
  209. }
  210. }
  211. if e.Domain != "" && len(e.DomainAns) > 0 {
  212. domains = append(domains, BaseDomain(e.Domain))
  213. }
  214. }
  215. return
  216. }
  217. func GetNodeEgressInfo(targetNode *models.Node, eli []schema.Egress, acls []models.Acl) {
  218. req := models.EgressGatewayRequest{
  219. NodeID: targetNode.ID.String(),
  220. NetID: targetNode.Network,
  221. NatEnabled: "yes",
  222. }
  223. for _, e := range eli {
  224. if !e.Status || e.Network != targetNode.Network {
  225. continue
  226. }
  227. if metric, ok := e.Nodes[targetNode.ID.String()]; ok {
  228. m64, err := metric.(json.Number).Int64()
  229. if err != nil {
  230. m64 = 256
  231. }
  232. m := uint32(m64)
  233. if e.Range != "" {
  234. req.Ranges = append(req.Ranges, e.Range)
  235. req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
  236. Network: e.Range,
  237. Nat: e.Nat,
  238. RouteMetric: m,
  239. })
  240. }
  241. if e.Domain != "" && len(e.DomainAns) > 0 {
  242. req.Ranges = append(req.Ranges, e.DomainAns...)
  243. for _, domainAnsI := range e.DomainAns {
  244. req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
  245. Network: domainAnsI,
  246. Nat: e.Nat,
  247. RouteMetric: m,
  248. })
  249. }
  250. }
  251. }
  252. for tagID := range targetNode.Tags {
  253. if metric, ok := e.Tags[tagID.String()]; ok {
  254. m64, err := metric.(json.Number).Int64()
  255. if err != nil {
  256. m64 = 256
  257. }
  258. m := uint32(m64)
  259. if e.Range != "" {
  260. req.Ranges = append(req.Ranges, e.Range)
  261. } else {
  262. req.Ranges = append(req.Ranges, e.DomainAns...)
  263. }
  264. if e.Range != "" {
  265. req.Ranges = append(req.Ranges, e.Range)
  266. req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
  267. Network: e.Range,
  268. Nat: e.Nat,
  269. RouteMetric: m,
  270. })
  271. }
  272. if e.Domain != "" && len(e.DomainAns) > 0 {
  273. req.Ranges = append(req.Ranges, e.DomainAns...)
  274. for _, domainAnsI := range e.DomainAns {
  275. req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
  276. Network: domainAnsI,
  277. Nat: e.Nat,
  278. RouteMetric: m,
  279. })
  280. }
  281. }
  282. break
  283. }
  284. }
  285. }
  286. if targetNode.Mutex != nil {
  287. targetNode.Mutex.Lock()
  288. }
  289. if len(req.Ranges) > 0 {
  290. targetNode.EgressDetails.IsEgressGateway = true
  291. targetNode.EgressDetails.EgressGatewayRanges = req.Ranges
  292. targetNode.EgressDetails.EgressGatewayRequest = req
  293. } else {
  294. targetNode.EgressDetails = models.EgressDetails{}
  295. }
  296. if targetNode.Mutex != nil {
  297. targetNode.Mutex.Unlock()
  298. }
  299. }
  300. func RemoveNodeFromEgress(node models.Node) {
  301. egs, _ := (&schema.Egress{
  302. Network: node.Network,
  303. }).ListByNetwork(db.WithContext(context.TODO()))
  304. for _, egI := range egs {
  305. if _, ok := egI.Nodes[node.ID.String()]; ok {
  306. delete(egI.Nodes, node.ID.String())
  307. egI.Update(db.WithContext(context.TODO()))
  308. }
  309. }
  310. }
  311. func GetEgressRanges(netID models.NetworkID) (map[string][]string, map[string]struct{}, error) {
  312. resultMap := make(map[string]struct{})
  313. nodeEgressMap := make(map[string][]string)
  314. networkNodes, err := GetNetworkNodes(netID.String())
  315. if err != nil {
  316. return nil, nil, err
  317. }
  318. for _, currentNode := range networkNodes {
  319. if currentNode.Network != netID.String() {
  320. continue
  321. }
  322. if currentNode.EgressDetails.IsEgressGateway { // add the egress gateway range(s) to the result
  323. if len(currentNode.EgressDetails.EgressGatewayRanges) > 0 {
  324. nodeEgressMap[currentNode.ID.String()] = currentNode.EgressDetails.EgressGatewayRanges
  325. for _, egressRangeI := range currentNode.EgressDetails.EgressGatewayRanges {
  326. resultMap[egressRangeI] = struct{}{}
  327. }
  328. }
  329. }
  330. }
  331. extclients, _ := GetNetworkExtClients(netID.String())
  332. for _, extclient := range extclients {
  333. if len(extclient.ExtraAllowedIPs) > 0 {
  334. nodeEgressMap[extclient.ClientID] = extclient.ExtraAllowedIPs
  335. for _, extraAllowedIP := range extclient.ExtraAllowedIPs {
  336. resultMap[extraAllowedIP] = struct{}{}
  337. }
  338. }
  339. }
  340. return nodeEgressMap, resultMap, nil
  341. }
  342. func ListAllByRoutingNodeWithDomain(egs []schema.Egress, nodeID string) (egWithDomain []models.EgressDomain) {
  343. node, err := GetNodeByID(nodeID)
  344. if err != nil {
  345. return
  346. }
  347. host, err := GetHost(node.HostID.String())
  348. if err != nil {
  349. return
  350. }
  351. for _, egI := range egs {
  352. if !egI.Status || egI.Domain == "" {
  353. continue
  354. }
  355. if _, ok := egI.Nodes[nodeID]; ok {
  356. egWithDomain = append(egWithDomain, models.EgressDomain{
  357. ID: egI.ID,
  358. Domain: egI.Domain,
  359. Node: node,
  360. Host: *host,
  361. })
  362. }
  363. }
  364. return
  365. }
  366. func BaseDomain(host string) string {
  367. parts := strings.Split(host, ".")
  368. if len(parts) < 2 {
  369. return host // not a FQDN
  370. }
  371. return strings.Join(parts[len(parts)-2:], ".")
  372. }