forked from xoe-labs/coredns-ldap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sync.go
115 lines (97 loc) · 2.53 KB
/
sync.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
package ldap
import (
"context"
"fmt"
"strings"
"net"
"time"
"github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/file"
)
// Run updates the zone from ldap.
func (l *Ldap) Run(ctx context.Context) error {
if err := l.UpdateZones(); err != nil {
return err
}
loop := func() {
for {
select {
case <-ctx.Done():
log.Infof("Breaking out of Ldap update loop: %v", ctx.Err())
return
case <-time.After(l.syncInterval):
if err := l.UpdateZones(); err != nil && ctx.Err() == nil {
log.Errorf("Failed to update zones: %v", err)
}
}
}
}
go loop()
return nil
}
func (l *Ldap) UpdateZones() error {
zoneFileMap := make(map[string]*file.Zone, len(l.Zones.Names))
for _, zn := range l.Zones.Names {
zoneFileMap[zn] = nil
zoneFileMap[zn] = file.NewZone(zn, "")
zoneFileMap[zn].Upstream = l.Upstream
err := zoneFileMap[zn].Insert(SOA(zn))
if err != nil {
return fmt.Errorf("updating zones: %w", err)
}
}
ldapRecords, err := l.fetchLdapRecords()
if err != nil {
return fmt.Errorf("updating zones: %w", err)
}
for zn, lrpz := range l.mapLdapRecordsToZone(ldapRecords) {
if len(lrpz) == 0 {
continue
}
for _, lr := range lrpz {
err = zoneFileMap[zn].Insert(lr.AAAA())
err = zoneFileMap[zn].Insert(lr.A())
if err != nil {
return fmt.Errorf("updating zones: %w", err)
}
}
}
l.zMu.Lock()
for zn, zf := range zoneFileMap {
l.Zones.Z[zn] = zf
}
l.zMu.Unlock()
return nil
}
func (l *Ldap) mapLdapRecordsToZone(ldapRecords []ldapRecord) (ldapRecordsPerZone map[string][]ldapRecord) {
lrpz := make(map[string][]ldapRecord, len(l.Zones.Names))
for _, zn := range l.Zones.Names {
lrpz[zn] = nil
}
for _, lr := range ldapRecords {
zone := plugin.Zones(l.Zones.Names).Matches(lr.fqdn)
if zone != "" {
lrpz[zone] = append(lrpz[zone], lr)
}
}
return lrpz
}
func (l *Ldap) fetchLdapRecords() (ldapRecords []ldapRecord, err error) {
searchResult, err := l.Client.SearchWithPaging(l.SearchRequest, l.pagingLimit)
if err != nil {
return nil, fmt.Errorf("fetching data from server: %w", err)
}
ldapRecords = make([]ldapRecord, len(searchResult.Entries))
for i := 0; i < len(ldapRecords); i++ {
fqdn := searchResult.Entries[i].GetAttributeValue(l.FqdnAttr)
if !strings.HasSuffix(fqdn, ".") {
fqdn = fqdn + "."
}
ldapRecords[i] = ldapRecord{
fqdn: fqdn,
ip4: net.ParseIP(searchResult.Entries[i].GetAttributeValue(l.Ip4Attr)),
ip6: net.ParseIP(searchResult.Entries[i].GetAttributeValue(l.Ip6Attr)),
}
}
return ldapRecords, nil
}