Development of a Handler
Developing a new handler requires the source code of atomdns to be checked out, see
installation for instructions. It’s assume you are in the
cmd/atomdns/ subdirectory.
In this tutorial we are going to implement a handler called foo.
Registration
A new handler must be “registered” in atomdns. This process has been automated and only requires a go generate command, provided the following is done.
The name of our handler is “foo”, so the name of the main handler file must be foo.go and must contain
a Foo type. The Foo type must implement the handlers.Handler interface.
So: mkdir foo, and then $EDITOR handlers/foo/foo.go:
The contents of this file becomes:
Readme
Any handler needs documentation, and foo is not an exception. The documentation style is heavily influenced
by Unix manual pages. So create a handlers/foo/README.md with the following contents:
Once both are saved, run:
… to generate a handlers/foo/zerr.go file that has some bits atomdns uses. foo now is a full fledged
handler, but it doesn’t do much. This also generates a man/atomdns-foo.7 manual page.
If you compile atomdns (go build) and run it, you’ll see foo is listed as a handler:
At this point we assume this handler does not need any setup, so we defer implementing a setup function,
instead we flesh out the HandlerFunc method.
HandlerFunc
We’ll create a HandlerFunc that returns a single A record for every query. The address returned is a document IP address from RFC 5737.
We create an answer message from the reply - this way we can re-use the buffer.
dnsutil.SetReply is documented locally, but also in go.dev.
Next we create our A record:
This utilizes dns.Zone to get the DNS zone that atomdns has linked to our foo handler, i.e.
Would make dns.Zone return “example.org.”.
Lastly we want to perform any registered (by other handlers) modification functions and then io.Copy the
reply back to the client.
This make the full code of handlers/foo/foo.go:
Testing
We can already this what we have now, create a Conffile with this contents:
Then run ./atomdns -c Conffile and query the example.org zone: dig @localhost +noall +answer -p 1053 www.example.org, this should display: example.org. 3600 IN A 198.51.100.1.
Setup
Let’s say we want to make the returned IP address configurable, in the Conffile with something like:
Where the IP is an optional argument to the foo handler.
For this foo needs to implement the handler.Setupper interface.
The Foo type needs to be slightly changed from type Foo int to
Then we create handlers/foo/setup.go, with the following in it:
Here we utilize reading from *dnsserver.Controller to get the token from the configuration file. We check if
we got an IP address (co.RemainingIPs()) and if so set to f’s IP field. If none are set we set the default
address that we used before.
Just by the virtue of having Setup method it will be used by atomdns.
Our HandleFunc does not use this information yet. This difference with the previous iteration is:
With a slightly amended config file we can return any IP we want:
Startup and Shutdown Functions
If for some reason start up function and tear down functions need to be run you can use
- co.OnStartup to run on startup. It is customary to announce your existence:
- co.OnShutdown to run on at shutdown. It is customary to announce your existence:
These need to be added to handlers/foo/setup.go. Note that on
reload these functions are run.