@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/CHANGELOG.md
CHANGED
|
@@ -4,9 +4,24 @@ Notable changes to this project are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
#### Unreleased
|
|
6
6
|
|
|
7
|
-
### [1.
|
|
7
|
+
### [1.5.0] - 2026-03-22
|
|
8
|
+
|
|
9
|
+
- feat(RRSIG, SIG, TSIG): added toBind, toTinydns, fromTinydns
|
|
10
|
+
- feat(TSIG): added missing setters
|
|
11
|
+
- feat(fromTinydns): added to APL, DHCID, HIP, KX, RRSIG, RP, WKS
|
|
12
|
+
- feat(CERT): validate mnemonic values
|
|
13
|
+
- fix: hardened polynomial regexes #56
|
|
14
|
+
- fix(NAPTR): replace polynomial regexp
|
|
15
|
+
- test: coverage is at 98% 🎉
|
|
16
|
+
- test(NSEC3PARAM): added test cases, better binary parser, better salt
|
|
17
|
+
- test(AAAA, APL, CERT, KEY, NAPTR, NSEC3, NSEC3PARAM, RRSIG, SIG, SSHFP, TSIG, URL): added test coverage
|
|
18
|
+
- doc(README): updated RR table completion status
|
|
19
|
+
- style(es6): use ?. and ?? operators (nullish coalescing) #57
|
|
20
|
+
- style(es6): use argument expansion / destructured parameters
|
|
21
|
+
- style(es6): substring -> slice #55
|
|
22
|
+
- style(es6): use more trim() #55
|
|
8
23
|
|
|
9
|
-
|
|
24
|
+
### [1.4.0] - 2026-03-21
|
|
10
25
|
|
|
11
26
|
- feat(toBind): added to nsec3param, rrsig
|
|
12
27
|
- feat(toTinydns): added to key, nsec3param, nxt, openpgpkey
|
|
@@ -350,3 +365,4 @@ Notable changes to this project are documented in this file.
|
|
|
350
365
|
[1.3.0]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.3.0
|
|
351
366
|
[1.3.1]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.3.1
|
|
352
367
|
[1.4.0]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.4.0
|
|
368
|
+
[1.5.0]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.5.0
|
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@ This module is used to:
|
|
|
19
19
|
| **[Tinydns](https://cr.yp.to/djbdns/tinydns-data.html)** | :white_check_mark: | :white_check_mark: |
|
|
20
20
|
| **MaraDNS** | | :white_check_mark: |
|
|
21
21
|
| **JS** | :white_check_mark: | :white_check_mark: |
|
|
22
|
+
| **PowerDNS** | | |
|
|
22
23
|
|
|
23
24
|
This package intends to import and export RFC compliant DNS resource records. Please [raise an issue](https://github.com/NicTool/dns-resource-record/issues) if a valid resource record fails to pass or an invalid resource record passes.
|
|
24
25
|
|
|
@@ -189,44 +190,44 @@ PRs are welcome, especially PRs with tests.
|
|
|
189
190
|
| :------------: | :----------------: | :----------------: | :----------------: | :----------------: |
|
|
190
191
|
| **A** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
191
192
|
| **AAAA** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
192
|
-
| **APL** | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
193
|
+
| **APL** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
193
194
|
| **CAA** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
194
|
-
| **CERT** | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
195
|
+
| **CERT** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
195
196
|
| **CNAME** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
196
|
-
| **DHCID** | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
197
|
+
| **DHCID** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
197
198
|
| **DNAME** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
198
199
|
| **DNSKEY** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
199
200
|
| **DS** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
200
201
|
| **HINFO** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
201
|
-
| **HIP** | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
202
|
-
| **HTTPS** | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
202
|
+
| **HIP** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
203
|
+
| **HTTPS** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
203
204
|
| **IPSECKEY** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
204
|
-
| **KEY** |
|
|
205
|
-
| **KX** | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
205
|
+
| **KEY** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
206
|
+
| **KX** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
206
207
|
| **LOC** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
207
208
|
| **MX** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
208
209
|
| **NAPTR** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
209
210
|
| **NS** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
210
|
-
| **NSEC** | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
211
|
-
| **NSEC3** | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
212
|
-
| **NSEC3PARAM** |
|
|
213
|
-
| **NXT** |
|
|
214
|
-
| **OPENPGPKEY** |
|
|
211
|
+
| **NSEC** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
212
|
+
| **NSEC3** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
213
|
+
| **NSEC3PARAM** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
214
|
+
| **NXT** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
215
|
+
| **OPENPGPKEY** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
215
216
|
| **PTR** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
216
|
-
| **RP** | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
217
|
-
| **RRSIG** |
|
|
218
|
-
| **SIG** |
|
|
219
|
-
| **SMIMEA** | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
217
|
+
| **RP** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
218
|
+
| **RRSIG** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
219
|
+
| **SIG** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
220
|
+
| **SMIMEA** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
220
221
|
| **SOA** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
221
222
|
| **SPF** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
222
223
|
| **SRV** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
223
224
|
| **SSHFP** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
224
|
-
| **SVCB** | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
225
|
+
| **SVCB** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
225
226
|
| **TLSA** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
226
|
-
| **TSIG** |
|
|
227
|
+
| **TSIG** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
227
228
|
| **TXT** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
228
229
|
| **URI** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
229
|
-
| **WKS** | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
230
|
+
| **WKS** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
230
231
|
|
|
231
232
|
## TIPS
|
|
232
233
|
|
package/lib/tinydns.js
CHANGED
|
@@ -33,7 +33,7 @@ export function unescapeOctal(str) {
|
|
|
33
33
|
|
|
34
34
|
export function octalToChar(str) {
|
|
35
35
|
// relace instances of \NNN with ASCII
|
|
36
|
-
return str.replace(octalRe, (o) => String.fromCharCode(parseInt(o.
|
|
36
|
+
return str.replace(octalRe, (o) => String.fromCharCode(parseInt(o.slice(1), 8)))
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export function octalToHex(str) {
|
|
@@ -41,29 +41,29 @@ export function octalToHex(str) {
|
|
|
41
41
|
return str.replace(octalRe, (o) => {
|
|
42
42
|
// parseInt(n, 8) -> from octal to decimal
|
|
43
43
|
// .toString(16) -> decimal to hex
|
|
44
|
-
return parseInt(o.
|
|
44
|
+
return parseInt(o.slice(1), 8).toString(16).padStart(2, 0)
|
|
45
45
|
})
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export function octalToUInt8(str) {
|
|
49
49
|
const b = Buffer.alloc(1)
|
|
50
|
-
b.writeUInt8(parseInt(str.
|
|
50
|
+
b.writeUInt8(parseInt(str.slice(1, 4), 8), 0)
|
|
51
51
|
return b.readUInt8()
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
export function octalToUInt16(str) {
|
|
55
55
|
const b = Buffer.alloc(2)
|
|
56
|
-
b.writeUInt8(parseInt(str.
|
|
57
|
-
b.writeUInt8(parseInt(str.
|
|
56
|
+
b.writeUInt8(parseInt(str.slice(1, 4), 8), 0)
|
|
57
|
+
b.writeUInt8(parseInt(str.slice(5, 8), 8), 1)
|
|
58
58
|
return b.readUInt16BE()
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
export function octalToUInt32(str) {
|
|
62
62
|
const b = Buffer.alloc(4)
|
|
63
|
-
b.writeUInt8(parseInt(str.
|
|
64
|
-
b.writeUInt8(parseInt(str.
|
|
65
|
-
b.writeUInt8(parseInt(str.
|
|
66
|
-
b.writeUInt8(parseInt(str.
|
|
63
|
+
b.writeUInt8(parseInt(str.slice(1, 4), 8), 0)
|
|
64
|
+
b.writeUInt8(parseInt(str.slice(5, 8), 8), 1)
|
|
65
|
+
b.writeUInt8(parseInt(str.slice(9, 12), 8), 2)
|
|
66
|
+
b.writeUInt8(parseInt(str.slice(13, 16), 8), 3)
|
|
67
67
|
return b.readUInt32BE()
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -99,7 +99,7 @@ export function packDomainName(fqdn) {
|
|
|
99
99
|
// RFC 1035, 3.3 Standard RRs
|
|
100
100
|
// The standard wire format for DNS names. (1 octet length + octets)
|
|
101
101
|
let packed = ''
|
|
102
|
-
fqdn.split('.').
|
|
102
|
+
fqdn.split('.').forEach((label) => {
|
|
103
103
|
if (label === undefined || !label.length) return
|
|
104
104
|
|
|
105
105
|
const len = Buffer.alloc(1)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nictool/dns-resource-record",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "DNS Resource Records",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"type": "module",
|
|
13
13
|
"scripts": {
|
|
14
14
|
"format:check": "npm run prettier; npm run lint",
|
|
15
|
-
"format": "npm run prettier -- --write && npm run lint
|
|
15
|
+
"format": "npm run prettier -- --write && npm run lint:fix",
|
|
16
16
|
"lint": "npx eslint **/*.js",
|
|
17
17
|
"lint:fix": "npm run lint -- --fix",
|
|
18
18
|
"prettier": "npx prettier --ignore-path .gitignore --check .",
|
package/rr/a.js
CHANGED
|
@@ -39,9 +39,9 @@ export default class A extends RR {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/****** IMPORTERS *******/
|
|
42
|
-
fromTinydns(
|
|
42
|
+
fromTinydns({ tinyline }) {
|
|
43
43
|
// +fqdn:ip:ttl:timestamp:lo
|
|
44
|
-
const [owner, ip, ttl, ts, loc] =
|
|
44
|
+
const [owner, ip, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
45
45
|
|
|
46
46
|
return new A({
|
|
47
47
|
owner: this.fullyQualify(owner),
|
|
@@ -49,13 +49,13 @@ export default class A extends RR {
|
|
|
49
49
|
address: ip,
|
|
50
50
|
ttl: parseInt(ttl, 10),
|
|
51
51
|
timestamp: ts,
|
|
52
|
-
location: loc
|
|
52
|
+
location: loc?.trim() ?? '',
|
|
53
53
|
})
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
fromBind(
|
|
56
|
+
fromBind({ bindline }) {
|
|
57
57
|
// test.example.com 3600 IN A 192.0.2.127
|
|
58
|
-
const [owner, ttl, c, type, address] =
|
|
58
|
+
const [owner, ttl, c, type, address] = bindline.split(/\s+/)
|
|
59
59
|
return new A({
|
|
60
60
|
owner,
|
|
61
61
|
ttl: parseInt(ttl, 10),
|
package/rr/aaaa.js
CHANGED
|
@@ -15,7 +15,7 @@ export default class AAAA extends RR {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
getCompressed(val) {
|
|
18
|
-
return this.compress(val
|
|
18
|
+
return this.compress(val ?? this.get('address'))
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
getDescription() {
|
|
@@ -45,14 +45,14 @@ export default class AAAA extends RR {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/****** IMPORTERS *******/
|
|
48
|
-
fromTinydns(
|
|
49
|
-
const str =
|
|
48
|
+
fromTinydns({ tinyline }) {
|
|
49
|
+
const str = tinyline
|
|
50
50
|
let fqdn, ip, n, rdata, ttl, ts, loc
|
|
51
51
|
|
|
52
52
|
switch (str[0]) {
|
|
53
53
|
case ':':
|
|
54
54
|
// GENERIC => :fqdn:28:rdata:ttl:timestamp:lo
|
|
55
|
-
;[fqdn, n, rdata, ttl, ts, loc] = str.
|
|
55
|
+
;[fqdn, n, rdata, ttl, ts, loc] = str.slice(1).split(':')
|
|
56
56
|
if (n != 28) this.throwHelp('AAAA fromTinydns, invalid n')
|
|
57
57
|
ip = TINYDNS.octalToHex(rdata)
|
|
58
58
|
.match(/([0-9a-fA-F]{4})/g)
|
|
@@ -62,7 +62,7 @@ export default class AAAA extends RR {
|
|
|
62
62
|
case '6':
|
|
63
63
|
// AAAA => 3fqdn:ip:x:ttl:timestamp:lo
|
|
64
64
|
// AAAA,PTR => 6fqdn:ip:x:ttl:timestamp:lo
|
|
65
|
-
;[fqdn, rdata, ttl, ts, loc] = str.
|
|
65
|
+
;[fqdn, rdata, ttl, ts, loc] = str.slice(1).split(':')
|
|
66
66
|
ip = rdata.match(/(.{4})/g).join(':')
|
|
67
67
|
break
|
|
68
68
|
}
|
|
@@ -73,13 +73,13 @@ export default class AAAA extends RR {
|
|
|
73
73
|
type: 'AAAA',
|
|
74
74
|
address: ip,
|
|
75
75
|
timestamp: ts,
|
|
76
|
-
location: loc
|
|
76
|
+
location: loc?.trim() ?? '',
|
|
77
77
|
})
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
fromBind(
|
|
80
|
+
fromBind({ bindline }) {
|
|
81
81
|
// test.example.com 3600 IN AAAA ...
|
|
82
|
-
const [owner, ttl, c, type, ip] =
|
|
82
|
+
const [owner, ttl, c, type, ip] = bindline.split(/\s+/)
|
|
83
83
|
return new AAAA({
|
|
84
84
|
owner,
|
|
85
85
|
ttl: parseInt(ttl, 10),
|
|
@@ -124,7 +124,7 @@ export default class AAAA extends RR {
|
|
|
124
124
|
if (delimiter === undefined) delimiter = ':'
|
|
125
125
|
|
|
126
126
|
const colons = val.match(/:/g)
|
|
127
|
-
if (colons
|
|
127
|
+
if (colons?.length < 7) {
|
|
128
128
|
// console.log(`AAAA: restoring compressed colons`)
|
|
129
129
|
val = val.replace(/::/, ':'.repeat(9 - colons.length))
|
|
130
130
|
}
|
package/rr/apl.js
CHANGED
|
@@ -42,9 +42,56 @@ export default class APL extends RR {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/****** IMPORTERS *******/
|
|
45
|
-
|
|
45
|
+
fromTinydns({ tinyline }) {
|
|
46
|
+
// APL via generic, :fqdn:42:rdata:ttl:timestamp:lo
|
|
47
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
48
|
+
if (n != 42) this.throwHelp('APL fromTinydns, invalid n')
|
|
49
|
+
|
|
50
|
+
const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
51
|
+
const items = []
|
|
52
|
+
let pos = 0
|
|
53
|
+
|
|
54
|
+
while (pos < bytes.length) {
|
|
55
|
+
const afi = bytes.readUInt16BE(pos)
|
|
56
|
+
pos += 2
|
|
57
|
+
const prefix = bytes.readUInt8(pos)
|
|
58
|
+
pos++
|
|
59
|
+
const adfLenByte = bytes.readUInt8(pos)
|
|
60
|
+
pos++
|
|
61
|
+
const neg = (adfLenByte & 0x80) !== 0
|
|
62
|
+
const addrLen = adfLenByte & 0x7f
|
|
63
|
+
const addrBytes = bytes.slice(pos, pos + addrLen)
|
|
64
|
+
pos += addrLen
|
|
65
|
+
|
|
66
|
+
let addr
|
|
67
|
+
if (afi === 1) {
|
|
68
|
+
const padded = Buffer.alloc(4)
|
|
69
|
+
addrBytes.copy(padded)
|
|
70
|
+
addr = [...padded].join('.')
|
|
71
|
+
} else {
|
|
72
|
+
const padded = Buffer.alloc(16)
|
|
73
|
+
addrBytes.copy(padded)
|
|
74
|
+
const groups = []
|
|
75
|
+
for (let i = 0; i < 16; i += 2) groups.push(padded.readUInt16BE(i).toString(16).padStart(4, '0'))
|
|
76
|
+
addr = this.compressIPv6(groups.join(':'))
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
items.push(`${neg ? '!' : ''}${afi}:${addr}/${prefix}`)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return new APL({
|
|
83
|
+
owner: this.fullyQualify(fqdn),
|
|
84
|
+
ttl: parseInt(ttl, 10),
|
|
85
|
+
type: 'APL',
|
|
86
|
+
'apl rdata': items.join(' '),
|
|
87
|
+
timestamp: ts,
|
|
88
|
+
location: loc?.trim() ?? '',
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
fromBind({ bindline }) {
|
|
46
93
|
// test.example.com 3600 IN APL {[!]afi:address/prefix}*
|
|
47
|
-
const parts =
|
|
94
|
+
const parts = bindline.split(/\s+/)
|
|
48
95
|
const [owner, ttl, c, type] = parts
|
|
49
96
|
return new APL({
|
|
50
97
|
owner,
|
package/rr/caa.js
CHANGED
|
@@ -91,17 +91,17 @@ export default class CAA extends RR {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/****** IMPORTERS *******/
|
|
94
|
-
fromTinydns(
|
|
94
|
+
fromTinydns({ tinyline }) {
|
|
95
95
|
// CAA via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
96
|
-
const [fqdn, n, rdata, ttl, ts, loc] =
|
|
96
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
97
97
|
if (n != 257) this.throwHelp('CAA fromTinydns, invalid n')
|
|
98
98
|
|
|
99
|
-
const flags = TINYDNS.octalToUInt8(rdata.
|
|
100
|
-
const taglen = TINYDNS.octalToUInt8(rdata.
|
|
99
|
+
const flags = TINYDNS.octalToUInt8(rdata.slice(0, 4))
|
|
100
|
+
const taglen = TINYDNS.octalToUInt8(rdata.slice(4, 8))
|
|
101
101
|
|
|
102
|
-
const unescaped = TINYDNS.octalToChar(rdata.
|
|
103
|
-
const tag = unescaped.
|
|
104
|
-
const fingerprint = unescaped.
|
|
102
|
+
const unescaped = TINYDNS.octalToChar(rdata.slice(8))
|
|
103
|
+
const tag = unescaped.slice(0, taglen)
|
|
104
|
+
const fingerprint = unescaped.slice(taglen)
|
|
105
105
|
|
|
106
106
|
return new CAA({
|
|
107
107
|
owner: this.fullyQualify(fqdn),
|
|
@@ -111,17 +111,23 @@ export default class CAA extends RR {
|
|
|
111
111
|
tag,
|
|
112
112
|
value: fingerprint,
|
|
113
113
|
timestamp: ts,
|
|
114
|
-
location: loc
|
|
114
|
+
location: loc?.trim() ?? '',
|
|
115
115
|
})
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
fromBind(
|
|
118
|
+
fromBind({ bindline }) {
|
|
119
119
|
// test.example.com 3600 IN CAA flags, tags, value
|
|
120
|
-
const regex =
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
const regex =
|
|
121
|
+
/^(?<owner>\S+)\s+(?<ttl>\d{1,10})\s+(?<class>IN)\s+(?<type>CAA)\s+(?<flags>\d+)\s+(?<tag>\w+)\s+(?:"(?<quotedValue>[^"]+)"|(?<unquotedValue>\S+))$/i
|
|
122
|
+
|
|
123
|
+
const match = bindline.trim().match(regex)
|
|
124
|
+
|
|
125
|
+
if (!match) {
|
|
126
|
+
this.throwHelp(`unable to parse CAA: ${bindline}`)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const { owner, ttl, class: c, type, flags, tag, quotedValue, unquotedValue } = match.groups
|
|
123
130
|
|
|
124
|
-
const [owner, ttl, c, type, flags, tag, value] = fields.slice(1)
|
|
125
131
|
return new CAA({
|
|
126
132
|
owner,
|
|
127
133
|
ttl: parseInt(ttl, 10),
|
|
@@ -129,21 +135,18 @@ export default class CAA extends RR {
|
|
|
129
135
|
type,
|
|
130
136
|
flags: parseInt(flags, 10),
|
|
131
137
|
tag,
|
|
132
|
-
value,
|
|
138
|
+
value: quotedValue ?? unquotedValue,
|
|
133
139
|
})
|
|
134
140
|
}
|
|
135
141
|
|
|
136
142
|
/****** EXPORTERS *******/
|
|
137
143
|
|
|
138
144
|
toTinydns() {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
rdata += TINYDNS.escapeOctal(/[\r\n\t:\\/]/, this.getQuoted('value'))
|
|
146
|
-
|
|
147
|
-
return this.getTinydnsGeneric(rdata)
|
|
145
|
+
return this.getTinydnsGeneric(
|
|
146
|
+
TINYDNS.UInt8toOctal(this.get('flags')) +
|
|
147
|
+
TINYDNS.UInt8toOctal(this.get('tag').length) +
|
|
148
|
+
TINYDNS.escapeOctal(/[\r\n\t:\\/]/, this.get('tag')) +
|
|
149
|
+
TINYDNS.escapeOctal(/[\r\n\t:\\/]/, this.getQuoted('value')),
|
|
150
|
+
)
|
|
148
151
|
}
|
|
149
152
|
}
|
package/rr/cert.js
CHANGED
|
@@ -11,8 +11,29 @@ export default class CERT extends RR {
|
|
|
11
11
|
setCertType(val) {
|
|
12
12
|
// The type field is the certificate type
|
|
13
13
|
// the type field as an unsigned decimal integer or as a mnemonic symbol
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
if (val === undefined || val === null || val === '') {
|
|
15
|
+
this.throwHelp('cert type is required')
|
|
16
|
+
}
|
|
17
|
+
// Accept both mnemonic and numeric, but validate mnemonic
|
|
18
|
+
if (typeof val === 'string') {
|
|
19
|
+
const types = {
|
|
20
|
+
PKIX: 1,
|
|
21
|
+
SPKI: 2,
|
|
22
|
+
PGP: 3,
|
|
23
|
+
IPKIX: 4,
|
|
24
|
+
ISPKI: 5,
|
|
25
|
+
IPGP: 6,
|
|
26
|
+
ACPKIX: 7,
|
|
27
|
+
IACPKIX: 8,
|
|
28
|
+
URI: 253,
|
|
29
|
+
OID: 254,
|
|
30
|
+
}
|
|
31
|
+
if (!Object.hasOwn(types, val)) {
|
|
32
|
+
this.throwHelp(`CERT: unknown cert type mnemonic: ${val}`)
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
this.is16bitInt('CERT', 'cert type', val)
|
|
36
|
+
}
|
|
16
37
|
this.set('cert type', val)
|
|
17
38
|
}
|
|
18
39
|
|
|
@@ -54,6 +75,9 @@ export default class CERT extends RR {
|
|
|
54
75
|
setCertificate(val) {
|
|
55
76
|
// certificate/CRL portion is represented in base 64 [16] and may be
|
|
56
77
|
// divided into any number of white-space-separated substrings
|
|
78
|
+
if (val === undefined || val === null || val === '') {
|
|
79
|
+
this.throwHelp('certificate is required and cannot be empty')
|
|
80
|
+
}
|
|
57
81
|
this.set('certificate', val)
|
|
58
82
|
}
|
|
59
83
|
|
|
@@ -75,8 +99,8 @@ export default class CERT extends RR {
|
|
|
75
99
|
|
|
76
100
|
/****** IMPORTERS *******/
|
|
77
101
|
|
|
78
|
-
fromTinydns(
|
|
79
|
-
const [owner, n, rdata, ttl, ts, loc] =
|
|
102
|
+
fromTinydns({ tinyline }) {
|
|
103
|
+
const [owner, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
80
104
|
if (n != 37) this.throwHelp('CERT fromTinydns, invalid n')
|
|
81
105
|
|
|
82
106
|
const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
@@ -106,13 +130,13 @@ export default class CERT extends RR {
|
|
|
106
130
|
algorithm: bytes.readUInt8(4),
|
|
107
131
|
certificate: bytes.slice(5).toString(),
|
|
108
132
|
timestamp: ts,
|
|
109
|
-
location: loc
|
|
133
|
+
location: loc?.trim() ?? '',
|
|
110
134
|
})
|
|
111
135
|
}
|
|
112
136
|
|
|
113
|
-
fromBind(
|
|
137
|
+
fromBind({ bindline }) {
|
|
114
138
|
// test.example.com 3600 IN CERT certtype, keytag, algo, cert
|
|
115
|
-
const [owner, ttl, c, type, certtype, keytag, algo, certificate] =
|
|
139
|
+
const [owner, ttl, c, type, certtype, keytag, algo, certificate] = bindline.split(/\s+/)
|
|
116
140
|
return new CERT({
|
|
117
141
|
owner,
|
|
118
142
|
ttl: parseInt(ttl, 10),
|
package/rr/cname.js
CHANGED
|
@@ -38,9 +38,9 @@ export default class CNAME extends RR {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/****** IMPORTERS *******/
|
|
41
|
-
fromTinydns(
|
|
41
|
+
fromTinydns({ tinyline }) {
|
|
42
42
|
// Cfqdn:p:ttl:timestamp:lo
|
|
43
|
-
const [fqdn, p, ttl, ts, loc] =
|
|
43
|
+
const [fqdn, p, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
44
44
|
|
|
45
45
|
return new CNAME({
|
|
46
46
|
owner: this.fullyQualify(fqdn),
|
|
@@ -48,13 +48,13 @@ export default class CNAME extends RR {
|
|
|
48
48
|
type: 'CNAME',
|
|
49
49
|
cname: this.fullyQualify(p),
|
|
50
50
|
timestamp: ts,
|
|
51
|
-
location: loc
|
|
51
|
+
location: loc?.trim() ?? '',
|
|
52
52
|
})
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
fromBind(
|
|
55
|
+
fromBind({ bindline }) {
|
|
56
56
|
// test.example.com 3600 IN CNAME ...
|
|
57
|
-
const [owner, ttl, c, type, cname] =
|
|
57
|
+
const [owner, ttl, c, type, cname] = bindline.split(/\s+/)
|
|
58
58
|
return new CNAME({
|
|
59
59
|
owner,
|
|
60
60
|
ttl: parseInt(ttl, 10),
|
package/rr/dhcid.js
CHANGED
|
@@ -40,9 +40,24 @@ export default class DHCID extends RR {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/****** IMPORTERS *******/
|
|
43
|
-
|
|
43
|
+
fromTinydns({ tinyline }) {
|
|
44
|
+
// DHCID via generic, :fqdn:49:rdata:ttl:timestamp:lo
|
|
45
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
46
|
+
if (n != 49) this.throwHelp('DHCID fromTinydns, invalid n')
|
|
47
|
+
|
|
48
|
+
return new DHCID({
|
|
49
|
+
owner: this.fullyQualify(fqdn),
|
|
50
|
+
ttl: parseInt(ttl, 10),
|
|
51
|
+
type: 'DHCID',
|
|
52
|
+
data: TINYDNS.octalToBase64(rdata),
|
|
53
|
+
timestamp: ts,
|
|
54
|
+
location: loc?.trim() ?? '',
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
fromBind({ bindline }) {
|
|
44
59
|
// host.example.com 3600 IN DHCID <base64data>
|
|
45
|
-
const parts =
|
|
60
|
+
const parts = bindline.split(/\s+/)
|
|
46
61
|
const [owner, ttl, c, type] = parts
|
|
47
62
|
return new DHCID({
|
|
48
63
|
owner,
|
package/rr/dname.js
CHANGED
|
@@ -36,9 +36,9 @@ export default class DNAME extends RR {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/****** IMPORTERS *******/
|
|
39
|
-
fromTinydns(
|
|
39
|
+
fromTinydns({ tinyline }) {
|
|
40
40
|
// DNAME via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
41
|
-
const [fqdn, n, rdata, ttl, ts, loc] =
|
|
41
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
42
42
|
if (n != 39) this.throwHelp('DNAME fromTinydns, invalid n')
|
|
43
43
|
|
|
44
44
|
return new DNAME({
|
|
@@ -47,13 +47,13 @@ export default class DNAME extends RR {
|
|
|
47
47
|
target: TINYDNS.unpackDomainName(rdata)[0],
|
|
48
48
|
ttl: parseInt(ttl, 10),
|
|
49
49
|
timestamp: ts,
|
|
50
|
-
location: loc
|
|
50
|
+
location: loc?.trim() ?? '',
|
|
51
51
|
})
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
fromBind(
|
|
54
|
+
fromBind({ bindline }) {
|
|
55
55
|
// test.example.com 3600 IN DNAME ...
|
|
56
|
-
const [owner, ttl, c, type, target] =
|
|
56
|
+
const [owner, ttl, c, type, target] = bindline.split(/\s+/)
|
|
57
57
|
return new DNAME({
|
|
58
58
|
owner,
|
|
59
59
|
ttl: parseInt(ttl, 10),
|
package/rr/dnskey.js
CHANGED
|
@@ -93,12 +93,18 @@ export default class DNSKEY extends RR {
|
|
|
93
93
|
|
|
94
94
|
/****** IMPORTERS *******/
|
|
95
95
|
|
|
96
|
-
fromBind(
|
|
96
|
+
fromBind({ bindline }) {
|
|
97
97
|
// test.example.com 3600 IN DNSKEY Flags Protocol Algorithm PublicKey
|
|
98
|
-
const regex =
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const
|
|
98
|
+
const regex =
|
|
99
|
+
/^(?<owner>\S+)\s+(?<ttl>\d+)\s+(?<cls>\w+)\s+(?<type>DNSKEY)\s+(?<flags>\d+)\s+(?<protocol>\d+)\s+(?<algorithm>\d+)\s+(?<publickey>\S.*)$/i
|
|
100
|
+
|
|
101
|
+
const match = bindline.trim().match(regex)
|
|
102
|
+
|
|
103
|
+
if (!match) {
|
|
104
|
+
this.throwHelp(`unable to parse DNSKEY: ${bindline}`)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const { owner, ttl, c, type, flags, protocol, algorithm, publickey } = match.groups
|
|
102
108
|
|
|
103
109
|
return new DNSKEY({
|
|
104
110
|
owner,
|
|
@@ -112,8 +118,8 @@ export default class DNSKEY extends RR {
|
|
|
112
118
|
})
|
|
113
119
|
}
|
|
114
120
|
|
|
115
|
-
fromTinydns(
|
|
116
|
-
const [fqdn, n, rdata, ttl, ts, loc] =
|
|
121
|
+
fromTinydns({ tinyline }) {
|
|
122
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.substring(1).split(':')
|
|
117
123
|
if (n != 48) this.throwHelp('DNSKEY fromTinydns, invalid n')
|
|
118
124
|
|
|
119
125
|
const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
@@ -127,7 +133,7 @@ export default class DNSKEY extends RR {
|
|
|
127
133
|
algorithm: bytes.readUInt8(3),
|
|
128
134
|
publickey: bytes.slice(4).toString(),
|
|
129
135
|
timestamp: ts,
|
|
130
|
-
location: loc
|
|
136
|
+
location: loc?.trim() ?? '',
|
|
131
137
|
})
|
|
132
138
|
}
|
|
133
139
|
|
package/rr/ds.js
CHANGED
|
@@ -64,9 +64,9 @@ export default class DS extends RR {
|
|
|
64
64
|
|
|
65
65
|
/****** IMPORTERS *******/
|
|
66
66
|
|
|
67
|
-
fromBind(
|
|
67
|
+
fromBind({ bindline }) {
|
|
68
68
|
// test.example.com 3600 IN DS Key Tag Algorithm, Digest Type, Digest
|
|
69
|
-
const [owner, ttl, c, type, keytag, algorithm, digesttype] =
|
|
69
|
+
const [owner, ttl, c, type, keytag, algorithm, digesttype] = bindline.split(/\s+/)
|
|
70
70
|
return new DS({
|
|
71
71
|
owner,
|
|
72
72
|
ttl: parseInt(ttl, 10),
|
|
@@ -75,12 +75,12 @@ export default class DS extends RR {
|
|
|
75
75
|
'key tag': parseInt(keytag, 10),
|
|
76
76
|
algorithm: parseInt(algorithm, 10),
|
|
77
77
|
'digest type': parseInt(digesttype, 10),
|
|
78
|
-
digest:
|
|
78
|
+
digest: bindline.split(/\s+/).slice(7).join(' ').trim(),
|
|
79
79
|
})
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
fromTinydns(
|
|
83
|
-
const [fqdn, n, rdata, ttl, ts, loc] =
|
|
82
|
+
fromTinydns({ tinyline }) {
|
|
83
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
84
84
|
if (n != 43) this.throwHelp('DS fromTinydns, invalid n')
|
|
85
85
|
|
|
86
86
|
const binRdata = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
@@ -94,7 +94,7 @@ export default class DS extends RR {
|
|
|
94
94
|
'digest type': binRdata.readUInt8(3),
|
|
95
95
|
digest: binRdata.slice(4).toString(),
|
|
96
96
|
timestamp: ts,
|
|
97
|
-
location: loc
|
|
97
|
+
location: loc?.trim() ?? '',
|
|
98
98
|
})
|
|
99
99
|
}
|
|
100
100
|
|