diff --git a/Makefile b/Makefile index c5421e97..f8eab9d4 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ $(STATIC): $(JSFILES) client/node_modules $(TARGET): $(STATIC) *.go coredns_plugin/*.go dnsfilter/*.go mkdir -p $(GOPATH)/src/github.com/AdguardTeam - if [ ! -h $(GOPATH)/src/github.com/AdguardTeam/AdGuardHome ]; then rm -rf $(GOPATH)/src/github.com/AdguardTeam/AdGuardHome && ln -fs ../../../../.. $(GOPATH)/src/github.com/AdguardTeam/AdGuardHome; fi + if [ ! -h $(GOPATH)/src/github.com/AdguardTeam/AdGuardHome ]; then rm -rf $(GOPATH)/src/github.com/AdguardTeam/AdGuardHome && ln -fs $(mkfile_dir) $(GOPATH)/src/github.com/AdguardTeam/AdGuardHome; fi GOPATH=$(GOPATH) go get -v -d . GOPATH=$(GOPATH) GOOS=$(NATIVE_GOOS) GOARCH=$(NATIVE_GOARCH) go get -v github.com/gobuffalo/packr/... mkdir -p $(GOPATH)/src/github.com/AdguardTeam/AdGuardHome/build/static ## work around packr bug diff --git a/control.go b/control.go index 0c895b7e..091c1b3f 100644 --- a/control.go +++ b/control.go @@ -114,109 +114,6 @@ func handleProtectionDisable(w http.ResponseWriter, r *http.Request) { // ----- // stats // ----- -func handleStats(w http.ResponseWriter, r *http.Request) { - resp, err := client.Get("http://127.0.0.1:8618/stats") - if err != nil { - errortext := fmt.Sprintf("Couldn't get stats_top from coredns: %T %s\n", err, err) - log.Println(errortext) - http.Error(w, errortext, http.StatusBadGateway) - return - } - if resp != nil && resp.Body != nil { - defer resp.Body.Close() - } - - // read the body entirely - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - errortext := fmt.Sprintf("Couldn't read response body: %s", err) - log.Println(errortext) - http.Error(w, errortext, http.StatusBadGateway) - return - } - - // forward body entirely with status code - w.Header().Set("Content-Type", "application/json") - w.Header().Set("Content-Length", strconv.Itoa(len(body))) - w.WriteHeader(resp.StatusCode) - _, err = w.Write(body) - if err != nil { - errortext := fmt.Sprintf("Couldn't write body: %s", err) - log.Println(errortext) - http.Error(w, errortext, http.StatusInternalServerError) - } -} - -func handleStatsHistory(w http.ResponseWriter, r *http.Request) { - resp, err := client.Get("http://127.0.0.1:8618/stats_history?" + r.URL.RawQuery) - if err != nil { - errortext := fmt.Sprintf("Couldn't get stats_top from coredns: %T %s\n", err, err) - log.Println(errortext) - http.Error(w, errortext, http.StatusBadGateway) - return - } - if resp != nil && resp.Body != nil { - defer resp.Body.Close() - } - - // read the body entirely - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - errortext := fmt.Sprintf("Couldn't read response body: %s", err) - log.Println(errortext) - http.Error(w, errortext, http.StatusBadGateway) - return - } - - // forward body entirely with status code - w.Header().Set("Content-Type", "application/json") - w.Header().Set("Content-Length", strconv.Itoa(len(body))) - w.WriteHeader(resp.StatusCode) - _, err = w.Write(body) - if err != nil { - errortext := fmt.Sprintf("Couldn't write body: %s", err) - log.Println(errortext) - http.Error(w, errortext, http.StatusInternalServerError) - } -} - -func handleQueryLog(w http.ResponseWriter, r *http.Request) { - isDownload := r.URL.Query().Get("download") != "" - resp, err := client.Get("http://127.0.0.1:8618/querylog") - if err != nil { - errortext := fmt.Sprintf("Couldn't get querylog from coredns: %T %s\n", err, err) - log.Println(errortext) - http.Error(w, errortext, http.StatusBadGateway) - return - } - if resp != nil && resp.Body != nil { - defer resp.Body.Close() - } - - // read the body entirely - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - errortext := fmt.Sprintf("Couldn't read response body: %s", err) - log.Println(errortext) - http.Error(w, errortext, http.StatusBadGateway) - return - } - - // forward body entirely with status code - w.Header().Set("Content-Type", "application/json") - w.Header().Set("Content-Length", strconv.Itoa(len(body))) - if isDownload { - w.Header().Set("Content-Disposition", "attachment; filename=querylog.json") - } - w.WriteHeader(resp.StatusCode) - _, err = w.Write(body) - if err != nil { - errortext := fmt.Sprintf("Couldn't write body: %s", err) - log.Println(errortext) - http.Error(w, errortext, http.StatusInternalServerError) - } -} - func handleQueryLogEnable(w http.ResponseWriter, r *http.Request) { config.CoreDNS.QueryLogEnabled = true httpUpdateConfigReloadDNSReturnOK(w, r) @@ -227,72 +124,6 @@ func handleQueryLogDisable(w http.ResponseWriter, r *http.Request) { httpUpdateConfigReloadDNSReturnOK(w, r) } -func handleStatsReset(w http.ResponseWriter, r *http.Request) { - resp, err := client.Post("http://127.0.0.1:8618/stats_reset", "text/plain", nil) - if err != nil { - errortext := fmt.Sprintf("Couldn't get stats_top from coredns: %T %s\n", err, err) - log.Println(errortext) - http.Error(w, errortext, http.StatusBadGateway) - return - } - if resp != nil && resp.Body != nil { - defer resp.Body.Close() - } - - // read the body entirely - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - errortext := fmt.Sprintf("Couldn't read response body: %s", err) - log.Println(errortext) - http.Error(w, errortext, http.StatusBadGateway) - return - } - - // forward body entirely with status code - w.Header().Set("Content-Type", "application/json") - w.Header().Set("Content-Length", strconv.Itoa(len(body))) - w.WriteHeader(resp.StatusCode) - _, err = w.Write(body) - if err != nil { - errortext := fmt.Sprintf("Couldn't write body: %s", err) - log.Println(errortext) - http.Error(w, errortext, http.StatusInternalServerError) - } -} - -func handleStatsTop(w http.ResponseWriter, r *http.Request) { - resp, err := client.Get("http://127.0.0.1:8618/stats_top") - if err != nil { - errortext := fmt.Sprintf("Couldn't get stats_top from coredns: %T %s\n", err, err) - log.Println(errortext) - http.Error(w, errortext, http.StatusBadGateway) - return - } - if resp != nil && resp.Body != nil { - defer resp.Body.Close() - } - - // read the body entirely - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - errortext := fmt.Sprintf("Couldn't read response body: %s", err) - log.Println(errortext) - http.Error(w, errortext, http.StatusBadGateway) - return - } - - // forward body entirely with status code - w.Header().Set("Content-Type", "application/json") - w.Header().Set("Content-Length", strconv.Itoa(len(body))) - w.WriteHeader(resp.StatusCode) - _, err = w.Write(body) - if err != nil { - errortext := fmt.Sprintf("Couldn't write body: %s", err) - log.Println(errortext) - http.Error(w, errortext, http.StatusInternalServerError) - } -} - func httpError(w http.ResponseWriter, code int, format string, args ...interface{}) { text := fmt.Sprintf(format, args...) log.Println(text) @@ -1107,15 +938,15 @@ func registerControlHandlers() { http.HandleFunc("/control/status", optionalAuth(ensureGET(handleStatus))) http.HandleFunc("/control/enable_protection", optionalAuth(ensurePOST(handleProtectionEnable))) http.HandleFunc("/control/disable_protection", optionalAuth(ensurePOST(handleProtectionDisable))) - http.HandleFunc("/control/querylog", optionalAuth(ensureGET(handleQueryLog))) + http.HandleFunc("/control/querylog", optionalAuth(ensureGET(coredns_plugin.HandleQueryLog))) http.HandleFunc("/control/querylog_enable", optionalAuth(ensurePOST(handleQueryLogEnable))) http.HandleFunc("/control/querylog_disable", optionalAuth(ensurePOST(handleQueryLogDisable))) http.HandleFunc("/control/set_upstream_dns", optionalAuth(ensurePOST(handleSetUpstreamDNS))) http.HandleFunc("/control/test_upstream_dns", optionalAuth(ensurePOST(handleTestUpstreamDNS))) - http.HandleFunc("/control/stats_top", optionalAuth(ensureGET(handleStatsTop))) - http.HandleFunc("/control/stats", optionalAuth(ensureGET(handleStats))) - http.HandleFunc("/control/stats_history", optionalAuth(ensureGET(handleStatsHistory))) - http.HandleFunc("/control/stats_reset", optionalAuth(ensurePOST(handleStatsReset))) + http.HandleFunc("/control/stats_top", optionalAuth(ensureGET(coredns_plugin.HandleStatsTop))) + http.HandleFunc("/control/stats", optionalAuth(ensureGET(coredns_plugin.HandleStats))) + http.HandleFunc("/control/stats_history", optionalAuth(ensureGET(coredns_plugin.HandleStatsHistory))) + http.HandleFunc("/control/stats_reset", optionalAuth(ensurePOST(coredns_plugin.HandleStatsReset))) http.HandleFunc("/control/version.json", optionalAuth(handleGetVersionJSON)) http.HandleFunc("/control/filtering/enable", optionalAuth(ensurePOST(handleFilteringEnable))) http.HandleFunc("/control/filtering/disable", optionalAuth(ensurePOST(handleFilteringDisable))) diff --git a/coredns_plugin/coredns_plugin.go b/coredns_plugin/coredns_plugin.go index 6d51b217..8bd8b74c 100644 --- a/coredns_plugin/coredns_plugin.go +++ b/coredns_plugin/coredns_plugin.go @@ -177,7 +177,9 @@ func setupPlugin(c *caddy.Controller) (*plug, error) { if p.settings.QueryLogEnabled { onceQueryLog.Do(func() { - go startQueryLogServer() // TODO: how to handle errors? + go periodicQueryLogRotate() + go periodicHourlyTopRotate() + go statsRotator() }) } diff --git a/coredns_plugin/coredns_stats.go b/coredns_plugin/coredns_stats.go index 22ad57d0..b138911e 100644 --- a/coredns_plugin/coredns_stats.go +++ b/coredns_plugin/coredns_stats.go @@ -227,7 +227,7 @@ func (h *histogram) Collect(ch chan<- prometheus.Metric) { // ----- // stats // ----- -func handleStats(w http.ResponseWriter, r *http.Request) { +func HandleStats(w http.ResponseWriter, r *http.Request) { const numHours = 24 histrical := generateMapFromStats(&statistics.PerHour, 0, numHours) // sum them up @@ -299,7 +299,7 @@ func generateMapFromStats(stats *periodicStats, start int, end int) map[string]i return result } -func handleStatsHistory(w http.ResponseWriter, r *http.Request) { +func HandleStatsHistory(w http.ResponseWriter, r *http.Request) { // handle time unit and prepare our time window size now := time.Now() timeUnitString := r.URL.Query().Get("time_unit") @@ -378,6 +378,16 @@ func handleStatsHistory(w http.ResponseWriter, r *http.Request) { } } +func HandleStatsReset(w http.ResponseWriter, r *http.Request) { + purgeStats() + _, err := fmt.Fprintf(w, "OK\n") + if err != nil { + errortext := fmt.Sprintf("Couldn't write body: %s", err) + log.Println(errortext) + http.Error(w, errortext, http.StatusInternalServerError) + } +} + func clamp(value, low, high int) int { if value < low { return low diff --git a/coredns_plugin/querylog.go b/coredns_plugin/querylog.go index 34a23bab..787a15b7 100644 --- a/coredns_plugin/querylog.go +++ b/coredns_plugin/querylog.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "log" - "net" "net/http" "os" "path" @@ -108,7 +107,7 @@ func logRequest(question *dns.Msg, answer *dns.Msg, result dnsfilter.Result, ela } } -func handleQueryLog(w http.ResponseWriter, r *http.Request) { +func HandleQueryLog(w http.ResponseWriter, r *http.Request) { queryLogLock.RLock() values := make([]*logEntry, len(queryLogCache)) copy(values, queryLogCache) @@ -226,22 +225,6 @@ func handleQueryLog(w http.ResponseWriter, r *http.Request) { } } -func startQueryLogServer() { - listenAddr := net.JoinHostPort("127.0.0.1", queryLogAPIPort) - - go periodicQueryLogRotate() - go periodicHourlyTopRotate() - go statsRotator() - - http.HandleFunc("/querylog", handleQueryLog) - http.HandleFunc("/stats", handleStats) - http.HandleFunc("/stats_top", handleStatsTop) - http.HandleFunc("/stats_history", handleStatsHistory) - if err := http.ListenAndServe(listenAddr, nil); err != nil { - log.Fatalf("error in ListenAndServe: %s", err) - } -} - func trace(format string, args ...interface{}) { pc := make([]uintptr, 10) // at least 1 entry needed runtime.Callers(2, pc) diff --git a/coredns_plugin/querylog_top.go b/coredns_plugin/querylog_top.go index 78cedd7a..d4cc6e0d 100644 --- a/coredns_plugin/querylog_top.go +++ b/coredns_plugin/querylog_top.go @@ -268,7 +268,7 @@ func fillStatsFromQueryLog() error { return nil } -func handleStatsTop(w http.ResponseWriter, r *http.Request) { +func HandleStatsTop(w http.ResponseWriter, r *http.Request) { domains := map[string]int{} blocked := map[string]int{} clients := map[string]int{}