-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathserve.go
138 lines (112 loc) · 3.69 KB
/
serve.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
132
133
134
135
136
137
138
package tailscale
import (
"context"
"net"
"strings"
"github.com/miekg/dns"
"github.com/coredns/coredns/plugin"
clog "github.com/coredns/coredns/plugin/pkg/log"
)
var log = clog.NewWithPlugin("tailscale")
const (
TypeAll = iota
TypeA
TypeAAAA
)
// ServeDNS implements the plugin.Handler interface. This method gets called when tailscale is used
// in a Server.
func (t *Tailscale) resolveA(domainName string, msg *dns.Msg) {
name := strings.Split(domainName, ".")[0]
entries, ok := t.entries[name]["A"]
if ok {
log.Debugf("Found an v4 entry after lookup for: %s", name)
for _, entry := range entries {
msg.Answer = append(msg.Answer, &dns.A{
Hdr: dns.RR_Header{Name: domainName, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60},
A: net.ParseIP(entry),
})
}
} else {
// There's no A record, so see if a CNAME exists
log.Debug("No v4 entry after lookup, so trying CNAME")
t.resolveCNAME(domainName, msg, TypeA)
}
}
func (t *Tailscale) resolveAAAA(domainName string, msg *dns.Msg) {
name := strings.Split(domainName, ".")[0]
entries, ok := t.entries[name]["AAAA"]
if ok {
log.Debugf("Found a v6 entry after lookup for: %s", name)
for _, entry := range entries {
msg.Answer = append(msg.Answer, &dns.AAAA{
Hdr: dns.RR_Header{Name: domainName, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 60},
AAAA: net.ParseIP(entry),
})
}
} else {
// There's no AAAA record, so see if a CNAME exists
log.Debug("No v6 entry after lookup, so trying CNAME")
t.resolveCNAME(domainName, msg, TypeAAAA)
}
}
func (t *Tailscale) resolveCNAME(domainName string, msg *dns.Msg, lookupType int) {
name := strings.Split(domainName, ".")[0]
targets, ok := t.entries[name]["CNAME"]
if ok {
log.Debugf("Found a CNAME entry after lookup for: %s", name)
for _, target := range targets {
msg.Answer = append(msg.Answer, &dns.CNAME{
Hdr: dns.RR_Header{Name: domainName, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: 60},
Target: target,
})
// Resolve local zone A or AAAA records if they exist for the referenced target
if lookupType == TypeAll || lookupType == TypeA {
log.Debug("CNAME record found, lookup up local recursive A")
t.resolveA(target, msg)
}
if lookupType == TypeAll || lookupType == TypeAAAA {
log.Debug("CNAME record found, lookup up local recursive AAAA")
t.resolveAAAA(target, msg)
}
}
}
}
func (t *Tailscale) handleNoRecords(ctx context.Context, w dns.ResponseWriter, r *dns.Msg, msg *dns.Msg) (int, error) {
if t.fall.Through(r.Question[0].Name) {
log.Debug("falling through")
return plugin.NextOrFailure(t.Name(), t.next, ctx, w, r)
} else {
log.Debugf("Writing response: %+v", msg)
w.WriteMsg(msg)
return dns.RcodeNameError, nil
}
}
func (t *Tailscale) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
log.Debugf("Received request for name: %v", r.Question[0].Name)
log.Debugf("Tailscale peers list has %d entries", len(t.entries))
msg := dns.Msg{}
msg.SetReply(r)
msg.Authoritative = true
name := r.Question[0].Name
t.mu.RLock()
switch r.Question[0].Qtype {
case dns.TypeA:
log.Debug("Handling A record lookup")
t.resolveA(name, &msg)
case dns.TypeAAAA:
log.Debug("Handling AAAA record lookup")
t.resolveAAAA(name, &msg)
case dns.TypeCNAME:
log.Debug("Handling CNAME record lookup")
t.resolveCNAME(name, &msg, TypeAll)
}
defer t.mu.RUnlock()
if len(msg.Answer) == 0 {
return t.handleNoRecords(ctx, w, r, &msg)
}
// Export metric with the server label set to the current server handling the request.
//requestCount.WithLabelValues(metrics.WithServer(ctx)).Inc()
log.Debugf("Writing response: %+v", msg)
w.WriteMsg(&msg)
return dns.RcodeSuccess, nil
}