Commit Diff


commit - efd494bd5b7398121f3a56854b91384bd53f358e
commit + f4835a3962d972a64a38ccdc989c49ab0020ffb6
blob - 1eb11d5777f06ecc8a324d0de1c0172428f45467 (mode 644)
blob + /dev/null
--- README
+++ /dev/null
@@ -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
blob - /dev/null
blob + 0659c0f0cc8f4e900c44b36c5aa2428a71a99481 (mode 644)
--- /dev/null
+++ 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)
blob - /dev/null
blob + f115ce3d610690835f4c3a60eebac23730a3be42 (mode 644)
--- /dev/null
+++ 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.
blob - fc5b9ed23d60d067d3cad2e053f453f573b0da13
blob + 4dfe05064164e62235c18a2944c7105c9d4e15ba
--- cmd/dohproxy/dohproxy.go
+++ 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.Reque
 				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.Reque
 				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.Reque
 		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.Reque
 		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.Reque
 	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,22 +95,34 @@ func dnsHandler(w http.ResponseWriter, req *http.Reque
 	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
 	conf, err = configFromFile("dohproxy.conf")
@@ -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))
 }