From 01e05e8df5f56d605dfd75456a424527e76a2955 Mon Sep 17 00:00:00 2001 From: radhitya Date: Sat, 13 Jun 2026 12:46:38 +0700 Subject: dns codec, udp server (reuseport, 4096 buffers), tcp server, doh listener post get without tls, concurrent, ends0, fuzz) --- internal/server/doh.go | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 internal/server/doh.go (limited to 'internal/server/doh.go') diff --git a/internal/server/doh.go b/internal/server/doh.go new file mode 100644 index 0000000..e9cf466 --- /dev/null +++ b/internal/server/doh.go @@ -0,0 +1,75 @@ +package server + +import ( + "encoding/base64" + "github.com/miekg/dns" + "io" + "log/slog" + "net/http" +) + +func (s *Server) dohHandler(w http.ResponseWriter, r *http.Request) { + var raw []byte + + switch r.Method { + case http.MethodPost: + ct := r.Header.Get("Content-Type") + if ct != "application/dns-message" { + http.Error(w, "unsupported content type", http.StatusUnsupportedMediaType) + return + } + body, err := io.ReadAll(http.MaxBytesReader(w, r.Body, 65535)) + if err != nil { + http.Error(w, "read body", http.StatusBadRequest) + return + } + raw = body + case http.MethodGet: + param := r.URL.Query().Get("dns") + if param == "" { + http.Error(w, "missing dns param", http.StatusBadRequest) + return + } + decoded, err := base64.RawURLEncoding.DecodeString(param) + if err != nil { + http.Error(w, "invalid base64url", http.StatusBadRequest) + return + } + raw = decoded + default: + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + + msg := new(dns.Msg) + if err := msg.Unpack(raw); err != nil { + http.Error(w, "invalid dns message", http.StatusBadRequest) + return + } + + if len(msg.Question) == 0 { + http.Error(w, "no question", http.StatusBadRequest) + return + } + + resp := buildResponse(msg) + packed, err := resp.Pack() + if err != nil { + http.Error(w, "pack response", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/dns-message") + w.Header().Set("Cache-Control", "no-cache, max-age=0") + if _, err := w.Write(packed); err != nil { + slog.Error("doh write failed", "err", err) + return + } + + slog.Info("doh query served", + "qname", msg.Question[0].Name, + "qtype", dns.TypeToString[msg.Question[0].Qtype], + "rcode", dns.RcodeToString[resp.Rcode], + "client", r.RemoteAddr, + ) +} -- cgit v1.2.3