ext_client.go 23 KB

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