Last active
February 2, 2016 09:24
-
-
Save grobie/ca8bb6fae5264c139308 to your computer and use it in GitHub Desktop.
small experiment to split internal/public DNS requests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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