Skip to content

Commit

Permalink
ADD: reverse lookup support from https://github.com/christian-marie/m…
Browse files Browse the repository at this point in the history
  • Loading branch information
andreaspeters committed Aug 1, 2023
1 parent 3c6fc84 commit 5340448
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 12 deletions.
5 changes: 5 additions & 0 deletions docs/docs/configuration-parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ The configuration file should include the following fields:
"weave": ["172.17.0.1"]
},
"timeout": 5,
"reversednson": false,
"httpon": true,
"dnson": true,
"httpport": 8123,
Expand Down Expand Up @@ -82,6 +83,10 @@ It is sufficient to specify just one of the `zk` or `masters` field. If both are

`dnson` is a boolean field that controls whether Mesos-DNS listens for DNS requests or not. The default value is `true`.

`reversednson` is a boolean field that controls whether Mesos-DNS acts as an authoritative nameserver for the in-addr.arpa and ip6.arpa domains, returning unambiguous PTR records to tasks dynamically. Enabling this option will turn
off the previous default of forwarding reverse DNS lookups, which could break many set-ups. It is recommended only to use this experimental feature if you
know what you are doing.

`httpon` is a boolean field that controls whether Mesos-DNS listens for HTTP requests or not. The default value is `true`.

`httpport` is the port number that Mesos-DNS monitors for incoming HTTP requests. The default value is `8123`.
Expand Down
6 changes: 6 additions & 0 deletions docs/docs/naming.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ The following table illustrates the rules that govern SRV generation:
| | yes | yes | {task}.framework.domain | di-port | container-ip |
| _{task}._{proto}.framework.slave.domain | n/a | n/a | {task}.framework.slave.domain | host-port | slave-ip |

# PTR records (Experimental, Reverse DNS)

Mesos-DNS can behave as an authorative server for the ip6.arpa and the in-addr.arpa zones, providing reverse DNS resolution in the form of PTR records for non-ambiguous task records.

This is enabled with the `reversednson` configuration option.

## Other Records

Mesos-DNS generates a few special records:
Expand Down
11 changes: 6 additions & 5 deletions records/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,9 @@ type Config struct {
// Value of RecursionAvailable for responses in Mesos domain
RecurseOn bool
// Enable serving DSN and HTTP requests
DNSOn bool `json:"DnsOn"`
HTTPOn bool `json:"HttpOn"`
DNSOn bool `json:"DnsOn"`
ReverseDNSOn bool `json:"ReverseDnsOn"`
HTTPOn bool `json:"HttpOn"`
// Enable replies for external requests
ExternalOn bool
// EnforceRFC952 will enforce an older, more strict set of rules for DNS labels
Expand Down Expand Up @@ -113,9 +114,9 @@ type Config struct {
// NewConfig return the default config of the resolver
func NewConfig() Config {
return Config{
ZkDetectionTimeout: 30,
RefreshSeconds: 60,
TTL: 60,
ZkDetectionTimeout: 30,
RefreshSeconds: 60,
TTL: 60,
SRVRecordDefaultWeight: 1,
Domain: "mesos",
Port: 53,
Expand Down
36 changes: 29 additions & 7 deletions records/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/AVENTER-UG/mesos-dns/records/state"
"github.com/AVENTER-UG/mesos-dns/records/state/client"
"github.com/AVENTER-UG/mesos-dns/urls"
"github.com/miekg/dns"
"github.com/tv42/zbase32"
)

Expand Down Expand Up @@ -72,6 +73,8 @@ type rrsKind string
const (
// A record types
A rrsKind = "A"
// PTR record types
PTR = "PTR"
// AAAA record types
AAAA rrsKind = "AAAA"
// SRV record types
Expand All @@ -82,6 +85,8 @@ func (kind rrsKind) rrs(rg *RecordGenerator) rrs {
switch kind {
case A:
return rg.As
case PTR:
return rg.PTRs
case AAAA:
return rg.AAAAs
case SRV:
Expand All @@ -97,6 +102,7 @@ type RecordGenerator struct {
As rrs
AAAAs rrs
SRVs rrs
PTRs rrs
SlaveIPs map[string][]string
EnumData EnumerationData
stateLoader func(masters []string) (state.State, error)
Expand Down Expand Up @@ -207,6 +213,7 @@ func (rg *RecordGenerator) InsertState(sj state.State, domain, ns, listener stri
rg.SRVs = rrs{}
rg.As = rrs{}
rg.AAAAs = rrs{}
rg.PTRs = rrs{}
rg.frameworkRecords(sj, domain, spec)
rg.slaveRecords(sj, domain, spec)
rg.listenerRecord(listener, ns)
Expand All @@ -217,8 +224,9 @@ func (rg *RecordGenerator) InsertState(sj state.State, domain, ns, listener stri
}

// frameworkRecords injects A, AAAA, and SRV records into the generator store:
// frameworkname.domain. // resolves to IPs of each framework
// _framework._tcp.frameworkname.domain. // resolves to the driver port and IP of each framework
//
// frameworkname.domain. // resolves to IPs of each framework
// _framework._tcp.frameworkname.domain. // resolves to the driver port and IP of each framework
func (rg *RecordGenerator) frameworkRecords(sj state.State, domain string, spec labels.Func) {
for _, f := range sj.Frameworks {
host, port := f.HostPort()
Expand All @@ -237,8 +245,9 @@ func (rg *RecordGenerator) frameworkRecords(sj state.State, domain string, spec
}

// slaveRecords injects A and SRV records into the generator store:
// slave.domain. // resolves to IPs of all slaves
// _slave._tcp.domain. // resolves to the driver port and IP of all slaves
//
// slave.domain. // resolves to IPs of all slaves
// _slave._tcp.domain. // resolves to the driver port and IP of all slaves
func (rg *RecordGenerator) slaveRecords(sj state.State, domain string, spec labels.Func) {
a := "slave." + domain + "."
for _, slave := range sj.Slaves {
Expand All @@ -262,9 +271,10 @@ func (rg *RecordGenerator) slaveRecords(sj state.State, domain string, spec labe
}

// masterRecord injects A and SRV records into the generator store:
// master.domain. // resolves to IPs of all masters
// masterN.domain. // one IP address for each master
// leader.domain. // one IP address for the leading master
//
// master.domain. // resolves to IPs of all masters
// masterN.domain. // one IP address for each master
// leader.domain. // one IP address for the leading master
//
// The current func implementation makes an assumption about the order of masters:
// it's the order in which you expect the enumerated masterN records to be created.
Expand Down Expand Up @@ -438,6 +448,9 @@ func (rg *RecordGenerator) taskContextRecord(ctx context, task state.Task, f sta
for _, tIP := range ctx.taskIPs {
rg.insertTaskRR(arec+tail, tIP.String(), rrsKindForIP(tIP), enumTask)
rg.insertTaskRR(canonical+tail, tIP.String(), rrsKindForIP(tIP), enumTask)
// insert PTR records, these are only served when ReverseDnsOn is true,
// which sets up a handler for the reveverse DNS zones
rg.insertTaskRR(arec+tail, tIP.String(), PTR, enumTask)
}

for _, sIPStr := range ctx.slaveIPs {
Expand Down Expand Up @@ -546,6 +559,15 @@ func (rg *RecordGenerator) insertTaskRR(name, host string, kind rrsKind, enumTas

func (rg *RecordGenerator) insertRR(name, host string, kind rrsKind) (added bool) {
if rrsByKind := kind.rrs(rg); rrsByKind != nil {
if kind == PTR {
// Flip the octets, add .in-addr.arpa etc
rev, err := dns.ReverseAddr(host)
if err != nil {
return false
}
host = name
name = rev
}
if added = rrsByKind.add(name, host); added {
logging.VeryVerbose.Println("[" + string(kind) + "]\t" + name + ": " + host)
}
Expand Down
39 changes: 39 additions & 0 deletions resolver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ func (res *Resolver) records() *records.RecordGenerator {
func (res *Resolver) LaunchDNS() <-chan error {
// Handers for Mesos requests
dns.HandleFunc(res.config.Domain+".", panicRecover(res.HandleMesos))

if res.config.ReverseDNSOn {
dns.HandleFunc("in-addr.arpa.", panicRecover(res.HandleMesos))
dns.HandleFunc("ip6.arpa.", panicRecover(res.HandleMesos))
}

// Handlers for nonMesos requests
for zone, fwd := range res.zoneFwds {
dns.HandleFunc(
Expand Down Expand Up @@ -261,6 +267,20 @@ func (res *Resolver) formatAAAA(dom string, target string) (*dns.AAAA, error) {
}, nil
}

// returns the PTR resource record pointing from dom (ip) to ptr
func (res *Resolver) formatPTR(dom string, ptr string) (*dns.PTR, error) {
ttl := uint32(res.config.TTL)

return &dns.PTR{
Hdr: dns.RR_Header{
Name: dom,
Rrtype: dns.TypePTR,
Class: dns.ClassINET,
Ttl: ttl},
Ptr: ptr,
}, nil
}

// formatSOA returns the SOA resource record for the mesos domain
func (res *Resolver) formatSOA(dom string) *dns.SOA {
ttl := uint32(res.config.TTL)
Expand Down Expand Up @@ -353,6 +373,8 @@ func (res *Resolver) HandleMesos(w dns.ResponseWriter, r *dns.Msg) {
errs.Add(res.handleSRV(rs, name, m, r))
case dns.TypeA:
errs.Add(res.handleA(rs, name, m))
case dns.TypePTR:
errs.Add(res.handlePTR(rs, name, m))
case dns.TypeAAAA:
errs.Add(res.handleAAAA(rs, name, m))
case dns.TypeSOA:
Expand Down Expand Up @@ -384,6 +406,23 @@ func (res *Resolver) HandleMesos(w dns.ResponseWriter, r *dns.Msg) {
reply(w, m, res.config.SetTruncateBit)
}

func (res *Resolver) handlePTR(rs *records.RecordGenerator, name string, m *dns.Msg) error {
var errs multiError
ptrs := rs.PTRs[name]
// > 1 PTR for a given IP implies ambiguity, so, no soup for you!
if len(ptrs) < 2 {
for ptr := range ptrs {
rr, err := res.formatPTR(name, ptr)
if err != nil {
errs.Add(err)
continue
}
m.Answer = append(m.Answer, rr)
}
}
return errs
}

func (res *Resolver) handleSRV(rs *records.RecordGenerator, name string, m, r *dns.Msg) error {
var errs multiError
aAdded := map[string]struct{}{} // track the A RR's we've already added, avoid dups
Expand Down

0 comments on commit 5340448

Please sign in to comment.