ext_client.go 22 KB

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