ext_client.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. package controller
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "net"
  7. "net/http"
  8. "strconv"
  9. "github.com/gorilla/mux"
  10. "github.com/gravitl/netmaker/database"
  11. "github.com/gravitl/netmaker/logger"
  12. "github.com/gravitl/netmaker/logic"
  13. "github.com/gravitl/netmaker/models"
  14. "github.com/gravitl/netmaker/mq"
  15. "github.com/skip2/go-qrcode"
  16. "golang.org/x/exp/slog"
  17. "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
  18. )
  19. func extClientHandlers(r *mux.Router) {
  20. r.HandleFunc("/api/extclients", logic.SecurityCheck(true, http.HandlerFunc(getAllExtClients))).Methods(http.MethodGet)
  21. r.HandleFunc("/api/extclients/{network}", logic.SecurityCheck(true, http.HandlerFunc(getNetworkExtClients))).Methods(http.MethodGet)
  22. r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(getExtClient))).Methods(http.MethodGet)
  23. r.HandleFunc("/api/extclients/{network}/{clientid}/{type}", logic.SecurityCheck(false, http.HandlerFunc(getExtClientConf))).Methods(http.MethodGet)
  24. r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(updateExtClient))).Methods(http.MethodPut)
  25. r.HandleFunc("/api/extclients/{network}/{clientid}", logic.SecurityCheck(false, http.HandlerFunc(deleteExtClient))).Methods(http.MethodDelete)
  26. r.HandleFunc("/api/extclients/{network}/{nodeid}", logic.SecurityCheck(false, checkFreeTierLimits(limitChoiceMachines, http.HandlerFunc(createExtClient)))).Methods(http.MethodPost)
  27. r.HandleFunc("/api/cache/extclients", getCacheExtClients)
  28. }
  29. func getCacheExtClients(w http.ResponseWriter, r *http.Request) {
  30. //Returns all the extclients in JSON format
  31. w.WriteHeader(http.StatusOK)
  32. json.NewEncoder(w).Encode(logic.GetAllExtclientsFromCache())
  33. }
  34. func checkIngressExists(nodeID string) bool {
  35. node, err := logic.GetNodeByID(nodeID)
  36. if err != nil {
  37. return false
  38. }
  39. return node.IsIngressGateway
  40. }
  41. // swagger:route GET /api/extclients/{network} ext_client getNetworkExtClients
  42. //
  43. // Get all extclients associated with network.
  44. // Gets all extclients associated with network, including pending extclients.
  45. //
  46. // Schemes: https
  47. //
  48. // Security:
  49. // oauth
  50. //
  51. // Responses:
  52. // 200: extClientSliceResponse
  53. func getNetworkExtClients(w http.ResponseWriter, r *http.Request) {
  54. w.Header().Set("Content-Type", "application/json")
  55. var extclients []models.ExtClient
  56. var params = mux.Vars(r)
  57. network := params["network"]
  58. extclients, err := logic.GetNetworkExtClients(network)
  59. if err != nil {
  60. logger.Log(0, r.Header.Get("user"),
  61. fmt.Sprintf("failed to get ext clients for network [%s]: %v", network, err))
  62. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  63. return
  64. }
  65. //Returns all the extclients in JSON format
  66. w.WriteHeader(http.StatusOK)
  67. json.NewEncoder(w).Encode(extclients)
  68. }
  69. // swagger:route GET /api/extclients ext_client getAllExtClients
  70. //
  71. // A separate function to get all extclients, not just extclients for a particular network.
  72. //
  73. // Schemes: https
  74. //
  75. // Security:
  76. // oauth
  77. //
  78. // Responses:
  79. // 200: extClientSliceResponse
  80. //
  81. // Not quite sure if this is necessary. Probably necessary based on front end but may
  82. // want to review after iteration 1 if it's being used or not
  83. func getAllExtClients(w http.ResponseWriter, r *http.Request) {
  84. w.Header().Set("Content-Type", "application/json")
  85. clients, err := logic.GetAllExtClients()
  86. if err != nil && !database.IsEmptyRecord(err) {
  87. logger.Log(0, "failed to get all extclients: ", err.Error())
  88. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  89. return
  90. }
  91. //Return all the extclients in JSON format
  92. logic.SortExtClient(clients[:])
  93. w.WriteHeader(http.StatusOK)
  94. json.NewEncoder(w).Encode(clients)
  95. }
  96. // swagger:route GET /api/extclients/{network}/{clientid} ext_client getExtClient
  97. //
  98. // Get an individual extclient.
  99. //
  100. // Schemes: https
  101. //
  102. // Security:
  103. // oauth
  104. //
  105. // Responses:
  106. // 200: extClientResponse
  107. func getExtClient(w http.ResponseWriter, r *http.Request) {
  108. // set header.
  109. w.Header().Set("Content-Type", "application/json")
  110. var params = mux.Vars(r)
  111. clientid := params["clientid"]
  112. network := params["network"]
  113. client, err := logic.GetExtClient(clientid, network)
  114. if err != nil {
  115. logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to get extclient for [%s] on network [%s]: %v",
  116. clientid, network, err))
  117. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  118. return
  119. }
  120. if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), client) {
  121. // check if user has access to extclient
  122. slog.Error("failed to get extclient", "network", network, "clientID",
  123. clientid, "error", errors.New("access is denied"))
  124. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
  125. return
  126. }
  127. w.WriteHeader(http.StatusOK)
  128. json.NewEncoder(w).Encode(client)
  129. }
  130. // swagger:route GET /api/extclients/{network}/{clientid}/{type} ext_client getExtClientConf
  131. //
  132. // Get an individual extclient.
  133. //
  134. // Schemes: https
  135. //
  136. // Security:
  137. // oauth
  138. //
  139. // Responses:
  140. // 200: extClientResponse
  141. func getExtClientConf(w http.ResponseWriter, r *http.Request) {
  142. // set header.
  143. w.Header().Set("Content-Type", "application/json")
  144. var params = mux.Vars(r)
  145. clientid := params["clientid"]
  146. networkid := params["network"]
  147. client, err := logic.GetExtClient(clientid, networkid)
  148. if err != nil {
  149. logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to get extclient for [%s] on network [%s]: %v",
  150. clientid, networkid, err))
  151. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  152. return
  153. }
  154. if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), client) {
  155. slog.Error("failed to get extclient", "network", networkid, "clientID",
  156. clientid, "error", errors.New("access is denied"))
  157. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
  158. return
  159. }
  160. gwnode, err := logic.GetNodeByID(client.IngressGatewayID)
  161. if err != nil {
  162. logger.Log(0, r.Header.Get("user"),
  163. fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", client.IngressGatewayID, err))
  164. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  165. return
  166. }
  167. host, err := logic.GetHost(gwnode.HostID.String())
  168. if err != nil {
  169. logger.Log(0, r.Header.Get("user"),
  170. fmt.Sprintf("failed to get host for ingress gateway node [%s] info: %v", client.IngressGatewayID, err))
  171. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  172. return
  173. }
  174. network, err := logic.GetParentNetwork(client.Network)
  175. if err != nil {
  176. logger.Log(1, r.Header.Get("user"), "Could not retrieve Ingress Gateway Network", client.Network)
  177. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  178. return
  179. }
  180. addrString := client.Address
  181. if addrString != "" {
  182. addrString += "/32"
  183. }
  184. if client.Address6 != "" {
  185. if addrString != "" {
  186. addrString += ","
  187. }
  188. addrString += client.Address6 + "/128"
  189. }
  190. keepalive := ""
  191. if network.DefaultKeepalive != 0 {
  192. keepalive = "PersistentKeepalive = " + strconv.Itoa(int(network.DefaultKeepalive))
  193. }
  194. gwendpoint := ""
  195. if host.EndpointIP.To4() == nil {
  196. gwendpoint = fmt.Sprintf("[%s]:%d", host.EndpointIP.String(), host.ListenPort)
  197. } else {
  198. gwendpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), host.ListenPort)
  199. }
  200. newAllowedIPs := network.AddressRange
  201. if newAllowedIPs != "" && network.AddressRange6 != "" {
  202. newAllowedIPs += ","
  203. }
  204. if network.AddressRange6 != "" {
  205. newAllowedIPs += network.AddressRange6
  206. }
  207. if egressGatewayRanges, err := logic.GetEgressRangesOnNetwork(&client); err == nil {
  208. for _, egressGatewayRange := range egressGatewayRanges {
  209. newAllowedIPs += "," + egressGatewayRange
  210. }
  211. }
  212. defaultDNS := ""
  213. if client.DNS != "" {
  214. defaultDNS = "DNS = " + client.DNS
  215. } else if gwnode.IngressDNS != "" {
  216. defaultDNS = "DNS = " + gwnode.IngressDNS
  217. }
  218. defaultMTU := 1420
  219. if host.MTU != 0 {
  220. defaultMTU = host.MTU
  221. }
  222. config := fmt.Sprintf(`[Interface]
  223. Address = %s
  224. PrivateKey = %s
  225. MTU = %d
  226. %s
  227. [Peer]
  228. PublicKey = %s
  229. AllowedIPs = %s
  230. Endpoint = %s
  231. %s
  232. `, addrString,
  233. client.PrivateKey,
  234. defaultMTU,
  235. defaultDNS,
  236. host.PublicKey,
  237. newAllowedIPs,
  238. gwendpoint,
  239. keepalive)
  240. if params["type"] == "qr" {
  241. bytes, err := qrcode.Encode(config, qrcode.Medium, 220)
  242. if err != nil {
  243. logger.Log(1, r.Header.Get("user"), "failed to encode qr code: ", err.Error())
  244. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  245. return
  246. }
  247. w.Header().Set("Content-Type", "image/png")
  248. w.WriteHeader(http.StatusOK)
  249. _, err = w.Write(bytes)
  250. if err != nil {
  251. logger.Log(1, r.Header.Get("user"), "response writer error (qr) ", err.Error())
  252. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  253. return
  254. }
  255. return
  256. }
  257. if params["type"] == "file" {
  258. name := client.ClientID + ".conf"
  259. w.Header().Set("Content-Type", "application/config")
  260. w.Header().Set("Content-Disposition", "attachment; filename=\""+name+"\"")
  261. w.WriteHeader(http.StatusOK)
  262. _, err := fmt.Fprint(w, config)
  263. if err != nil {
  264. logger.Log(1, r.Header.Get("user"), "response writer error (file) ", err.Error())
  265. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  266. }
  267. return
  268. }
  269. logger.Log(2, r.Header.Get("user"), "retrieved ext client config")
  270. w.WriteHeader(http.StatusOK)
  271. json.NewEncoder(w).Encode(client)
  272. }
  273. // swagger:route POST /api/extclients/{network}/{nodeid} ext_client createExtClient
  274. //
  275. // Create an individual extclient. Must have valid key and be unique.
  276. //
  277. // Schemes: https
  278. //
  279. // Security:
  280. // oauth
  281. // Responses:
  282. // 200: okResponse
  283. func createExtClient(w http.ResponseWriter, r *http.Request) {
  284. w.Header().Set("Content-Type", "application/json")
  285. var params = mux.Vars(r)
  286. nodeid := params["nodeid"]
  287. ingressExists := checkIngressExists(nodeid)
  288. if !ingressExists {
  289. err := errors.New("ingress does not exist")
  290. slog.Error("failed to create extclient", "user", r.Header.Get("user"), "error", err)
  291. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  292. return
  293. }
  294. var customExtClient models.CustomExtClient
  295. if err := json.NewDecoder(r.Body).Decode(&customExtClient); err != nil {
  296. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  297. return
  298. }
  299. if err := validateCustomExtClient(&customExtClient, true); err != nil {
  300. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  301. return
  302. }
  303. node, err := logic.GetNodeByID(nodeid)
  304. if err != nil {
  305. logger.Log(0, r.Header.Get("user"),
  306. fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", nodeid, err))
  307. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  308. return
  309. }
  310. var userName string
  311. if r.Header.Get("ismaster") == "yes" {
  312. userName = logic.MasterUser
  313. } else {
  314. caller, err := logic.GetUser(r.Header.Get("user"))
  315. if err != nil {
  316. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  317. return
  318. }
  319. userName = caller.UserName
  320. if !caller.IsAdmin && !caller.IsSuperAdmin {
  321. if _, ok := caller.RemoteGwIDs[nodeid]; !ok {
  322. err = errors.New("permission denied")
  323. slog.Error("failed to create extclient", "error", err)
  324. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  325. return
  326. }
  327. // check if user has a config already for remote access client
  328. extclients, err := logic.GetNetworkExtClients(node.Network)
  329. if err != nil {
  330. slog.Error("failed to get extclients", "error", err)
  331. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  332. return
  333. }
  334. for _, extclient := range extclients {
  335. if extclient.RemoteAccessClientID != "" &&
  336. extclient.RemoteAccessClientID == customExtClient.RemoteAccessClientID && nodeid == extclient.IngressGatewayID {
  337. // extclient on the gw already exists for the remote access client
  338. err = errors.New("remote client config already exists on the gateway")
  339. slog.Error("failed to create extclient", "user", userName, "error", err)
  340. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  341. return
  342. }
  343. }
  344. }
  345. }
  346. extclient := logic.UpdateExtClient(&models.ExtClient{}, &customExtClient)
  347. extclient.OwnerID = userName
  348. extclient.RemoteAccessClientID = customExtClient.RemoteAccessClientID
  349. extclient.IngressGatewayID = nodeid
  350. // set extclient dns to ingressdns if extclient dns is not explicitly set
  351. if (extclient.DNS == "") && (node.IngressDNS != "") {
  352. extclient.DNS = node.IngressDNS
  353. }
  354. extclient.Network = node.Network
  355. host, err := logic.GetHost(node.HostID.String())
  356. if err != nil {
  357. logger.Log(0, r.Header.Get("user"),
  358. fmt.Sprintf("failed to get ingress gateway host for node [%s] info: %v", nodeid, err))
  359. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  360. return
  361. }
  362. listenPort := logic.GetPeerListenPort(host)
  363. extclient.IngressGatewayEndpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), listenPort)
  364. extclient.Enabled = true
  365. parentNetwork, err := logic.GetNetwork(node.Network)
  366. if err == nil { // check if parent network default ACL is enabled (yes) or not (no)
  367. extclient.Enabled = parentNetwork.DefaultACL == "yes"
  368. }
  369. if err := logic.SetClientDefaultACLs(&extclient); err != nil {
  370. slog.Error("failed to set default acls for extclient", "user", r.Header.Get("user"), "network", node.Network, "error", err)
  371. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  372. return
  373. }
  374. if err = logic.CreateExtClient(&extclient); err != nil {
  375. slog.Error("failed to create extclient", "user", r.Header.Get("user"), "network", node.Network, "error", err)
  376. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  377. return
  378. }
  379. slog.Info("created extclient", "user", r.Header.Get("user"), "network", node.Network, "clientid", extclient.ClientID)
  380. w.WriteHeader(http.StatusOK)
  381. go func() {
  382. if err := mq.PublishPeerUpdate(); err != nil {
  383. logger.Log(1, "error setting ext peers on "+nodeid+": "+err.Error())
  384. }
  385. if err := mq.PublishExtClientDNS(&extclient); err != nil {
  386. logger.Log(1, "error publishing extclient dns", err.Error())
  387. }
  388. }()
  389. }
  390. // swagger:route PUT /api/extclients/{network}/{clientid} ext_client updateExtClient
  391. //
  392. // Update an individual extclient.
  393. //
  394. // Schemes: https
  395. //
  396. // Security:
  397. // oauth
  398. //
  399. // Responses:
  400. // 200: extClientResponse
  401. func updateExtClient(w http.ResponseWriter, r *http.Request) {
  402. w.Header().Set("Content-Type", "application/json")
  403. var params = mux.Vars(r)
  404. var update models.CustomExtClient
  405. //var oldExtClient models.ExtClient
  406. var sendPeerUpdate bool
  407. err := json.NewDecoder(r.Body).Decode(&update)
  408. if err != nil {
  409. logger.Log(0, r.Header.Get("user"), "error decoding request body: ",
  410. err.Error())
  411. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  412. return
  413. }
  414. clientid := params["clientid"]
  415. network := params["network"]
  416. oldExtClient, err := logic.GetExtClientByName(clientid)
  417. if err != nil {
  418. slog.Error("failed to retrieve extclient", "user", r.Header.Get("user"), "id", clientid, "error", err)
  419. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  420. return
  421. }
  422. if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), oldExtClient) {
  423. // check if user has access to extclient
  424. slog.Error("failed to get extclient", "network", network, "clientID",
  425. clientid, "error", errors.New("access is denied"))
  426. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
  427. return
  428. }
  429. if oldExtClient.ClientID == update.ClientID {
  430. if err := validateCustomExtClient(&update, false); err != nil {
  431. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  432. return
  433. }
  434. } else {
  435. if err := validateCustomExtClient(&update, true); err != nil {
  436. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  437. return
  438. }
  439. }
  440. var changedID = update.ClientID != oldExtClient.ClientID
  441. if len(update.DeniedACLs) != len(oldExtClient.DeniedACLs) {
  442. sendPeerUpdate = true
  443. logic.SetClientACLs(&oldExtClient, update.DeniedACLs)
  444. }
  445. if update.Enabled != oldExtClient.Enabled {
  446. sendPeerUpdate = true
  447. }
  448. newclient := logic.UpdateExtClient(&oldExtClient, &update)
  449. if err := logic.DeleteExtClient(oldExtClient.Network, oldExtClient.ClientID); err != nil {
  450. slog.Error("failed to delete ext client", "user", r.Header.Get("user"), "id", oldExtClient.ClientID, "network", oldExtClient.Network, "error", err)
  451. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  452. return
  453. }
  454. if err := logic.SaveExtClient(&newclient); err != nil {
  455. slog.Error("failed to save ext client", "user", r.Header.Get("user"), "id", newclient.ClientID, "network", newclient.Network, "error", err)
  456. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  457. return
  458. }
  459. logger.Log(0, r.Header.Get("user"), "updated ext client", update.ClientID)
  460. if sendPeerUpdate { // need to send a peer update to the ingress node as enablement of one of it's clients has changed
  461. if ingressNode, err := logic.GetNodeByID(newclient.IngressGatewayID); err == nil {
  462. if err = mq.PublishPeerUpdate(); err != nil {
  463. logger.Log(1, "error setting ext peers on", ingressNode.ID.String(), ":", err.Error())
  464. }
  465. }
  466. }
  467. w.WriteHeader(http.StatusOK)
  468. json.NewEncoder(w).Encode(newclient)
  469. if changedID {
  470. go func() {
  471. if err := mq.PublishExtClientDNSUpdate(oldExtClient, newclient, oldExtClient.Network); err != nil {
  472. logger.Log(1, "error pubishing dns update for extcient update", err.Error())
  473. }
  474. }()
  475. }
  476. }
  477. // swagger:route DELETE /api/extclients/{network}/{clientid} ext_client deleteExtClient
  478. //
  479. // Delete an individual extclient.
  480. //
  481. // Schemes: https
  482. //
  483. // Security:
  484. // oauth
  485. //
  486. // Responses:
  487. // 200: successResponse
  488. func deleteExtClient(w http.ResponseWriter, r *http.Request) {
  489. // Set header
  490. w.Header().Set("Content-Type", "application/json")
  491. // get params
  492. var params = mux.Vars(r)
  493. clientid := params["clientid"]
  494. network := params["network"]
  495. extclient, err := logic.GetExtClient(clientid, network)
  496. if err != nil {
  497. logger.Log(0, r.Header.Get("user"),
  498. fmt.Sprintf("failed to get extclient [%s],network [%s]: %v", clientid, network, err))
  499. err = errors.New("Could not delete extclient " + params["clientid"])
  500. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  501. return
  502. }
  503. if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), extclient) {
  504. slog.Error("user not allowed to delete", "network", network, "clientID",
  505. clientid, "error", errors.New("access is denied"))
  506. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
  507. return
  508. }
  509. ingressnode, err := logic.GetNodeByID(extclient.IngressGatewayID)
  510. if err != nil {
  511. logger.Log(0, r.Header.Get("user"),
  512. fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", extclient.IngressGatewayID, err))
  513. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  514. return
  515. }
  516. err = logic.DeleteExtClient(params["network"], params["clientid"])
  517. if err != nil {
  518. logger.Log(0, r.Header.Get("user"),
  519. fmt.Sprintf("failed to delete extclient [%s],network [%s]: %v", clientid, network, err))
  520. err = errors.New("Could not delete extclient " + params["clientid"])
  521. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  522. return
  523. }
  524. go func() {
  525. if err := mq.PublishDeletedClientPeerUpdate(&extclient); err != nil {
  526. logger.Log(1, "error setting ext peers on "+ingressnode.ID.String()+": "+err.Error())
  527. }
  528. if err = mq.PublishDeleteExtClientDNS(&extclient); err != nil {
  529. logger.Log(1, "error publishing dns update for extclient deletion", err.Error())
  530. }
  531. }()
  532. logger.Log(0, r.Header.Get("user"),
  533. "Deleted extclient client", params["clientid"], "from network", params["network"])
  534. logic.ReturnSuccessResponse(w, r, params["clientid"]+" deleted.")
  535. }
  536. // validateCustomExtClient Validates the extclient object
  537. func validateCustomExtClient(customExtClient *models.CustomExtClient, checkID bool) error {
  538. //validate clientid
  539. if customExtClient.ClientID != "" {
  540. if err := isValid(customExtClient.ClientID, checkID); err != nil {
  541. return fmt.Errorf("client validatation: %v", err)
  542. }
  543. }
  544. //extclient.ClientID = customExtClient.ClientID
  545. if len(customExtClient.PublicKey) > 0 {
  546. if _, err := wgtypes.ParseKey(customExtClient.PublicKey); err != nil {
  547. return errInvalidExtClientPubKey
  548. }
  549. //extclient.PublicKey = customExtClient.PublicKey
  550. }
  551. //validate extra ips
  552. if len(customExtClient.ExtraAllowedIPs) > 0 {
  553. for _, ip := range customExtClient.ExtraAllowedIPs {
  554. if _, _, err := net.ParseCIDR(ip); err != nil {
  555. return errInvalidExtClientExtraIP
  556. }
  557. }
  558. //extclient.ExtraAllowedIPs = customExtClient.ExtraAllowedIPs
  559. }
  560. //validate DNS
  561. if customExtClient.DNS != "" {
  562. if ip := net.ParseIP(customExtClient.DNS); ip == nil {
  563. return errInvalidExtClientDNS
  564. }
  565. //extclient.DNS = customExtClient.DNS
  566. }
  567. return nil
  568. }
  569. // isValid Checks if the clientid is valid
  570. func isValid(clientid string, checkID bool) error {
  571. if !validName(clientid) {
  572. return errInvalidExtClientID
  573. }
  574. if checkID {
  575. extclients, err := logic.GetAllExtClients()
  576. if err != nil {
  577. return fmt.Errorf("extclients isValid: %v", err)
  578. }
  579. for _, extclient := range extclients {
  580. if clientid == extclient.ClientID {
  581. return errDuplicateExtClientName
  582. }
  583. }
  584. }
  585. return nil
  586. }