-
Notifications
You must be signed in to change notification settings - Fork 0
/
types.go
293 lines (245 loc) · 4.67 KB
/
types.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
package dnsmsg
import (
"strconv"
"strings"
)
type Type uint16
func (t Type) String() string {
switch t {
case TypeA:
return "A"
case TypeNS:
return "NS"
case TypeCNAME:
return "CNAME"
case TypeSOA:
return "SOA"
case TypePTR:
return "PTR"
case TypeMX:
return "MX"
case TypeTXT:
return "TXT"
case TypeAAAA:
return "AAAA"
case TypeOPT:
return "OPT"
default:
return "0x" + strconv.FormatInt(int64(t), 16)
}
}
const (
TypeA Type = 1
TypeNS Type = 2
TypeCNAME Type = 5
TypeSOA Type = 6
TypePTR Type = 12
TypeMX Type = 15
TypeTXT Type = 16
TypeAAAA Type = 28
TypeOPT Type = 41
)
type Class uint16
func (t Class) String() string {
switch t {
case ClassIN:
return "IN"
default:
return "0x" + strconv.FormatInt(int64(t), 16)
}
}
const (
ClassIN Class = 1
)
type Bit uint8
const (
BitAA Bit = 10
BitTC Bit = 9
BitRD Bit = 8
BitRA Bit = 7
BitAD Bit = 5
BitCD Bit = 4
)
type OpCode uint8
const (
OpCodeQuery OpCode = 0
)
type RCode uint8
func (r RCode) String() string {
switch r {
case RCodeSuccess:
return "success"
case RCodeFormatError:
return "format erro"
case RCodeServerFail:
return "server failure"
case RCodeNameError:
return "name error"
case RCodeNotImpl:
return "not implemented"
case RCodeRefused:
return "refused"
default:
return "0x" + strconv.FormatInt(int64(r), 16)
}
}
const (
RCodeSuccess RCode = iota
RCodeFormatError
RCodeServerFail
RCodeNameError
RCodeNotImpl
RCodeRefused
)
type Flags uint16
const bitQR = 1 << 15
func (f Flags) Query() bool {
return f&bitQR == 0
}
func (f Flags) Response() bool {
return f&bitQR != 0
}
func (f Flags) Bit(bit Bit) bool {
return f&(1<<bit) != 0
}
func (f Flags) OpCode() OpCode {
return OpCode((f >> 11) & 0b1111)
}
func (f Flags) RCode() RCode {
return RCode(f & 0b1111)
}
func (f *Flags) SetQuery() {
*f &= ^Flags(bitQR) // zero the QR bit
}
func (f *Flags) SetResponse() {
*f |= bitQR
}
func (f *Flags) SetBit(bit Bit, val bool) {
*f &= ^Flags(1 << bit) // zero bit
if !val {
return
}
*f |= (1 << bit)
}
func (f *Flags) SetOpCode(o OpCode) {
*f &= ^Flags(0b1111 << 11) // zero the opcode bits
*f |= Flags(o) << 11
}
func (f *Flags) SetRCode(r RCode) {
*f &= ^Flags(0b1111) // zero the rcode bits
*f |= Flags(r)
}
const headerLen = 12
type Header struct {
ID uint16
Flags Flags
QDCount uint16
ANCount uint16
NSCount uint16
ARCount uint16
}
func (h *Header) unpack(msg [headerLen]byte) {
h.ID = unpackUint16(msg[:2])
h.Flags = Flags(unpackUint16(msg[2:4]))
h.QDCount = unpackUint16(msg[4:6])
h.ANCount = unpackUint16(msg[6:8])
h.NSCount = unpackUint16(msg[8:10])
h.ARCount = unpackUint16(msg[10:12])
}
func (h *Header) pack(msg *[headerLen]byte) {
packUint16(msg[:2], h.ID)
packUint16(msg[2:4], uint16(h.Flags))
packUint16(msg[4:6], h.QDCount)
packUint16(msg[6:8], h.ANCount)
packUint16(msg[8:10], h.NSCount)
packUint16(msg[10:12], h.ARCount)
}
type Question struct {
Name Name
Type Type
Class Class
}
type ResourceHeader struct {
Name Name
Type Type
Class Class
TTL uint32
Length uint16
}
type ResourceA struct {
A [4]byte
}
type ResourceNS struct {
NS Name
}
type ResourceCNAME struct {
CNAME Name
}
type ResourceSOA struct {
NS Name
Mbox Name
Serial uint32
Refresh uint32
Retry uint32
Expire uint32
Minimum uint32
}
type ResourcePTR struct {
PTR Name
}
type ResourceMX struct {
MX Name
Pref uint16
}
type ResourceTXT struct {
TXT [][]byte
}
type RawResourceTXT struct {
// TXT is as defined by RFC 1035 a "One or more <character-string>s"
// so it is a one or more byte-length prefixed data
TXT []byte
}
func (r RawResourceTXT) ToResourceTXT() ResourceTXT {
var txts [][]byte
for i := 0; i < len(r.TXT); i += int(r.TXT[i]) + 1 {
txts = append(txts, r.TXT[i:i+int(r.TXT[i])])
}
return ResourceTXT{TXT: txts}
}
func (txt RawResourceTXT) isValid() bool {
for i := 0; i < len(txt.TXT); {
i += int(txt.TXT[i]) + 1
if i == len(txt.TXT) {
return true
}
}
return false
}
func (r RawResourceTXT) concatLength() int {
length := 0
for i := 0; i < len(r.TXT); i += int(r.TXT[i]) + 1 {
length += len(r.TXT[i : i+int(r.TXT[i])])
}
return length
}
func (r RawResourceTXT) Concat() []byte {
buf := make([]byte, 0, r.concatLength())
for i := 0; i < len(r.TXT); i += int(r.TXT[i]) + 1 {
buf = append(buf, r.TXT[i:i+int(r.TXT[i])]...)
}
return buf
}
func (r RawResourceTXT) String() string {
var b strings.Builder
b.Grow(r.concatLength())
for i := 0; i < len(r.TXT); i += int(r.TXT[i]) + 1 {
b.Write(r.TXT[i : i+int(r.TXT[i])])
}
return b.String()
}
type ResourceAAAA struct {
AAAA [16]byte
}
type noCopy struct{}
func (*noCopy) Lock() {}
func (*noCopy) Unlock() {}