2
0

ext_client.go 23 KB

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