nodeHttpController.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. package controller
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "net/http"
  6. "strings"
  7. "time"
  8. "github.com/gorilla/mux"
  9. "github.com/gravitl/netmaker/database"
  10. "github.com/gravitl/netmaker/functions"
  11. "github.com/gravitl/netmaker/logic"
  12. "github.com/gravitl/netmaker/models"
  13. "github.com/gravitl/netmaker/servercfg"
  14. "golang.org/x/crypto/bcrypt"
  15. )
  16. func nodeHandlers(r *mux.Router) {
  17. r.HandleFunc("/api/nodes", authorize(false, "user", http.HandlerFunc(getAllNodes))).Methods("GET")
  18. r.HandleFunc("/api/nodes/{network}", authorize(true, "network", http.HandlerFunc(getNetworkNodes))).Methods("GET")
  19. r.HandleFunc("/api/nodes/{network}/{macaddress}", authorize(true, "node", http.HandlerFunc(getNode))).Methods("GET")
  20. r.HandleFunc("/api/nodes/{network}/{macaddress}", authorize(true, "node", http.HandlerFunc(updateNode))).Methods("PUT")
  21. r.HandleFunc("/api/nodes/{network}/{macaddress}", authorize(true, "node", http.HandlerFunc(deleteNode))).Methods("DELETE")
  22. r.HandleFunc("/api/nodes/{network}/{macaddress}/createrelay", authorize(true, "user", http.HandlerFunc(createRelay))).Methods("POST")
  23. r.HandleFunc("/api/nodes/{network}/{macaddress}/deleterelay", authorize(true, "user", http.HandlerFunc(deleteRelay))).Methods("DELETE")
  24. r.HandleFunc("/api/nodes/{network}/{macaddress}/creategateway", authorize(true, "user", http.HandlerFunc(createEgressGateway))).Methods("POST")
  25. r.HandleFunc("/api/nodes/{network}/{macaddress}/deletegateway", authorize(true, "user", http.HandlerFunc(deleteEgressGateway))).Methods("DELETE")
  26. r.HandleFunc("/api/nodes/{network}/{macaddress}/createingress", securityCheck(false, http.HandlerFunc(createIngressGateway))).Methods("POST")
  27. r.HandleFunc("/api/nodes/{network}/{macaddress}/deleteingress", securityCheck(false, http.HandlerFunc(deleteIngressGateway))).Methods("DELETE")
  28. r.HandleFunc("/api/nodes/{network}/{macaddress}/approve", authorize(true, "user", http.HandlerFunc(uncordonNode))).Methods("POST")
  29. r.HandleFunc("/api/nodes/{network}", createNode).Methods("POST")
  30. r.HandleFunc("/api/nodes/adm/{network}/lastmodified", authorize(true, "network", http.HandlerFunc(getLastModified))).Methods("GET")
  31. r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods("POST")
  32. }
  33. //Node authenticates using its password and retrieves a JWT for authorization.
  34. func authenticate(response http.ResponseWriter, request *http.Request) {
  35. var params = mux.Vars(request)
  36. networkname := params["network"]
  37. //Auth request consists of Mac Address and Password (from node that is authorizing
  38. //in case of Master, auth is ignored and mac is set to "mastermac"
  39. var authRequest models.AuthParams
  40. var result models.Node
  41. var errorResponse = models.ErrorResponse{
  42. Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
  43. }
  44. //Get password fnd mac rom request
  45. decoder := json.NewDecoder(request.Body)
  46. decoderErr := decoder.Decode(&authRequest)
  47. defer request.Body.Close()
  48. if decoderErr != nil {
  49. errorResponse.Code = http.StatusBadRequest
  50. errorResponse.Message = decoderErr.Error()
  51. returnErrorResponse(response, request, errorResponse)
  52. return
  53. } else {
  54. errorResponse.Code = http.StatusBadRequest
  55. if authRequest.MacAddress == "" {
  56. errorResponse.Message = "W1R3: MacAddress can't be empty"
  57. returnErrorResponse(response, request, errorResponse)
  58. return
  59. } else if authRequest.Password == "" {
  60. errorResponse.Message = "W1R3: Password can't be empty"
  61. returnErrorResponse(response, request, errorResponse)
  62. return
  63. } else {
  64. //Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API until approved).
  65. collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
  66. if err != nil {
  67. errorResponse.Code = http.StatusBadRequest
  68. errorResponse.Message = err.Error()
  69. returnErrorResponse(response, request, errorResponse)
  70. return
  71. }
  72. for _, value := range collection {
  73. if err := json.Unmarshal([]byte(value), &result); err != nil {
  74. continue
  75. }
  76. if result.MacAddress == authRequest.MacAddress && result.IsPending != "yes" && result.Network == networkname {
  77. break
  78. }
  79. }
  80. if err != nil {
  81. errorResponse.Code = http.StatusBadRequest
  82. errorResponse.Message = err.Error()
  83. returnErrorResponse(response, request, errorResponse)
  84. return
  85. }
  86. //compare password from request to stored password in database
  87. //might be able to have a common hash (certificates?) and compare those so that a password isn't passed in in plain text...
  88. //TODO: Consider a way of hashing the password client side before sending, or using certificates
  89. err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(authRequest.Password))
  90. if err != nil {
  91. errorResponse.Code = http.StatusBadRequest
  92. errorResponse.Message = err.Error()
  93. returnErrorResponse(response, request, errorResponse)
  94. return
  95. } else {
  96. //Create a new JWT for the node
  97. tokenString, _ := logic.CreateJWT(authRequest.MacAddress, result.Network)
  98. if tokenString == "" {
  99. errorResponse.Code = http.StatusBadRequest
  100. errorResponse.Message = "Could not create Token"
  101. returnErrorResponse(response, request, errorResponse)
  102. return
  103. }
  104. var successResponse = models.SuccessResponse{
  105. Code: http.StatusOK,
  106. Message: "W1R3: Device " + authRequest.MacAddress + " Authorized",
  107. Response: models.SuccessfulLoginResponse{
  108. AuthToken: tokenString,
  109. MacAddress: authRequest.MacAddress,
  110. },
  111. }
  112. //Send back the JWT
  113. successJSONResponse, jsonError := json.Marshal(successResponse)
  114. if jsonError != nil {
  115. errorResponse.Code = http.StatusBadRequest
  116. errorResponse.Message = err.Error()
  117. returnErrorResponse(response, request, errorResponse)
  118. return
  119. }
  120. response.WriteHeader(http.StatusOK)
  121. response.Header().Set("Content-Type", "application/json")
  122. response.Write(successJSONResponse)
  123. }
  124. }
  125. }
  126. }
  127. //The middleware for most requests to the API
  128. //They all pass through here first
  129. //This will validate the JWT (or check for master token)
  130. //This will also check against the authNetwork and make sure the node should be accessing that endpoint,
  131. //even if it's technically ok
  132. //This is kind of a poor man's RBAC. There's probably a better/smarter way.
  133. //TODO: Consider better RBAC implementations
  134. func authorize(networkCheck bool, authNetwork string, next http.Handler) http.HandlerFunc {
  135. return func(w http.ResponseWriter, r *http.Request) {
  136. var errorResponse = models.ErrorResponse{
  137. Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
  138. }
  139. var params = mux.Vars(r)
  140. networkexists, _ := functions.NetworkExists(params["network"])
  141. //check that the request is for a valid network
  142. //if (networkCheck && !networkexists) || err != nil {
  143. if networkCheck && !networkexists {
  144. errorResponse = models.ErrorResponse{
  145. Code: http.StatusNotFound, Message: "W1R3: This network does not exist. ",
  146. }
  147. returnErrorResponse(w, r, errorResponse)
  148. return
  149. } else {
  150. w.Header().Set("Content-Type", "application/json")
  151. //get the auth token
  152. bearerToken := r.Header.Get("Authorization")
  153. var tokenSplit = strings.Split(bearerToken, " ")
  154. //I put this in in case the user doesn't put in a token at all (in which case it's empty)
  155. //There's probably a smarter way of handling this.
  156. var authToken = "928rt238tghgwe@TY@$Y@#WQAEGB2FC#@HG#@$Hddd"
  157. if len(tokenSplit) > 1 {
  158. authToken = tokenSplit[1]
  159. } else {
  160. errorResponse = models.ErrorResponse{
  161. Code: http.StatusUnauthorized, Message: "W1R3: Missing Auth Token.",
  162. }
  163. returnErrorResponse(w, r, errorResponse)
  164. return
  165. }
  166. //This checks if
  167. //A: the token is the master password
  168. //B: the token corresponds to a mac address, and if so, which one
  169. //TODO: There's probably a better way of dealing with the "master token"/master password. Plz Help.
  170. var isAuthorized = false
  171. var macaddress = ""
  172. username, networks, isadmin, errN := logic.VerifyUserToken(authToken)
  173. isnetadmin := isadmin
  174. if errN == nil && isadmin {
  175. macaddress = "mastermac"
  176. isAuthorized = true
  177. r.Header.Set("ismasterkey", "yes")
  178. }
  179. if !isadmin && params["network"] != "" {
  180. if functions.SliceContains(networks, params["network"]) {
  181. isnetadmin = true
  182. }
  183. }
  184. //The mastermac (login with masterkey from config) can do everything!! May be dangerous.
  185. if macaddress == "mastermac" {
  186. isAuthorized = true
  187. r.Header.Set("ismasterkey", "yes")
  188. //for everyone else, there's poor man's RBAC. The "cases" are defined in the routes in the handlers
  189. //So each route defines which access network should be allowed to access it
  190. } else {
  191. switch authNetwork {
  192. case "all":
  193. isAuthorized = true
  194. case "nodes":
  195. isAuthorized = (macaddress != "") || isnetadmin
  196. case "network":
  197. if isnetadmin {
  198. isAuthorized = true
  199. } else {
  200. node, err := logic.GetNodeByMacAddress(params["network"], macaddress)
  201. if err != nil {
  202. errorResponse = models.ErrorResponse{
  203. Code: http.StatusUnauthorized, Message: "W1R3: Missing Auth Token.",
  204. }
  205. returnErrorResponse(w, r, errorResponse)
  206. return
  207. }
  208. isAuthorized = (node.Network == params["network"])
  209. }
  210. case "node":
  211. if isnetadmin {
  212. isAuthorized = true
  213. } else {
  214. isAuthorized = (macaddress == params["macaddress"])
  215. }
  216. case "user":
  217. isAuthorized = true
  218. default:
  219. isAuthorized = false
  220. }
  221. }
  222. if !isAuthorized {
  223. errorResponse = models.ErrorResponse{
  224. Code: http.StatusUnauthorized, Message: "W1R3: You are unauthorized to access this endpoint.",
  225. }
  226. returnErrorResponse(w, r, errorResponse)
  227. return
  228. } else {
  229. //If authorized, this function passes along it's request and output to the appropriate route function.
  230. if username == "" {
  231. username = "(user not found)"
  232. }
  233. r.Header.Set("user", username)
  234. next.ServeHTTP(w, r)
  235. }
  236. }
  237. }
  238. }
  239. //Gets all nodes associated with network, including pending nodes
  240. func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
  241. w.Header().Set("Content-Type", "application/json")
  242. var nodes []models.Node
  243. var params = mux.Vars(r)
  244. networkName := params["network"]
  245. nodes, err := logic.GetNetworkNodes(networkName)
  246. if err != nil {
  247. returnErrorResponse(w, r, formatError(err, "internal"))
  248. return
  249. }
  250. //Returns all the nodes in JSON format
  251. functions.PrintUserLog(r.Header.Get("user"), "fetched nodes on network"+networkName, 2)
  252. w.WriteHeader(http.StatusOK)
  253. json.NewEncoder(w).Encode(nodes)
  254. }
  255. //A separate function to get all nodes, not just nodes for a particular network.
  256. //Not quite sure if this is necessary. Probably necessary based on front end but may want to review after iteration 1 if it's being used or not
  257. func getAllNodes(w http.ResponseWriter, r *http.Request) {
  258. w.Header().Set("Content-Type", "application/json")
  259. user, err := logic.GetUser(r.Header.Get("user"))
  260. if err != nil && r.Header.Get("ismasterkey") != "yes" {
  261. returnErrorResponse(w, r, formatError(err, "internal"))
  262. return
  263. }
  264. var nodes []models.Node
  265. if user.IsAdmin || r.Header.Get("ismasterkey") == "yes" {
  266. nodes, err = logic.GetAllNodes()
  267. if err != nil {
  268. returnErrorResponse(w, r, formatError(err, "internal"))
  269. return
  270. }
  271. } else {
  272. nodes, err = getUsersNodes(user)
  273. if err != nil {
  274. returnErrorResponse(w, r, formatError(err, "internal"))
  275. return
  276. }
  277. }
  278. //Return all the nodes in JSON format
  279. functions.PrintUserLog(r.Header.Get("user"), "fetched nodes", 2)
  280. w.WriteHeader(http.StatusOK)
  281. json.NewEncoder(w).Encode(nodes)
  282. }
  283. func getUsersNodes(user models.User) ([]models.Node, error) {
  284. var nodes []models.Node
  285. var err error
  286. for _, networkName := range user.Networks {
  287. tmpNodes, err := logic.GetNetworkNodes(networkName)
  288. if err != nil {
  289. continue
  290. }
  291. nodes = append(nodes, tmpNodes...)
  292. }
  293. return nodes, err
  294. }
  295. //Get an individual node. Nothin fancy here folks.
  296. func getNode(w http.ResponseWriter, r *http.Request) {
  297. // set header.
  298. w.Header().Set("Content-Type", "application/json")
  299. var params = mux.Vars(r)
  300. node, err := GetNode(params["macaddress"], params["network"])
  301. if err != nil {
  302. returnErrorResponse(w, r, formatError(err, "internal"))
  303. return
  304. }
  305. functions.PrintUserLog(r.Header.Get("user"), "fetched node "+params["macaddress"], 2)
  306. w.WriteHeader(http.StatusOK)
  307. json.NewEncoder(w).Encode(node)
  308. }
  309. //Get the time that a network of nodes was last modified.
  310. //TODO: This needs to be refactored
  311. //Potential way to do this: On UpdateNode, set a new field for "LastModified"
  312. //If we go with the existing way, we need to at least set network.NodesLastModified on UpdateNode
  313. func getLastModified(w http.ResponseWriter, r *http.Request) {
  314. // set header.
  315. w.Header().Set("Content-Type", "application/json")
  316. var params = mux.Vars(r)
  317. network, err := GetNetwork(params["network"])
  318. if err != nil {
  319. returnErrorResponse(w, r, formatError(err, "internal"))
  320. return
  321. }
  322. functions.PrintUserLog(r.Header.Get("user"), "called last modified", 2)
  323. w.WriteHeader(http.StatusOK)
  324. json.NewEncoder(w).Encode(network.NodesLastModified)
  325. }
  326. func createNode(w http.ResponseWriter, r *http.Request) {
  327. w.Header().Set("Content-Type", "application/json")
  328. var params = mux.Vars(r)
  329. var errorResponse = models.ErrorResponse{
  330. Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
  331. }
  332. networkName := params["network"]
  333. networkexists, err := functions.NetworkExists(networkName)
  334. if err != nil {
  335. returnErrorResponse(w, r, formatError(err, "internal"))
  336. return
  337. } else if !networkexists {
  338. errorResponse = models.ErrorResponse{
  339. Code: http.StatusNotFound, Message: "W1R3: Network does not exist! ",
  340. }
  341. returnErrorResponse(w, r, errorResponse)
  342. return
  343. }
  344. var node models.Node
  345. //get node from body of request
  346. err = json.NewDecoder(r.Body).Decode(&node)
  347. if err != nil {
  348. returnErrorResponse(w, r, formatError(err, "internal"))
  349. return
  350. }
  351. node.Network = networkName
  352. network, err := logic.GetNetworkByNode(&node)
  353. if err != nil {
  354. returnErrorResponse(w, r, formatError(err, "internal"))
  355. return
  356. }
  357. //Check to see if key is valid
  358. //TODO: Triple inefficient!!! This is the third call to the DB we make for networks
  359. validKey := logic.IsKeyValid(networkName, node.AccessKey)
  360. if !validKey {
  361. //Check to see if network will allow manual sign up
  362. //may want to switch this up with the valid key check and avoid a DB call that way.
  363. if network.AllowManualSignUp == "yes" {
  364. node.IsPending = "yes"
  365. } else {
  366. errorResponse = models.ErrorResponse{
  367. Code: http.StatusUnauthorized, Message: "W1R3: Key invalid, or none provided.",
  368. }
  369. returnErrorResponse(w, r, errorResponse)
  370. return
  371. }
  372. }
  373. node, err = logic.CreateNode(node, networkName)
  374. if err != nil {
  375. returnErrorResponse(w, r, formatError(err, "internal"))
  376. return
  377. }
  378. functions.PrintUserLog(r.Header.Get("user"), "created new node "+node.Name+" on network "+node.Network, 1)
  379. w.WriteHeader(http.StatusOK)
  380. json.NewEncoder(w).Encode(node)
  381. }
  382. //Takes node out of pending state
  383. //TODO: May want to use cordon/uncordon terminology instead of "ispending".
  384. func uncordonNode(w http.ResponseWriter, r *http.Request) {
  385. var params = mux.Vars(r)
  386. w.Header().Set("Content-Type", "application/json")
  387. node, err := UncordonNode(params["network"], params["macaddress"])
  388. if err != nil {
  389. returnErrorResponse(w, r, formatError(err, "internal"))
  390. return
  391. }
  392. functions.PrintUserLog(r.Header.Get("user"), "uncordoned node "+node.Name, 1)
  393. w.WriteHeader(http.StatusOK)
  394. json.NewEncoder(w).Encode("SUCCESS")
  395. }
  396. // UncordonNode - approves a node to join a network
  397. func UncordonNode(network, macaddress string) (models.Node, error) {
  398. node, err := logic.GetNodeByMacAddress(network, macaddress)
  399. if err != nil {
  400. return models.Node{}, err
  401. }
  402. node.SetLastModified()
  403. node.IsPending = "no"
  404. node.PullChanges = "yes"
  405. data, err := json.Marshal(&node)
  406. if err != nil {
  407. return node, err
  408. }
  409. key, err := logic.GetRecordKey(node.MacAddress, node.Network)
  410. if err != nil {
  411. return node, err
  412. }
  413. err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
  414. return node, err
  415. }
  416. func createEgressGateway(w http.ResponseWriter, r *http.Request) {
  417. var gateway models.EgressGatewayRequest
  418. var params = mux.Vars(r)
  419. w.Header().Set("Content-Type", "application/json")
  420. err := json.NewDecoder(r.Body).Decode(&gateway)
  421. if err != nil {
  422. returnErrorResponse(w, r, formatError(err, "internal"))
  423. return
  424. }
  425. gateway.NetID = params["network"]
  426. gateway.NodeID = params["macaddress"]
  427. node, err := CreateEgressGateway(gateway)
  428. if err != nil {
  429. returnErrorResponse(w, r, formatError(err, "internal"))
  430. return
  431. }
  432. functions.PrintUserLog(r.Header.Get("user"), "created egress gateway on node "+gateway.NodeID+" on network "+gateway.NetID, 1)
  433. w.WriteHeader(http.StatusOK)
  434. json.NewEncoder(w).Encode(node)
  435. }
  436. // CreateEgressGateway - creates an egress gateway
  437. func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, error) {
  438. node, err := logic.GetNodeByMacAddress(gateway.NetID, gateway.NodeID)
  439. if node.OS == "windows" || node.OS == "macos" { // add in darwin later
  440. return models.Node{}, errors.New(node.OS + " is unsupported for egress gateways")
  441. }
  442. if err != nil {
  443. return models.Node{}, err
  444. }
  445. err = ValidateEgressGateway(gateway)
  446. if err != nil {
  447. return models.Node{}, err
  448. }
  449. node.IsEgressGateway = "yes"
  450. node.EgressGatewayRanges = gateway.Ranges
  451. postUpCmd := "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
  452. postDownCmd := "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
  453. if gateway.PostUp != "" {
  454. postUpCmd = gateway.PostUp
  455. }
  456. if gateway.PostDown != "" {
  457. postDownCmd = gateway.PostDown
  458. }
  459. if node.PostUp != "" {
  460. if !strings.Contains(node.PostUp, postUpCmd) {
  461. postUpCmd = node.PostUp + "; " + postUpCmd
  462. }
  463. }
  464. if node.PostDown != "" {
  465. if !strings.Contains(node.PostDown, postDownCmd) {
  466. postDownCmd = node.PostDown + "; " + postDownCmd
  467. }
  468. }
  469. key, err := logic.GetRecordKey(gateway.NodeID, gateway.NetID)
  470. if err != nil {
  471. return node, err
  472. }
  473. node.PostUp = postUpCmd
  474. node.PostDown = postDownCmd
  475. node.SetLastModified()
  476. node.PullChanges = "yes"
  477. nodeData, err := json.Marshal(&node)
  478. if err != nil {
  479. return node, err
  480. }
  481. if err = database.Insert(key, string(nodeData), database.NODES_TABLE_NAME); err != nil {
  482. return models.Node{}, err
  483. }
  484. if err = functions.NetworkNodesUpdatePullChanges(node.Network); err != nil {
  485. return models.Node{}, err
  486. }
  487. return node, nil
  488. }
  489. func ValidateEgressGateway(gateway models.EgressGatewayRequest) error {
  490. var err error
  491. //isIp := functions.IsIpCIDR(gateway.RangeString)
  492. empty := len(gateway.Ranges) == 0
  493. if empty {
  494. err = errors.New("IP Ranges Cannot Be Empty")
  495. }
  496. empty = gateway.Interface == ""
  497. if empty {
  498. err = errors.New("Interface cannot be empty")
  499. }
  500. return err
  501. }
  502. func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
  503. w.Header().Set("Content-Type", "application/json")
  504. var params = mux.Vars(r)
  505. nodeMac := params["macaddress"]
  506. netid := params["network"]
  507. node, err := DeleteEgressGateway(netid, nodeMac)
  508. if err != nil {
  509. returnErrorResponse(w, r, formatError(err, "internal"))
  510. return
  511. }
  512. functions.PrintUserLog(r.Header.Get("user"), "deleted egress gateway "+nodeMac+" on network "+netid, 1)
  513. w.WriteHeader(http.StatusOK)
  514. json.NewEncoder(w).Encode(node)
  515. }
  516. // DeleteEgressGateway - deletes egress from node
  517. func DeleteEgressGateway(network, macaddress string) (models.Node, error) {
  518. node, err := logic.GetNodeByMacAddress(network, macaddress)
  519. if err != nil {
  520. return models.Node{}, err
  521. }
  522. node.IsEgressGateway = "no"
  523. node.EgressGatewayRanges = []string{}
  524. node.PostUp = ""
  525. node.PostDown = ""
  526. if node.IsIngressGateway == "yes" { // check if node is still an ingress gateway before completely deleting postdown/up rules
  527. node.PostUp = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + node.Interface + " -j MASQUERADE"
  528. node.PostDown = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE"
  529. }
  530. node.SetLastModified()
  531. node.PullChanges = "yes"
  532. key, err := logic.GetRecordKey(node.MacAddress, node.Network)
  533. if err != nil {
  534. return models.Node{}, err
  535. }
  536. data, err := json.Marshal(&node)
  537. if err != nil {
  538. return models.Node{}, err
  539. }
  540. if err = database.Insert(key, string(data), database.NODES_TABLE_NAME); err != nil {
  541. return models.Node{}, err
  542. }
  543. if err = functions.NetworkNodesUpdatePullChanges(network); err != nil {
  544. return models.Node{}, err
  545. }
  546. return node, nil
  547. }
  548. // == INGRESS ==
  549. func createIngressGateway(w http.ResponseWriter, r *http.Request) {
  550. var params = mux.Vars(r)
  551. w.Header().Set("Content-Type", "application/json")
  552. nodeMac := params["macaddress"]
  553. netid := params["network"]
  554. node, err := CreateIngressGateway(netid, nodeMac)
  555. if err != nil {
  556. returnErrorResponse(w, r, formatError(err, "internal"))
  557. return
  558. }
  559. functions.PrintUserLog(r.Header.Get("user"), "created ingress gateway on node "+nodeMac+" on network "+netid, 1)
  560. w.WriteHeader(http.StatusOK)
  561. json.NewEncoder(w).Encode(node)
  562. }
  563. // CreateIngressGateway - creates an ingress gateway
  564. func CreateIngressGateway(netid string, macaddress string) (models.Node, error) {
  565. node, err := logic.GetNodeByMacAddress(netid, macaddress)
  566. if node.OS == "windows" || node.OS == "macos" { // add in darwin later
  567. return models.Node{}, errors.New(node.OS + " is unsupported for ingress gateways")
  568. }
  569. if err != nil {
  570. return models.Node{}, err
  571. }
  572. network, err := logic.GetParentNetwork(netid)
  573. if err != nil {
  574. return models.Node{}, err
  575. }
  576. node.IsIngressGateway = "yes"
  577. node.IngressGatewayRange = network.AddressRange
  578. postUpCmd := "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + node.Interface + " -j MASQUERADE"
  579. postDownCmd := "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE"
  580. if node.PostUp != "" {
  581. if !strings.Contains(node.PostUp, postUpCmd) {
  582. postUpCmd = node.PostUp + "; " + postUpCmd
  583. }
  584. }
  585. if node.PostDown != "" {
  586. if !strings.Contains(node.PostDown, postDownCmd) {
  587. postDownCmd = node.PostDown + "; " + postDownCmd
  588. }
  589. }
  590. node.SetLastModified()
  591. node.PostUp = postUpCmd
  592. node.PostDown = postDownCmd
  593. node.PullChanges = "yes"
  594. node.UDPHolePunch = "no"
  595. key, err := logic.GetRecordKey(node.MacAddress, node.Network)
  596. if err != nil {
  597. return models.Node{}, err
  598. }
  599. data, err := json.Marshal(&node)
  600. if err != nil {
  601. return models.Node{}, err
  602. }
  603. err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
  604. if err != nil {
  605. return models.Node{}, err
  606. }
  607. err = logic.SetNetworkNodesLastModified(netid)
  608. return node, err
  609. }
  610. func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
  611. w.Header().Set("Content-Type", "application/json")
  612. var params = mux.Vars(r)
  613. nodeMac := params["macaddress"]
  614. node, err := DeleteIngressGateway(params["network"], nodeMac)
  615. if err != nil {
  616. returnErrorResponse(w, r, formatError(err, "internal"))
  617. return
  618. }
  619. functions.PrintUserLog(r.Header.Get("user"), "deleted ingress gateway"+nodeMac, 1)
  620. w.WriteHeader(http.StatusOK)
  621. json.NewEncoder(w).Encode(node)
  622. }
  623. // DeleteIngressGateway - deletes an ingress gateway
  624. func DeleteIngressGateway(networkName string, macaddress string) (models.Node, error) {
  625. node, err := logic.GetNodeByMacAddress(networkName, macaddress)
  626. if err != nil {
  627. return models.Node{}, err
  628. }
  629. network, err := logic.GetParentNetwork(networkName)
  630. if err != nil {
  631. return models.Node{}, err
  632. }
  633. // delete ext clients belonging to ingress gateway
  634. if err = DeleteGatewayExtClients(macaddress, networkName); err != nil {
  635. return models.Node{}, err
  636. }
  637. node.UDPHolePunch = network.DefaultUDPHolePunch
  638. node.LastModified = time.Now().Unix()
  639. node.IsIngressGateway = "no"
  640. node.IngressGatewayRange = ""
  641. node.PullChanges = "yes"
  642. key, err := logic.GetRecordKey(node.MacAddress, node.Network)
  643. if err != nil {
  644. return models.Node{}, err
  645. }
  646. data, err := json.Marshal(&node)
  647. if err != nil {
  648. return models.Node{}, err
  649. }
  650. err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
  651. if err != nil {
  652. return models.Node{}, err
  653. }
  654. err = logic.SetNetworkNodesLastModified(networkName)
  655. return node, err
  656. }
  657. func updateNode(w http.ResponseWriter, r *http.Request) {
  658. w.Header().Set("Content-Type", "application/json")
  659. var params = mux.Vars(r)
  660. var node models.Node
  661. //start here
  662. node, err := logic.GetNodeByMacAddress(params["network"], params["macaddress"])
  663. if err != nil {
  664. returnErrorResponse(w, r, formatError(err, "internal"))
  665. return
  666. }
  667. var newNode models.Node
  668. // we decode our body request params
  669. err = json.NewDecoder(r.Body).Decode(&newNode)
  670. if err != nil {
  671. returnErrorResponse(w, r, formatError(err, "badrequest"))
  672. return
  673. }
  674. newNode.PullChanges = "yes"
  675. relayupdate := false
  676. if node.IsRelay == "yes" && len(newNode.RelayAddrs) > 0 {
  677. if len(newNode.RelayAddrs) != len(node.RelayAddrs) {
  678. relayupdate = true
  679. } else {
  680. for i, addr := range newNode.RelayAddrs {
  681. if addr != node.RelayAddrs[i] {
  682. relayupdate = true
  683. }
  684. }
  685. }
  686. }
  687. err = logic.UpdateNode(&node, &newNode)
  688. if err != nil {
  689. returnErrorResponse(w, r, formatError(err, "internal"))
  690. return
  691. }
  692. if relayupdate {
  693. UpdateRelay(node.Network, node.RelayAddrs, newNode.RelayAddrs)
  694. if err = functions.NetworkNodesUpdatePullChanges(node.Network); err != nil {
  695. functions.PrintUserLog("netmaker", "error setting relay updates: "+err.Error(), 1)
  696. }
  697. }
  698. if servercfg.IsDNSMode() {
  699. err = logic.SetDNS()
  700. }
  701. if err != nil {
  702. returnErrorResponse(w, r, formatError(err, "internal"))
  703. return
  704. }
  705. functions.PrintUserLog(r.Header.Get("user"), "updated node "+node.MacAddress+" on network "+node.Network, 1)
  706. w.WriteHeader(http.StatusOK)
  707. json.NewEncoder(w).Encode(newNode)
  708. }
  709. //Delete a node
  710. //Pretty straightforward
  711. func deleteNode(w http.ResponseWriter, r *http.Request) {
  712. // Set header
  713. w.Header().Set("Content-Type", "application/json")
  714. // get params
  715. var params = mux.Vars(r)
  716. err := DeleteNode(params["macaddress"]+"###"+params["network"], false)
  717. if err != nil {
  718. returnErrorResponse(w, r, formatError(err, "internal"))
  719. return
  720. }
  721. functions.PrintUserLog(r.Header.Get("user"), "Deleted node "+params["macaddress"]+" from network "+params["network"], 1)
  722. returnSuccessResponse(w, r, params["macaddress"]+" deleted.")
  723. }