dns.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. package controller
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "net/http"
  8. "strings"
  9. "time"
  10. "github.com/google/uuid"
  11. "github.com/gorilla/mux"
  12. "github.com/gravitl/netmaker/database"
  13. "github.com/gravitl/netmaker/db"
  14. "github.com/gravitl/netmaker/logger"
  15. "github.com/gravitl/netmaker/logic"
  16. "github.com/gravitl/netmaker/models"
  17. "github.com/gravitl/netmaker/mq"
  18. "github.com/gravitl/netmaker/schema"
  19. "github.com/gravitl/netmaker/servercfg"
  20. "gorm.io/datatypes"
  21. )
  22. func dnsHandlers(r *mux.Router) {
  23. r.HandleFunc("/api/dns", logic.SecurityCheck(true, http.HandlerFunc(getAllDNS))).
  24. Methods(http.MethodGet)
  25. r.HandleFunc("/api/dns/adm/{network}/nodes", logic.SecurityCheck(true, http.HandlerFunc(getNodeDNS))).
  26. Methods(http.MethodGet)
  27. r.HandleFunc("/api/dns/adm/{network}/custom", logic.SecurityCheck(true, http.HandlerFunc(getCustomDNS))).
  28. Methods(http.MethodGet)
  29. r.HandleFunc("/api/dns/adm/{network}", logic.SecurityCheck(true, http.HandlerFunc(getDNS))).
  30. Methods(http.MethodGet)
  31. r.HandleFunc("/api/dns/adm/{network}/sync", logic.SecurityCheck(true, http.HandlerFunc(syncDNS))).
  32. Methods(http.MethodPost)
  33. r.HandleFunc("/api/dns/{network}", logic.SecurityCheck(true, http.HandlerFunc(createDNS))).
  34. Methods(http.MethodPost)
  35. r.HandleFunc("/api/dns/adm/pushdns", logic.SecurityCheck(true, http.HandlerFunc(pushDNS))).
  36. Methods(http.MethodPost)
  37. r.HandleFunc("/api/dns/{network}/{domain}", logic.SecurityCheck(true, http.HandlerFunc(deleteDNS))).
  38. Methods(http.MethodDelete)
  39. r.HandleFunc("/api/v1/nameserver", logic.SecurityCheck(true, http.HandlerFunc(createNs))).Methods(http.MethodPost)
  40. r.HandleFunc("/api/v1/nameserver", logic.SecurityCheck(true, http.HandlerFunc(listNs))).Methods(http.MethodGet)
  41. r.HandleFunc("/api/v1/nameserver", logic.SecurityCheck(true, http.HandlerFunc(updateNs))).Methods(http.MethodPut)
  42. r.HandleFunc("/api/v1/nameserver", logic.SecurityCheck(true, http.HandlerFunc(deleteEgress))).Methods(http.MethodDelete)
  43. }
  44. // @Summary Create Nameserver
  45. // @Router /api/v1/nameserver [post]
  46. // @Tags DNS
  47. // @Accept json
  48. // @Param body body models.NameserverReq
  49. // @Success 200 {object} models.SuccessResponse
  50. // @Failure 400 {object} models.ErrorResponse
  51. // @Failure 401 {object} models.ErrorResponse
  52. // @Failure 500 {object} models.ErrorResponse
  53. func createNs(w http.ResponseWriter, r *http.Request) {
  54. var req models.NameserverReq
  55. err := json.NewDecoder(r.Body).Decode(&req)
  56. if err != nil {
  57. logger.Log(0, "error decoding request body: ",
  58. err.Error())
  59. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  60. return
  61. }
  62. if err := logic.ValidateNameserverReq(req); err != nil {
  63. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  64. return
  65. }
  66. if req.Tags == nil {
  67. req.Tags = []string{}
  68. }
  69. tagMap := make(datatypes.JSONMap)
  70. for _, tagI := range req.Tags {
  71. tagMap[tagI] = struct{}{}
  72. }
  73. ns := schema.Nameserver{
  74. ID: uuid.New().String(),
  75. Name: req.Name,
  76. Network: req.Network,
  77. Description: req.Description,
  78. MatchDomain: req.MatchDomain,
  79. Servers: req.Servers,
  80. Tags: tagMap,
  81. Status: true,
  82. CreatedBy: r.Header.Get("user"),
  83. CreatedAt: time.Now().UTC(),
  84. }
  85. err = ns.Create(db.WithContext(r.Context()))
  86. if err != nil {
  87. logic.ReturnErrorResponse(
  88. w,
  89. r,
  90. logic.FormatError(errors.New("error creating nameserver "+err.Error()), logic.Internal),
  91. )
  92. return
  93. }
  94. logic.LogEvent(&models.Event{
  95. Action: models.Create,
  96. Source: models.Subject{
  97. ID: r.Header.Get("user"),
  98. Name: r.Header.Get("user"),
  99. Type: models.UserSub,
  100. },
  101. TriggeredBy: r.Header.Get("user"),
  102. Target: models.Subject{
  103. ID: ns.ID,
  104. Name: ns.Name,
  105. Type: models.NameserverSub,
  106. },
  107. NetworkID: models.NetworkID(ns.Network),
  108. Origin: models.Dashboard,
  109. })
  110. go mq.PublishPeerUpdate(false)
  111. logic.ReturnSuccessResponseWithJson(w, r, ns, "created nameserver")
  112. }
  113. // @Summary List Nameservers
  114. // @Router /api/v1/nameserver [get]
  115. // @Tags Auth
  116. // @Accept json
  117. // @Param query network string
  118. // @Success 200 {object} models.SuccessResponse
  119. // @Failure 400 {object} models.ErrorResponse
  120. // @Failure 401 {object} models.ErrorResponse
  121. // @Failure 500 {object} models.ErrorResponse
  122. func listNs(w http.ResponseWriter, r *http.Request) {
  123. network := r.URL.Query().Get("network")
  124. if network == "" {
  125. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("network is required"), "badrequest"))
  126. return
  127. }
  128. ns := schema.Nameserver{Network: network}
  129. list, err := ns.ListByNetwork(db.WithContext(r.Context()))
  130. if err != nil {
  131. logic.ReturnErrorResponse(
  132. w,
  133. r,
  134. logic.FormatError(errors.New("error listing egress resource"+err.Error()), "internal"),
  135. )
  136. return
  137. }
  138. logic.ReturnSuccessResponseWithJson(w, r, list, "fetched nameservers")
  139. }
  140. // @Summary Update Nameserver
  141. // @Router /api/v1/nameserver [put]
  142. // @Tags Auth
  143. // @Accept json
  144. // @Param body body models.NameserverReq
  145. // @Success 200 {object} models.SuccessResponse
  146. // @Failure 400 {object} models.ErrorResponse
  147. // @Failure 401 {object} models.ErrorResponse
  148. // @Failure 500 {object} models.ErrorResponse
  149. func updateNs(w http.ResponseWriter, r *http.Request) {
  150. var updateNs schema.Nameserver
  151. err := json.NewDecoder(r.Body).Decode(&updateNs)
  152. if err != nil {
  153. logger.Log(0, "error decoding request body: ",
  154. err.Error())
  155. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  156. return
  157. }
  158. if err := logic.ValidateUpdateNameserverReq(updateNs); err != nil {
  159. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  160. return
  161. }
  162. if updateNs.Tags == nil {
  163. updateNs.Tags = make(datatypes.JSONMap)
  164. }
  165. ns := schema.Nameserver{ID: updateNs.ID}
  166. err = ns.Get(db.WithContext(r.Context()))
  167. if err != nil {
  168. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  169. return
  170. }
  171. var updateStatus bool
  172. if updateNs.Status != ns.Status {
  173. updateStatus = true
  174. }
  175. event := &models.Event{
  176. Action: models.Update,
  177. Source: models.Subject{
  178. ID: r.Header.Get("user"),
  179. Name: r.Header.Get("user"),
  180. Type: models.UserSub,
  181. },
  182. TriggeredBy: r.Header.Get("user"),
  183. Target: models.Subject{
  184. ID: ns.ID,
  185. Name: updateNs.Name,
  186. Type: models.NameserverSub,
  187. },
  188. Diff: models.Diff{
  189. Old: ns,
  190. New: updateNs,
  191. },
  192. NetworkID: models.NetworkID(ns.Network),
  193. Origin: models.Dashboard,
  194. }
  195. ns.Servers = updateNs.Servers
  196. ns.Tags = updateNs.Tags
  197. ns.Description = updateNs.Description
  198. ns.Name = updateNs.Name
  199. ns.Status = updateNs.Status
  200. ns.UpdatedAt = time.Now().UTC()
  201. err = ns.Update(db.WithContext(context.TODO()))
  202. if err != nil {
  203. logic.ReturnErrorResponse(
  204. w,
  205. r,
  206. logic.FormatError(errors.New("error creating egress resource"+err.Error()), "internal"),
  207. )
  208. return
  209. }
  210. if updateStatus {
  211. ns.UpdateStatus(db.WithContext(context.TODO()))
  212. }
  213. logic.LogEvent(event)
  214. go mq.PublishPeerUpdate(false)
  215. logic.ReturnSuccessResponseWithJson(w, r, ns, "updated nameserver")
  216. }
  217. // @Summary Delete Nameserver Resource
  218. // @Router /api/v1/nameserver [delete]
  219. // @Tags Auth
  220. // @Accept json
  221. // @Param body body models.Egress
  222. // @Success 200 {object} models.SuccessResponse
  223. // @Failure 400 {object} models.ErrorResponse
  224. // @Failure 401 {object} models.ErrorResponse
  225. // @Failure 500 {object} models.ErrorResponse
  226. func deleteNs(w http.ResponseWriter, r *http.Request) {
  227. id := r.URL.Query().Get("id")
  228. if id == "" {
  229. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("id is required"), "badrequest"))
  230. return
  231. }
  232. ns := schema.Nameserver{ID: id}
  233. err := ns.Get(db.WithContext(r.Context()))
  234. if err != nil {
  235. logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.BadReq))
  236. return
  237. }
  238. err = ns.Delete(db.WithContext(r.Context()))
  239. if err != nil {
  240. logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.Internal))
  241. return
  242. }
  243. logic.LogEvent(&models.Event{
  244. Action: models.Delete,
  245. Source: models.Subject{
  246. ID: r.Header.Get("user"),
  247. Name: r.Header.Get("user"),
  248. Type: models.UserSub,
  249. },
  250. TriggeredBy: r.Header.Get("user"),
  251. Target: models.Subject{
  252. ID: ns.ID,
  253. Name: ns.Name,
  254. Type: models.NameserverSub,
  255. },
  256. NetworkID: models.NetworkID(ns.Network),
  257. Origin: models.Dashboard,
  258. })
  259. go mq.PublishPeerUpdate(false)
  260. logic.ReturnSuccessResponseWithJson(w, r, nil, "deleted nameserver resource")
  261. }
  262. // @Summary Gets node DNS entries associated with a network
  263. // @Router /api/dns/{network} [get]
  264. // @Tags DNS
  265. // @Accept json
  266. // @Param network path string true "Network identifier"
  267. // @Success 200 {array} models.DNSEntry
  268. // @Failure 500 {object} models.ErrorResponse
  269. func getNodeDNS(w http.ResponseWriter, r *http.Request) {
  270. w.Header().Set("Content-Type", "application/json")
  271. var dns []models.DNSEntry
  272. var params = mux.Vars(r)
  273. network := params["network"]
  274. dns, err := logic.GetNodeDNS(network)
  275. if err != nil {
  276. logger.Log(0, r.Header.Get("user"),
  277. fmt.Sprintf("failed to get node DNS entries for network [%s]: %v", network, err))
  278. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  279. return
  280. }
  281. w.WriteHeader(http.StatusOK)
  282. json.NewEncoder(w).Encode(dns)
  283. }
  284. // @Summary Get all DNS entries
  285. // @Router /api/dns [get]
  286. // @Tags DNS
  287. // @Accept json
  288. // @Success 200 {array} models.DNSEntry
  289. // @Failure 500 {object} models.ErrorResponse
  290. func getAllDNS(w http.ResponseWriter, r *http.Request) {
  291. w.Header().Set("Content-Type", "application/json")
  292. dns, err := logic.GetAllDNS()
  293. if err != nil {
  294. logger.Log(0, r.Header.Get("user"), "failed to get all DNS entries: ", err.Error())
  295. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  296. return
  297. }
  298. logic.SortDNSEntrys(dns[:])
  299. w.WriteHeader(http.StatusOK)
  300. json.NewEncoder(w).Encode(dns)
  301. }
  302. // @Summary Gets custom DNS entries associated with a network
  303. // @Router /api/dns/adm/{network}/custom [get]
  304. // @Tags DNS
  305. // @Accept json
  306. // @Param network path string true "Network identifier"
  307. // @Success 200 {array} models.DNSEntry
  308. // @Failure 500 {object} models.ErrorResponse
  309. func getCustomDNS(w http.ResponseWriter, r *http.Request) {
  310. w.Header().Set("Content-Type", "application/json")
  311. var dns []models.DNSEntry
  312. var params = mux.Vars(r)
  313. network := params["network"]
  314. dns, err := logic.GetCustomDNS(network)
  315. if err != nil {
  316. logger.Log(
  317. 0,
  318. r.Header.Get("user"),
  319. fmt.Sprintf(
  320. "failed to get custom DNS entries for network [%s]: %v",
  321. network,
  322. err.Error(),
  323. ),
  324. )
  325. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  326. return
  327. }
  328. w.WriteHeader(http.StatusOK)
  329. json.NewEncoder(w).Encode(dns)
  330. }
  331. // @Summary Get all DNS entries associated with the network
  332. // @Router /api/dns/adm/{network} [get]
  333. // @Tags DNS
  334. // @Accept json
  335. // @Param network path string true "Network identifier"
  336. // @Success 200 {array} models.DNSEntry
  337. // @Failure 500 {object} models.ErrorResponse
  338. func getDNS(w http.ResponseWriter, r *http.Request) {
  339. w.Header().Set("Content-Type", "application/json")
  340. var dns []models.DNSEntry
  341. var params = mux.Vars(r)
  342. network := params["network"]
  343. dns, err := logic.GetDNS(network)
  344. if err != nil {
  345. logger.Log(0, r.Header.Get("user"),
  346. fmt.Sprintf("failed to get all DNS entries for network [%s]: %v", network, err.Error()))
  347. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  348. return
  349. }
  350. w.WriteHeader(http.StatusOK)
  351. json.NewEncoder(w).Encode(dns)
  352. }
  353. // @Summary Create a new DNS entry
  354. // @Router /api/dns/adm/{network} [post]
  355. // @Tags DNS
  356. // @Accept json
  357. // @Param network path string true "Network identifier"
  358. // @Param body body models.DNSEntry true "DNS entry details"
  359. // @Success 200 {object} models.DNSEntry
  360. // @Failure 400 {object} models.ErrorResponse
  361. // @Failure 500 {object} models.ErrorResponse
  362. func createDNS(w http.ResponseWriter, r *http.Request) {
  363. w.Header().Set("Content-Type", "application/json")
  364. var entry models.DNSEntry
  365. var params = mux.Vars(r)
  366. netID := params["network"]
  367. _ = json.NewDecoder(r.Body).Decode(&entry)
  368. entry.Network = params["network"]
  369. err := logic.ValidateDNSCreate(entry)
  370. if err != nil {
  371. logger.Log(0, r.Header.Get("user"),
  372. fmt.Sprintf("invalid DNS entry %+v: %v", entry, err))
  373. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  374. return
  375. }
  376. // check if default domain is appended if not append
  377. if logic.GetDefaultDomain() != "" &&
  378. !strings.HasSuffix(entry.Name, logic.GetDefaultDomain()) {
  379. entry.Name += "." + logic.GetDefaultDomain()
  380. }
  381. entry, err = logic.CreateDNS(entry)
  382. if err != nil {
  383. logger.Log(0, r.Header.Get("user"),
  384. fmt.Sprintf("Failed to create DNS entry %+v: %v", entry, err))
  385. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  386. return
  387. }
  388. if servercfg.IsDNSMode() {
  389. err = logic.SetDNS()
  390. if err != nil {
  391. logger.Log(0, r.Header.Get("user"),
  392. fmt.Sprintf("Failed to set DNS entries on file: %v", err))
  393. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  394. return
  395. }
  396. }
  397. if logic.GetManageDNS() {
  398. mq.SendDNSSyncByNetwork(netID)
  399. }
  400. logger.Log(1, "new DNS record added:", entry.Name)
  401. logger.Log(2, r.Header.Get("user"),
  402. fmt.Sprintf("DNS entry is set: %+v", entry))
  403. w.WriteHeader(http.StatusOK)
  404. json.NewEncoder(w).Encode(entry)
  405. }
  406. // @Summary Delete a DNS entry
  407. // @Router /api/dns/{network}/{domain} [delete]
  408. // @Tags DNS
  409. // @Accept json
  410. // @Param network path string true "Network identifier"
  411. // @Param domain path string true "Domain Name"
  412. // @Success 200 {array} models.DNSEntry
  413. // @Failure 500 {object} models.ErrorResponse
  414. func deleteDNS(w http.ResponseWriter, r *http.Request) {
  415. // Set header
  416. w.Header().Set("Content-Type", "application/json")
  417. // get params
  418. var params = mux.Vars(r)
  419. netID := params["network"]
  420. entrytext := params["domain"] + "." + params["network"]
  421. err := logic.DeleteDNS(params["domain"], params["network"])
  422. if err != nil {
  423. logger.Log(0, "failed to delete dns entry: ", entrytext)
  424. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  425. return
  426. }
  427. logger.Log(1, "deleted dns entry: ", entrytext)
  428. if servercfg.IsDNSMode() {
  429. err = logic.SetDNS()
  430. if err != nil {
  431. logger.Log(0, r.Header.Get("user"),
  432. fmt.Sprintf("Failed to set DNS entries on file: %v", err))
  433. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  434. return
  435. }
  436. }
  437. if logic.GetManageDNS() {
  438. mq.SendDNSSyncByNetwork(netID)
  439. }
  440. json.NewEncoder(w).Encode(entrytext + " deleted.")
  441. }
  442. // GetDNSEntry - gets a DNS entry
  443. func GetDNSEntry(domain string, network string) (models.DNSEntry, error) {
  444. var entry models.DNSEntry
  445. key, err := logic.GetRecordKey(domain, network)
  446. if err != nil {
  447. return entry, err
  448. }
  449. record, err := database.FetchRecord(database.DNS_TABLE_NAME, key)
  450. if err != nil {
  451. return entry, err
  452. }
  453. err = json.Unmarshal([]byte(record), &entry)
  454. return entry, err
  455. }
  456. // @Summary Push DNS entries to nameserver
  457. // @Router /api/dns/adm/pushdns [post]
  458. // @Tags DNS
  459. // @Accept json
  460. // @Success 200 {string} string "DNS Pushed to CoreDNS"
  461. // @Failure 400 {object} models.ErrorResponse
  462. // @Failure 500 {object} models.ErrorResponse
  463. func pushDNS(w http.ResponseWriter, r *http.Request) {
  464. // Set header
  465. w.Header().Set("Content-Type", "application/json")
  466. if !servercfg.IsDNSMode() {
  467. logic.ReturnErrorResponse(
  468. w,
  469. r,
  470. logic.FormatError(errors.New("DNS Mode is set to off"), "badrequest"),
  471. )
  472. return
  473. }
  474. err := logic.SetDNS()
  475. if err != nil {
  476. logger.Log(0, r.Header.Get("user"),
  477. fmt.Sprintf("Failed to set DNS entries on file: %v", err))
  478. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  479. return
  480. }
  481. logger.Log(1, r.Header.Get("user"), "pushed DNS updates to nameserver")
  482. json.NewEncoder(w).Encode("DNS Pushed to CoreDNS")
  483. }
  484. // @Summary Sync DNS entries for a given network
  485. // @Router /api/dns/adm/{network}/sync [post]
  486. // @Tags DNS
  487. // @Accept json
  488. // @Success 200 {string} string "DNS Sync completed successfully"
  489. // @Failure 400 {object} models.ErrorResponse
  490. // @Failure 500 {object} models.ErrorResponse
  491. func syncDNS(w http.ResponseWriter, r *http.Request) {
  492. // Set header
  493. w.Header().Set("Content-Type", "application/json")
  494. if !logic.GetManageDNS() {
  495. logic.ReturnErrorResponse(
  496. w,
  497. r,
  498. logic.FormatError(errors.New("manage DNS is set to false"), "badrequest"),
  499. )
  500. return
  501. }
  502. var params = mux.Vars(r)
  503. netID := params["network"]
  504. k, err := logic.GetDNS(netID)
  505. if err == nil && len(k) > 0 {
  506. err = mq.PushSyncDNS(k)
  507. }
  508. if err != nil {
  509. logger.Log(0, r.Header.Get("user"),
  510. fmt.Sprintf("Failed to Sync DNS entries to network %s: %v", netID, err))
  511. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  512. return
  513. }
  514. logger.Log(1, r.Header.Get("user"), "DNS Sync complelted successfully")
  515. json.NewEncoder(w).Encode("DNS Sync completed successfully")
  516. }