geodns.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. package main
  2. /*
  3. Copyright 2012-2015 Ask Bjørn Hansen
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. import (
  15. "flag"
  16. "fmt"
  17. "log"
  18. "net"
  19. "os"
  20. "os/signal"
  21. "path/filepath"
  22. "runtime"
  23. "runtime/pprof"
  24. "strings"
  25. "time"
  26. "github.com/abh/geodns/applog"
  27. "github.com/abh/geodns/health"
  28. "github.com/abh/geodns/monitor"
  29. "github.com/abh/geodns/querylog"
  30. "github.com/abh/geodns/server"
  31. "github.com/abh/geodns/targeting"
  32. "github.com/abh/geodns/targeting/geoip2"
  33. "github.com/abh/geodns/zones"
  34. "github.com/pborman/uuid"
  35. )
  36. // VERSION is the current version of GeoDNS
  37. var VERSION string = "3.1.0-dev"
  38. var buildTime string
  39. var gitVersion string
  40. // Set development with the 'devel' build flag to load
  41. // templates from disk instead of from the binary.
  42. var development bool
  43. var (
  44. serverInfo *monitor.ServerInfo
  45. )
  46. var (
  47. flagconfig = flag.String("config", "./dns/", "directory of zone files")
  48. flagconfigfile = flag.String("configfile", "geodns.conf", "filename of config file (in 'config' directory)")
  49. flagcheckconfig = flag.Bool("checkconfig", false, "check configuration and exit")
  50. flagidentifier = flag.String("identifier", "", "identifier (hostname, pop name or similar)")
  51. flaginter = flag.String("interface", "*", "set the listener address")
  52. flagport = flag.String("port", "53", "default port number")
  53. flaghttp = flag.String("http", ":8053", "http listen address (:8053)")
  54. flaglog = flag.Bool("log", false, "be more verbose")
  55. flagcpus = flag.Int("cpus", 1, "Set the maximum number of CPUs to use")
  56. flagLogFile = flag.String("logfile", "", "log to file")
  57. flagPrivateDebug = flag.Bool("privatedebug", false, "Make debugging queries accepted only on loopback")
  58. flagShowVersion = flag.Bool("version", false, "Show GeoDNS version")
  59. cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
  60. memprofile = flag.String("memprofile", "", "write memory profile to this file")
  61. )
  62. func init() {
  63. if len(gitVersion) > 0 {
  64. VERSION = VERSION + "/" + gitVersion
  65. }
  66. log.SetPrefix("geodns ")
  67. log.SetFlags(log.Lmicroseconds | log.Lshortfile)
  68. serverInfo = &monitor.ServerInfo{}
  69. serverInfo.Version = VERSION
  70. serverInfo.UUID = uuid.New()
  71. serverInfo.Started = time.Now()
  72. }
  73. func main() {
  74. flag.Parse()
  75. if *memprofile != "" {
  76. runtime.MemProfileRate = 1024
  77. }
  78. if *flagShowVersion {
  79. extra := []string{}
  80. if len(buildTime) > 0 {
  81. extra = append(extra, buildTime)
  82. }
  83. extra = append(extra, runtime.Version())
  84. fmt.Printf("geodns %s (%s)\n", VERSION, strings.Join(extra, ", "))
  85. os.Exit(0)
  86. }
  87. if *flaglog {
  88. applog.Enabled = true
  89. }
  90. if len(*flagLogFile) > 0 {
  91. applog.FileOpen(*flagLogFile)
  92. }
  93. if len(*flagidentifier) > 0 {
  94. ids := strings.Split(*flagidentifier, ",")
  95. serverInfo.ID = ids[0]
  96. if len(ids) > 1 {
  97. serverInfo.Groups = ids[1:]
  98. }
  99. }
  100. var configFileName string
  101. if filepath.IsAbs(*flagconfigfile) {
  102. configFileName = *flagconfigfile
  103. } else {
  104. configFileName = filepath.Clean(filepath.Join(*flagconfig, *flagconfigfile))
  105. }
  106. if *flagcheckconfig {
  107. err := configReader(configFileName)
  108. if err != nil {
  109. log.Println("Errors reading config", err)
  110. os.Exit(2)
  111. }
  112. dirName := *flagconfig
  113. _, err = zones.NewMuxManager(dirName, &zones.NilReg{})
  114. if err != nil {
  115. log.Println("Errors reading zones", err)
  116. os.Exit(2)
  117. }
  118. // todo: setup health stuff when configured
  119. return
  120. }
  121. if *flagcpus == 0 {
  122. runtime.GOMAXPROCS(runtime.NumCPU())
  123. } else {
  124. runtime.GOMAXPROCS(*flagcpus)
  125. }
  126. log.Printf("Starting geodns %s (%s)\n", VERSION, runtime.Version())
  127. if *cpuprofile != "" {
  128. prof, err := os.Create(*cpuprofile)
  129. if err != nil {
  130. panic(err.Error())
  131. }
  132. pprof.StartCPUProfile(prof)
  133. defer func() {
  134. log.Println("closing file")
  135. prof.Close()
  136. }()
  137. defer func() {
  138. log.Println("stopping profile")
  139. pprof.StopCPUProfile()
  140. }()
  141. }
  142. // load geodns.conf config
  143. configReader(configFileName)
  144. if len(Config.Health.Directory) > 0 {
  145. go health.DirectoryReader(Config.Health.Directory)
  146. }
  147. // load (and re-load) zone data
  148. go configWatcher(configFileName)
  149. if *flaginter == "*" {
  150. addrs, _ := net.InterfaceAddrs()
  151. ips := make([]string, 0)
  152. for _, addr := range addrs {
  153. ip, _, err := net.ParseCIDR(addr.String())
  154. if err != nil {
  155. continue
  156. }
  157. if !(ip.IsLoopback() || ip.IsGlobalUnicast()) {
  158. continue
  159. }
  160. ips = append(ips, ip.String())
  161. }
  162. *flaginter = strings.Join(ips, ",")
  163. }
  164. inter := getInterfaces()
  165. if Config.HasStatHat() {
  166. log.Println("StatHat integration has been removed in favor of more generic metrics")
  167. }
  168. if len(Config.GeoIPDirectory()) > 0 {
  169. geoProvider, err := geoip2.New(Config.GeoIPDirectory())
  170. if err != nil {
  171. log.Printf("Configuring geo provider: %s", err)
  172. }
  173. if geoProvider != nil {
  174. targeting.Setup(geoProvider)
  175. }
  176. }
  177. srv := server.NewServer(serverInfo)
  178. if qlc := Config.QueryLog; len(qlc.Path) > 0 {
  179. ql, err := querylog.NewFileLogger(qlc.Path, qlc.MaxSize, qlc.Keep)
  180. if err != nil {
  181. log.Fatalf("Could not start file query logger: %s", err)
  182. }
  183. srv.SetQueryLogger(ql)
  184. }
  185. muxm, err := zones.NewMuxManager(*flagconfig, srv)
  186. if err != nil {
  187. log.Printf("error loading zones: %s", err)
  188. }
  189. go muxm.Run()
  190. for _, host := range inter {
  191. go srv.ListenAndServe(host)
  192. }
  193. if len(*flaghttp) > 0 {
  194. go func() {
  195. hs := NewHTTPServer(muxm, serverInfo)
  196. hs.Run(*flaghttp)
  197. }()
  198. }
  199. terminate := make(chan os.Signal)
  200. signal.Notify(terminate, os.Interrupt)
  201. <-terminate
  202. log.Printf("geodns: signal received, stopping")
  203. if *memprofile != "" {
  204. f, err := os.Create(*memprofile)
  205. if err != nil {
  206. log.Fatal(err)
  207. }
  208. pprof.WriteHeapProfile(f)
  209. f.Close()
  210. }
  211. applog.FileClose()
  212. }