coredns-ldap/ldap.go
2020-06-09 21:54:01 -05:00

112 lines
2.9 KiB
Go

// Package ldap is a CoreDNS plugin that resolves A, AAAA y PTR RR from a ldap backend.
//
// 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.
// fqdn and ip4 / ip6 information is mapped from it's repsective ldap schema and
// served as DNS records over coredns. Mapping is configurable. To reduce load
// on the backend, a configurable cache is bundled.
package ldap
import (
"errors"
"net"
"sync"
"time"
"github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/file"
"github.com/coredns/coredns/plugin/pkg/fall"
"github.com/coredns/coredns/plugin/pkg/upstream"
"github.com/miekg/dns"
"gopkg.in/ldap.v3"
)
type ldapRecord struct {
fqdn string
ip net.IP
}
func (r *ldapRecord) A() (A *dns.A) {
return &dns.A{Hdr: dns.RR_Header{Name: r.fqdn, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}, A: r.ip}
}
// Ldap is an ldap plugin to serve zone entries from a ldap backend.
type Ldap struct {
Next plugin.Handler
Fall fall.F
Upstream *upstream.Upstream
Client ldap.Client
Zones file.Zones
searchRequest *ldap.SearchRequest
ldapURL string
pagingLimit uint32
syncInterval time.Duration
username string
password string
sasl bool
fqdnAttr string
ip4Attr string
zMu sync.RWMutex
ttl time.Duration
}
// New returns an initialized Ldap with defaults.
func New(zoneNames []string) *Ldap {
l := new(Ldap)
l.Zones.Names = zoneNames
l.pagingLimit = 0
// SearchRequest defaults
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
return l
}
var (
errNoItems = errors.New("no items found")
errNsNotExposed = errors.New("namespace is not exposed")
errInvalidRequest = errors.New("invalid query name")
)
// InitClient initializes a Ldap client.
func (l *Ldap) InitClient() (err error) {
l.Client, err = ldap.DialURL(l.ldapURL)
if err != nil {
log.Fatal(err)
return err
}
defer l.Client.Close()
return nil
}
// SOA returns a syntetic SOA record for a zone.
func SOA(zone string) (dns.RR) {
ttl := uint32(300)
header := dns.RR_Header{Name: zone, Rrtype: dns.TypeSOA, Ttl: ttl, Class: dns.ClassINET}
Mbox := hostmaster + "."
Ns := "ns.dns."
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,
}
}
const hostmaster = "hostmaster"