@nictool/dns-resource-record 1.4.0 → 1.5.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 +18 -2
- package/README.md +20 -19
- package/lib/tinydns.js +10 -10
- package/package.json +2 -2
- package/rr/a.js +5 -5
- package/rr/aaaa.js +9 -9
- package/rr/apl.js +49 -2
- package/rr/caa.js +26 -23
- package/rr/cert.js +31 -7
- package/rr/cname.js +5 -5
- package/rr/dhcid.js +17 -2
- package/rr/dname.js +5 -5
- package/rr/dnskey.js +14 -8
- package/rr/ds.js +6 -6
- package/rr/hinfo.js +13 -10
- package/rr/hip.js +43 -2
- package/rr/https.js +22 -9
- package/rr/ipseckey.js +16 -16
- package/rr/key.js +13 -17
- package/rr/kx.js +18 -2
- package/rr/loc.js +14 -14
- package/rr/mx.js +5 -5
- package/rr/naptr.js +23 -19
- package/rr/ns.js +5 -5
- package/rr/nsec.js +6 -6
- package/rr/nsec3.js +52 -7
- package/rr/nsec3param.js +35 -22
- package/rr/nxt.js +7 -7
- package/rr/openpgpkey.js +14 -8
- package/rr/ptr.js +5 -5
- package/rr/rp.js +19 -2
- package/rr/rrsig.js +84 -10
- package/rr/sig.js +88 -12
- package/rr/smimea.js +6 -6
- package/rr/soa.js +6 -6
- package/rr/spf.js +3 -3
- package/rr/srv.js +11 -11
- package/rr/sshfp.js +8 -8
- package/rr/svcb.js +25 -10
- package/rr/tlsa.js +8 -8
- package/rr/tsig.js +139 -13
- package/rr/txt.js +10 -11
- package/rr/uri.js +8 -8
- package/rr/wks.js +26 -2
- package/rr.js +52 -7
package/rr/svcb.js
CHANGED
|
@@ -46,11 +46,11 @@ export default class SVCB extends RR {
|
|
|
46
46
|
|
|
47
47
|
/****** IMPORTERS *******/
|
|
48
48
|
|
|
49
|
-
fromBind(
|
|
49
|
+
fromBind({ bindline }) {
|
|
50
50
|
// test.example.com 3600 IN SVCB Priority TargetName Params
|
|
51
51
|
// _8443._foo.api.example.com. 7200 IN SVCB 0 svc4.example.net.
|
|
52
52
|
// svc4.example.net. 7200 IN SVCB 3 svc4.example.net. ( alpn="bar" port="8004" )
|
|
53
|
-
const [owner, ttl, c, type, pri, fqdn] =
|
|
53
|
+
const [owner, ttl, c, type, pri, fqdn] = bindline.split(/\s+/)
|
|
54
54
|
return new SVCB({
|
|
55
55
|
owner,
|
|
56
56
|
ttl: parseInt(ttl, 10),
|
|
@@ -58,22 +58,35 @@ export default class SVCB extends RR {
|
|
|
58
58
|
type,
|
|
59
59
|
priority: parseInt(pri, 10),
|
|
60
60
|
'target name': fqdn,
|
|
61
|
-
params:
|
|
61
|
+
params: bindline.split(/\s+/).slice(6).join(' ').trim(),
|
|
62
62
|
})
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
fromTinydns({
|
|
65
|
+
fromTinydns({ tinyline }) {
|
|
66
|
+
const [owner, _typeId, rd, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
67
|
+
|
|
66
68
|
if (rd.length < 6) {
|
|
67
69
|
this.throwHelp(`SVCB: RDATA too short: ${rd}`)
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
+
// Convert escaped octal RDATA into a binary buffer for reliable parsing
|
|
73
|
+
const binary = Buffer.from(TINYDNS.octalToChar(rd), 'binary')
|
|
72
74
|
|
|
73
|
-
const
|
|
75
|
+
const priority = binary.readUInt16BE(0)
|
|
74
76
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
// parse domain name from binary starting at offset 2
|
|
78
|
+
let pos = 2
|
|
79
|
+
const labels = []
|
|
80
|
+
while (true) {
|
|
81
|
+
const len = binary.readUInt8(pos)
|
|
82
|
+
pos += 1
|
|
83
|
+
if (len === 0) break
|
|
84
|
+
labels.push(binary.slice(pos, pos + len).toString())
|
|
85
|
+
pos += len
|
|
86
|
+
}
|
|
87
|
+
const targetName = `${labels.join('.')}.`
|
|
88
|
+
// remaining params are ASCII text after the domain
|
|
89
|
+
const params = binary.slice(pos).toString()
|
|
77
90
|
|
|
78
91
|
return new SVCB({
|
|
79
92
|
owner: this.fullyQualify(owner),
|
|
@@ -81,7 +94,9 @@ export default class SVCB extends RR {
|
|
|
81
94
|
type: 'SVCB',
|
|
82
95
|
priority: priority,
|
|
83
96
|
'target name': targetName,
|
|
84
|
-
params:
|
|
97
|
+
params: params,
|
|
98
|
+
timestamp: ts,
|
|
99
|
+
location: loc?.trim() ?? '',
|
|
85
100
|
})
|
|
86
101
|
}
|
|
87
102
|
|
package/rr/tlsa.js
CHANGED
|
@@ -76,12 +76,12 @@ export default class TLSA extends RR {
|
|
|
76
76
|
|
|
77
77
|
/****** IMPORTERS *******/
|
|
78
78
|
|
|
79
|
-
fromBind(
|
|
79
|
+
fromBind({ bindline }) {
|
|
80
80
|
// test.example.com 3600 IN TLSA, usage, selector, match, data
|
|
81
81
|
const regex =
|
|
82
|
-
/^(?<owner>\S+)\s+(?<ttl>\d{1,10})\s+(?<cls>IN)\s+(?<type>TLSA)\s+(?<usage>\d+)\s+(?<selector>\d+)\s+(?<matchtype>\d+)\s+(?<cad
|
|
83
|
-
const match =
|
|
84
|
-
if (!match) this.throwHelp(`unable to parse TLSA: ${
|
|
82
|
+
/^(?<owner>\S+)\s+(?<ttl>\d{1,10})\s+(?<cls>IN)\s+(?<type>TLSA)\s+(?<usage>\d+)\s+(?<selector>\d+)\s+(?<matchtype>\d+)\s+(?<cad>\S.*)$/i
|
|
83
|
+
const match = bindline.trim().match(regex)
|
|
84
|
+
if (!match) this.throwHelp(`unable to parse TLSA: ${bindline}`)
|
|
85
85
|
const { owner, ttl, cls, type, usage, selector, matchtype, cad } = match.groups
|
|
86
86
|
|
|
87
87
|
return new TLSA({
|
|
@@ -92,12 +92,12 @@ export default class TLSA extends RR {
|
|
|
92
92
|
'certificate usage': parseInt(usage, 10),
|
|
93
93
|
selector: parseInt(selector, 10),
|
|
94
94
|
'matching type': parseInt(matchtype, 10),
|
|
95
|
-
'certificate association data': cad,
|
|
95
|
+
'certificate association data': cad.trim(),
|
|
96
96
|
})
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
fromTinydns(
|
|
100
|
-
const [fqdn, n, rdata, ttl, ts, loc] =
|
|
99
|
+
fromTinydns({ tinyline }) {
|
|
100
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
101
101
|
if (n != 52) this.throwHelp('TLSA fromTinydns, invalid n')
|
|
102
102
|
|
|
103
103
|
const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
@@ -111,7 +111,7 @@ export default class TLSA extends RR {
|
|
|
111
111
|
'matching type': bytes.readUInt8(2),
|
|
112
112
|
'certificate association data': bytes.slice(3).toString(),
|
|
113
113
|
timestamp: ts,
|
|
114
|
-
location: loc
|
|
114
|
+
location: loc?.trim() ?? '',
|
|
115
115
|
})
|
|
116
116
|
}
|
|
117
117
|
|
package/rr/tsig.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import RR from '../rr.js'
|
|
2
|
+
import * as TINYDNS from '../lib/tinydns.js'
|
|
2
3
|
|
|
3
4
|
export default class TSIG extends RR {
|
|
4
5
|
constructor(opts) {
|
|
@@ -17,32 +18,157 @@ export default class TSIG extends RR {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
getRFCs() {
|
|
20
|
-
return [2845]
|
|
21
|
+
return [2845, 8945]
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
getTypeId() {
|
|
24
25
|
return 250
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
setClass(t) {
|
|
29
|
+
if (t !== 'ANY') this.throwHelp('TSIG: Class is required to be ANY')
|
|
30
|
+
this.set('class', t)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
setTtl(t) {
|
|
34
|
+
if (t !== 0) this.throwHelp('TSIG: TTL is required to be 0')
|
|
35
|
+
this.set('ttl', t)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
setAlgorithmName(val) {
|
|
39
|
+
if (!val) this.throwHelp(`TSIG: 'algorithm name' is required`)
|
|
40
|
+
this.set('algorithm name', val)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
setTimeSigned(val) {
|
|
44
|
+
// a 48-bit unsigned integer, as seconds since the UNIX epoch
|
|
45
|
+
if (val === undefined) this.throwHelp(`TSIG: 'time signed' is required`)
|
|
46
|
+
this.set('time signed', val)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
setFudge(val) {
|
|
50
|
+
// 16-bit unsigned
|
|
51
|
+
this.is16bitInt('TSIG', 'fudge', val)
|
|
52
|
+
this.set('fudge', val)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
setMac(val) {
|
|
56
|
+
this.set('mac', val ?? '')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
setOriginalId(val) {
|
|
60
|
+
this.is16bitInt('TSIG', 'original id', val)
|
|
61
|
+
this.set('original id', val)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
setError(val) {
|
|
65
|
+
this.is16bitInt('TSIG', 'error', val)
|
|
66
|
+
this.set('error', val)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
setOther(val) {
|
|
70
|
+
this.set('other', val ?? '')
|
|
71
|
+
}
|
|
72
|
+
|
|
27
73
|
/****** IMPORTERS *******/
|
|
28
74
|
|
|
29
|
-
fromBind(
|
|
30
|
-
//
|
|
31
|
-
const
|
|
75
|
+
fromBind({ bindline }) {
|
|
76
|
+
// owner ttl ANY TSIG alg time fudge mac_size mac original_id error other_len
|
|
77
|
+
const parts = bindline.trimEnd().split('\t')
|
|
78
|
+
const [owner, ttl, cls, type, alg, time, fudge, , mac, origId, error] = parts
|
|
79
|
+
|
|
32
80
|
return new TSIG({
|
|
33
81
|
owner,
|
|
34
82
|
ttl: parseInt(ttl, 10),
|
|
35
|
-
class:
|
|
36
|
-
type: type,
|
|
37
|
-
algorithm:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
83
|
+
class: cls,
|
|
84
|
+
type: type.toUpperCase(),
|
|
85
|
+
'algorithm name': alg,
|
|
86
|
+
'time signed': parseInt(time, 10),
|
|
87
|
+
fudge: parseInt(fudge, 10),
|
|
88
|
+
mac: mac || '',
|
|
89
|
+
'original id': parseInt(origId, 10),
|
|
90
|
+
error: parseInt(error, 10),
|
|
91
|
+
other: '',
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
fromTinydns({ tinyline }) {
|
|
96
|
+
const [owner, _typeId, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
97
|
+
|
|
98
|
+
const algUnpacked = TINYDNS.unpackDomainName(rdata)
|
|
99
|
+
const algBinaryLen = algUnpacked[2]
|
|
100
|
+
|
|
101
|
+
const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
102
|
+
let bpos = algBinaryLen
|
|
103
|
+
|
|
104
|
+
const timeSigned = bytes.readUInt32BE(bpos)
|
|
105
|
+
bpos += 4
|
|
106
|
+
const fudge = bytes.readUInt16BE(bpos)
|
|
107
|
+
bpos += 2
|
|
108
|
+
const macSize = bytes.readUInt16BE(bpos)
|
|
109
|
+
bpos += 2
|
|
110
|
+
const mac = macSize > 0 ? bytes.slice(bpos, bpos + macSize).toString('hex') : ''
|
|
111
|
+
bpos += macSize
|
|
112
|
+
const originalId = bytes.readUInt16BE(bpos)
|
|
113
|
+
bpos += 2
|
|
114
|
+
const error = bytes.readUInt16BE(bpos)
|
|
115
|
+
bpos += 2
|
|
116
|
+
const other = bpos < bytes.length ? bytes.slice(bpos).toString() : ''
|
|
117
|
+
|
|
118
|
+
return new TSIG({
|
|
119
|
+
owner: this.fullyQualify(owner),
|
|
120
|
+
ttl: parseInt(ttl, 10),
|
|
121
|
+
class: 'ANY',
|
|
122
|
+
type: 'TSIG',
|
|
123
|
+
'algorithm name': algUnpacked[0],
|
|
124
|
+
'time signed': timeSigned,
|
|
125
|
+
fudge,
|
|
126
|
+
mac,
|
|
127
|
+
'original id': originalId,
|
|
128
|
+
error,
|
|
129
|
+
other,
|
|
130
|
+
timestamp: ts,
|
|
131
|
+
location: loc?.trim() ?? '',
|
|
44
132
|
})
|
|
45
133
|
}
|
|
46
134
|
|
|
47
135
|
/****** EXPORTERS *******/
|
|
136
|
+
toBind(zone_opts) {
|
|
137
|
+
const mac = this.get('mac') ?? ''
|
|
138
|
+
const macSize = mac.length > 0 ? mac.length : ''
|
|
139
|
+
const other = this.get('other') ?? ''
|
|
140
|
+
const otherLen = other.length > 0 ? other.length : 0
|
|
141
|
+
return (
|
|
142
|
+
[
|
|
143
|
+
this.getFQDN('owner', zone_opts),
|
|
144
|
+
this.get('ttl'),
|
|
145
|
+
this.get('class'),
|
|
146
|
+
this.get('type'),
|
|
147
|
+
this.get('algorithm name'),
|
|
148
|
+
this.get('time signed'),
|
|
149
|
+
this.get('fudge'),
|
|
150
|
+
macSize,
|
|
151
|
+
mac,
|
|
152
|
+
this.get('original id'),
|
|
153
|
+
this.get('error'),
|
|
154
|
+
otherLen,
|
|
155
|
+
].join('\t') + '\n'
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
toTinydns() {
|
|
160
|
+
const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
|
|
161
|
+
const alg = this.get('algorithm name') || ''
|
|
162
|
+
|
|
163
|
+
return this.getTinydnsGeneric(
|
|
164
|
+
TINYDNS.packDomainName(alg) +
|
|
165
|
+
TINYDNS.UInt32toOctal(this.get('time signed') ?? 0) +
|
|
166
|
+
TINYDNS.UInt16toOctal(this.get('fudge')) +
|
|
167
|
+
TINYDNS.UInt16toOctal(this.get('mac size') ?? 0) +
|
|
168
|
+
(this.get('mac size') > 0 ? TINYDNS.escapeOctal(dataRe, this.get('mac')) : '') +
|
|
169
|
+
TINYDNS.UInt16toOctal(this.get('original id') ?? 0) +
|
|
170
|
+
TINYDNS.UInt16toOctal(this.get('error') ?? 0) +
|
|
171
|
+
(this.get('other').length > 0 ? TINYDNS.escapeOctal(dataRe, this.get('other')) : ''),
|
|
172
|
+
)
|
|
173
|
+
}
|
|
48
174
|
}
|
package/rr/txt.js
CHANGED
|
@@ -29,12 +29,12 @@ export default class TXT extends RR {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/****** IMPORTERS *******/
|
|
32
|
-
fromTinydns(
|
|
33
|
-
const str =
|
|
32
|
+
fromTinydns({ tinyline }) {
|
|
33
|
+
const str = tinyline
|
|
34
34
|
let fqdn, rdata, s, ttl, ts, loc
|
|
35
35
|
// 'fqdn:s:ttl:timestamp:lo
|
|
36
36
|
if (str[0] === "'") {
|
|
37
|
-
;[fqdn, s, ttl, ts, loc] = str.
|
|
37
|
+
;[fqdn, s, ttl, ts, loc] = str.slice(1).split(':')
|
|
38
38
|
rdata = TINYDNS.octalToChar(s)
|
|
39
39
|
} else {
|
|
40
40
|
;[fqdn, rdata, ttl, ts, loc] = this.fromTinydnsGeneric(str)
|
|
@@ -46,14 +46,14 @@ export default class TXT extends RR {
|
|
|
46
46
|
type: 'TXT',
|
|
47
47
|
data: rdata,
|
|
48
48
|
timestamp: ts,
|
|
49
|
-
location: loc
|
|
49
|
+
location: loc?.trim() || '',
|
|
50
50
|
})
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
fromTinydnsGeneric(str) {
|
|
54
54
|
// generic: :fqdn:n:rdata:ttl:timestamp:location
|
|
55
55
|
// eslint-disable-next-line prefer-const
|
|
56
|
-
let [fqdn, n, rdata, ttl, ts, loc] = str.
|
|
56
|
+
let [fqdn, n, rdata, ttl, ts, loc] = str.slice(1).split(':')
|
|
57
57
|
if (n != 16) this.throwHelp('TXT fromTinydns, invalid n')
|
|
58
58
|
|
|
59
59
|
rdata = TINYDNS.octalToChar(rdata)
|
|
@@ -61,19 +61,18 @@ export default class TXT extends RR {
|
|
|
61
61
|
let len = rdata[0].charCodeAt(0)
|
|
62
62
|
let pos = 1
|
|
63
63
|
while (pos < rdata.length) {
|
|
64
|
-
s += rdata.
|
|
64
|
+
s += rdata.slice(pos, +(len + pos))
|
|
65
65
|
pos = len + pos
|
|
66
66
|
len = rdata.charCodeAt(pos + 1)
|
|
67
67
|
}
|
|
68
68
|
return [fqdn, s, ttl, ts, loc]
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
fromBind(
|
|
71
|
+
fromBind({ bindline }) {
|
|
72
72
|
// test.example.com 3600 IN TXT "..."
|
|
73
|
-
const regex =
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if (!match) this.throwHelp(`unable to parse TXT: ${opts.bindline}`)
|
|
73
|
+
const regex = /^(?<owner>\S{1,255})\s+(?<ttl>\d{1,10})\s+(?<cls>IN)\s+(?<type>\w{3})\s+(?<rdata>\S.*)$/i
|
|
74
|
+
const match = bindline.trim().match(regex)
|
|
75
|
+
if (!match) this.throwHelp(`unable to parse TXT: ${bindline}`)
|
|
77
76
|
|
|
78
77
|
const { owner, ttl, cls, type, rdata } = match.groups
|
|
79
78
|
|
package/rr/uri.js
CHANGED
|
@@ -27,26 +27,26 @@ export default class URI extends RR {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/****** IMPORTERS *******/
|
|
30
|
-
fromTinydns(
|
|
30
|
+
fromTinydns({ tinyline }) {
|
|
31
31
|
// URI via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
32
|
-
const [fqdn, n, rdata, ttl, ts, loc] =
|
|
32
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
33
33
|
if (n != 256) this.throwHelp('URI fromTinydns, invalid n')
|
|
34
34
|
|
|
35
35
|
return new URI({
|
|
36
36
|
type: 'URI',
|
|
37
37
|
owner: this.fullyQualify(fqdn),
|
|
38
|
-
priority: TINYDNS.octalToUInt16(rdata.
|
|
39
|
-
weight: TINYDNS.octalToUInt16(rdata.
|
|
40
|
-
target: TINYDNS.octalToChar(rdata.
|
|
38
|
+
priority: TINYDNS.octalToUInt16(rdata.slice(0, 8)),
|
|
39
|
+
weight: TINYDNS.octalToUInt16(rdata.slice(8, 16)),
|
|
40
|
+
target: TINYDNS.octalToChar(rdata.slice(16)),
|
|
41
41
|
ttl: parseInt(ttl, 10),
|
|
42
42
|
timestamp: ts,
|
|
43
|
-
location: loc
|
|
43
|
+
location: loc?.trim() ?? '',
|
|
44
44
|
})
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
fromBind(
|
|
47
|
+
fromBind({ bindline }) {
|
|
48
48
|
// test.example.com 3600 IN URI priority, weight, target
|
|
49
|
-
const [owner, ttl, c, type, priority, weight, target] =
|
|
49
|
+
const [owner, ttl, c, type, priority, weight, target] = bindline.split(/\s+/)
|
|
50
50
|
return new URI({
|
|
51
51
|
class: c,
|
|
52
52
|
type: type,
|
package/rr/wks.js
CHANGED
|
@@ -43,9 +43,9 @@ export default class WKS extends RR {
|
|
|
43
43
|
|
|
44
44
|
/****** IMPORTERS *******/
|
|
45
45
|
|
|
46
|
-
fromBind(
|
|
46
|
+
fromBind({ bindline }) {
|
|
47
47
|
// test.example.com 3600 IN WKS 192.168.1.1 TCP ftp smtp
|
|
48
|
-
const parts =
|
|
48
|
+
const parts = bindline.split(/\s+/)
|
|
49
49
|
const [owner, ttl, c, type, address, protocol] = parts
|
|
50
50
|
return new WKS({
|
|
51
51
|
owner,
|
|
@@ -58,6 +58,30 @@ export default class WKS extends RR {
|
|
|
58
58
|
})
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
fromTinydns({ tinyline }) {
|
|
62
|
+
const [owner, _typeId, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
63
|
+
|
|
64
|
+
const binary = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
65
|
+
const address = [binary.readUInt8(0), binary.readUInt8(1), binary.readUInt8(2), binary.readUInt8(3)].join(
|
|
66
|
+
'.',
|
|
67
|
+
)
|
|
68
|
+
const protoNum = binary.readUInt8(4)
|
|
69
|
+
const protoMap = { 6: 'TCP', 17: 'UDP' }
|
|
70
|
+
const protocol = protoMap[protoNum] ?? protoNum
|
|
71
|
+
const bitmap = binary.slice(5).toString()
|
|
72
|
+
|
|
73
|
+
return new WKS({
|
|
74
|
+
owner: this.fullyQualify(owner),
|
|
75
|
+
ttl: parseInt(ttl, 10),
|
|
76
|
+
type: 'WKS',
|
|
77
|
+
address,
|
|
78
|
+
protocol,
|
|
79
|
+
'bit map': bitmap,
|
|
80
|
+
timestamp: ts,
|
|
81
|
+
location: loc?.trim() ?? '',
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
61
85
|
/****** EXPORTERS *******/
|
|
62
86
|
|
|
63
87
|
toTinydns() {
|
package/rr.js
CHANGED
|
@@ -4,10 +4,10 @@ export default class RR extends Map {
|
|
|
4
4
|
|
|
5
5
|
if (opts === null) return
|
|
6
6
|
|
|
7
|
-
if (opts
|
|
7
|
+
if (opts?.default) this.default = opts.default
|
|
8
8
|
|
|
9
|
-
if (opts
|
|
10
|
-
if (opts
|
|
9
|
+
if (opts?.bindline) return this.fromBind(opts)
|
|
10
|
+
if (opts?.tinyline) return this.fromTinydns(opts)
|
|
11
11
|
|
|
12
12
|
// tinydns specific
|
|
13
13
|
this.setLocation(opts?.location)
|
|
@@ -21,10 +21,10 @@ export default class RR extends Map {
|
|
|
21
21
|
for (const f of this.getFields('rdata')) {
|
|
22
22
|
const fnName = `set${this.ucFirst(f)}`
|
|
23
23
|
if (this[fnName] === undefined) this.throwHelp(`Missing ${fnName} in class ${this.get('type')}`)
|
|
24
|
-
this[fnName](opts[f])
|
|
24
|
+
this[fnName](opts?.[f])
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
if (opts
|
|
27
|
+
if (opts?.comment) this.set('comment', opts.comment)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
ucFirst(str) {
|
|
@@ -91,7 +91,7 @@ export default class RR extends Map {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
setTtl(t) {
|
|
94
|
-
|
|
94
|
+
t = t ?? this.default?.ttl
|
|
95
95
|
if (t === undefined) {
|
|
96
96
|
if (['SOA', 'SSHPF'].includes(this.get('type'))) return
|
|
97
97
|
this.throwHelp('TTL is required, no default available')
|
|
@@ -157,7 +157,7 @@ export default class RR extends Map {
|
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
getEmpty(prop) {
|
|
160
|
-
return this.get(prop)
|
|
160
|
+
return this.get(prop) ?? ''
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
getComment(prop) {
|
|
@@ -307,6 +307,51 @@ export default class RR extends Map {
|
|
|
307
307
|
)
|
|
308
308
|
}
|
|
309
309
|
|
|
310
|
+
compressIPv6(val) {
|
|
311
|
+
// * RFC 5952
|
|
312
|
+
// * 4.1. Leading zeros MUST be suppressed...A single 16-bit 0000 field MUST be represented as 0.
|
|
313
|
+
// * 4.2.1 The use of the symbol "::" MUST be used to its maximum capability.
|
|
314
|
+
// * 4.2.2 The symbol "::" MUST NOT be used to shorten just one 16-bit 0 field.
|
|
315
|
+
// * 4.2.3 When choosing placement of a "::", the longest run...MUST be shortened
|
|
316
|
+
// * 4.3 The characters a-f in an IPv6 address MUST be represented in lowercase.
|
|
317
|
+
|
|
318
|
+
// 4.3 Lowercase and 4.1 remove leading zeros per segment
|
|
319
|
+
const segments = val
|
|
320
|
+
.toLowerCase()
|
|
321
|
+
.split(':')
|
|
322
|
+
.map((s) => s.replace(/^0+/, '') || '0')
|
|
323
|
+
|
|
324
|
+
let bestStart = -1
|
|
325
|
+
let bestLen = 0
|
|
326
|
+
let curStart = -1
|
|
327
|
+
let curLen = 0
|
|
328
|
+
|
|
329
|
+
// 4.2.1 & 4.2.3 Find the longest consecutive run of '0'
|
|
330
|
+
for (let i = 0; i < segments.length; i++) {
|
|
331
|
+
if (segments[i] === '0') {
|
|
332
|
+
if (curStart === -1) curStart = i
|
|
333
|
+
curLen++
|
|
334
|
+
if (curLen > bestLen) {
|
|
335
|
+
bestLen = curLen
|
|
336
|
+
bestStart = curStart
|
|
337
|
+
}
|
|
338
|
+
} else {
|
|
339
|
+
curStart = -1
|
|
340
|
+
curLen = 0
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// 4.2.2 Don't shorten a single 16-bit 0 field
|
|
345
|
+
if (bestLen < 2) {
|
|
346
|
+
return segments.join(':')
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const head = segments.slice(0, bestStart).join(':')
|
|
350
|
+
const tail = segments.slice(bestStart + bestLen).join(':')
|
|
351
|
+
|
|
352
|
+
return `${head}::${tail}`
|
|
353
|
+
}
|
|
354
|
+
|
|
310
355
|
toBind(zone_opts) {
|
|
311
356
|
return `${this.getPrefix(zone_opts)}\t${this.getRdataFields()
|
|
312
357
|
.map((f) => this.getQuoted(f))
|