forked from xoe-labs/coredns-ldap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathldap.go
131 lines (109 loc) · 3.21 KB
/
ldap.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// 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 respective 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 (
"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"
"github.com/go-ldap/ldap/v3"
)
type ldapRecord struct {
fqdn string
ip4 net.IP
ip6 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.ip4}
}
func (r *ldapRecord) AAAA() (a *dns.AAAA) {
return &dns.AAAA{Hdr: dns.RR_Header{Name: r.fqdn, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 86400}, AAAA: r.ip6}
}
// 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
// Exported for mocking in test
SearchRequest *ldap.SearchRequest
FqdnAttr string
Ip4Attr string
Ip6Attr string
ldapURL string
pagingLimit uint32
syncInterval time.Duration
username string
password string
sasl bool
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
l.syncInterval = 60 * time.Second
// 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
l.Zones.Z = make(map[string]*file.Zone, len(zoneNames))
for _, zn := range zoneNames {
l.Zones.Z[zn] = nil
}
return l
}
// 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
}
err = l.Client.Bind(l.username, l.password)
if err != nil {
log.Fatal(err)
}
if err := l.UpdateZones(); err != nil {
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"