ext_client.go 22 KB

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