# Writing CoreDNS Middleware

> If it is not for me, give it to the next one.

Writing CoreDNS middleware consists out of four parts:

1. The actual middleware; the `ServeDNS` method that gets the request.
2. The setup part, the gets the Corefile configuration and creates the middleware.
3. Documentation.
4. Registration.

Note that part 1 and 2 also need tests!

## Middleware

Let's take a look at the chaos middleware that returns author and version information
in the CH class. The main entry point for the whole thing is the `Chaos` structure. That structure
holds some information and most importantly the `Next` middleware.Handler for chaining it to the
next middleware:

~~~ go
type Chaos struct {
    Next    middleware.Handler
    Version string
    Authors map[string]bool // get randomization for free \o/
}
~~~

The middleware needs to implement the `middleware.Handler` interface. That means implementing the
`ServerDNS` method:

~~~ go
func (c Chaos) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {

    state := middleware.State{W: w, Req: r}

    if state.QClass() != dns.ClassCHAOS ||
        state.QType() != dns.TypeTXT {
            return c.Next.ServeDNS(ctx, w, r)
    }
    /* do the chaos thing */
~~~

Here we create a `state` structure that provides use with some handy helper functions, see the
section helper functions below.

Next we check if we should handle this request, and, if not, call the next middleware to handle it.

In `chaos_test.go` we test the middleware using ResponseRecorder what allows us to inspect the
message sent. This all mimics the `net/http` package of Go that has the same functionality.

Taking an excerpt from the test:

~~~ go
req := new(dns.Msg)
if test.qtype == 0 {
    test.qtype = dns.TypeTXT
}
req.SetQuestion(dns.Fqdn(test.qname), test.qtype)
em.Next = test.next

rec := middleware.NewResponseRecorder(&middleware.TestResponseWriter{})
code, err := em.ServeDNS(ctx, rec, req)
/* ... */
~~~

Calling `em.ServeDNS` with the recorder will record the returned message that can retrieved with
`rec.Msg()`.

## Setup

The setup function for Chaos, parses the Corefile and returns the handler, the whole function is
small enough to display here:

~~~ go
func Chaos(c *Controller) (middleware.Middleware, error) {
    version, authors, err := chaosParse(c)
    if err != nil {
        return nil, err
    }

    return func(next middleware.Handler) middleware.Handler {
        return chaos.Chaos{
            Next:    next,
            Version: version,
            Authors: authors,
        }
    }, nil
}
~~~

This just fills in the Chaos structure and returns it as a middleware.Handler. This *also* needs
tests which should test some example Corefile invocations, see `core/setup/chaos_test.go` for an
example.

## Documentation

Third, write a short document detailing the middleware, see `chaos.md` as an example. It should
explain what the middleware does, how to use it and contain some examples. It will
need an Introduction, a Syntax and an Example section.

## Registration

The file `core/directives.go` contain all the middleware for CoreDNS. This is the place where you'll
let CoreDNS know that your new middleware exists. For chaos we just add

~~~ go
{"chaos", setup.Chaos},
~~~

In the list. The index in the list is important, because this will be the order in which the
middleware will be called.

## Helper functions

As said the `state` structure contains a lot of helper function, for instance `Family`:

~~~ txt
func (s State) Family() int
    Family returns the family of the transport. 1 for IPv4 and 2 for IPv6.
~~~

There are other like `Name` and `Zones` which allow for easier name matching in your middleware.
These are likely to improved and expanded in the future, think of item like getting the UDP buffer
size, DO bit, etc. etc..

