Categorygithub.com/jimlambrt/respwriter
modulepackage
0.0.0-20240229021648-6624448290a7
Repository: https://github.com/jimlambrt/respwriter.git
Documentation: pkg.go.dev

# README

respwriter package

Go Reference Go Report Card


respwriter is a Go pkg that provides a meikg/dns.HandlerFunc with support for request timeouts via a dns.ResponseWriter wrapper. Among other things, it provides:

  • NewHandler(...): Creates a new dns.HandlerFunc that wraps the given handler with a RespWriter. The returned handler will use the given logger and requestTimeout to create the RespWriter.
  • NewRespWriter(...): Creates a RespWriter which is a wrapper around dns.ResponseWriter that provides "base" capabilities for the wrapped writer. Among other things, this is useful for ensuring that the wrapped writer is not used after the context is canceled.

Example

./exampes/simple/main.go

  import (
	"fmt"
	"net"
	"time"

	"github.com/jimlambrt/respwriter"
	"github.com/miekg/dns"
)

func main() {
	mux := dns.NewServeMux()
	// wrap the handler with a 100ms timeout
	handlerWithTimeout, err := respwriter.NewHandlerFunc(100*time.Millisecond, new(dnsHandler).ServeDNS)
	if err != nil {
		fmt.Printf("Failed to create handler: %s\n", err.Error())
		return
	}
	mux.HandleFunc(".", handlerWithTimeout)
	pc, err := net.ListenPacket("udp", ":0")

	if err != nil {
		fmt.Printf("Failed to start listener: %s\n", err.Error())
		return
	}

	server := &dns.Server{
		PacketConn: pc,
		Net:        "udp",
		Handler:    mux,
		UDPSize:    65535,
		ReusePort:  true,
	}

	fmt.Printf("Starting DNS server on %s\n", pc.LocalAddr())
	err = server.ListenAndServe()
	if err != nil {
		fmt.Printf("Failed to start server: %s\n", err.Error())
		return
	}
}

type dnsHandler struct{}

func (h *dnsHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
	_, ok := w.(*respwriter.RespWriter)
	if !ok {
		// this cannot happen given the way we're using
		// respwriter.NewHandlerFunc to wrap ServeDNS
		fmt.Println("Failed to cast to RespWriter")
	}
	msg := new(dns.Msg)
	msg.SetReply(r)
	msg.Authoritative = true
	for _, question := range r.Question {
		fmt.Printf("Received query: %s\n", question.Name)
		answers := resolve(question.Name, question.Qtype)
		msg.Answer = append(msg.Answer, answers...)
	}
	w.WriteMsg(msg)
}

func resolve(domain string, qtype uint16) []dns.RR {
	m := new(dns.Msg)
	m.SetQuestion(dns.Fqdn(domain), qtype)
	m.RecursionDesired = true

	c := new(dns.Client)
	in, _, err := c.Exchange(m, "8.8.8.8:53")
	if err != nil {
		fmt.Println(err)
		return nil
	}
	return in.Answer
}

# Packages

No description provided by the author

# Functions

NewHandlerFunc returns a new dns.HandlerFunc that wraps the given handler with a RespWriter.
NewRespWriter returns a new RespWriter that wraps the given dns.ResponseWriter.
WithLogger allows you to specify an optional logger.

# Variables

No description provided by the author

# Structs

RespWriter is a wrapper around dns.ResponseWriter that provides "base" capabilities for the wrapped writer.

# Type aliases

Option defines a common functional options type which can be used in a variadic parameter pattern.