Skip to content

Instantly share code, notes, and snippets.

@grobie
Last active February 2, 2016 09:24
Show Gist options
  • Save grobie/ca8bb6fae5264c139308 to your computer and use it in GitHub Desktop.
Save grobie/ca8bb6fae5264c139308 to your computer and use it in GitHub Desktop.
small experiment to split internal/public DNS requests
package main
import (
"flag"
"fmt"
"log"
"net"
"strings"
"github.com/miekg/dns"
)
func main() {
var (
addr = flag.String("addr", ":5353", "Address to the nameserver on")
domain = flag.String("internal.domain", "", "Internal domain")
internalNS = flag.String("internal.ns", "", "Internal nameserver")
publicNS = flag.String("public.ns", "8.8.8.8:53", "Public nameserver")
)
flag.Parse()
if !strings.HasSuffix(*domain, ".") {
log.Fatal("malformed internal.domain parameter (example: my.domain.)")
}
if *internalNS == "" {
log.Fatal("missing internal.ns parameter")
}
if *publicNS == "" {
log.Fatal("missing public.ns parameter")
}
dns.Handle(".", handle(*domain, *internalNS, *publicNS))
errc := make(chan error, 1)
go runDNS(*addr, "tcp", errc)
go runDNS(*addr, "udp", errc)
log.Printf("started DNS server on %s", *addr)
log.Fatal(<-errc)
}
func handle(domain, internalNS, publicNS string) dns.HandlerFunc {
return func(resp dns.ResponseWriter, req *dns.Msg) {
if len(req.Question) == 0 {
respond(resp, req, dns.RcodeFormatError)
return
}
recursor := publicNS
if strings.HasSuffix(req.Question[0].Name, domain) {
recursor = internalNS
}
network := "udp"
if _, ok := resp.RemoteAddr().(*net.TCPAddr); ok {
network = "tcp"
}
c := &dns.Client{Net: network}
r, _, err := c.Exchange(req, recursor)
if err == nil {
log.Printf("[info] using %s to answer %s", recursor, req.Question[0].Name)
if err := resp.WriteMsg(r); err != nil {
log.Printf("[WARN] dns: failed to respond: %v", err)
}
return
}
respond(resp, req, dns.RcodeServerFailure)
}
}
func respond(resp dns.ResponseWriter, req *dns.Msg, code int) {
m := &dns.Msg{}
m.SetReply(req)
m.RecursionAvailable = true
m.SetRcode(req, code)
resp.WriteMsg(m)
}
func runDNS(addr, net string, errc chan error) {
s := &dns.Server{
Addr: addr,
Net: net,
}
errc <- fmt.Errorf("dns error: %s", s.ListenAndServe())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment