package home import ( "encoding/json" "fmt" "net/http" "github.com/AdguardTeam/AdGuardHome/dnsforward" "github.com/AdguardTeam/golibs/log" "github.com/NYTimes/gziphandler" ) // ---------------- // helper functions // ---------------- func returnOK(w http.ResponseWriter) { _, err := fmt.Fprintf(w, "OK\n") if err != nil { httpError(w, http.StatusInternalServerError, "Couldn't write body: %s", err) } } func httpError(w http.ResponseWriter, code int, format string, args ...interface{}) { text := fmt.Sprintf(format, args...) log.Info(text) http.Error(w, text, code) } // --------------- // dns run control // --------------- func writeAllConfigsAndReloadDNS() error { err := writeAllConfigs() if err != nil { log.Error("Couldn't write all configs: %s", err) return err } return reconfigureDNSServer() } func addDNSAddress(dnsAddresses *[]string, addr string) { if config.DNS.Port != 53 { addr = fmt.Sprintf("%s:%d", addr, config.DNS.Port) } *dnsAddresses = append(*dnsAddresses, addr) } // Get the list of DNS addresses the server is listening on func getDNSAddresses() []string { dnsAddresses := []string{} if config.DNS.BindHost == "0.0.0.0" { ifaces, e := getValidNetInterfacesForWeb() if e != nil { log.Error("Couldn't get network interfaces: %v", e) return []string{} } for _, iface := range ifaces { for _, addr := range iface.Addresses { addDNSAddress(&dnsAddresses, addr) } } } else { addDNSAddress(&dnsAddresses, config.DNS.BindHost) } if config.TLS.Enabled && len(config.TLS.ServerName) != 0 { if config.TLS.PortHTTPS != 0 { addr := config.TLS.ServerName if config.TLS.PortHTTPS != 443 { addr = fmt.Sprintf("%s:%d", addr, config.TLS.PortHTTPS) } addr = fmt.Sprintf("https://%s/dns-query", addr) dnsAddresses = append(dnsAddresses, addr) } if config.TLS.PortDNSOverTLS != 0 { addr := fmt.Sprintf("tls://%s:%d", config.TLS.ServerName, config.TLS.PortDNSOverTLS) dnsAddresses = append(dnsAddresses, addr) } } return dnsAddresses } func handleStatus(w http.ResponseWriter, r *http.Request) { c := dnsforward.FilteringConfig{} if config.dnsServer != nil { config.dnsServer.WriteDiskConfig(&c) } data := map[string]interface{}{ "dns_addresses": getDNSAddresses(), "http_port": config.BindPort, "dns_port": config.DNS.Port, "running": isRunning(), "version": versionString, "language": config.Language, "protection_enabled": c.ProtectionEnabled, "bootstrap_dns": c.BootstrapDNS, "upstream_dns": c.UpstreamDNS, "all_servers": c.AllServers, } jsonVal, err := json.Marshal(data) if err != nil { httpError(w, http.StatusInternalServerError, "Unable to marshal status json: %s", err) return } w.Header().Set("Content-Type", "application/json") _, err = w.Write(jsonVal) if err != nil { httpError(w, http.StatusInternalServerError, "Unable to write response json: %s", err) return } } type profileJSON struct { Name string `json:"name"` } func handleGetProfile(w http.ResponseWriter, r *http.Request) { pj := profileJSON{} u := config.auth.GetCurrentUser(r) pj.Name = u.Name data, err := json.Marshal(pj) if err != nil { httpError(w, http.StatusInternalServerError, "json.Marshal: %s", err) return } _, _ = w.Write(data) } // -------------- // DNS-over-HTTPS // -------------- func handleDOH(w http.ResponseWriter, r *http.Request) { if r.TLS == nil { httpError(w, http.StatusNotFound, "Not Found") return } if !isRunning() { httpError(w, http.StatusInternalServerError, "DNS server is not running") return } config.dnsServer.ServeHTTP(w, r) } // ------------------------ // registration of handlers // ------------------------ func registerControlHandlers() { httpRegister(http.MethodGet, "/control/status", handleStatus) httpRegister(http.MethodPost, "/control/i18n/change_language", handleI18nChangeLanguage) httpRegister(http.MethodGet, "/control/i18n/current_language", handleI18nCurrentLanguage) http.HandleFunc("/control/version.json", postInstall(optionalAuth(handleGetVersionJSON))) httpRegister(http.MethodPost, "/control/update", handleUpdate) httpRegister(http.MethodGet, "/control/access/list", handleAccessList) httpRegister(http.MethodPost, "/control/access/set", handleAccessSet) httpRegister("GET", "/control/profile", handleGetProfile) RegisterFilteringHandlers() RegisterTLSHandlers() RegisterBlockedServicesHandlers() RegisterAuthHandlers() http.HandleFunc("/dns-query", postInstall(handleDOH)) } func httpRegister(method string, url string, handler func(http.ResponseWriter, *http.Request)) { http.Handle(url, postInstallHandler(optionalAuthHandler(gziphandler.GzipHandler(ensureHandler(method, handler))))) }