ext_client.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  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/slices"
  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. w.WriteHeader(http.StatusOK)
  120. json.NewEncoder(w).Encode(client)
  121. }
  122. // swagger:route GET /api/extclients/{network}/{clientid}/{type} ext_client getExtClientConf
  123. //
  124. // Get an individual extclient.
  125. //
  126. // Schemes: https
  127. //
  128. // Security:
  129. // oauth
  130. //
  131. // Responses:
  132. // 200: extClientResponse
  133. func getExtClientConf(w http.ResponseWriter, r *http.Request) {
  134. // set header.
  135. w.Header().Set("Content-Type", "application/json")
  136. var params = mux.Vars(r)
  137. clientid := params["clientid"]
  138. networkid := params["network"]
  139. client, err := logic.GetExtClient(clientid, networkid)
  140. if err != nil {
  141. logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to get extclient for [%s] on network [%s]: %v",
  142. clientid, networkid, err))
  143. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  144. return
  145. }
  146. gwnode, err := logic.GetNodeByID(client.IngressGatewayID)
  147. if err != nil {
  148. logger.Log(0, r.Header.Get("user"),
  149. fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", client.IngressGatewayID, err))
  150. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  151. return
  152. }
  153. host, err := logic.GetHost(gwnode.HostID.String())
  154. if err != nil {
  155. logger.Log(0, r.Header.Get("user"),
  156. fmt.Sprintf("failed to get host for ingress gateway node [%s] info: %v", client.IngressGatewayID, err))
  157. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  158. return
  159. }
  160. network, err := logic.GetParentNetwork(client.Network)
  161. if err != nil {
  162. logger.Log(1, r.Header.Get("user"), "Could not retrieve Ingress Gateway Network", client.Network)
  163. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  164. return
  165. }
  166. preferredIp := strings.TrimSpace(r.URL.Query().Get("preferredip"))
  167. if preferredIp != "" {
  168. allowedPreferredIps := []string{}
  169. for i := range gwnode.AdditionalRagIps {
  170. allowedPreferredIps = append(allowedPreferredIps, gwnode.AdditionalRagIps[i].String())
  171. }
  172. allowedPreferredIps = append(allowedPreferredIps, host.EndpointIP.String())
  173. allowedPreferredIps = append(allowedPreferredIps, host.EndpointIPv6.String())
  174. if !slices.Contains(allowedPreferredIps, preferredIp) {
  175. slog.Warn("preferred endpoint ip is not associated with the RAG. proceeding with preferred ip", "preferred ip", preferredIp)
  176. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("preferred endpoint ip is not associated with the RAG"), "badrequest"))
  177. return
  178. }
  179. if net.ParseIP(preferredIp).To4() == nil {
  180. preferredIp = fmt.Sprintf("[%s]", preferredIp)
  181. }
  182. }
  183. addrString := client.Address
  184. if addrString != "" {
  185. addrString += "/32"
  186. }
  187. if client.Address6 != "" {
  188. if addrString != "" {
  189. addrString += ","
  190. }
  191. addrString += client.Address6 + "/128"
  192. }
  193. keepalive := ""
  194. if network.DefaultKeepalive != 0 {
  195. keepalive = "PersistentKeepalive = " + strconv.Itoa(int(network.DefaultKeepalive))
  196. }
  197. gwendpoint := ""
  198. if preferredIp == "" {
  199. if host.EndpointIP.To4() == nil {
  200. gwendpoint = fmt.Sprintf("[%s]:%d", host.EndpointIPv6.String(), host.ListenPort)
  201. } else {
  202. gwendpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), host.ListenPort)
  203. }
  204. } else {
  205. gwendpoint = fmt.Sprintf("%s:%d", preferredIp, host.ListenPort)
  206. }
  207. var newAllowedIPs string
  208. if logic.IsInternetGw(gwnode) || gwnode.InternetGwID != "" {
  209. egressrange := "0.0.0.0/0"
  210. if gwnode.Address6.IP != nil && client.Address6 != "" {
  211. egressrange += "," + "::/0"
  212. }
  213. newAllowedIPs = egressrange
  214. } else {
  215. newAllowedIPs = network.AddressRange
  216. if newAllowedIPs != "" && network.AddressRange6 != "" {
  217. newAllowedIPs += ","
  218. }
  219. if network.AddressRange6 != "" {
  220. newAllowedIPs += network.AddressRange6
  221. }
  222. if egressGatewayRanges, err := logic.GetEgressRangesOnNetwork(&client); err == nil {
  223. for _, egressGatewayRange := range egressGatewayRanges {
  224. newAllowedIPs += "," + egressGatewayRange
  225. }
  226. }
  227. }
  228. defaultDNS := ""
  229. if client.DNS != "" {
  230. defaultDNS = "DNS = " + client.DNS
  231. } else if gwnode.IngressDNS != "" {
  232. defaultDNS = "DNS = " + gwnode.IngressDNS
  233. }
  234. defaultMTU := 1420
  235. if host.MTU != 0 {
  236. defaultMTU = host.MTU
  237. }
  238. postUp := strings.Builder{}
  239. if client.PostUp != "" && params["type"] != "qr" {
  240. for _, loc := range strings.Split(client.PostUp, "\n") {
  241. postUp.WriteString(fmt.Sprintf("PostUp = %s\n", loc))
  242. }
  243. }
  244. postDown := strings.Builder{}
  245. if client.PostDown != "" && params["type"] != "qr" {
  246. for _, loc := range strings.Split(client.PostDown, "\n") {
  247. postDown.WriteString(fmt.Sprintf("PostDown = %s\n", loc))
  248. }
  249. }
  250. config := fmt.Sprintf(`[Interface]
  251. Address = %s
  252. PrivateKey = %s
  253. MTU = %d
  254. %s
  255. %s
  256. %s
  257. [Peer]
  258. PublicKey = %s
  259. AllowedIPs = %s
  260. Endpoint = %s
  261. %s
  262. `, addrString,
  263. client.PrivateKey,
  264. defaultMTU,
  265. defaultDNS,
  266. postUp.String(),
  267. postDown.String(),
  268. host.PublicKey,
  269. newAllowedIPs,
  270. gwendpoint,
  271. keepalive,
  272. )
  273. if params["type"] == "qr" {
  274. bytes, err := qrcode.Encode(config, qrcode.Medium, 220)
  275. if err != nil {
  276. logger.Log(1, r.Header.Get("user"), "failed to encode qr code: ", err.Error())
  277. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  278. return
  279. }
  280. w.Header().Set("Content-Type", "image/png")
  281. w.WriteHeader(http.StatusOK)
  282. _, err = w.Write(bytes)
  283. if err != nil {
  284. logger.Log(1, r.Header.Get("user"), "response writer error (qr) ", err.Error())
  285. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  286. return
  287. }
  288. return
  289. }
  290. if params["type"] == "file" {
  291. name := client.ClientID + ".conf"
  292. w.Header().Set("Content-Type", "application/config")
  293. w.Header().Set("Content-Disposition", "attachment; filename=\""+name+"\"")
  294. w.WriteHeader(http.StatusOK)
  295. _, err := fmt.Fprint(w, config)
  296. if err != nil {
  297. logger.Log(1, r.Header.Get("user"), "response writer error (file) ", err.Error())
  298. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  299. }
  300. return
  301. }
  302. logger.Log(2, r.Header.Get("user"), "retrieved ext client config")
  303. w.WriteHeader(http.StatusOK)
  304. json.NewEncoder(w).Encode(client)
  305. }
  306. // swagger:route POST /api/extclients/{network}/{nodeid} ext_client createExtClient
  307. //
  308. // Create an individual extclient. Must have valid key and be unique.
  309. //
  310. // Schemes: https
  311. //
  312. // Security:
  313. // oauth
  314. // Responses:
  315. // 200: okResponse
  316. func createExtClient(w http.ResponseWriter, r *http.Request) {
  317. w.Header().Set("Content-Type", "application/json")
  318. var params = mux.Vars(r)
  319. nodeid := params["nodeid"]
  320. ingressExists := checkIngressExists(nodeid)
  321. if !ingressExists {
  322. err := errors.New("ingress does not exist")
  323. slog.Error("failed to create extclient", "user", r.Header.Get("user"), "error", err)
  324. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  325. return
  326. }
  327. var customExtClient models.CustomExtClient
  328. if err := json.NewDecoder(r.Body).Decode(&customExtClient); err != nil {
  329. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  330. return
  331. }
  332. if err := validateCustomExtClient(&customExtClient, true); err != nil {
  333. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  334. return
  335. }
  336. var gateway models.EgressGatewayRequest
  337. gateway.NetID = params["network"]
  338. gateway.Ranges = customExtClient.ExtraAllowedIPs
  339. err := logic.ValidateEgressRange(gateway)
  340. if err != nil {
  341. logger.Log(0, r.Header.Get("user"), "error validating egress range: ", err.Error())
  342. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  343. return
  344. }
  345. node, err := logic.GetNodeByID(nodeid)
  346. if err != nil {
  347. logger.Log(0, r.Header.Get("user"),
  348. fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", nodeid, err))
  349. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  350. return
  351. }
  352. var userName string
  353. if r.Header.Get("ismaster") == "yes" {
  354. userName = logic.MasterUser
  355. } else {
  356. caller, err := logic.GetUser(r.Header.Get("user"))
  357. if err != nil {
  358. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  359. return
  360. }
  361. userName = caller.UserName
  362. // check if user has a config already for remote access client
  363. extclients, err := logic.GetNetworkExtClients(node.Network)
  364. if err != nil {
  365. slog.Error("failed to get extclients", "error", err)
  366. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  367. return
  368. }
  369. for _, extclient := range extclients {
  370. if extclient.RemoteAccessClientID != "" &&
  371. extclient.RemoteAccessClientID == customExtClient.RemoteAccessClientID && extclient.OwnerID == caller.UserName && nodeid == extclient.IngressGatewayID {
  372. // extclient on the gw already exists for the remote access client
  373. err = errors.New("remote client config already exists on the gateway")
  374. slog.Error("failed to create extclient", "user", userName, "error", err)
  375. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  376. return
  377. }
  378. }
  379. }
  380. extclient := logic.UpdateExtClient(&models.ExtClient{}, &customExtClient)
  381. extclient.OwnerID = userName
  382. extclient.RemoteAccessClientID = customExtClient.RemoteAccessClientID
  383. extclient.IngressGatewayID = nodeid
  384. // set extclient dns to ingressdns if extclient dns is not explicitly set
  385. if (extclient.DNS == "") && (node.IngressDNS != "") {
  386. extclient.DNS = node.IngressDNS
  387. }
  388. extclient.Network = node.Network
  389. host, err := logic.GetHost(node.HostID.String())
  390. if err != nil {
  391. logger.Log(0, r.Header.Get("user"),
  392. fmt.Sprintf("failed to get ingress gateway host for node [%s] info: %v", nodeid, err))
  393. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  394. return
  395. }
  396. listenPort := logic.GetPeerListenPort(host)
  397. extclient.IngressGatewayEndpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), listenPort)
  398. extclient.Enabled = true
  399. parentNetwork, err := logic.GetNetwork(node.Network)
  400. if err == nil { // check if parent network default ACL is enabled (yes) or not (no)
  401. extclient.Enabled = parentNetwork.DefaultACL == "yes"
  402. }
  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. slog.Info("created extclient", "user", r.Header.Get("user"), "network", node.Network, "clientid", extclient.ClientID)
  409. w.WriteHeader(http.StatusOK)
  410. go func() {
  411. if err := logic.SetClientDefaultACLs(&extclient); err != nil {
  412. slog.Error("failed to set default acls for extclient", "user", r.Header.Get("user"), "network", node.Network, "error", err)
  413. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  414. return
  415. }
  416. if err := mq.PublishPeerUpdate(false); err != nil {
  417. logger.Log(1, "error setting ext peers on "+nodeid+": "+err.Error())
  418. }
  419. if servercfg.IsDNSMode() {
  420. logic.SetDNS()
  421. }
  422. }()
  423. }
  424. // swagger:route PUT /api/extclients/{network}/{clientid} ext_client updateExtClient
  425. //
  426. // Update an individual extclient.
  427. //
  428. // Schemes: https
  429. //
  430. // Security:
  431. // oauth
  432. //
  433. // Responses:
  434. // 200: extClientResponse
  435. func updateExtClient(w http.ResponseWriter, r *http.Request) {
  436. w.Header().Set("Content-Type", "application/json")
  437. var params = mux.Vars(r)
  438. var update models.CustomExtClient
  439. //var oldExtClient models.ExtClient
  440. var sendPeerUpdate bool
  441. err := json.NewDecoder(r.Body).Decode(&update)
  442. if err != nil {
  443. logger.Log(0, r.Header.Get("user"), "error decoding request body: ",
  444. err.Error())
  445. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  446. return
  447. }
  448. clientid := params["clientid"]
  449. oldExtClient, err := logic.GetExtClientByName(clientid)
  450. if err != nil {
  451. slog.Error("failed to retrieve extclient", "user", r.Header.Get("user"), "id", clientid, "error", err)
  452. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  453. return
  454. }
  455. if oldExtClient.ClientID == update.ClientID {
  456. if err := validateCustomExtClient(&update, false); err != nil {
  457. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  458. return
  459. }
  460. } else {
  461. if err := validateCustomExtClient(&update, true); err != nil {
  462. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  463. return
  464. }
  465. }
  466. var gateway models.EgressGatewayRequest
  467. gateway.NetID = params["network"]
  468. gateway.Ranges = update.ExtraAllowedIPs
  469. err = logic.ValidateEgressRange(gateway)
  470. if err != nil {
  471. logger.Log(0, r.Header.Get("user"), "error validating egress range: ", err.Error())
  472. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  473. return
  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. ingressnode, err := logic.GetNodeByID(extclient.IngressGatewayID)
  554. if err != nil {
  555. logger.Log(0, r.Header.Get("user"),
  556. fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", extclient.IngressGatewayID, err))
  557. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  558. return
  559. }
  560. err = logic.DeleteExtClientAndCleanup(extclient)
  561. if err != nil {
  562. slog.Error("deleteExtClient: ", "Error", err.Error())
  563. err = errors.New("Could not delete extclient " + params["clientid"])
  564. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  565. return
  566. }
  567. go func() {
  568. if err := mq.PublishDeletedClientPeerUpdate(&extclient); err != nil {
  569. slog.Error("error setting ext peers on " + ingressnode.ID.String() + ": " + err.Error())
  570. }
  571. if servercfg.IsDNSMode() {
  572. logic.SetDNS()
  573. }
  574. }()
  575. logger.Log(0, r.Header.Get("user"),
  576. "Deleted extclient client", params["clientid"], "from network", params["network"])
  577. logic.ReturnSuccessResponse(w, r, params["clientid"]+" deleted.")
  578. }
  579. // validateCustomExtClient Validates the extclient object
  580. func validateCustomExtClient(customExtClient *models.CustomExtClient, checkID bool) error {
  581. v := validator.New()
  582. err := v.Struct(customExtClient)
  583. if err != nil {
  584. return err
  585. }
  586. //validate clientid
  587. if customExtClient.ClientID != "" {
  588. if err := isValid(customExtClient.ClientID, checkID); err != nil {
  589. return fmt.Errorf("client validatation: %v", err)
  590. }
  591. }
  592. //extclient.ClientID = customExtClient.ClientID
  593. if len(customExtClient.PublicKey) > 0 {
  594. if _, err := wgtypes.ParseKey(customExtClient.PublicKey); err != nil {
  595. return errInvalidExtClientPubKey
  596. }
  597. //extclient.PublicKey = customExtClient.PublicKey
  598. }
  599. //validate extra ips
  600. if len(customExtClient.ExtraAllowedIPs) > 0 {
  601. for _, ip := range customExtClient.ExtraAllowedIPs {
  602. if _, _, err := net.ParseCIDR(ip); err != nil {
  603. return errInvalidExtClientExtraIP
  604. }
  605. }
  606. //extclient.ExtraAllowedIPs = customExtClient.ExtraAllowedIPs
  607. }
  608. //validate DNS
  609. if customExtClient.DNS != "" {
  610. if ip := net.ParseIP(customExtClient.DNS); ip == nil {
  611. return errInvalidExtClientDNS
  612. }
  613. //extclient.DNS = customExtClient.DNS
  614. }
  615. return nil
  616. }
  617. // isValid Checks if the clientid is valid
  618. func isValid(clientid string, checkID bool) error {
  619. if !validName(clientid) {
  620. return errInvalidExtClientID
  621. }
  622. if checkID {
  623. extclients, err := logic.GetAllExtClients()
  624. if err != nil {
  625. return fmt.Errorf("extclients isValid: %v", err)
  626. }
  627. for _, extclient := range extclients {
  628. if clientid == extclient.ClientID {
  629. return errDuplicateExtClientName
  630. }
  631. }
  632. }
  633. return nil
  634. }