dns

DNS client and server implementations using the Go project's dnsmessage package
Log | Files | Refs | README | LICENSE

commit f4835a3962d972a64a38ccdc989c49ab0020ffb6
parent efd494bd5b7398121f3a56854b91384bd53f358e
Author: Oliver Lowe <o@olowe.co>
Date:   Mon, 22 Nov 2021 16:03:11 +1100

docs: add READMEs, refer to online docs

Diffstat:
DREADME | 11-----------
AREADME.md | 9+++++++++
Acmd/dohproxy/README.md | 25+++++++++++++++++++++++++
Mcmd/dohproxy/dohproxy.go | 26++++++++++++++++++++++++++
4 files changed, 60 insertions(+), 11 deletions(-)

diff --git a/README b/README @@ -1,11 +0,0 @@ -Please don't use this yet - - $ cd cmd/dohproxy - $ go build - $ curl -v --doh-insecure --doh-url https://127.0.0.1:8080/dns-query http://www.olowe.co - -Adjust upstream resolver by changing `quad9` to some other address. - -https://blog.nlnetlabs.nl/dns-over-https-in-unbound/ - -https://datatracker.ietf.org/doc/html/rfc8484 diff --git a/README.md b/README.md @@ -0,0 +1,9 @@ +Package dns provides an interface for interacting with DNS servers over both plain UDP and DNS over TLS (DoT). It uses no third party dependencies. + +# Reference + +[![godocs.io](http://godocs.io/git.sr.ht/~otl/dns?status.svg)](http://godocs.io/git.sr.ht/~otl/dns) + +# Learn More + +For more documentation, see the [documentation site](https://man.sr.ht/~otl/dns-docs) diff --git a/cmd/dohproxy/README.md b/cmd/dohproxy/README.md @@ -0,0 +1,25 @@ +dohproxy is a basic DNS over HTTPS (DoH) server. It forwards all DNS queries to an upstream resolver via plain DNS or DNS over TLS (DoT), and returns the response to the DoH client. + +dohproxy listens on the standard HTTPS port (443) with certificates automatically requested from Let's Encrypt via ACME. DoH requests are made to the standard path `/dns-query`. + +The latest version of dohproxy is running at https://syd.olowe.co. +You can test the server by using the `--doh-url` flag of `curl`(1): + + curl --doh-url https://syd.olowe.co/dns-query http://www.example.com + +# Build + +No make. Just use the standard go tools: + + go build + +# Test + +Run: + + go test + +# Documentation + +The [dohproxy documentation](https://man.sr.ht/~otl/dns-docs/dohproxy) contains +details on configuration. diff --git a/cmd/dohproxy/dohproxy.go b/cmd/dohproxy/dohproxy.go @@ -13,6 +13,12 @@ import ( "git.sr.ht/~otl/dns" ) +type metrics struct { + httpOK int + httpError int + httpBadReq int +} + func dnsHandler(w http.ResponseWriter, req *http.Request) { if v, ok := req.Header["Content-Type"]; ok { for _, s := range v { @@ -20,6 +26,7 @@ func dnsHandler(w http.ResponseWriter, req *http.Request) { err := fmt.Errorf("unsupported media type %s", s) log.Println(err.Error()) http.Error(w, err.Error(), http.StatusUnsupportedMediaType) + counter.httpBadReq++ return } } @@ -32,12 +39,14 @@ func dnsHandler(w http.ResponseWriter, req *http.Request) { err = fmt.Errorf("parse Content-Length: %v", err) log.Println(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) + counter.httpError++ return } if length > dns.MaxMsgSize { err = fmt.Errorf("content length %d larger than permitted %d", length, dns.MaxMsgSize) log.Println(err.Error()) http.Error(w, err.Error(), http.StatusRequestEntityTooLarge) + counter.httpBadReq++ return } } @@ -47,6 +56,7 @@ func dnsHandler(w http.ResponseWriter, req *http.Request) { err := fmt.Errorf("invalid HTTP method %s, must be GET or POST", req.Method) log.Println(err.Error()) http.Error(w, err.Error(), http.StatusNotImplemented) + counter.httpBadReq++ return } @@ -58,6 +68,7 @@ func dnsHandler(w http.ResponseWriter, req *http.Request) { n, err = req.Body.Read(buf) if err != nil && err != io.EOF { http.Error(w, err.Error(), http.StatusInternalServerError) + counter.httpError++ return } req.Body.Close() @@ -71,6 +82,8 @@ func dnsHandler(w http.ResponseWriter, req *http.Request) { if err := msg.Unpack(buf[:n]); err != nil { log.Println("unpack query:", err) http.Error(w, "unpack query: "+err.Error(), http.StatusInternalServerError) + counter.httpError++ + return } var resolved dnsmessage.Message @@ -82,21 +95,33 @@ func dnsHandler(w http.ResponseWriter, req *http.Request) { if err != nil { log.Println(err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) + counter.httpError++ return } packed, err := resolved.Pack() if err != nil { log.Println("pack resolved query:", err.Error()) http.Error(w, err.Error(), http.StatusInternalServerError) + counter.httpError++ return } w.Header().Add("Content-Type", dns.MediaType) if _, err := w.Write(packed); err != nil { log.Fatalln(err) } + counter.httpOK++ } var conf config +var counter metrics + +func metricsHandler (w http.ResponseWriter, req *http.Request) { + w.Header().Add("Content-Type", "text/plain") + w.Write([]byte("# TYPE http_requests_total counter\n")) + w.Write([]byte(fmt.Sprintf("http_requests_total{code=\"%d\"} %d\n", http.StatusOK, counter.httpOK))) + w.Write([]byte(fmt.Sprintf("http_requests_total{code=\"%d\"} %d\n", http.StatusInternalServerError, counter.httpError))) + w.Write([]byte(fmt.Sprintf("http_requests_total{code=\"4xx\"} %d\n", counter.httpBadReq))) +} func main() { var err error @@ -106,5 +131,6 @@ func main() { os.Exit(1) } http.HandleFunc("/dns-query", dnsHandler) + http.HandleFunc("/metrics", metricsHandler) log.Fatalln(http.Serve(autocert.NewListener(conf.listenaddr), nil)) }