ext_client.go 21 KB

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