gateway.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. package logic
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "strings"
  6. "time"
  7. "github.com/gravitl/netmaker/database"
  8. "github.com/gravitl/netmaker/logger"
  9. "github.com/gravitl/netmaker/models"
  10. )
  11. // CreateEgressGateway - creates an egress gateway
  12. func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, error) {
  13. node, err := GetNodeByID(gateway.NodeID)
  14. if err != nil {
  15. return models.Node{}, err
  16. }
  17. if node.OS != "linux" && node.OS != "freebsd" { // add in darwin later
  18. return models.Node{}, errors.New(node.OS + " is unsupported for egress gateways")
  19. }
  20. if gateway.NatEnabled == "" {
  21. gateway.NatEnabled = "yes"
  22. }
  23. err = ValidateEgressGateway(gateway)
  24. if err != nil {
  25. return models.Node{}, err
  26. }
  27. node.IsEgressGateway = "yes"
  28. node.EgressGatewayRanges = gateway.Ranges
  29. node.EgressGatewayNatEnabled = gateway.NatEnabled
  30. postUpCmd := ""
  31. postDownCmd := ""
  32. if node.OS == "linux" {
  33. postUpCmd = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; "
  34. postUpCmd += "iptables -A FORWARD -o " + node.Interface + " -j ACCEPT"
  35. postDownCmd = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; "
  36. postDownCmd += "iptables -D FORWARD -o " + node.Interface + " -j ACCEPT"
  37. if node.EgressGatewayNatEnabled == "yes" {
  38. postUpCmd += "; iptables -t nat -A POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
  39. postDownCmd += "; iptables -t nat -D POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
  40. }
  41. }
  42. if node.OS == "freebsd" {
  43. postUpCmd = "kldload ipfw ipfw_nat ; "
  44. postUpCmd += "ipfw disable one_pass ; "
  45. postUpCmd += "ipfw nat 1 config if " + gateway.Interface + " same_ports unreg_only reset ; "
  46. postUpCmd += "ipfw add 64000 reass all from any to any in ; "
  47. postUpCmd += "ipfw add 64000 nat 1 ip from any to any in via " + gateway.Interface + " ; "
  48. postUpCmd += "ipfw add 64000 check-state ; "
  49. postUpCmd += "ipfw add 64000 nat 1 ip from any to any out via " + gateway.Interface + " ; "
  50. postUpCmd += "ipfw add 65534 allow ip from any to any ; "
  51. postDownCmd = "ipfw delete 64000 ; "
  52. postDownCmd += "ipfw delete 65534 ; "
  53. postDownCmd += "kldunload ipfw_nat ipfw"
  54. }
  55. if gateway.PostUp != "" {
  56. postUpCmd = gateway.PostUp
  57. }
  58. if gateway.PostDown != "" {
  59. postDownCmd = gateway.PostDown
  60. }
  61. if node.PostUp != "" {
  62. if !strings.Contains(node.PostUp, postUpCmd) {
  63. postUpCmd = node.PostUp + "; " + postUpCmd
  64. }
  65. }
  66. if node.PostDown != "" {
  67. if !strings.Contains(node.PostDown, postDownCmd) {
  68. postDownCmd = node.PostDown + "; " + postDownCmd
  69. }
  70. }
  71. node.PostUp = postUpCmd
  72. node.PostDown = postDownCmd
  73. node.SetLastModified()
  74. nodeData, err := json.Marshal(&node)
  75. if err != nil {
  76. return node, err
  77. }
  78. if err = database.Insert(node.ID, string(nodeData), database.NODES_TABLE_NAME); err != nil {
  79. return models.Node{}, err
  80. }
  81. if err = NetworkNodesUpdatePullChanges(node.Network); err != nil {
  82. return models.Node{}, err
  83. }
  84. return node, nil
  85. }
  86. // ValidateEgressGateway - validates the egress gateway model
  87. func ValidateEgressGateway(gateway models.EgressGatewayRequest) error {
  88. var err error
  89. empty := len(gateway.Ranges) == 0
  90. if empty {
  91. err = errors.New("IP Ranges Cannot Be Empty")
  92. }
  93. empty = gateway.Interface == ""
  94. if empty {
  95. err = errors.New("interface cannot be empty")
  96. }
  97. return err
  98. }
  99. // DeleteEgressGateway - deletes egress from node
  100. func DeleteEgressGateway(network, nodeid string) (models.Node, error) {
  101. node, err := GetNodeByID(nodeid)
  102. if err != nil {
  103. return models.Node{}, err
  104. }
  105. node.IsEgressGateway = "no"
  106. node.EgressGatewayRanges = []string{}
  107. node.PostUp = ""
  108. node.PostDown = ""
  109. if node.IsIngressGateway == "yes" { // check if node is still an ingress gateway before completely deleting postdown/up rules
  110. if node.OS == "linux" {
  111. node.PostUp = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT ; "
  112. node.PostUp += "iptables -A FORWARD -o " + node.Interface + " -j ACCEPT ; "
  113. node.PostUp += "iptables -t nat -A POSTROUTING -o " + node.Interface + " -j MASQUERADE"
  114. node.PostDown = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT ; "
  115. node.PostDown += "iptables -D FORWARD -o " + node.Interface + " -j ACCEPT ; "
  116. node.PostDown += "iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE"
  117. }
  118. if node.OS == "freebsd" {
  119. node.PostUp = ""
  120. node.PostDown = "ipfw delete 64000 ; "
  121. node.PostDown += "ipfw delete 65534 ; "
  122. node.PostDown += "kldunload ipfw_nat ipfw"
  123. }
  124. }
  125. node.SetLastModified()
  126. data, err := json.Marshal(&node)
  127. if err != nil {
  128. return models.Node{}, err
  129. }
  130. if err = database.Insert(node.ID, string(data), database.NODES_TABLE_NAME); err != nil {
  131. return models.Node{}, err
  132. }
  133. if err = NetworkNodesUpdatePullChanges(network); err != nil {
  134. return models.Node{}, err
  135. }
  136. return node, nil
  137. }
  138. // CreateIngressGateway - creates an ingress gateway
  139. func CreateIngressGateway(netid string, nodeid string) (models.Node, error) {
  140. node, err := GetNodeByID(nodeid)
  141. if node.OS != "linux" { // add in darwin later
  142. return models.Node{}, errors.New(node.OS + " is unsupported for ingress gateways")
  143. }
  144. if err != nil {
  145. return models.Node{}, err
  146. }
  147. network, err := GetParentNetwork(netid)
  148. if err != nil {
  149. return models.Node{}, err
  150. }
  151. node.IsIngressGateway = "yes"
  152. node.IngressGatewayRange = network.AddressRange
  153. postUpCmd := "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT ; "
  154. postUpCmd += "iptables -A FORWARD -o " + node.Interface + " -j ACCEPT ; "
  155. postUpCmd += "iptables -t nat -A POSTROUTING -o " + node.Interface + " -j MASQUERADE"
  156. postDownCmd := "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT ; "
  157. postDownCmd += "iptables -D FORWARD -o " + node.Interface + " -j ACCEPT ; "
  158. postDownCmd += "iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE"
  159. if node.PostUp != "" {
  160. if !strings.Contains(node.PostUp, postUpCmd) {
  161. postUpCmd = node.PostUp + "; " + postUpCmd
  162. }
  163. }
  164. if node.PostDown != "" {
  165. if !strings.Contains(node.PostDown, postDownCmd) {
  166. postDownCmd = node.PostDown + "; " + postDownCmd
  167. }
  168. }
  169. node.SetLastModified()
  170. node.PostUp = postUpCmd
  171. node.PostDown = postDownCmd
  172. node.UDPHolePunch = "no"
  173. data, err := json.Marshal(&node)
  174. if err != nil {
  175. return models.Node{}, err
  176. }
  177. err = database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
  178. if err != nil {
  179. return models.Node{}, err
  180. }
  181. err = SetNetworkNodesLastModified(netid)
  182. return node, err
  183. }
  184. // DeleteIngressGateway - deletes an ingress gateway
  185. func DeleteIngressGateway(networkName string, nodeid string) (models.Node, error) {
  186. node, err := GetNodeByID(nodeid)
  187. if err != nil {
  188. return models.Node{}, err
  189. }
  190. network, err := GetParentNetwork(networkName)
  191. if err != nil {
  192. return models.Node{}, err
  193. }
  194. // delete ext clients belonging to ingress gateway
  195. if err = DeleteGatewayExtClients(node.ID, networkName); err != nil {
  196. return models.Node{}, err
  197. }
  198. node.UDPHolePunch = network.DefaultUDPHolePunch
  199. node.LastModified = time.Now().Unix()
  200. node.IsIngressGateway = "no"
  201. node.IngressGatewayRange = ""
  202. data, err := json.Marshal(&node)
  203. if err != nil {
  204. return models.Node{}, err
  205. }
  206. err = database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
  207. if err != nil {
  208. return models.Node{}, err
  209. }
  210. err = SetNetworkNodesLastModified(networkName)
  211. return node, err
  212. }
  213. // DeleteGatewayExtClients - deletes ext clients based on gateway (mac) of ingress node and network
  214. func DeleteGatewayExtClients(gatewayID string, networkName string) error {
  215. currentExtClients, err := GetNetworkExtClients(networkName)
  216. if err != nil && !database.IsEmptyRecord(err) {
  217. return err
  218. }
  219. for _, extClient := range currentExtClients {
  220. if extClient.IngressGatewayID == gatewayID {
  221. if err = DeleteExtClient(networkName, extClient.ClientID); err != nil {
  222. logger.Log(1, "failed to remove ext client", extClient.ClientID)
  223. continue
  224. }
  225. }
  226. }
  227. return nil
  228. }