@nictool/dns-resource-record 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -6
- package/README.md +328 -198
- package/dist/dns-rr.min.js +26 -0
- package/dist/dns-rr.min.js.map +7 -0
- package/index.js +12 -11
- package/lib/binary.js +108 -0
- package/lib/bind.js +94 -0
- package/lib/dns-query.js +67 -0
- package/lib/tinydns.js +128 -44
- package/lib/wire.js +519 -0
- package/package.json +29 -10
- package/rr/TEMPLATE.js +124 -0
- package/rr/a.js +8 -48
- package/rr/aaaa.js +13 -80
- package/rr/apl.js +123 -27
- package/rr/caa.js +27 -50
- package/rr/cert.js +58 -87
- package/rr/cname.js +7 -63
- package/rr/dhcid.js +20 -30
- package/rr/dname.js +9 -36
- package/rr/dnskey.js +38 -32
- package/rr/ds.js +43 -57
- package/rr/hinfo.js +21 -40
- package/rr/hip.js +88 -26
- package/rr/https.js +28 -40
- package/rr/ipseckey.js +97 -18
- package/rr/key.js +39 -29
- package/rr/kx.js +16 -27
- package/rr/loc.js +42 -12
- package/rr/mx.js +16 -51
- package/rr/naptr.js +58 -33
- package/rr/ns.js +8 -36
- package/rr/nsec.js +89 -18
- package/rr/nsec3.js +62 -26
- package/rr/nsec3param.js +56 -53
- package/rr/nxt.js +57 -18
- package/rr/openpgpkey.js +24 -30
- package/rr/ptr.js +7 -47
- package/rr/rp.js +17 -32
- package/rr/rrsig.js +80 -85
- package/rr/sig.js +70 -45
- package/rr/smimea.js +33 -33
- package/rr/soa.js +31 -49
- package/rr/spf.js +10 -17
- package/rr/srv.js +22 -62
- package/rr/sshfp.js +25 -53
- package/rr/svcb.js +27 -40
- package/rr/tlsa.js +34 -34
- package/rr/tsig.js +87 -24
- package/rr/txt.js +40 -59
- package/rr/uri.js +19 -29
- package/rr/wks.js +154 -22
- package/rr.js +290 -109
- package/lib/readme.js +0 -84
package/rr/tsig.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import RR from '../rr.js'
|
|
2
2
|
import * as TINYDNS from '../lib/tinydns.js'
|
|
3
|
+
import * as BINARY from '../lib/binary.js'
|
|
4
|
+
import * as WIRE from '../lib/wire.js'
|
|
3
5
|
|
|
4
6
|
export default class TSIG extends RR {
|
|
7
|
+
static typeName = 'TSIG'
|
|
8
|
+
static typeId = 250
|
|
9
|
+
static RFCs = [2845, 8945]
|
|
10
|
+
static rdataFields = ['algorithm name', 'time signed', 'fudge', 'mac', 'original id', 'error', 'other']
|
|
11
|
+
|
|
5
12
|
constructor(opts) {
|
|
6
13
|
super(opts)
|
|
7
14
|
if (opts === null) return
|
|
@@ -13,18 +20,6 @@ export default class TSIG extends RR {
|
|
|
13
20
|
return 'Transaction Signature'
|
|
14
21
|
}
|
|
15
22
|
|
|
16
|
-
getRdataFields(arg) {
|
|
17
|
-
return ['algorithm name', 'time signed', 'fudge', 'mac', 'original id', 'error', 'other']
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
getRFCs() {
|
|
21
|
-
return [2845, 8945]
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
getTypeId() {
|
|
25
|
-
return 250
|
|
26
|
-
}
|
|
27
|
-
|
|
28
23
|
getCanonical() {
|
|
29
24
|
return {
|
|
30
25
|
owner: 'test.example.',
|
|
@@ -114,22 +109,23 @@ export default class TSIG extends RR {
|
|
|
114
109
|
const algUnpacked = TINYDNS.unpackDomainName(rdata)
|
|
115
110
|
const algBinaryLen = algUnpacked[2]
|
|
116
111
|
|
|
117
|
-
const bytes =
|
|
112
|
+
const bytes = Uint8Array.from(TINYDNS.octalToChar(rdata), (c) => c.charCodeAt(0))
|
|
113
|
+
const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)
|
|
118
114
|
let bpos = algBinaryLen
|
|
119
115
|
|
|
120
|
-
const timeSigned =
|
|
116
|
+
const timeSigned = dv.getUint32(bpos)
|
|
121
117
|
bpos += 4
|
|
122
|
-
const fudge =
|
|
118
|
+
const fudge = dv.getUint16(bpos)
|
|
123
119
|
bpos += 2
|
|
124
|
-
const macSize =
|
|
120
|
+
const macSize = dv.getUint16(bpos)
|
|
125
121
|
bpos += 2
|
|
126
|
-
const mac = macSize > 0 ? bytes.
|
|
122
|
+
const mac = macSize > 0 ? BINARY.bytesToHex(bytes.subarray(bpos, bpos + macSize)) : ''
|
|
127
123
|
bpos += macSize
|
|
128
|
-
const originalId =
|
|
124
|
+
const originalId = dv.getUint16(bpos)
|
|
129
125
|
bpos += 2
|
|
130
|
-
const error =
|
|
126
|
+
const error = dv.getUint16(bpos)
|
|
131
127
|
bpos += 2
|
|
132
|
-
const other = bpos < bytes.length ? bytes.
|
|
128
|
+
const other = bpos < bytes.length ? new TextDecoder().decode(bytes.subarray(bpos)) : ''
|
|
133
129
|
|
|
134
130
|
return new TSIG({
|
|
135
131
|
owner: this.fullyQualify(owner),
|
|
@@ -148,6 +144,38 @@ export default class TSIG extends RR {
|
|
|
148
144
|
})
|
|
149
145
|
}
|
|
150
146
|
|
|
147
|
+
fromWire({ owner, cls, ttl, rdata }) {
|
|
148
|
+
const { fqdn: algorithmName, end } = this.wireUnpackDomain(rdata, 0)
|
|
149
|
+
const dv = new DataView(rdata.buffer, rdata.byteOffset)
|
|
150
|
+
let pos = end
|
|
151
|
+
const timeSigned = dv.getUint32(pos)
|
|
152
|
+
pos += 4
|
|
153
|
+
const fudge = dv.getUint16(pos)
|
|
154
|
+
pos += 2
|
|
155
|
+
const macSize = dv.getUint16(pos)
|
|
156
|
+
pos += 2
|
|
157
|
+
const mac = macSize > 0 ? BINARY.bytesToHex(rdata.subarray(pos, pos + macSize)) : ''
|
|
158
|
+
pos += macSize
|
|
159
|
+
const originalId = dv.getUint16(pos)
|
|
160
|
+
pos += 2
|
|
161
|
+
const error = dv.getUint16(pos)
|
|
162
|
+
pos += 2
|
|
163
|
+
const other = pos < rdata.length ? new TextDecoder().decode(rdata.subarray(pos)) : ''
|
|
164
|
+
return new TSIG({
|
|
165
|
+
owner,
|
|
166
|
+
ttl: 0,
|
|
167
|
+
class: 'ANY',
|
|
168
|
+
type: 'TSIG',
|
|
169
|
+
'algorithm name': algorithmName,
|
|
170
|
+
'time signed': timeSigned,
|
|
171
|
+
fudge,
|
|
172
|
+
mac,
|
|
173
|
+
'original id': originalId,
|
|
174
|
+
error,
|
|
175
|
+
other,
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
|
|
151
179
|
/****** EXPORTERS *******/
|
|
152
180
|
toBind(zone_opts) {
|
|
153
181
|
const mac = this.get('mac') ?? ''
|
|
@@ -172,19 +200,54 @@ export default class TSIG extends RR {
|
|
|
172
200
|
)
|
|
173
201
|
}
|
|
174
202
|
|
|
203
|
+
getWireRdata() {
|
|
204
|
+
const algWire = WIRE.wirePackDomain(this.get('algorithm name') || '')
|
|
205
|
+
const mac = this.get('mac') ?? ''
|
|
206
|
+
const macBytes = mac.length > 0 ? BINARY.hexToBytes(mac) : new Uint8Array()
|
|
207
|
+
const other = this.get('other') ?? ''
|
|
208
|
+
const otherBytes = other.length > 0 ? new TextEncoder().encode(other) : new Uint8Array()
|
|
209
|
+
|
|
210
|
+
const bytes = new Uint8Array(algWire.length + 4 + 2 + 2 + macBytes.length + 2 + 2 + otherBytes.length)
|
|
211
|
+
const dv = new DataView(bytes.buffer, bytes.byteOffset)
|
|
212
|
+
let pos = 0
|
|
213
|
+
|
|
214
|
+
bytes.set(algWire, pos)
|
|
215
|
+
pos += algWire.length
|
|
216
|
+
dv.setUint32(pos, this.get('time signed') ?? 0)
|
|
217
|
+
pos += 4
|
|
218
|
+
dv.setUint16(pos, this.get('fudge') ?? 0)
|
|
219
|
+
pos += 2
|
|
220
|
+
dv.setUint16(pos, macBytes.length)
|
|
221
|
+
pos += 2
|
|
222
|
+
if (macBytes.length > 0) {
|
|
223
|
+
bytes.set(macBytes, pos)
|
|
224
|
+
pos += macBytes.length
|
|
225
|
+
}
|
|
226
|
+
dv.setUint16(pos, this.get('original id') ?? 0)
|
|
227
|
+
pos += 2
|
|
228
|
+
dv.setUint16(pos, this.get('error') ?? 0)
|
|
229
|
+
pos += 2
|
|
230
|
+
if (otherBytes.length > 0) bytes.set(otherBytes, pos)
|
|
231
|
+
|
|
232
|
+
return bytes
|
|
233
|
+
}
|
|
234
|
+
|
|
175
235
|
toTinydns() {
|
|
176
|
-
const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
|
|
177
236
|
const alg = this.get('algorithm name') || ''
|
|
237
|
+
const mac = this.get('mac') ?? ''
|
|
238
|
+
const macByteLen = mac.length > 0 ? mac.length / 2 : 0
|
|
178
239
|
|
|
179
240
|
return this.getTinydnsGeneric(
|
|
180
241
|
TINYDNS.packDomainName(alg) +
|
|
181
242
|
TINYDNS.UInt32toOctal(this.get('time signed') ?? 0) +
|
|
182
243
|
TINYDNS.UInt16toOctal(this.get('fudge')) +
|
|
183
|
-
TINYDNS.UInt16toOctal(
|
|
184
|
-
(
|
|
244
|
+
TINYDNS.UInt16toOctal(macByteLen) +
|
|
245
|
+
(macByteLen > 0 ? TINYDNS.packHex(mac) : '') +
|
|
185
246
|
TINYDNS.UInt16toOctal(this.get('original id') ?? 0) +
|
|
186
247
|
TINYDNS.UInt16toOctal(this.get('error') ?? 0) +
|
|
187
|
-
(this.get('other').length > 0
|
|
248
|
+
(this.get('other').length > 0
|
|
249
|
+
? TINYDNS.escapeOctal(new RegExp(/[\r\n\t:\\/]/, 'g'), this.get('other'))
|
|
250
|
+
: ''),
|
|
188
251
|
)
|
|
189
252
|
}
|
|
190
253
|
}
|
package/rr/txt.js
CHANGED
|
@@ -3,6 +3,13 @@ import RR from '../rr.js'
|
|
|
3
3
|
import * as TINYDNS from '../lib/tinydns.js'
|
|
4
4
|
|
|
5
5
|
export default class TXT extends RR {
|
|
6
|
+
static typeName = 'TXT'
|
|
7
|
+
static typeId = 16
|
|
8
|
+
static RFCs = [1035, 4408, 7208, 6376]
|
|
9
|
+
static tinydnsType = "'"
|
|
10
|
+
static rdataFields = [['data', 'charstrs']]
|
|
11
|
+
static tags = ['common']
|
|
12
|
+
|
|
6
13
|
constructor(opts) {
|
|
7
14
|
super(opts)
|
|
8
15
|
}
|
|
@@ -16,22 +23,6 @@ export default class TXT extends RR {
|
|
|
16
23
|
return 'Text'
|
|
17
24
|
}
|
|
18
25
|
|
|
19
|
-
getTags() {
|
|
20
|
-
return ['common']
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
getRdataFields(arg) {
|
|
24
|
-
return ['data']
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
getRFCs() {
|
|
28
|
-
return [1035, 4408, 7208, 6376]
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
getTypeId() {
|
|
32
|
-
return 16
|
|
33
|
-
}
|
|
34
|
-
|
|
35
26
|
getCanonical() {
|
|
36
27
|
return {
|
|
37
28
|
owner: 'example.com.',
|
|
@@ -82,26 +73,6 @@ export default class TXT extends RR {
|
|
|
82
73
|
return [fqdn, s, ttl, ts, loc]
|
|
83
74
|
}
|
|
84
75
|
|
|
85
|
-
fromBind({ bindline }) {
|
|
86
|
-
// test.example.com 3600 IN TXT "..."
|
|
87
|
-
const regex = /^(?<owner>\S{1,255})\s+(?<ttl>\d{1,10})\s+(?<cls>IN)\s+(?<type>\w{3})\s+(?<rdata>\S.*)$/i
|
|
88
|
-
const match = bindline.trim().match(regex)
|
|
89
|
-
if (!match) this.throwHelp(`unable to parse TXT: ${bindline}`)
|
|
90
|
-
|
|
91
|
-
const { owner, ttl, cls, type, rdata } = match.groups
|
|
92
|
-
|
|
93
|
-
return new this.constructor({
|
|
94
|
-
owner,
|
|
95
|
-
ttl: parseInt(ttl, 10),
|
|
96
|
-
class: cls,
|
|
97
|
-
type: type.toUpperCase(),
|
|
98
|
-
data: rdata
|
|
99
|
-
.match(/"([^"]+?)"/g)
|
|
100
|
-
.map((s) => s.replace(/^"|"$/g, ''))
|
|
101
|
-
.join(''),
|
|
102
|
-
})
|
|
103
|
-
}
|
|
104
|
-
|
|
105
76
|
/****** EXPORTERS *******/
|
|
106
77
|
toBind(zone_opts) {
|
|
107
78
|
return `${this.getPrefix(zone_opts)}\t"${asQuotedStrings(this.get('data'))}"\n`
|
|
@@ -127,38 +98,48 @@ export default class TXT extends RR {
|
|
|
127
98
|
}
|
|
128
99
|
|
|
129
100
|
function asQuotedStrings(data) {
|
|
130
|
-
//
|
|
101
|
+
// RFC 1035 character-strings are 255 bytes max; chunk by UTF-8 bytes,
|
|
102
|
+
// not JS chars, so non-ASCII TXT data doesn't overflow the 255-byte limit.
|
|
103
|
+
const enc = new TextEncoder()
|
|
104
|
+
|
|
131
105
|
if (Array.isArray(data)) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
return hasTooLong
|
|
137
|
-
? data
|
|
138
|
-
.join('')
|
|
139
|
-
.match(/(.{1,255})/g)
|
|
140
|
-
.join('" "')
|
|
141
|
-
: data.join('" "')
|
|
106
|
+
const anyTooLong = data.some((s) => enc.encode(s).length > 255)
|
|
107
|
+
if (!anyTooLong) return data.join('" "')
|
|
108
|
+
return chunkByBytes(data.join(''), 255).join('" "')
|
|
142
109
|
}
|
|
143
110
|
|
|
144
|
-
if (data.length
|
|
145
|
-
|
|
146
|
-
|
|
111
|
+
if (enc.encode(data).length <= 255) return data
|
|
112
|
+
return chunkByBytes(data, 255).join('" "')
|
|
113
|
+
}
|
|
147
114
|
|
|
148
|
-
|
|
115
|
+
function chunkByBytes(str, maxBytes) {
|
|
116
|
+
const bytes = new TextEncoder().encode(str)
|
|
117
|
+
const dec = new TextDecoder()
|
|
118
|
+
const chunks = []
|
|
119
|
+
let start = 0
|
|
120
|
+
while (start < bytes.length) {
|
|
121
|
+
let end = Math.min(start + maxBytes, bytes.length)
|
|
122
|
+
// back up to a UTF-8 codepoint boundary so decode() returns whole chars
|
|
123
|
+
while (end < bytes.length && (bytes[end] & 0xc0) === 0x80) end--
|
|
124
|
+
chunks.push(dec.decode(bytes.subarray(start, end)))
|
|
125
|
+
start = end
|
|
126
|
+
}
|
|
127
|
+
return chunks
|
|
149
128
|
}
|
|
150
129
|
|
|
151
130
|
function packStringWire(str) {
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
131
|
+
const encoded = new TextEncoder().encode(str)
|
|
132
|
+
if (encoded.length === 0) return new Uint8Array([0])
|
|
133
|
+
|
|
134
|
+
const chunks = []
|
|
135
|
+
for (let i = 0; i < encoded.length; i += 255) chunks.push(encoded.subarray(i, i + 255))
|
|
155
136
|
|
|
156
|
-
const buf =
|
|
137
|
+
const buf = new Uint8Array(encoded.length + chunks.length)
|
|
157
138
|
let offset = 0
|
|
158
|
-
for (const
|
|
159
|
-
buf.
|
|
160
|
-
buf.
|
|
161
|
-
offset +=
|
|
139
|
+
for (const chunk of chunks) {
|
|
140
|
+
buf[offset++] = chunk.length
|
|
141
|
+
buf.set(chunk, offset)
|
|
142
|
+
offset += chunk.length
|
|
162
143
|
}
|
|
163
144
|
return buf
|
|
164
145
|
}
|
package/rr/uri.js
CHANGED
|
@@ -3,6 +3,15 @@ import RR from '../rr.js'
|
|
|
3
3
|
import * as TINYDNS from '../lib/tinydns.js'
|
|
4
4
|
|
|
5
5
|
export default class URI extends RR {
|
|
6
|
+
static typeName = 'URI'
|
|
7
|
+
static typeId = 256
|
|
8
|
+
static RFCs = [7553]
|
|
9
|
+
static rdataFields = [
|
|
10
|
+
['priority', 'u16'],
|
|
11
|
+
['weight', 'u16'],
|
|
12
|
+
['target', 'qstr'],
|
|
13
|
+
]
|
|
14
|
+
|
|
6
15
|
constructor(opts) {
|
|
7
16
|
super(opts)
|
|
8
17
|
}
|
|
@@ -44,37 +53,11 @@ export default class URI extends RR {
|
|
|
44
53
|
})
|
|
45
54
|
}
|
|
46
55
|
|
|
47
|
-
fromBind({ bindline }) {
|
|
48
|
-
// test.example.com 3600 IN URI priority, weight, target
|
|
49
|
-
const [owner, ttl, c, type, priority, weight, target] = bindline.split(/\s+/)
|
|
50
|
-
return new URI({
|
|
51
|
-
class: c,
|
|
52
|
-
type: type,
|
|
53
|
-
owner,
|
|
54
|
-
priority: parseInt(priority, 10),
|
|
55
|
-
weight: parseInt(weight, 10),
|
|
56
|
-
target: target.replace(/^"|"$/g, ''),
|
|
57
|
-
ttl: parseInt(ttl, 10),
|
|
58
|
-
})
|
|
59
|
-
}
|
|
60
|
-
|
|
61
56
|
/****** MISC *******/
|
|
62
57
|
getDescription() {
|
|
63
58
|
return 'URI'
|
|
64
59
|
}
|
|
65
60
|
|
|
66
|
-
getRdataFields(arg) {
|
|
67
|
-
return ['priority', 'weight', 'target']
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
getRFCs() {
|
|
71
|
-
return [7553]
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
getTypeId() {
|
|
75
|
-
return 256
|
|
76
|
-
}
|
|
77
|
-
|
|
78
61
|
getCanonical() {
|
|
79
62
|
return {
|
|
80
63
|
owner: 'www.example.com.',
|
|
@@ -87,11 +70,18 @@ export default class URI extends RR {
|
|
|
87
70
|
}
|
|
88
71
|
}
|
|
89
72
|
|
|
90
|
-
|
|
91
|
-
|
|
73
|
+
/****** EXPORTERS *******/
|
|
74
|
+
|
|
75
|
+
getWireRdata() {
|
|
76
|
+
const target = new TextEncoder().encode(this.get('target'))
|
|
77
|
+
const result = new Uint8Array(4 + target.length)
|
|
78
|
+
const dv = new DataView(result.buffer)
|
|
79
|
+
dv.setUint16(0, this.get('priority'))
|
|
80
|
+
dv.setUint16(2, this.get('weight'))
|
|
81
|
+
result.set(target, 4)
|
|
82
|
+
return result
|
|
92
83
|
}
|
|
93
84
|
|
|
94
|
-
/****** EXPORTERS *******/
|
|
95
85
|
toTinydns() {
|
|
96
86
|
const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
|
|
97
87
|
let rdata = ''
|
package/rr/wks.js
CHANGED
|
@@ -2,7 +2,102 @@ import RR from '../rr.js'
|
|
|
2
2
|
|
|
3
3
|
import * as TINYDNS from '../lib/tinydns.js'
|
|
4
4
|
|
|
5
|
+
const WELL_KNOWN_PORTS = {
|
|
6
|
+
echo: 7,
|
|
7
|
+
discard: 9,
|
|
8
|
+
systat: 11,
|
|
9
|
+
daytime: 13,
|
|
10
|
+
netstat: 15,
|
|
11
|
+
ftp_data: 20,
|
|
12
|
+
ftp: 21,
|
|
13
|
+
ssh: 22,
|
|
14
|
+
telnet: 23,
|
|
15
|
+
smtp: 25,
|
|
16
|
+
time: 37,
|
|
17
|
+
rlp: 39,
|
|
18
|
+
nameserver: 42,
|
|
19
|
+
nicname: 43,
|
|
20
|
+
domain: 53,
|
|
21
|
+
mtp: 57,
|
|
22
|
+
bootps: 67,
|
|
23
|
+
bootpc: 68,
|
|
24
|
+
tftp: 69,
|
|
25
|
+
gopher: 70,
|
|
26
|
+
rje: 77,
|
|
27
|
+
finger: 79,
|
|
28
|
+
http: 80,
|
|
29
|
+
link: 87,
|
|
30
|
+
supdup: 95,
|
|
31
|
+
hostnames: 101,
|
|
32
|
+
iso_tsap: 102,
|
|
33
|
+
csnet_ns: 105,
|
|
34
|
+
pop_2: 109,
|
|
35
|
+
pop3: 110,
|
|
36
|
+
sunrpc: 111,
|
|
37
|
+
auth: 113,
|
|
38
|
+
sftp: 115,
|
|
39
|
+
uucp_path: 117,
|
|
40
|
+
nntp: 119,
|
|
41
|
+
ntp: 123,
|
|
42
|
+
netbios_ns: 137,
|
|
43
|
+
netbios_dgm: 138,
|
|
44
|
+
netbios_ssn: 139,
|
|
45
|
+
imap: 143,
|
|
46
|
+
sql_net: 150,
|
|
47
|
+
snmp: 161,
|
|
48
|
+
snmp_trap: 162,
|
|
49
|
+
cmip_man: 163,
|
|
50
|
+
cmip_agent: 164,
|
|
51
|
+
xdmcp: 177,
|
|
52
|
+
nextstep: 178,
|
|
53
|
+
bgp: 179,
|
|
54
|
+
prospero: 191,
|
|
55
|
+
irc: 194,
|
|
56
|
+
smux: 199,
|
|
57
|
+
at_rtmp: 201,
|
|
58
|
+
at_nbp: 202,
|
|
59
|
+
at_echo: 204,
|
|
60
|
+
at_zis: 206,
|
|
61
|
+
qmtp: 209,
|
|
62
|
+
z3950: 210,
|
|
63
|
+
ipx: 213,
|
|
64
|
+
imap3: 220,
|
|
65
|
+
ulistproc: 372,
|
|
66
|
+
https: 443,
|
|
67
|
+
snpp: 444,
|
|
68
|
+
microsoft_ds: 445,
|
|
69
|
+
kpasswd: 464,
|
|
70
|
+
urd: 465,
|
|
71
|
+
saft: 487,
|
|
72
|
+
isakmp: 500,
|
|
73
|
+
exec: 512,
|
|
74
|
+
biff: 512,
|
|
75
|
+
login: 513,
|
|
76
|
+
who: 513,
|
|
77
|
+
cmd: 514,
|
|
78
|
+
syslog: 514,
|
|
79
|
+
printer: 515,
|
|
80
|
+
talk: 517,
|
|
81
|
+
ntalk: 518,
|
|
82
|
+
route: 520,
|
|
83
|
+
timed: 525,
|
|
84
|
+
tempo: 526,
|
|
85
|
+
courier: 530,
|
|
86
|
+
netnews: 532,
|
|
87
|
+
netwall: 533,
|
|
88
|
+
uucp: 540,
|
|
89
|
+
remotefs: 556,
|
|
90
|
+
nntps: 563,
|
|
91
|
+
ldap: 389,
|
|
92
|
+
}
|
|
93
|
+
|
|
5
94
|
export default class WKS extends RR {
|
|
95
|
+
static typeName = 'WKS'
|
|
96
|
+
static typeId = 11
|
|
97
|
+
static RFCs = [883, 1035]
|
|
98
|
+
static rdataFields = ['address', 'protocol', 'bit map']
|
|
99
|
+
static tags = ['obsolete']
|
|
100
|
+
|
|
6
101
|
constructor(opts) {
|
|
7
102
|
super(opts)
|
|
8
103
|
}
|
|
@@ -29,22 +124,6 @@ export default class WKS extends RR {
|
|
|
29
124
|
return 'Well Known Service'
|
|
30
125
|
}
|
|
31
126
|
|
|
32
|
-
getTags() {
|
|
33
|
-
return ['obsolete']
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
getRdataFields(arg) {
|
|
37
|
-
return ['address', 'protocol', 'bit map']
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
getRFCs() {
|
|
41
|
-
return [883, 1035]
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
getTypeId() {
|
|
45
|
-
return 11
|
|
46
|
-
}
|
|
47
|
-
|
|
48
127
|
getCanonical() {
|
|
49
128
|
return {
|
|
50
129
|
owner: 'host.example.com.',
|
|
@@ -77,14 +156,12 @@ export default class WKS extends RR {
|
|
|
77
156
|
fromTinydns({ tinyline }) {
|
|
78
157
|
const [owner, _typeId, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
79
158
|
|
|
80
|
-
const binary =
|
|
81
|
-
const address = [binary
|
|
82
|
-
|
|
83
|
-
)
|
|
84
|
-
const protoNum = binary.readUInt8(4)
|
|
159
|
+
const binary = Uint8Array.from(TINYDNS.octalToChar(rdata), (c) => c.charCodeAt(0))
|
|
160
|
+
const address = [binary[0], binary[1], binary[2], binary[3]].join('.')
|
|
161
|
+
const protoNum = binary[4]
|
|
85
162
|
const protoMap = { 6: 'TCP', 17: 'UDP' }
|
|
86
163
|
const protocol = protoMap[protoNum] ?? protoNum
|
|
87
|
-
const bitmap = binary.
|
|
164
|
+
const bitmap = new TextDecoder().decode(binary.subarray(5))
|
|
88
165
|
|
|
89
166
|
return new WKS({
|
|
90
167
|
owner: this.fullyQualify(owner),
|
|
@@ -98,6 +175,33 @@ export default class WKS extends RR {
|
|
|
98
175
|
})
|
|
99
176
|
}
|
|
100
177
|
|
|
178
|
+
fromWire({ owner, cls, ttl, rdata }) {
|
|
179
|
+
const address = [...rdata.subarray(0, 4)].join('.')
|
|
180
|
+
const protoNum = rdata[4]
|
|
181
|
+
const protoMap = { 6: 'TCP', 17: 'UDP' }
|
|
182
|
+
const protocol = protoMap[protoNum] ?? String(protoNum)
|
|
183
|
+
const PORT_NAMES = Object.fromEntries(Object.entries(WELL_KNOWN_PORTS).map(([k, v]) => [v, k]))
|
|
184
|
+
const bitmap = rdata.subarray(5)
|
|
185
|
+
const ports = []
|
|
186
|
+
for (let i = 0; i < bitmap.length; i++) {
|
|
187
|
+
for (let bit = 0; bit < 8; bit++) {
|
|
188
|
+
if (bitmap[i] & (0x80 >> bit)) {
|
|
189
|
+
const port = i * 8 + bit
|
|
190
|
+
ports.push(PORT_NAMES[port] ?? String(port))
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return new WKS({
|
|
195
|
+
owner,
|
|
196
|
+
ttl,
|
|
197
|
+
class: cls,
|
|
198
|
+
type: 'WKS',
|
|
199
|
+
address,
|
|
200
|
+
protocol,
|
|
201
|
+
'bit map': ports.join(' '),
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
|
|
101
205
|
/****** EXPORTERS *******/
|
|
102
206
|
|
|
103
207
|
toTinydns() {
|
|
@@ -111,4 +215,32 @@ export default class WKS extends RR {
|
|
|
111
215
|
TINYDNS.escapeOctal(dataRe, this.get('bit map')),
|
|
112
216
|
)
|
|
113
217
|
}
|
|
218
|
+
|
|
219
|
+
getWireRdata() {
|
|
220
|
+
const protoMap = { TCP: 6, UDP: 17, 6: 6, 17: 17 }
|
|
221
|
+
const addrBytes = this.get('address').split('.').map(Number)
|
|
222
|
+
const protoNum = protoMap[this.get('protocol')]
|
|
223
|
+
|
|
224
|
+
const portNums = this.get('bit map')
|
|
225
|
+
.trim()
|
|
226
|
+
.split(/\s+/)
|
|
227
|
+
.map((s) => {
|
|
228
|
+
if (/^\d+$/.test(s)) return parseInt(s, 10)
|
|
229
|
+
return WELL_KNOWN_PORTS[s.toLowerCase()]
|
|
230
|
+
})
|
|
231
|
+
.filter((p) => p !== undefined)
|
|
232
|
+
|
|
233
|
+
if (portNums.length === 0) return new Uint8Array([...addrBytes, protoNum])
|
|
234
|
+
|
|
235
|
+
const maxPort = Math.max(...portNums)
|
|
236
|
+
const bitmapLen = Math.floor(maxPort / 8) + 1
|
|
237
|
+
const bitmap = new Uint8Array(bitmapLen)
|
|
238
|
+
for (const port of portNums) bitmap[Math.floor(port / 8)] |= 0x80 >> (port % 8)
|
|
239
|
+
|
|
240
|
+
const result = new Uint8Array(5 + bitmapLen)
|
|
241
|
+
result.set(addrBytes)
|
|
242
|
+
result[4] = protoNum
|
|
243
|
+
result.set(bitmap, 5)
|
|
244
|
+
return result
|
|
245
|
+
}
|
|
114
246
|
}
|