ext_client.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  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. clients, err := logic.GetAllExtClients()
  80. if err != nil && !database.IsEmptyRecord(err) {
  81. logger.Log(0, "failed to get all extclients: ", err.Error())
  82. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  83. return
  84. }
  85. //Return all the extclients in JSON format
  86. logic.SortExtClient(clients[:])
  87. w.WriteHeader(http.StatusOK)
  88. json.NewEncoder(w).Encode(clients)
  89. }
  90. // swagger:route GET /api/extclients/{network}/{clientid} ext_client getExtClient
  91. //
  92. // Get an individual extclient.
  93. //
  94. // Schemes: https
  95. //
  96. // Security:
  97. // oauth
  98. //
  99. // Responses:
  100. // 200: extClientResponse
  101. func getExtClient(w http.ResponseWriter, r *http.Request) {
  102. // set header.
  103. w.Header().Set("Content-Type", "application/json")
  104. var params = mux.Vars(r)
  105. clientid := params["clientid"]
  106. network := params["network"]
  107. client, err := logic.GetExtClient(clientid, network)
  108. if err != nil {
  109. logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to get extclient for [%s] on network [%s]: %v",
  110. clientid, network, err))
  111. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  112. return
  113. }
  114. if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), client) {
  115. // check if user has access to extclient
  116. slog.Error("failed to get extclient", "network", network, "clientID",
  117. clientid, "error", errors.New("access is denied"))
  118. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
  119. return
  120. }
  121. w.WriteHeader(http.StatusOK)
  122. json.NewEncoder(w).Encode(client)
  123. }
  124. // swagger:route GET /api/extclients/{network}/{clientid}/{type} ext_client getExtClientConf
  125. //
  126. // Get an individual extclient.
  127. //
  128. // Schemes: https
  129. //
  130. // Security:
  131. // oauth
  132. //
  133. // Responses:
  134. // 200: extClientResponse
  135. func getExtClientConf(w http.ResponseWriter, r *http.Request) {
  136. // set header.
  137. w.Header().Set("Content-Type", "application/json")
  138. var params = mux.Vars(r)
  139. clientid := params["clientid"]
  140. networkid := params["network"]
  141. client, err := logic.GetExtClient(clientid, networkid)
  142. if err != nil {
  143. logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to get extclient for [%s] on network [%s]: %v",
  144. clientid, networkid, err))
  145. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  146. return
  147. }
  148. if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), client) {
  149. slog.Error("failed to get extclient", "network", networkid, "clientID",
  150. clientid, "error", errors.New("access is denied"))
  151. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
  152. return
  153. }
  154. gwnode, err := logic.GetNodeByID(client.IngressGatewayID)
  155. if err != nil {
  156. logger.Log(0, r.Header.Get("user"),
  157. fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", client.IngressGatewayID, err))
  158. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  159. return
  160. }
  161. host, err := logic.GetHost(gwnode.HostID.String())
  162. if err != nil {
  163. logger.Log(0, r.Header.Get("user"),
  164. fmt.Sprintf("failed to get host for ingress gateway node [%s] info: %v", client.IngressGatewayID, err))
  165. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  166. return
  167. }
  168. network, err := logic.GetParentNetwork(client.Network)
  169. if err != nil {
  170. logger.Log(1, r.Header.Get("user"), "Could not retrieve Ingress Gateway Network", client.Network)
  171. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  172. return
  173. }
  174. addrString := client.Address
  175. if addrString != "" {
  176. addrString += "/32"
  177. }
  178. if client.Address6 != "" {
  179. if addrString != "" {
  180. addrString += ","
  181. }
  182. addrString += client.Address6 + "/128"
  183. }
  184. keepalive := ""
  185. if network.DefaultKeepalive != 0 {
  186. keepalive = "PersistentKeepalive = " + strconv.Itoa(int(network.DefaultKeepalive))
  187. }
  188. gwendpoint := ""
  189. if host.EndpointIP.To4() == nil {
  190. gwendpoint = fmt.Sprintf("[%s]:%d", host.EndpointIP.String(), host.ListenPort)
  191. } else {
  192. gwendpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), host.ListenPort)
  193. }
  194. var newAllowedIPs string
  195. if logic.IsInternetGw(gwnode) {
  196. egressrange := "0.0.0.0/0"
  197. if gwnode.Address6.IP != nil && client.Address6 != "" {
  198. egressrange += "," + "::/0"
  199. }
  200. newAllowedIPs = egressrange
  201. } else {
  202. newAllowedIPs = network.AddressRange
  203. if newAllowedIPs != "" && network.AddressRange6 != "" {
  204. newAllowedIPs += ","
  205. }
  206. if network.AddressRange6 != "" {
  207. newAllowedIPs += network.AddressRange6
  208. }
  209. if egressGatewayRanges, err := logic.GetEgressRangesOnNetwork(&client); err == nil {
  210. for _, egressGatewayRange := range egressGatewayRanges {
  211. newAllowedIPs += "," + egressGatewayRange
  212. }
  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. // Responses:
  285. // 200: okResponse
  286. func createExtClient(w http.ResponseWriter, r *http.Request) {
  287. w.Header().Set("Content-Type", "application/json")
  288. var params = mux.Vars(r)
  289. nodeid := params["nodeid"]
  290. ingressExists := checkIngressExists(nodeid)
  291. if !ingressExists {
  292. err := errors.New("ingress does not exist")
  293. slog.Error("failed to create extclient", "user", r.Header.Get("user"), "error", err)
  294. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  295. return
  296. }
  297. var customExtClient models.CustomExtClient
  298. if err := json.NewDecoder(r.Body).Decode(&customExtClient); err != nil {
  299. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  300. return
  301. }
  302. if err := validateCustomExtClient(&customExtClient, true); err != nil {
  303. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  304. return
  305. }
  306. node, err := logic.GetNodeByID(nodeid)
  307. if err != nil {
  308. logger.Log(0, r.Header.Get("user"),
  309. fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", nodeid, err))
  310. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  311. return
  312. }
  313. var userName string
  314. if r.Header.Get("ismaster") == "yes" {
  315. userName = logic.MasterUser
  316. } else {
  317. caller, err := logic.GetUser(r.Header.Get("user"))
  318. if err != nil {
  319. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  320. return
  321. }
  322. userName = caller.UserName
  323. if !caller.IsAdmin && !caller.IsSuperAdmin {
  324. if _, ok := caller.RemoteGwIDs[nodeid]; !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")
  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. }
  349. extclient := logic.UpdateExtClient(&models.ExtClient{}, &customExtClient)
  350. extclient.OwnerID = userName
  351. extclient.RemoteAccessClientID = customExtClient.RemoteAccessClientID
  352. extclient.IngressGatewayID = nodeid
  353. // set extclient dns to ingressdns if extclient dns is not explicitly set
  354. if (extclient.DNS == "") && (node.IngressDNS != "") {
  355. extclient.DNS = node.IngressDNS
  356. }
  357. extclient.Network = node.Network
  358. host, err := logic.GetHost(node.HostID.String())
  359. if err != nil {
  360. logger.Log(0, r.Header.Get("user"),
  361. fmt.Sprintf("failed to get ingress gateway host for node [%s] info: %v", nodeid, err))
  362. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  363. return
  364. }
  365. listenPort := logic.GetPeerListenPort(host)
  366. extclient.IngressGatewayEndpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), listenPort)
  367. extclient.Enabled = true
  368. parentNetwork, err := logic.GetNetwork(node.Network)
  369. if err == nil { // check if parent network default ACL is enabled (yes) or not (no)
  370. extclient.Enabled = parentNetwork.DefaultACL == "yes"
  371. }
  372. if err := logic.SetClientDefaultACLs(&extclient); err != nil {
  373. slog.Error("failed to set default acls for extclient", "user", r.Header.Get("user"), "network", node.Network, "error", err)
  374. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  375. return
  376. }
  377. if err = logic.CreateExtClient(&extclient); err != nil {
  378. slog.Error("failed to create extclient", "user", r.Header.Get("user"), "network", node.Network, "error", err)
  379. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  380. return
  381. }
  382. slog.Info("created extclient", "user", r.Header.Get("user"), "network", node.Network, "clientid", extclient.ClientID)
  383. w.WriteHeader(http.StatusOK)
  384. go func() {
  385. if err := mq.PublishPeerUpdate(); err != nil {
  386. logger.Log(1, "error setting ext peers on "+nodeid+": "+err.Error())
  387. }
  388. if err := mq.PublishExtClientDNS(&extclient); err != nil {
  389. logger.Log(1, "error publishing extclient dns", err.Error())
  390. }
  391. }()
  392. }
  393. // swagger:route PUT /api/extclients/{network}/{clientid} ext_client updateExtClient
  394. //
  395. // Update an individual extclient.
  396. //
  397. // Schemes: https
  398. //
  399. // Security:
  400. // oauth
  401. //
  402. // Responses:
  403. // 200: extClientResponse
  404. func updateExtClient(w http.ResponseWriter, r *http.Request) {
  405. w.Header().Set("Content-Type", "application/json")
  406. var params = mux.Vars(r)
  407. var update models.CustomExtClient
  408. //var oldExtClient models.ExtClient
  409. var sendPeerUpdate bool
  410. err := json.NewDecoder(r.Body).Decode(&update)
  411. if err != nil {
  412. logger.Log(0, r.Header.Get("user"), "error decoding request body: ",
  413. err.Error())
  414. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  415. return
  416. }
  417. clientid := params["clientid"]
  418. network := params["network"]
  419. oldExtClient, err := logic.GetExtClientByName(clientid)
  420. if err != nil {
  421. slog.Error("failed to retrieve extclient", "user", r.Header.Get("user"), "id", clientid, "error", err)
  422. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  423. return
  424. }
  425. if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), oldExtClient) {
  426. // check if user has access to extclient
  427. slog.Error("failed to get extclient", "network", network, "clientID",
  428. clientid, "error", errors.New("access is denied"))
  429. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
  430. return
  431. }
  432. if oldExtClient.ClientID == update.ClientID {
  433. if err := validateCustomExtClient(&update, false); err != nil {
  434. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  435. return
  436. }
  437. } else {
  438. if err := validateCustomExtClient(&update, true); err != nil {
  439. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  440. return
  441. }
  442. }
  443. var changedID = update.ClientID != oldExtClient.ClientID
  444. if len(update.DeniedACLs) != len(oldExtClient.DeniedACLs) {
  445. sendPeerUpdate = true
  446. logic.SetClientACLs(&oldExtClient, update.DeniedACLs)
  447. }
  448. if !logic.IsSlicesEqual(update.ExtraAllowedIPs, oldExtClient.ExtraAllowedIPs) {
  449. sendPeerUpdate = true
  450. }
  451. if update.Enabled != oldExtClient.Enabled {
  452. sendPeerUpdate = true
  453. }
  454. newclient := logic.UpdateExtClient(&oldExtClient, &update)
  455. if err := logic.DeleteExtClient(oldExtClient.Network, oldExtClient.ClientID); err != nil {
  456. slog.Error("failed to delete ext client", "user", r.Header.Get("user"), "id", oldExtClient.ClientID, "network", oldExtClient.Network, "error", err)
  457. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  458. return
  459. }
  460. if err := logic.SaveExtClient(&newclient); err != nil {
  461. slog.Error("failed to save ext client", "user", r.Header.Get("user"), "id", newclient.ClientID, "network", newclient.Network, "error", err)
  462. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  463. return
  464. }
  465. logger.Log(0, r.Header.Get("user"), "updated ext client", update.ClientID)
  466. if sendPeerUpdate { // need to send a peer update to the ingress node as enablement of one of it's clients has changed
  467. if ingressNode, err := logic.GetNodeByID(newclient.IngressGatewayID); err == nil {
  468. if err = mq.PublishPeerUpdate(); err != nil {
  469. logger.Log(1, "error setting ext peers on", ingressNode.ID.String(), ":", err.Error())
  470. }
  471. }
  472. }
  473. w.WriteHeader(http.StatusOK)
  474. json.NewEncoder(w).Encode(newclient)
  475. if changedID {
  476. go func() {
  477. if err := mq.PublishExtClientDNSUpdate(oldExtClient, newclient, oldExtClient.Network); err != nil {
  478. logger.Log(1, "error pubishing dns update for extcient update", err.Error())
  479. }
  480. }()
  481. }
  482. }
  483. // swagger:route DELETE /api/extclients/{network}/{clientid} ext_client deleteExtClient
  484. //
  485. // Delete an individual extclient.
  486. //
  487. // Schemes: https
  488. //
  489. // Security:
  490. // oauth
  491. //
  492. // Responses:
  493. // 200: successResponse
  494. func deleteExtClient(w http.ResponseWriter, r *http.Request) {
  495. // Set header
  496. w.Header().Set("Content-Type", "application/json")
  497. // get params
  498. var params = mux.Vars(r)
  499. clientid := params["clientid"]
  500. network := params["network"]
  501. extclient, err := logic.GetExtClient(clientid, network)
  502. if err != nil {
  503. err = errors.New("Could not delete extclient " + params["clientid"])
  504. logger.Log(0, r.Header.Get("user"),
  505. fmt.Sprintf("failed to get extclient [%s],network [%s]: %v", clientid, network, err))
  506. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  507. return
  508. }
  509. if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), extclient) {
  510. slog.Error("user not allowed to delete", "network", network, "clientID",
  511. clientid, "error", errors.New("access is denied"))
  512. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
  513. return
  514. }
  515. ingressnode, err := logic.GetNodeByID(extclient.IngressGatewayID)
  516. if err != nil {
  517. logger.Log(0, r.Header.Get("user"),
  518. fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", extclient.IngressGatewayID, err))
  519. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  520. return
  521. }
  522. err = logic.DeleteExtClient(params["network"], params["clientid"])
  523. if err != nil {
  524. logger.Log(0, r.Header.Get("user"),
  525. fmt.Sprintf("failed to delete extclient [%s],network [%s]: %v", clientid, network, err))
  526. err = errors.New("Could not delete extclient " + params["clientid"])
  527. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  528. return
  529. }
  530. go func() {
  531. if err := mq.PublishDeletedClientPeerUpdate(&extclient); err != nil {
  532. logger.Log(1, "error setting ext peers on "+ingressnode.ID.String()+": "+err.Error())
  533. }
  534. if err = mq.PublishDeleteExtClientDNS(&extclient); err != nil {
  535. logger.Log(1, "error publishing dns update for extclient deletion", err.Error())
  536. }
  537. }()
  538. logger.Log(0, r.Header.Get("user"),
  539. "Deleted extclient client", params["clientid"], "from network", params["network"])
  540. logic.ReturnSuccessResponse(w, r, params["clientid"]+" deleted.")
  541. }
  542. // validateCustomExtClient Validates the extclient object
  543. func validateCustomExtClient(customExtClient *models.CustomExtClient, checkID bool) error {
  544. //validate clientid
  545. if customExtClient.ClientID != "" {
  546. if err := isValid(customExtClient.ClientID, checkID); err != nil {
  547. return fmt.Errorf("client validatation: %v", err)
  548. }
  549. }
  550. //extclient.ClientID = customExtClient.ClientID
  551. if len(customExtClient.PublicKey) > 0 {
  552. if _, err := wgtypes.ParseKey(customExtClient.PublicKey); err != nil {
  553. return errInvalidExtClientPubKey
  554. }
  555. //extclient.PublicKey = customExtClient.PublicKey
  556. }
  557. //validate extra ips
  558. if len(customExtClient.ExtraAllowedIPs) > 0 {
  559. for _, ip := range customExtClient.ExtraAllowedIPs {
  560. if _, _, err := net.ParseCIDR(ip); err != nil {
  561. return errInvalidExtClientExtraIP
  562. }
  563. }
  564. //extclient.ExtraAllowedIPs = customExtClient.ExtraAllowedIPs
  565. }
  566. //validate DNS
  567. if customExtClient.DNS != "" {
  568. if ip := net.ParseIP(customExtClient.DNS); ip == nil {
  569. return errInvalidExtClientDNS
  570. }
  571. //extclient.DNS = customExtClient.DNS
  572. }
  573. return nil
  574. }
  575. // isValid Checks if the clientid is valid
  576. func isValid(clientid string, checkID bool) error {
  577. if !validName(clientid) {
  578. return errInvalidExtClientID
  579. }
  580. if checkID {
  581. extclients, err := logic.GetAllExtClients()
  582. if err != nil {
  583. return fmt.Errorf("extclients isValid: %v", err)
  584. }
  585. for _, extclient := range extclients {
  586. if clientid == extclient.ClientID {
  587. return errDuplicateExtClientName
  588. }
  589. }
  590. }
  591. return nil
  592. }