From 24e2d5de00f6dbd3df7a932425fb21bc0cd715b6 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 18 Jun 2018 08:04:56 +0200 Subject: [PATCH] dnsd: serve prometheus metrics on port 8053 --- cmd/dnsd/dnsd.go | 23 +++++++++++++++++++++++ internal/dns/dns.go | 22 ++++++++++++++++++++-- internal/netconfig/netconfig.go | 9 +++++++-- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/cmd/dnsd/dnsd.go b/cmd/dnsd/dnsd.go index ce0a50a..f7122dd 100644 --- a/cmd/dnsd/dnsd.go +++ b/cmd/dnsd/dnsd.go @@ -6,15 +6,33 @@ import ( "flag" "io/ioutil" "log" + "net/http" "os" "os/signal" "syscall" + "github.com/gokrazy/gokrazy" + "router7/internal/dhcp4d" "router7/internal/dns" + "router7/internal/multilisten" "router7/internal/netconfig" + + _ "net/http/pprof" ) +func updateListeners() error { + hosts, err := gokrazy.PrivateInterfaceAddrs() + if err != nil { + return err + } + if net1, err := multilisten.IPv6Net1("/perm"); err == nil { + hosts = append(hosts, net1) + } + + return multilisten.ListenAndServe(hosts, "8053", http.DefaultServeMux) +} + func logic() error { // TODO: set correct upstream DNS resolver(s) ip, err := netconfig.LinkAddress("/perm", "lan0") @@ -37,10 +55,15 @@ func logic() error { if err := readLeases(); err != nil { log.Printf("cannot resolve DHCP hostnames: %v", err) } + http.Handle("/metrics", srv.PrometheusHandler()) + updateListeners() ch := make(chan os.Signal, 1) signal.Notify(ch, syscall.SIGUSR1) go func() { for range ch { + if err := updateListeners(); err != nil { + log.Printf("updateListeners: %v", err) + } if err := readLeases(); err != nil { log.Printf("readLeases: %v", err) } diff --git a/internal/dns/dns.go b/internal/dns/dns.go index 05e1a16..61e0def 100644 --- a/internal/dns/dns.go +++ b/internal/dns/dns.go @@ -3,6 +3,7 @@ package dns import ( "log" "net" + "net/http" "os" "strings" "sync" @@ -10,9 +11,10 @@ import ( "router7/internal/dhcp4d" - "golang.org/x/time/rate" - "github.com/miekg/dns" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + "golang.org/x/time/rate" ) type Server struct { @@ -21,6 +23,10 @@ type Server struct { domain string upstream string sometimes *rate.Limiter + prom struct { + registry *prometheus.Registry + queries prometheus.Counter + } mu sync.Mutex hostname, ip string @@ -40,6 +46,13 @@ func NewServer(addr, domain string) *Server { hostname: hostname, ip: ip, } + server.prom.registry = prometheus.NewRegistry() + server.prom.queries = prometheus.NewCounter(prometheus.CounterOpts{ + Name: "dns_queries", + Help: "Number of DNS queries received", + }) + server.prom.registry.MustRegister(server.prom.queries) + server.prom.registry.MustRegister(prometheus.NewGoCollector()) server.initHostsLocked() dns.HandleFunc(".", server.handleRequest) return server @@ -68,6 +81,10 @@ func (s *Server) hostByIP(n string) (string, bool) { return r, ok } +func (s *Server) PrometheusHandler() http.Handler { + return promhttp.HandlerFor(s.prom.registry, promhttp.HandlerOpts{}) +} + func (s *Server) SetLeases(leases []dhcp4d.Lease) { s.mu.Lock() defer s.mu.Unlock() @@ -126,6 +143,7 @@ func isLocalInAddrArpa(q string) bool { // TODO: require search domains to be present, then use HandleFunc("lan.", internalName) func (s *Server) handleRequest(w dns.ResponseWriter, r *dns.Msg) { + s.prom.queries.Inc() if len(r.Question) == 1 { // TODO: answer all questions we can answer q := r.Question[0] if q.Qtype == dns.TypeA && q.Qclass == dns.ClassINET { diff --git a/internal/netconfig/netconfig.go b/internal/netconfig/netconfig.go index 14f19c2..efc469f 100644 --- a/internal/netconfig/netconfig.go +++ b/internal/netconfig/netconfig.go @@ -547,8 +547,13 @@ func Apply(dir, root string) error { } } - if err := notify.Process("/user/dyndns", syscall.SIGUSR1); err != nil { - log.Printf("notifying dyndns: %v", err) + for _, process := range []string{ + "dyndns", // depends on the public IPv4 address + "dnsd", // listens on private IPv4/IPv6 and public IPv6Net1 + } { + if err := notify.Process("/user/"+process, syscall.SIGUSR1); err != nil { + log.Printf("notifying %s: %v", process, err) + } } if err := applySysctl(); err != nil {