2020-06-01 07:59:41 +00:00
|
|
|
// Package ldap is a CoreDNS plugin that resolves A, AAAA y PTR RR from a ldap backend.
|
2018-04-01 11:56:41 +00:00
|
|
|
//
|
2020-06-01 07:59:41 +00:00
|
|
|
// It serves as a backend connector for autoritative zone data.
|
|
|
|
// Ldap is often used for bare metal inventories. This use is the main use case
|
|
|
|
// for this plugin. Other use cases might eventually be supported.
|
2020-06-10 07:16:34 +00:00
|
|
|
// fqdn and ip4 / ip6 information is mapped from it's respective ldap schema and
|
2020-06-01 07:59:41 +00:00
|
|
|
// served as DNS records over coredns. Mapping is configurable. To reduce load
|
|
|
|
// on the backend, a configurable cache is bundled.
|
2020-06-01 07:48:07 +00:00
|
|
|
package ldap
|
2017-07-29 08:17:24 +00:00
|
|
|
|
|
|
|
import (
|
2020-06-09 19:07:31 +00:00
|
|
|
"net"
|
2020-06-08 04:12:18 +00:00
|
|
|
"sync"
|
|
|
|
"time"
|
2017-07-29 08:17:24 +00:00
|
|
|
|
2017-09-15 20:29:47 +00:00
|
|
|
"github.com/coredns/coredns/plugin"
|
2020-06-09 03:01:53 +00:00
|
|
|
"github.com/coredns/coredns/plugin/file"
|
2020-06-03 16:25:04 +00:00
|
|
|
"github.com/coredns/coredns/plugin/pkg/fall"
|
2020-06-08 04:12:18 +00:00
|
|
|
"github.com/coredns/coredns/plugin/pkg/upstream"
|
2018-02-27 11:39:01 +00:00
|
|
|
|
2017-07-29 08:17:24 +00:00
|
|
|
"github.com/miekg/dns"
|
2021-02-10 22:45:14 +00:00
|
|
|
"github.com/go-ldap/ldap/v3"
|
2017-07-29 08:17:24 +00:00
|
|
|
)
|
|
|
|
|
2020-06-09 03:01:53 +00:00
|
|
|
type ldapRecord struct {
|
|
|
|
fqdn string
|
|
|
|
ip net.IP
|
|
|
|
}
|
|
|
|
|
2020-06-10 08:03:59 +00:00
|
|
|
func (r *ldapRecord) A() (a *dns.A) {
|
2020-06-09 03:01:53 +00:00
|
|
|
return &dns.A{Hdr: dns.RR_Header{Name: r.fqdn, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}, A: r.ip}
|
|
|
|
}
|
|
|
|
|
2020-06-01 07:59:41 +00:00
|
|
|
// Ldap is an ldap plugin to serve zone entries from a ldap backend.
|
2020-06-01 07:48:07 +00:00
|
|
|
type Ldap struct {
|
2020-06-09 03:01:53 +00:00
|
|
|
Next plugin.Handler
|
|
|
|
Fall fall.F
|
|
|
|
Upstream *upstream.Upstream
|
|
|
|
Client ldap.Client
|
|
|
|
Zones file.Zones
|
2020-06-08 04:12:18 +00:00
|
|
|
|
2020-06-11 02:47:34 +00:00
|
|
|
// Exported for mocking in test
|
|
|
|
SearchRequest *ldap.SearchRequest
|
|
|
|
FqdnAttr string
|
|
|
|
Ip4Attr string
|
|
|
|
|
|
|
|
ldapURL string
|
|
|
|
pagingLimit uint32
|
|
|
|
syncInterval time.Duration
|
|
|
|
username string
|
|
|
|
password string
|
|
|
|
sasl bool
|
|
|
|
zMu sync.RWMutex
|
|
|
|
ttl time.Duration
|
2020-06-03 16:25:04 +00:00
|
|
|
}
|
2018-04-19 06:25:30 +00:00
|
|
|
|
2020-06-03 17:47:21 +00:00
|
|
|
// New returns an initialized Ldap with defaults.
|
2020-06-09 03:01:53 +00:00
|
|
|
func New(zoneNames []string) *Ldap {
|
|
|
|
l := new(Ldap)
|
|
|
|
l.Zones.Names = zoneNames
|
|
|
|
l.pagingLimit = 0
|
2020-06-11 02:47:34 +00:00
|
|
|
l.syncInterval = 60 * time.Second
|
2020-06-08 04:12:18 +00:00
|
|
|
// SearchRequest defaults
|
2020-06-11 02:47:34 +00:00
|
|
|
l.SearchRequest = new(ldap.SearchRequest)
|
|
|
|
l.SearchRequest.DerefAliases = ldap.NeverDerefAliases // TODO: Reason
|
|
|
|
l.SearchRequest.Scope = ldap.ScopeWholeSubtree // search whole subtree
|
|
|
|
l.SearchRequest.SizeLimit = 500 // TODO: Reason
|
|
|
|
l.SearchRequest.TimeLimit = 500 // TODO: Reason
|
|
|
|
l.SearchRequest.TypesOnly = false // TODO: Reason
|
|
|
|
l.Zones.Z = make(map[string]*file.Zone, len(zoneNames))
|
|
|
|
|
|
|
|
for _, zn := range zoneNames {
|
|
|
|
l.Zones.Z[zn] = nil
|
|
|
|
}
|
2020-06-10 07:41:44 +00:00
|
|
|
|
2020-06-09 03:01:53 +00:00
|
|
|
return l
|
2020-06-03 17:47:21 +00:00
|
|
|
}
|
|
|
|
|
2020-06-04 17:41:04 +00:00
|
|
|
// InitClient initializes a Ldap client.
|
2020-06-03 17:47:21 +00:00
|
|
|
func (l *Ldap) InitClient() (err error) {
|
2020-06-08 04:12:18 +00:00
|
|
|
l.Client, err = ldap.DialURL(l.ldapURL)
|
2020-06-03 17:47:21 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
2020-06-08 04:12:18 +00:00
|
|
|
return err
|
2020-06-03 17:47:21 +00:00
|
|
|
}
|
2020-06-04 17:41:04 +00:00
|
|
|
defer l.Client.Close()
|
2020-06-10 07:41:44 +00:00
|
|
|
|
2020-06-08 04:12:18 +00:00
|
|
|
return nil
|
2020-06-03 17:47:21 +00:00
|
|
|
}
|
|
|
|
|
2020-06-10 02:54:01 +00:00
|
|
|
// SOA returns a syntetic SOA record for a zone.
|
2020-06-10 07:16:34 +00:00
|
|
|
func SOA(zone string) dns.RR {
|
2020-06-10 02:54:01 +00:00
|
|
|
ttl := uint32(300)
|
|
|
|
header := dns.RR_Header{Name: zone, Rrtype: dns.TypeSOA, Ttl: ttl, Class: dns.ClassINET}
|
|
|
|
|
|
|
|
Mbox := hostmaster + "."
|
|
|
|
Ns := "ns.dns."
|
2020-06-10 07:41:44 +00:00
|
|
|
|
2020-06-10 02:54:01 +00:00
|
|
|
if zone[0] != '.' {
|
|
|
|
Mbox += zone
|
|
|
|
Ns += zone
|
|
|
|
}
|
|
|
|
|
|
|
|
return &dns.SOA{Hdr: header,
|
|
|
|
Mbox: Mbox,
|
|
|
|
Ns: Ns,
|
|
|
|
Serial: 12345,
|
|
|
|
Refresh: 7200,
|
|
|
|
Retry: 1800,
|
|
|
|
Expire: 86400,
|
|
|
|
Minttl: ttl,
|
|
|
|
}
|
|
|
|
}
|
2020-06-10 07:16:34 +00:00
|
|
|
|
2020-06-10 02:54:01 +00:00
|
|
|
const hostmaster = "hostmaster"
|