forked from coredns/coredns
-
Notifications
You must be signed in to change notification settings - Fork 0
/
typify.go
144 lines (124 loc) · 2.96 KB
/
typify.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
139
140
141
142
143
144
package response
import (
"fmt"
"time"
"github.com/miekg/dns"
)
// Type is the type of the message.
type Type int
const (
// NoError indicates a positive reply
NoError Type = iota
// NameError is a NXDOMAIN in header, SOA in auth.
NameError
// NoData indicates name found, but not the type: NOERROR in header, SOA in auth.
NoData
// Delegation is a msg with a pointer to another nameserver: NOERROR in header, NS in auth, optionally fluff in additional (not checked).
Delegation
// Meta indicates a meta message, NOTIFY, or a transfer: qType is IXFR or AXFR.
Meta
// Update is an dynamic update message.
Update
// OtherError indicates any other error: don't cache these.
OtherError
)
var toString = map[Type]string{
NoError: "NOERROR",
NameError: "NXDOMAIN",
NoData: "NODATA",
Delegation: "DELEGATION",
Meta: "META",
Update: "UPDATE",
OtherError: "OTHERERROR",
}
func (t Type) String() string { return toString[t] }
// TypeFromString returns the type from the string s. If not type matches
// the OtherError type and an error are returned.
func TypeFromString(s string) (Type, error) {
for t, str := range toString {
if s == str {
return t, nil
}
}
return NoError, fmt.Errorf("invalid Type: %s", s)
}
// Typify classifies a message, it returns the Type.
func Typify(m *dns.Msg, t time.Time) (Type, *dns.OPT) {
if m == nil {
return OtherError, nil
}
opt := m.IsEdns0()
do := false
if opt != nil {
do = opt.Do()
}
if m.Opcode == dns.OpcodeUpdate {
return Update, opt
}
// Check transfer and update first
if m.Opcode == dns.OpcodeNotify {
return Meta, opt
}
if len(m.Question) > 0 {
if m.Question[0].Qtype == dns.TypeAXFR || m.Question[0].Qtype == dns.TypeIXFR {
return Meta, opt
}
}
// If our message contains any expired sigs and we care about that, we should return expired
if do {
if expired := typifyExpired(m, t); expired {
return OtherError, opt
}
}
if len(m.Answer) > 0 && m.Rcode == dns.RcodeSuccess {
return NoError, opt
}
soa := false
ns := 0
for _, r := range m.Ns {
if r.Header().Rrtype == dns.TypeSOA {
soa = true
continue
}
if r.Header().Rrtype == dns.TypeNS {
ns++
}
}
if soa && m.Rcode == dns.RcodeSuccess {
return NoData, opt
}
if soa && m.Rcode == dns.RcodeNameError {
return NameError, opt
}
if ns > 0 && m.Rcode == dns.RcodeSuccess {
return Delegation, opt
}
if m.Rcode == dns.RcodeSuccess {
return NoError, opt
}
return OtherError, opt
}
func typifyExpired(m *dns.Msg, t time.Time) bool {
if expired := typifyExpiredRRSIG(m.Answer, t); expired {
return true
}
if expired := typifyExpiredRRSIG(m.Ns, t); expired {
return true
}
if expired := typifyExpiredRRSIG(m.Extra, t); expired {
return true
}
return false
}
func typifyExpiredRRSIG(rrs []dns.RR, t time.Time) bool {
for _, r := range rrs {
if r.Header().Rrtype != dns.TypeRRSIG {
continue
}
ok := r.(*dns.RRSIG).ValidityPeriod(t)
if !ok {
return true
}
}
return false
}