ext_client.go 22 KB

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