ext_client.go 21 KB

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