ext_client.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  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) || gwnode.InternetGwID != "" {
  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. if client.PostUp != "" && params["type"] != "qr" {
  232. for _, loc := range strings.Split(client.PostUp, "\n") {
  233. postUp.WriteString(fmt.Sprintf("PostUp = %s\n", loc))
  234. }
  235. }
  236. postDown := strings.Builder{}
  237. if client.PostDown != "" && params["type"] != "qr" {
  238. for _, loc := range strings.Split(client.PostDown, "\n") {
  239. postDown.WriteString(fmt.Sprintf("PostDown = %s\n", loc))
  240. }
  241. }
  242. config := fmt.Sprintf(`[Interface]
  243. Address = %s
  244. PrivateKey = %s
  245. MTU = %d
  246. %s
  247. %s
  248. %s
  249. [Peer]
  250. PublicKey = %s
  251. AllowedIPs = %s
  252. Endpoint = %s
  253. %s
  254. `, addrString,
  255. client.PrivateKey,
  256. defaultMTU,
  257. defaultDNS,
  258. postUp.String(),
  259. postDown.String(),
  260. host.PublicKey,
  261. newAllowedIPs,
  262. gwendpoint,
  263. keepalive,
  264. )
  265. if params["type"] == "qr" {
  266. bytes, err := qrcode.Encode(config, qrcode.Medium, 220)
  267. if err != nil {
  268. logger.Log(1, r.Header.Get("user"), "failed to encode qr code: ", err.Error())
  269. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  270. return
  271. }
  272. w.Header().Set("Content-Type", "image/png")
  273. w.WriteHeader(http.StatusOK)
  274. _, err = w.Write(bytes)
  275. if err != nil {
  276. logger.Log(1, r.Header.Get("user"), "response writer error (qr) ", err.Error())
  277. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  278. return
  279. }
  280. return
  281. }
  282. if params["type"] == "file" {
  283. name := client.ClientID + ".conf"
  284. w.Header().Set("Content-Type", "application/config")
  285. w.Header().Set("Content-Disposition", "attachment; filename=\""+name+"\"")
  286. w.WriteHeader(http.StatusOK)
  287. _, err := fmt.Fprint(w, config)
  288. if err != nil {
  289. logger.Log(1, r.Header.Get("user"), "response writer error (file) ", err.Error())
  290. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  291. }
  292. return
  293. }
  294. logger.Log(2, r.Header.Get("user"), "retrieved ext client config")
  295. w.WriteHeader(http.StatusOK)
  296. json.NewEncoder(w).Encode(client)
  297. }
  298. // swagger:route POST /api/extclients/{network}/{nodeid} ext_client createExtClient
  299. //
  300. // Create an individual extclient. Must have valid key and be unique.
  301. //
  302. // Schemes: https
  303. //
  304. // Security:
  305. // oauth
  306. // Responses:
  307. // 200: okResponse
  308. func createExtClient(w http.ResponseWriter, r *http.Request) {
  309. w.Header().Set("Content-Type", "application/json")
  310. var params = mux.Vars(r)
  311. nodeid := params["nodeid"]
  312. ingressExists := checkIngressExists(nodeid)
  313. if !ingressExists {
  314. err := errors.New("ingress does not exist")
  315. slog.Error("failed to create extclient", "user", r.Header.Get("user"), "error", err)
  316. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  317. return
  318. }
  319. var customExtClient models.CustomExtClient
  320. if err := json.NewDecoder(r.Body).Decode(&customExtClient); err != nil {
  321. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  322. return
  323. }
  324. if err := validateCustomExtClient(&customExtClient, true); err != nil {
  325. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  326. return
  327. }
  328. node, err := logic.GetNodeByID(nodeid)
  329. if err != nil {
  330. logger.Log(0, r.Header.Get("user"),
  331. fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", nodeid, err))
  332. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  333. return
  334. }
  335. var userName string
  336. if r.Header.Get("ismaster") == "yes" {
  337. userName = logic.MasterUser
  338. } else {
  339. caller, err := logic.GetUser(r.Header.Get("user"))
  340. if err != nil {
  341. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  342. return
  343. }
  344. userName = caller.UserName
  345. if _, ok := caller.RemoteGwIDs[nodeid]; (!caller.IsAdmin && !caller.IsSuperAdmin) && !ok {
  346. err = errors.New("permission denied")
  347. slog.Error("failed to create extclient", "error", err)
  348. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  349. return
  350. }
  351. // check if user has a config already for remote access client
  352. extclients, err := logic.GetNetworkExtClients(node.Network)
  353. if err != nil {
  354. slog.Error("failed to get extclients", "error", err)
  355. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  356. return
  357. }
  358. for _, extclient := range extclients {
  359. if extclient.RemoteAccessClientID != "" &&
  360. extclient.RemoteAccessClientID == customExtClient.RemoteAccessClientID && nodeid == extclient.IngressGatewayID {
  361. // extclient on the gw already exists for the remote access client
  362. 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")
  363. slog.Error("failed to create extclient", "user", userName, "error", err)
  364. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  365. return
  366. }
  367. }
  368. }
  369. extclient := logic.UpdateExtClient(&models.ExtClient{}, &customExtClient)
  370. extclient.OwnerID = userName
  371. extclient.RemoteAccessClientID = customExtClient.RemoteAccessClientID
  372. extclient.IngressGatewayID = nodeid
  373. // set extclient dns to ingressdns if extclient dns is not explicitly set
  374. if (extclient.DNS == "") && (node.IngressDNS != "") {
  375. extclient.DNS = node.IngressDNS
  376. }
  377. extclient.Network = node.Network
  378. host, err := logic.GetHost(node.HostID.String())
  379. if err != nil {
  380. logger.Log(0, r.Header.Get("user"),
  381. fmt.Sprintf("failed to get ingress gateway host for node [%s] info: %v", nodeid, err))
  382. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  383. return
  384. }
  385. listenPort := logic.GetPeerListenPort(host)
  386. extclient.IngressGatewayEndpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), listenPort)
  387. extclient.Enabled = true
  388. parentNetwork, err := logic.GetNetwork(node.Network)
  389. if err == nil { // check if parent network default ACL is enabled (yes) or not (no)
  390. extclient.Enabled = parentNetwork.DefaultACL == "yes"
  391. }
  392. if err = logic.CreateExtClient(&extclient); err != nil {
  393. slog.Error("failed to create extclient", "user", r.Header.Get("user"), "network", node.Network, "error", err)
  394. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  395. return
  396. }
  397. if err := logic.SetClientDefaultACLs(&extclient); err != nil {
  398. slog.Error("failed to set default acls for extclient", "user", r.Header.Get("user"), "network", node.Network, "error", err)
  399. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  400. return
  401. }
  402. slog.Info("created extclient", "user", r.Header.Get("user"), "network", node.Network, "clientid", extclient.ClientID)
  403. w.WriteHeader(http.StatusOK)
  404. go func() {
  405. if err := mq.PublishPeerUpdate(false); err != nil {
  406. logger.Log(1, "error setting ext peers on "+nodeid+": "+err.Error())
  407. }
  408. if servercfg.IsDNSMode() {
  409. logic.SetDNS()
  410. }
  411. }()
  412. }
  413. // swagger:route PUT /api/extclients/{network}/{clientid} ext_client updateExtClient
  414. //
  415. // Update an individual extclient.
  416. //
  417. // Schemes: https
  418. //
  419. // Security:
  420. // oauth
  421. //
  422. // Responses:
  423. // 200: extClientResponse
  424. func updateExtClient(w http.ResponseWriter, r *http.Request) {
  425. w.Header().Set("Content-Type", "application/json")
  426. var params = mux.Vars(r)
  427. var update models.CustomExtClient
  428. //var oldExtClient models.ExtClient
  429. var sendPeerUpdate bool
  430. err := json.NewDecoder(r.Body).Decode(&update)
  431. if err != nil {
  432. logger.Log(0, r.Header.Get("user"), "error decoding request body: ",
  433. err.Error())
  434. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  435. return
  436. }
  437. clientid := params["clientid"]
  438. network := params["network"]
  439. oldExtClient, err := logic.GetExtClientByName(clientid)
  440. if err != nil {
  441. slog.Error("failed to retrieve extclient", "user", r.Header.Get("user"), "id", clientid, "error", err)
  442. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  443. return
  444. }
  445. if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), oldExtClient) {
  446. // check if user has access to extclient
  447. slog.Error("failed to get extclient", "network", network, "clientID",
  448. clientid, "error", errors.New("access is denied"))
  449. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
  450. return
  451. }
  452. if oldExtClient.ClientID == update.ClientID {
  453. if err := validateCustomExtClient(&update, false); err != nil {
  454. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  455. return
  456. }
  457. } else {
  458. if err := validateCustomExtClient(&update, true); err != nil {
  459. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  460. return
  461. }
  462. }
  463. var changedID = update.ClientID != oldExtClient.ClientID
  464. if !reflect.DeepEqual(update.DeniedACLs, oldExtClient.DeniedACLs) {
  465. sendPeerUpdate = true
  466. logic.SetClientACLs(&oldExtClient, update.DeniedACLs)
  467. }
  468. if !logic.IsSlicesEqual(update.ExtraAllowedIPs, oldExtClient.ExtraAllowedIPs) {
  469. sendPeerUpdate = true
  470. }
  471. if update.Enabled != oldExtClient.Enabled {
  472. sendPeerUpdate = true
  473. }
  474. newclient := logic.UpdateExtClient(&oldExtClient, &update)
  475. if err := logic.DeleteExtClient(oldExtClient.Network, oldExtClient.ClientID); err != nil {
  476. slog.Error("failed to delete ext client", "user", r.Header.Get("user"), "id", oldExtClient.ClientID, "network", oldExtClient.Network, "error", err)
  477. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  478. return
  479. }
  480. if err := logic.SaveExtClient(&newclient); err != nil {
  481. slog.Error("failed to save ext client", "user", r.Header.Get("user"), "id", newclient.ClientID, "network", newclient.Network, "error", err)
  482. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  483. return
  484. }
  485. logger.Log(0, r.Header.Get("user"), "updated ext client", update.ClientID)
  486. w.WriteHeader(http.StatusOK)
  487. json.NewEncoder(w).Encode(newclient)
  488. go func() {
  489. if changedID && servercfg.IsDNSMode() {
  490. logic.SetDNS()
  491. }
  492. if sendPeerUpdate { // need to send a peer update to the ingress node as enablement of one of it's clients has changed
  493. ingressNode, err := logic.GetNodeByID(newclient.IngressGatewayID)
  494. if err == nil {
  495. if err = mq.PublishPeerUpdate(false); err != nil {
  496. logger.Log(1, "error setting ext peers on", ingressNode.ID.String(), ":", err.Error())
  497. }
  498. }
  499. if !update.Enabled {
  500. ingressHost, err := logic.GetHost(ingressNode.HostID.String())
  501. if err != nil {
  502. slog.Error("Failed to get ingress host", "node", ingressNode.ID.String(), "error", err)
  503. return
  504. }
  505. nodes, err := logic.GetAllNodes()
  506. if err != nil {
  507. slog.Error("Failed to get nodes", "error", err)
  508. return
  509. }
  510. go mq.PublishSingleHostPeerUpdate(ingressHost, nodes, nil, []models.ExtClient{oldExtClient}, false)
  511. }
  512. }
  513. }()
  514. }
  515. // swagger:route DELETE /api/extclients/{network}/{clientid} ext_client deleteExtClient
  516. //
  517. // Delete an individual extclient.
  518. //
  519. // Schemes: https
  520. //
  521. // Security:
  522. // oauth
  523. //
  524. // Responses:
  525. // 200: successResponse
  526. func deleteExtClient(w http.ResponseWriter, r *http.Request) {
  527. // Set header
  528. w.Header().Set("Content-Type", "application/json")
  529. // get params
  530. var params = mux.Vars(r)
  531. clientid := params["clientid"]
  532. network := params["network"]
  533. extclient, err := logic.GetExtClient(clientid, network)
  534. if err != nil {
  535. err = errors.New("Could not delete extclient " + params["clientid"])
  536. logger.Log(0, r.Header.Get("user"),
  537. fmt.Sprintf("failed to get extclient [%s],network [%s]: %v", clientid, network, err))
  538. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  539. return
  540. }
  541. if !logic.IsUserAllowedAccessToExtClient(r.Header.Get("user"), extclient) {
  542. slog.Error("user not allowed to delete", "network", network, "clientID",
  543. clientid, "error", errors.New("access is denied"))
  544. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("access is denied"), "forbidden"))
  545. return
  546. }
  547. ingressnode, err := logic.GetNodeByID(extclient.IngressGatewayID)
  548. if err != nil {
  549. logger.Log(0, r.Header.Get("user"),
  550. fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", extclient.IngressGatewayID, err))
  551. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  552. return
  553. }
  554. err = logic.DeleteExtClient(params["network"], params["clientid"])
  555. if err != nil {
  556. logger.Log(0, r.Header.Get("user"),
  557. fmt.Sprintf("failed to delete extclient [%s],network [%s]: %v", clientid, network, err))
  558. err = errors.New("Could not delete extclient " + params["clientid"])
  559. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  560. return
  561. }
  562. // delete client acls
  563. var networkAcls acls.ACLContainer
  564. networkAcls, err = networkAcls.Get(acls.ContainerID(network))
  565. if err != nil {
  566. slog.Error("failed to get network acls", "err", err)
  567. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  568. return
  569. }
  570. for objId := range networkAcls {
  571. delete(networkAcls[objId], acls.AclID(clientid))
  572. }
  573. delete(networkAcls, acls.AclID(clientid))
  574. if _, err = networkAcls.Save(acls.ContainerID(network)); err != nil {
  575. slog.Error("failed to update network acls", "err", err)
  576. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  577. return
  578. }
  579. go func() {
  580. if err := mq.PublishDeletedClientPeerUpdate(&extclient); err != nil {
  581. logger.Log(1, "error setting ext peers on "+ingressnode.ID.String()+": "+err.Error())
  582. }
  583. if servercfg.IsDNSMode() {
  584. logic.SetDNS()
  585. }
  586. }()
  587. logger.Log(0, r.Header.Get("user"),
  588. "Deleted extclient client", params["clientid"], "from network", params["network"])
  589. logic.ReturnSuccessResponse(w, r, params["clientid"]+" deleted.")
  590. }
  591. // validateCustomExtClient Validates the extclient object
  592. func validateCustomExtClient(customExtClient *models.CustomExtClient, checkID bool) error {
  593. v := validator.New()
  594. err := v.Struct(customExtClient)
  595. if err != nil {
  596. return err
  597. }
  598. //validate clientid
  599. if customExtClient.ClientID != "" {
  600. if err := isValid(customExtClient.ClientID, checkID); err != nil {
  601. return fmt.Errorf("client validatation: %v", err)
  602. }
  603. }
  604. //extclient.ClientID = customExtClient.ClientID
  605. if len(customExtClient.PublicKey) > 0 {
  606. if _, err := wgtypes.ParseKey(customExtClient.PublicKey); err != nil {
  607. return errInvalidExtClientPubKey
  608. }
  609. //extclient.PublicKey = customExtClient.PublicKey
  610. }
  611. //validate extra ips
  612. if len(customExtClient.ExtraAllowedIPs) > 0 {
  613. for _, ip := range customExtClient.ExtraAllowedIPs {
  614. if _, _, err := net.ParseCIDR(ip); err != nil {
  615. return errInvalidExtClientExtraIP
  616. }
  617. }
  618. //extclient.ExtraAllowedIPs = customExtClient.ExtraAllowedIPs
  619. }
  620. //validate DNS
  621. if customExtClient.DNS != "" {
  622. if ip := net.ParseIP(customExtClient.DNS); ip == nil {
  623. return errInvalidExtClientDNS
  624. }
  625. //extclient.DNS = customExtClient.DNS
  626. }
  627. return nil
  628. }
  629. // isValid Checks if the clientid is valid
  630. func isValid(clientid string, checkID bool) error {
  631. if !validName(clientid) {
  632. return errInvalidExtClientID
  633. }
  634. if checkID {
  635. extclients, err := logic.GetAllExtClients()
  636. if err != nil {
  637. return fmt.Errorf("extclients isValid: %v", err)
  638. }
  639. for _, extclient := range extclients {
  640. if clientid == extclient.ClientID {
  641. return errDuplicateExtClientName
  642. }
  643. }
  644. }
  645. return nil
  646. }