ext_client.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  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 !caller.IsAdmin && !caller.IsSuperAdmin {
  325. if _, ok := caller.RemoteGwIDs[nodeid]; !ok {
  326. err = errors.New("permission denied")
  327. slog.Error("failed to create extclient", "error", err)
  328. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  329. return
  330. }
  331. // check if user has a config already for remote access client
  332. extclients, err := logic.GetNetworkExtClients(node.Network)
  333. if err != nil {
  334. slog.Error("failed to get extclients", "error", err)
  335. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  336. return
  337. }
  338. for _, extclient := range extclients {
  339. if extclient.RemoteAccessClientID != "" &&
  340. extclient.RemoteAccessClientID == customExtClient.RemoteAccessClientID && nodeid == extclient.IngressGatewayID {
  341. // extclient on the gw already exists for the remote access client
  342. err = errors.New("remote client config already exists on the gateway")
  343. slog.Error("failed to create extclient", "user", userName, "error", err)
  344. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  345. return
  346. }
  347. }
  348. }
  349. }
  350. extclient := logic.UpdateExtClient(&models.ExtClient{}, &customExtClient)
  351. extclient.OwnerID = userName
  352. extclient.RemoteAccessClientID = customExtClient.RemoteAccessClientID
  353. extclient.IngressGatewayID = nodeid
  354. // set extclient dns to ingressdns if extclient dns is not explicitly set
  355. if (extclient.DNS == "") && (node.IngressDNS != "") {
  356. extclient.DNS = node.IngressDNS
  357. }
  358. extclient.Network = node.Network
  359. host, err := logic.GetHost(node.HostID.String())
  360. if err != nil {
  361. logger.Log(0, r.Header.Get("user"),
  362. fmt.Sprintf("failed to get ingress gateway host for node [%s] info: %v", nodeid, err))
  363. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  364. return
  365. }
  366. listenPort := logic.GetPeerListenPort(host)
  367. extclient.IngressGatewayEndpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), listenPort)
  368. extclient.Enabled = true
  369. parentNetwork, err := logic.GetNetwork(node.Network)
  370. if err == nil { // check if parent network default ACL is enabled (yes) or not (no)
  371. extclient.Enabled = parentNetwork.DefaultACL == "yes"
  372. }
  373. if err := logic.SetClientDefaultACLs(&extclient); err != nil {
  374. slog.Error("failed to set default acls for extclient", "user", r.Header.Get("user"), "network", node.Network, "error", err)
  375. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  376. return
  377. }
  378. if err = logic.CreateExtClient(&extclient); err != nil {
  379. slog.Error("failed to create extclient", "user", r.Header.Get("user"), "network", node.Network, "error", err)
  380. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  381. return
  382. }
  383. slog.Info("created extclient", "user", r.Header.Get("user"), "network", node.Network, "clientid", extclient.ClientID)
  384. w.WriteHeader(http.StatusOK)
  385. go func() {
  386. if err := mq.PublishPeerUpdate(); err != nil {
  387. logger.Log(1, "error setting ext peers on "+nodeid+": "+err.Error())
  388. }
  389. if servercfg.IsDNSMode() {
  390. logic.SetDNS()
  391. }
  392. }()
  393. }
  394. // swagger:route PUT /api/extclients/{network}/{clientid} ext_client updateExtClient
  395. //
  396. // Update an individual extclient.
  397. //
  398. // Schemes: https
  399. //
  400. // Security:
  401. // oauth
  402. //
  403. // Responses:
  404. // 200: extClientResponse
  405. func updateExtClient(w http.ResponseWriter, r *http.Request) {
  406. w.Header().Set("Content-Type", "application/json")
  407. var params = mux.Vars(r)
  408. var update models.CustomExtClient
  409. //var oldExtClient models.ExtClient
  410. var sendPeerUpdate bool
  411. err := json.NewDecoder(r.Body).Decode(&update)
  412. if err != nil {
  413. logger.Log(0, r.Header.Get("user"), "error decoding request body: ",
  414. err.Error())
  415. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  416. return
  417. }
  418. clientid := params["clientid"]
  419. network := params["network"]
  420. oldExtClient, err := logic.GetExtClientByName(clientid)
  421. if err != nil {
  422. slog.Error("failed to retrieve extclient", "user", r.Header.Get("user"), "id", clientid, "error", err)
  423. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  424. return
  425. }
  426. if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), oldExtClient) {
  427. // check if user has access to extclient
  428. slog.Error("failed to get extclient", "network", network, "clientID",
  429. clientid, "error", errors.New("access is denied"))
  430. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
  431. return
  432. }
  433. if oldExtClient.ClientID == update.ClientID {
  434. if err := validateCustomExtClient(&update, false); err != nil {
  435. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  436. return
  437. }
  438. } else {
  439. if err := validateCustomExtClient(&update, true); err != nil {
  440. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  441. return
  442. }
  443. }
  444. var changedID = update.ClientID != oldExtClient.ClientID
  445. if len(update.DeniedACLs) != len(oldExtClient.DeniedACLs) {
  446. sendPeerUpdate = true
  447. logic.SetClientACLs(&oldExtClient, update.DeniedACLs)
  448. }
  449. if !logic.IsSlicesEqual(update.ExtraAllowedIPs, oldExtClient.ExtraAllowedIPs) {
  450. sendPeerUpdate = true
  451. }
  452. if update.Enabled != oldExtClient.Enabled {
  453. sendPeerUpdate = true
  454. }
  455. newclient := logic.UpdateExtClient(&oldExtClient, &update)
  456. if err := logic.DeleteExtClient(oldExtClient.Network, oldExtClient.ClientID); err != nil {
  457. slog.Error("failed to delete ext client", "user", r.Header.Get("user"), "id", oldExtClient.ClientID, "network", oldExtClient.Network, "error", err)
  458. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  459. return
  460. }
  461. if err := logic.SaveExtClient(&newclient); err != nil {
  462. slog.Error("failed to save ext client", "user", r.Header.Get("user"), "id", newclient.ClientID, "network", newclient.Network, "error", err)
  463. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  464. return
  465. }
  466. logger.Log(0, r.Header.Get("user"), "updated ext client", update.ClientID)
  467. if sendPeerUpdate { // need to send a peer update to the ingress node as enablement of one of it's clients has changed
  468. if ingressNode, err := logic.GetNodeByID(newclient.IngressGatewayID); err == nil {
  469. if err = mq.PublishPeerUpdate(); err != nil {
  470. logger.Log(1, "error setting ext peers on", ingressNode.ID.String(), ":", err.Error())
  471. }
  472. }
  473. }
  474. w.WriteHeader(http.StatusOK)
  475. json.NewEncoder(w).Encode(newclient)
  476. if changedID {
  477. go func() {
  478. if servercfg.IsDNSMode() {
  479. logic.SetDNS()
  480. }
  481. }()
  482. }
  483. }
  484. // swagger:route DELETE /api/extclients/{network}/{clientid} ext_client deleteExtClient
  485. //
  486. // Delete an individual extclient.
  487. //
  488. // Schemes: https
  489. //
  490. // Security:
  491. // oauth
  492. //
  493. // Responses:
  494. // 200: successResponse
  495. func deleteExtClient(w http.ResponseWriter, r *http.Request) {
  496. // Set header
  497. w.Header().Set("Content-Type", "application/json")
  498. // get params
  499. var params = mux.Vars(r)
  500. clientid := params["clientid"]
  501. network := params["network"]
  502. extclient, err := logic.GetExtClient(clientid, network)
  503. if err != nil {
  504. err = errors.New("Could not delete extclient " + params["clientid"])
  505. logger.Log(0, r.Header.Get("user"),
  506. fmt.Sprintf("failed to get extclient [%s],network [%s]: %v", clientid, network, err))
  507. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  508. return
  509. }
  510. if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), extclient) {
  511. slog.Error("user not allowed to delete", "network", network, "clientID",
  512. clientid, "error", errors.New("access is denied"))
  513. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
  514. return
  515. }
  516. ingressnode, err := logic.GetNodeByID(extclient.IngressGatewayID)
  517. if err != nil {
  518. logger.Log(0, r.Header.Get("user"),
  519. fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", extclient.IngressGatewayID, err))
  520. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  521. return
  522. }
  523. err = logic.DeleteExtClient(params["network"], params["clientid"])
  524. if err != nil {
  525. logger.Log(0, r.Header.Get("user"),
  526. fmt.Sprintf("failed to delete extclient [%s],network [%s]: %v", clientid, network, err))
  527. err = errors.New("Could not delete extclient " + params["clientid"])
  528. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  529. return
  530. }
  531. go func() {
  532. if err := mq.PublishDeletedClientPeerUpdate(&extclient); err != nil {
  533. logger.Log(1, "error setting ext peers on "+ingressnode.ID.String()+": "+err.Error())
  534. }
  535. if servercfg.IsDNSMode() {
  536. logic.SetDNS()
  537. }
  538. }()
  539. logger.Log(0, r.Header.Get("user"),
  540. "Deleted extclient client", params["clientid"], "from network", params["network"])
  541. logic.ReturnSuccessResponse(w, r, params["clientid"]+" deleted.")
  542. }
  543. // validateCustomExtClient Validates the extclient object
  544. func validateCustomExtClient(customExtClient *models.CustomExtClient, checkID bool) error {
  545. //validate clientid
  546. if customExtClient.ClientID != "" {
  547. if err := isValid(customExtClient.ClientID, checkID); err != nil {
  548. return fmt.Errorf("client validatation: %v", err)
  549. }
  550. }
  551. //extclient.ClientID = customExtClient.ClientID
  552. if len(customExtClient.PublicKey) > 0 {
  553. if _, err := wgtypes.ParseKey(customExtClient.PublicKey); err != nil {
  554. return errInvalidExtClientPubKey
  555. }
  556. //extclient.PublicKey = customExtClient.PublicKey
  557. }
  558. //validate extra ips
  559. if len(customExtClient.ExtraAllowedIPs) > 0 {
  560. for _, ip := range customExtClient.ExtraAllowedIPs {
  561. if _, _, err := net.ParseCIDR(ip); err != nil {
  562. return errInvalidExtClientExtraIP
  563. }
  564. }
  565. //extclient.ExtraAllowedIPs = customExtClient.ExtraAllowedIPs
  566. }
  567. //validate DNS
  568. if customExtClient.DNS != "" {
  569. if ip := net.ParseIP(customExtClient.DNS); ip == nil {
  570. return errInvalidExtClientDNS
  571. }
  572. //extclient.DNS = customExtClient.DNS
  573. }
  574. return nil
  575. }
  576. // isValid Checks if the clientid is valid
  577. func isValid(clientid string, checkID bool) error {
  578. if !validName(clientid) {
  579. return errInvalidExtClientID
  580. }
  581. if checkID {
  582. extclients, err := logic.GetAllExtClients()
  583. if err != nil {
  584. return fmt.Errorf("extclients isValid: %v", err)
  585. }
  586. for _, extclient := range extclients {
  587. if clientid == extclient.ClientID {
  588. return errDuplicateExtClientName
  589. }
  590. }
  591. }
  592. return nil
  593. }