setup.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. package rehosts
  2. import (
  3. "os"
  4. "path/filepath"
  5. "strconv"
  6. "time"
  7. "github.com/coredns/caddy"
  8. "github.com/coredns/coredns/core/dnsserver"
  9. "github.com/coredns/coredns/plugin"
  10. clog "github.com/coredns/coredns/plugin/pkg/log"
  11. )
  12. var log = clog.NewWithPlugin("rehosts")
  13. func init() { plugin.Register("rehosts", setup) }
  14. func periodicRehostsReload(r *Rehosts) chan struct{} {
  15. exitChan := make(chan struct{})
  16. if r.options.reload == 0 {
  17. return exitChan
  18. }
  19. go func() {
  20. tickerChan := time.NewTicker(r.options.reload)
  21. defer tickerChan.Stop()
  22. for {
  23. select {
  24. case <-exitChan:
  25. return
  26. case <-tickerChan.C:
  27. r.readRehosts()
  28. }
  29. }
  30. }()
  31. return exitChan
  32. }
  33. func setup(c *caddy.Controller) error {
  34. r, err := parseConfig(c)
  35. if err != nil {
  36. plugin.Error("rehosts", err)
  37. }
  38. closeChan := periodicRehostsReload(&r)
  39. c.OnStartup(func() error {
  40. r.readRehosts()
  41. return nil
  42. })
  43. c.OnShutdown(func() error {
  44. close(closeChan)
  45. return nil
  46. })
  47. dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
  48. r.Next = next
  49. return r
  50. })
  51. return nil
  52. }
  53. func parseConfig(c *caddy.Controller) (Rehosts, error) {
  54. config := dnsserver.GetConfig(c)
  55. rh := Rehosts{
  56. RehostsFile: &RehostsFile{
  57. path: "/etc/hosts",
  58. options: newOptions(),
  59. },
  60. }
  61. i := 0
  62. for c.Next() {
  63. if i > 0 {
  64. return rh, plugin.ErrOnce
  65. }
  66. i++
  67. args := c.RemainingArgs()
  68. if len(args) >= 1 {
  69. rh.path = args[0]
  70. args = args[1:]
  71. if !filepath.IsAbs(rh.path) && config.Root != "" {
  72. rh.path = filepath.Join(config.Root, rh.path)
  73. }
  74. s, err := os.Stat(rh.path)
  75. if err != nil {
  76. if os.IsNotExist(err) {
  77. log.Warningf("File does not exist: %s", rh.path)
  78. } else {
  79. return rh, c.Errf("unable to access hosts file '%s': %v", rh.path, err)
  80. }
  81. }
  82. if s != nil && s.IsDir() {
  83. log.Warningf("Hosts file %q is a directory", rh.path)
  84. }
  85. }
  86. rh.Origins = plugin.OriginsFromArgsOrServerBlock(args, c.ServerBlockKeys)
  87. for c.NextBlock() {
  88. switch c.Val() {
  89. case "fallthrough":
  90. rh.Fall.SetZonesFromArgs(c.RemainingArgs())
  91. case "ttl":
  92. remaining := c.RemainingArgs()
  93. if len(remaining) < 1 {
  94. return rh, c.Errf("ttl needs a time in second")
  95. }
  96. ttl, err := strconv.Atoi(remaining[0])
  97. if err != nil {
  98. return rh, c.Errf("ttl needs a number of second")
  99. }
  100. if ttl <= 0 || ttl > 65535 {
  101. return rh, c.Errf("ttl provided is invalid")
  102. }
  103. rh.options.ttl = uint32(ttl)
  104. case "reload":
  105. remaining := c.RemainingArgs()
  106. if len(remaining) != 1 {
  107. return rh, c.Errf("reload needs a duration (zero seconds to disable)")
  108. }
  109. reload, err := time.ParseDuration(remaining[0])
  110. if err != nil {
  111. return rh, c.Errf("invalid duration for reload '%s'", remaining[0])
  112. }
  113. if reload < 0 {
  114. return rh, c.Errf("invalid negative duration for reload '%s'", remaining[0])
  115. }
  116. rh.options.reload = reload
  117. default:
  118. return rh, c.Errf("unknown property '%s'", c.Val())
  119. }
  120. }
  121. }
  122. return rh, nil
  123. }