Skip to content

Commit

Permalink
add --dns-map-exec flag to automatically reconfigure dns server
Browse files Browse the repository at this point in the history
  • Loading branch information
cppforlife committed Oct 1, 2018
1 parent fb22b5b commit 44528f1
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 26 deletions.
1 change: 1 addition & 0 deletions docs/cmd/kwt_net_start.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ sudo -E kwt net start
```
--debug Set logging level to debug
--dns-map strings Domain to IP mapping (can be specified multiple times) (example: 'test.=127.0.0.1')
--dns-map-exec strings Domain to IP mapping command to execute periodically (can be specified multiple times) (example: 'knctl dns-map')
--dns-mdns Start MDNS server (default true)
-r, --dns-recursor strings Recursor (can be specified multiple times)
-h, --help help for start
Expand Down
44 changes: 43 additions & 1 deletion pkg/kwt/cmd/net/dns_factory.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package net

import (
"encoding/json"
"fmt"
"net"
"os/exec"
"strings"

cmdcore "github.com/cppforlife/kwt/pkg/kwt/cmd/core"
Expand Down Expand Up @@ -59,6 +61,8 @@ func (f DNSServerFactory) buildServerOpts(kubeIPResolver ctldns.IPResolver) (ctl
// instead of relying on standard OS X resolution libraries
ctlmdns.Domain: kubeIPResolver,
},

DomainsFunc: DomainsMapExecs{f.dnsFlags.MapExecs}.Get,
}

if len(opts.RecursorAddrs) == 0 {
Expand Down Expand Up @@ -88,12 +92,50 @@ func (f DNSServerFactory) buildServerOpts(kubeIPResolver ctldns.IPResolver) (ctl
return ctldns.BuildOpts{}, fmt.Errorf("Expected domain to IP mapping to have valid IP '%s'", val)
}

opts.Domains[pieces[0]] = ctldns.NewStaticIPResolver(ip)
opts.Domains[pieces[0]] = ctldns.NewStaticIPsResolver([]net.IP{ip})
}

return opts, nil
}

type DomainsMapExecs struct {
cmds []string
}

func (e DomainsMapExecs) Get() (map[string]ctldns.IPResolver, error) {
domainToIPs := map[string][]string{}

for _, cmd := range e.cmds {
out, err := exec.Command("bash", "-c", cmd).Output()
if err != nil {
return nil, fmt.Errorf("Executing DNS map-exec '%s': %s", cmd, err)
}

err = json.Unmarshal(out, &domainToIPs)
if err != nil {
return nil, fmt.Errorf("Unmarshaling DNS map-exec '%s' output: %s", cmd, err)
}
}

domainToResolvers := map[string]ctldns.IPResolver{}

for domain, ipStrs := range domainToIPs {
var ips []net.IP

for _, ipStr := range ipStrs {
ip := net.ParseIP(ipStr)
if ip == nil {
return nil, fmt.Errorf("Unmarshaling DNS map-exec IP '%s'", ipStr)
}
ips = append(ips, ip)
}

domainToResolvers[domain] = ctldns.NewStaticIPsResolver(ips)
}

return domainToResolvers, nil
}

type ResolvConfDNSIPs struct {
ctldns.ResolvConf
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/kwt/cmd/net/dns_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const darwinOS = "darwin"
type DNSFlags struct {
Recursors []string
Map []string
MapExecs []string
MDNS bool
}

Expand All @@ -25,6 +26,7 @@ func (s *DNSFlags) SetWithPrefix(cmd *cobra.Command, prefix string) {

cmd.Flags().StringSliceVarP(&s.Recursors, prefix+"recursor", "r", nil, "Recursor (can be specified multiple times)")
cmd.Flags().StringSliceVar(&s.Map, prefix+"map", nil, "Domain to IP mapping (can be specified multiple times) (example: 'test.=127.0.0.1')")
cmd.Flags().StringSliceVar(&s.MapExecs, prefix+"map-exec", nil, "Domain to IP mapping command to execute periodically (can be specified multiple times) (example: 'knctl dns-map')")

// OS X needs mDNS resolver to cover .local domain
cmd.Flags().BoolVar(&s.MDNS, prefix+"mdns", runtime.GOOS == darwinOS, "Start MDNS server")
Expand Down
64 changes: 64 additions & 0 deletions pkg/kwt/dns/domains_mux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package dns

import (
"time"

"github.com/miekg/dns"
)

type DomainsFunc func() (map[string]IPResolver, error)

type DomainsMux struct {
mux *dns.ServeMux
domainsFunc DomainsFunc
prevDomains map[string]struct{}

logTag string
logger Logger
}

var _ dns.Handler = &DomainsMux{}

func NewDomainsMux(mux *dns.ServeMux, domainsFunc DomainsFunc, logger Logger) *DomainsMux {
return &DomainsMux{mux, domainsFunc, map[string]struct{}{}, "dns.DomainsMux", logger}
}

func (m *DomainsMux) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
m.mux.ServeDNS(w, r)
}

func (m *DomainsMux) UpdateDomainsContiniously() {
for {
err := m.updateDomainsOnce()
if err != nil {
m.logger.Debug(m.logTag, "Failed updating DNS domain handlers: %s", err)
}
time.Sleep(30 * time.Second)
}
}

func (m *DomainsMux) updateDomainsOnce() error {
domains, err := m.domainsFunc()
if err != nil {
return err
}

for domain, resolver := range domains {
delete(m.prevDomains, domain)
m.mux.Handle(domain, NewCustomHandler(resolver, m.logger))
}

// Delete previously registered handlers that were not replaced
for domain, _ := range m.prevDomains {
m.mux.HandleRemove(domain)
}

m.prevDomains = map[string]struct{}{}

// Record what was registered again
for domain, _ := range domains {
m.prevDomains[domain] = struct{}{}
}

return nil
}
8 changes: 6 additions & 2 deletions pkg/kwt/dns/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type BuildOpts struct {
ListenAddrs []string // include port
RecursorAddrs []string // include port
Domains map[string]IPResolver // example "test."
DomainsFunc DomainsFunc
}

func NewFactory() Factory { return Factory{} }
Expand All @@ -26,12 +27,15 @@ func (f Factory) Build(opts BuildOpts, logger Logger) (Server, error) {
mux.Handle("arpa.", arpaHandler)
mux.Handle(".", forwardHandler)

domainsMux := NewDomainsMux(mux, opts.DomainsFunc, logger)
go domainsMux.UpdateDomainsContiniously()

servers := []*dns.Server{}

for _, addr := range opts.ListenAddrs {
servers = append(servers,
&dns.Server{Addr: addr, Net: "tcp", Handler: mux},
&dns.Server{Addr: addr, Net: "udp", Handler: mux, UDPSize: 65535},
&dns.Server{Addr: addr, Net: "tcp", Handler: domainsMux},
&dns.Server{Addr: addr, Net: "udp", Handler: domainsMux, UDPSize: 65535},
)
}

Expand Down
23 changes: 0 additions & 23 deletions pkg/kwt/dns/static_ip_resolver.go

This file was deleted.

23 changes: 23 additions & 0 deletions pkg/kwt/dns/static_ips_resolver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package dns

import (
"net"
)

type StaticIPsResolver struct {
ips []net.IP
}

var _ IPResolver = StaticIPsResolver{}

func NewStaticIPsResolver(ips []net.IP) StaticIPsResolver {
return StaticIPsResolver{ips}
}

func (r StaticIPsResolver) ResolveIPv4(question string) ([]net.IP, bool, error) {
return r.ips, true, nil
}

func (r StaticIPsResolver) ResolveIPv6(question string) ([]net.IP, bool, error) {
return nil, true, nil
}

0 comments on commit 44528f1

Please sign in to comment.