@nictool/dns-resource-record 1.2.0 → 1.2.1
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 +9 -0
- package/README.md +3 -1
- package/index.js +6 -0
- package/package.json +1 -1
- package/rr/a.js +13 -3
- package/rr/aaaa.js +14 -4
- package/rr/caa.js +20 -10
- package/rr/cname.js +3 -3
- package/rr/dname.js +4 -4
- package/rr/dnskey.js +6 -11
- package/rr/ds.js +6 -8
- package/rr/hinfo.js +3 -3
- package/rr/https.js +62 -0
- package/rr/ipseckey.js +20 -9
- package/rr/key.js +2 -2
- package/rr/loc.js +4 -4
- package/rr/mx.js +15 -3
- package/rr/naptr.js +2 -2
- package/rr/ns.js +1 -1
- package/rr/nsec.js +2 -4
- package/rr/nsec3.js +6 -12
- package/rr/nsec3param.js +4 -9
- package/rr/nxt.js +2 -4
- package/rr/openpgpkey.js +7 -3
- package/rr/rrsig.js +3 -4
- package/rr/sig.js +1 -1
- package/rr/smimea.js +3 -5
- package/rr/soa.js +1 -2
- package/rr/spf.js +1 -1
- package/rr/srv.js +4 -4
- package/rr/sshfp.js +1 -1
- package/rr/svcb.js +64 -0
- package/rr/tlsa.js +5 -7
- package/rr/tsig.js +10 -2
- package/rr/txt.js +2 -2
- package/rr/uri.js +2 -2
- package/rr/wks.js +4 -3
- package/rr.js +32 -20
- package/.prettierrc.yml +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,14 @@ Notable changes to this project are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
#### Unreleased
|
|
6
6
|
|
|
7
|
+
### [1.2.1] - 2024-03-10
|
|
8
|
+
|
|
9
|
+
- fix(nsec3param): fixed setHash fname typo
|
|
10
|
+
- feat(SVCB,HTTPS): add record support (#29)
|
|
11
|
+
- feat(OPENGPGPKEY): improved bindline parser, added test
|
|
12
|
+
- feat(throwHelp): far more useful error messages (#41)
|
|
13
|
+
- feat(A,MX,AAAA,CAA,IPSECKEY): added getCanonical
|
|
14
|
+
|
|
7
15
|
### [1.2.0] - 2024-03-07
|
|
8
16
|
|
|
9
17
|
- feat(index): export typeMap (lookup table for type to id)
|
|
@@ -286,3 +294,4 @@ Notable changes to this project are documented in this file.
|
|
|
286
294
|
[1.1.5]: https://github.com/NicTool/dns-resource-record/releases/tag/1.1.5
|
|
287
295
|
[1.1.6]: https://github.com/NicTool/dns-resource-record/releases/tag/1.1.6
|
|
288
296
|
[1.1.8]: https://github.com/NicTool/dns-resource-record/releases/tag/1.1.8
|
|
297
|
+
[1.2.1]: https://github.com/NicTool/dns-resource-record/releases/tag/1.2.1
|
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ DNS resource record parser, validator, importer, and exporter.
|
|
|
10
10
|
This module is used to:
|
|
11
11
|
|
|
12
12
|
- validate well formedness and RFC compliance of DNS resource records
|
|
13
|
-
- import RRs
|
|
13
|
+
- import RRs to and from the following formats:
|
|
14
14
|
|
|
15
15
|
| **RR format** | **import** | **export** |
|
|
16
16
|
| :------------------------------------------------------: | :----------------: | :----------------: |
|
|
@@ -196,6 +196,7 @@ PRs are welcome, especially PRs with tests.
|
|
|
196
196
|
| **DNSKEY** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
197
197
|
| **DS** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
198
198
|
| **HINFO** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
199
|
+
| **HTTPS** | | | | |
|
|
199
200
|
| **IPSECKEY** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
200
201
|
| **KEY** | | | | |
|
|
201
202
|
| **LOC** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
@@ -215,6 +216,7 @@ PRs are welcome, especially PRs with tests.
|
|
|
215
216
|
| **SPF** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
216
217
|
| **SRV** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
217
218
|
| **SSHFP** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
219
|
+
| **SVCB** | | | | |
|
|
218
220
|
| **TLSA** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
|
219
221
|
| **TSIG** | | | | |
|
|
220
222
|
| **TXT** | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
package/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import DNAME from './rr/dname.js'
|
|
|
10
10
|
import DNSKEY from './rr/dnskey.js'
|
|
11
11
|
import DS from './rr/ds.js'
|
|
12
12
|
import HINFO from './rr/hinfo.js'
|
|
13
|
+
import HTTPS from './rr/https.js'
|
|
13
14
|
import IPSECKEY from './rr/ipseckey.js'
|
|
14
15
|
import KEY from './rr/key.js'
|
|
15
16
|
import LOC from './rr/loc.js'
|
|
@@ -29,6 +30,7 @@ import SOA from './rr/soa.js'
|
|
|
29
30
|
import SPF from './rr/spf.js'
|
|
30
31
|
import SRV from './rr/srv.js'
|
|
31
32
|
import SSHFP from './rr/sshfp.js'
|
|
33
|
+
import SVCB from './rr/svcb.js'
|
|
32
34
|
import TLSA from './rr/tlsa.js'
|
|
33
35
|
import TSIG from './rr/tsig.js'
|
|
34
36
|
import TXT from './rr/txt.js'
|
|
@@ -47,6 +49,7 @@ export {
|
|
|
47
49
|
DNSKEY,
|
|
48
50
|
DS,
|
|
49
51
|
HINFO,
|
|
52
|
+
HTTPS,
|
|
50
53
|
IPSECKEY,
|
|
51
54
|
KEY,
|
|
52
55
|
LOC,
|
|
@@ -66,6 +69,7 @@ export {
|
|
|
66
69
|
SOA,
|
|
67
70
|
SPF,
|
|
68
71
|
SRV,
|
|
72
|
+
SVCB,
|
|
69
73
|
TLSA,
|
|
70
74
|
TSIG,
|
|
71
75
|
TXT,
|
|
@@ -84,6 +88,7 @@ for (const c of [
|
|
|
84
88
|
DNSKEY,
|
|
85
89
|
DS,
|
|
86
90
|
HINFO,
|
|
91
|
+
HTTPS,
|
|
87
92
|
IPSECKEY,
|
|
88
93
|
KEY,
|
|
89
94
|
LOC,
|
|
@@ -103,6 +108,7 @@ for (const c of [
|
|
|
103
108
|
SOA,
|
|
104
109
|
SPF,
|
|
105
110
|
SRV,
|
|
111
|
+
SVCB,
|
|
106
112
|
TLSA,
|
|
107
113
|
TSIG,
|
|
108
114
|
TXT,
|
package/package.json
CHANGED
package/rr/a.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import net from 'net'
|
|
1
|
+
import net from 'node:net'
|
|
2
2
|
|
|
3
3
|
import RR from '../rr.js'
|
|
4
4
|
|
|
@@ -9,8 +9,8 @@ export default class A extends RR {
|
|
|
9
9
|
|
|
10
10
|
/****** Resource record specific setters *******/
|
|
11
11
|
setAddress(val) {
|
|
12
|
-
if (!val)
|
|
13
|
-
if (!net.isIPv4(val))
|
|
12
|
+
if (!val) this.throwHelp('A: address is required')
|
|
13
|
+
if (!net.isIPv4(val)) this.throwHelp('A address must be IPv4')
|
|
14
14
|
this.set('address', val)
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -30,6 +30,16 @@ export default class A extends RR {
|
|
|
30
30
|
return 1
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
getCanonical() {
|
|
34
|
+
return {
|
|
35
|
+
owner: 'host.example.com.',
|
|
36
|
+
class: 'IN',
|
|
37
|
+
ttl: 3600,
|
|
38
|
+
type: 'A',
|
|
39
|
+
address: '192.0.2.127',
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
33
43
|
/****** IMPORTERS *******/
|
|
34
44
|
fromTinydns(opts) {
|
|
35
45
|
// +fqdn:ip:ttl:timestamp:lo
|
package/rr/aaaa.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import net from 'net'
|
|
1
|
+
import net from 'node:net'
|
|
2
2
|
|
|
3
3
|
import RR from '../rr.js'
|
|
4
4
|
import * as TINYDNS from '../lib/tinydns.js'
|
|
@@ -10,8 +10,8 @@ export default class AAAA extends RR {
|
|
|
10
10
|
|
|
11
11
|
/****** Resource record specific setters *******/
|
|
12
12
|
setAddress(val) {
|
|
13
|
-
if (!val)
|
|
14
|
-
if (!net.isIPv6(val))
|
|
13
|
+
if (!val) this.throwHelp('AAAA: address is required')
|
|
14
|
+
if (!net.isIPv6(val)) this.throwHelp(`AAAA: address must be IPv6 (${val})`)
|
|
15
15
|
|
|
16
16
|
this.set('address', this.expand(val.toLowerCase())) // lower case: RFC 5952
|
|
17
17
|
}
|
|
@@ -36,6 +36,16 @@ export default class AAAA extends RR {
|
|
|
36
36
|
return 28
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
getCanonical() {
|
|
40
|
+
return {
|
|
41
|
+
owner: 'host.example.com.',
|
|
42
|
+
address: '2001:0db8:0020:000a:0000:0000:0000:0004',
|
|
43
|
+
class: 'IN',
|
|
44
|
+
ttl: 3600,
|
|
45
|
+
type: 'A',
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
39
49
|
/****** IMPORTERS *******/
|
|
40
50
|
fromTinydns(opts) {
|
|
41
51
|
const str = opts.tinyline
|
|
@@ -45,7 +55,7 @@ export default class AAAA extends RR {
|
|
|
45
55
|
case ':':
|
|
46
56
|
// GENERIC => :fqdn:28:rdata:ttl:timestamp:lo
|
|
47
57
|
;[fqdn, n, rdata, ttl, ts, loc] = str.substring(1).split(':')
|
|
48
|
-
if (n != 28)
|
|
58
|
+
if (n != 28) this.throwHelp('AAAA fromTinydns, invalid n')
|
|
49
59
|
ip = TINYDNS.octalToHex(rdata)
|
|
50
60
|
.match(/([0-9a-fA-F]{4})/g)
|
|
51
61
|
.join(':')
|
package/rr/caa.js
CHANGED
|
@@ -11,7 +11,7 @@ export default class CAA extends RR {
|
|
|
11
11
|
this.is8bitInt('CAA', 'flags', val)
|
|
12
12
|
|
|
13
13
|
if (![0, 128].includes(val)) {
|
|
14
|
-
|
|
14
|
+
this.throwHelp(`CAA flags ${val} not recognized`)
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
this.set('flags', val)
|
|
@@ -19,12 +19,12 @@ export default class CAA extends RR {
|
|
|
19
19
|
|
|
20
20
|
setTag(val) {
|
|
21
21
|
if (typeof val !== 'string' || val.length < 1 || /[^a-z0-9]/.test(val))
|
|
22
|
-
|
|
23
|
-
`CAA tag must be a sequence of ASCII letters and numbers in lowercase
|
|
22
|
+
this.throwHelp(
|
|
23
|
+
`CAA tag must be a sequence of ASCII letters and numbers in lowercase`,
|
|
24
24
|
)
|
|
25
25
|
|
|
26
26
|
if (!['issue', 'issuewild', 'iodef'].includes(val)) {
|
|
27
|
-
|
|
27
|
+
this.throwHelp(`CAA tag ${val} not recognized`)
|
|
28
28
|
}
|
|
29
29
|
this.set('tag', val)
|
|
30
30
|
}
|
|
@@ -35,16 +35,14 @@ export default class CAA extends RR {
|
|
|
35
35
|
if (this.isQuoted(val)) {
|
|
36
36
|
val = val.replace(/^["']|["']$/g, '') // strip quotes
|
|
37
37
|
} else {
|
|
38
|
-
// if (/\s/.test(val))
|
|
38
|
+
// if (/\s/.test(val)) this.throwHelp(`CAA value may not have spaces unless quoted`)
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// check if val starts with one of iodefSchemes
|
|
42
42
|
if (this.get('tag') === 'iodef') {
|
|
43
43
|
const iodefSchemes = ['mailto:', 'http:', 'https:']
|
|
44
44
|
if (!iodefSchemes.filter((s) => val.startsWith(s)).length) {
|
|
45
|
-
|
|
46
|
-
`CAA value must have valid iodefScheme prefix, ${this.citeRFC()}`,
|
|
47
|
-
)
|
|
45
|
+
this.throwHelp(`CAA value must have valid iodefScheme prefix`)
|
|
48
46
|
}
|
|
49
47
|
}
|
|
50
48
|
|
|
@@ -71,11 +69,23 @@ export default class CAA extends RR {
|
|
|
71
69
|
return 257
|
|
72
70
|
}
|
|
73
71
|
|
|
72
|
+
getCanonical() {
|
|
73
|
+
return {
|
|
74
|
+
owner: 'example.com.',
|
|
75
|
+
ttl: 3600,
|
|
76
|
+
class: 'IN',
|
|
77
|
+
type: 'CAA',
|
|
78
|
+
flags: 0,
|
|
79
|
+
tag: 'issue',
|
|
80
|
+
value: 'http://letsencrypt.org',
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
74
84
|
/****** IMPORTERS *******/
|
|
75
85
|
fromTinydns(opts) {
|
|
76
86
|
// CAA via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
77
87
|
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
78
|
-
if (n != 257)
|
|
88
|
+
if (n != 257) this.throwHelp('CAA fromTinydns, invalid n')
|
|
79
89
|
|
|
80
90
|
const flags = TINYDNS.octalToUInt8(rdata.substring(0, 4))
|
|
81
91
|
const taglen = TINYDNS.octalToUInt8(rdata.substring(4, 8))
|
|
@@ -101,7 +111,7 @@ export default class CAA extends RR {
|
|
|
101
111
|
const fields = opts.bindline.match(
|
|
102
112
|
/^([^\s]+)\s+([0-9]+)\s+(\w+)\s+(\w+)\s+([0-9]+)\s+(\w+)\s+("[^"]+"|[^\s]+?)\s*$/i,
|
|
103
113
|
)
|
|
104
|
-
if (!fields)
|
|
114
|
+
if (!fields) this.throwHelp(`unable to parse: ${opts.bindline}`)
|
|
105
115
|
|
|
106
116
|
const [owner, ttl, c, type, flags, tag, value] = fields.slice(1)
|
|
107
117
|
return new CAA({
|
package/rr/cname.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import net from 'net'
|
|
1
|
+
import net from 'node:net'
|
|
2
2
|
|
|
3
3
|
import RR from '../rr.js'
|
|
4
4
|
|
|
@@ -12,10 +12,10 @@ export default class CNAME extends RR {
|
|
|
12
12
|
// A <domain-name> which specifies the canonical or primary
|
|
13
13
|
// name for the owner. The owner name is an alias.
|
|
14
14
|
|
|
15
|
-
if (!val)
|
|
15
|
+
if (!val) this.throwHelp('CNAME: cname is required')
|
|
16
16
|
|
|
17
17
|
if (net.isIPv4(val) || net.isIPv6(val))
|
|
18
|
-
|
|
18
|
+
this.throwHelp(`CNAME: cname must be a FQDN: RFC 2181`)
|
|
19
19
|
|
|
20
20
|
if (!this.isFullyQualified('CNAME', 'cname', val)) return
|
|
21
21
|
if (!this.isValidHostname('CNAME', 'cname', val)) return
|
package/rr/dname.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import net from 'net'
|
|
1
|
+
import net from 'node:net'
|
|
2
2
|
|
|
3
3
|
import RR from '../rr.js'
|
|
4
4
|
import * as TINYDNS from '../lib/tinydns.js'
|
|
@@ -10,10 +10,10 @@ export default class DNAME extends RR {
|
|
|
10
10
|
|
|
11
11
|
/****** Resource record specific setters *******/
|
|
12
12
|
setTarget(val) {
|
|
13
|
-
if (!val)
|
|
13
|
+
if (!val) this.throwHelp('DNAME: target is required')
|
|
14
14
|
|
|
15
15
|
if (net.isIPv4(val) || net.isIPv6(val))
|
|
16
|
-
|
|
16
|
+
this.throwHelp(`DNAME: target must be a domain name`)
|
|
17
17
|
|
|
18
18
|
this.isFullyQualified('DNAME', 'target', val)
|
|
19
19
|
this.isValidHostname('DNAME', 'target', val)
|
|
@@ -42,7 +42,7 @@ export default class DNAME extends RR {
|
|
|
42
42
|
fromTinydns(opts) {
|
|
43
43
|
// DNAME via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
44
44
|
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
45
|
-
if (n != 39)
|
|
45
|
+
if (n != 39) this.throwHelp('DNAME fromTinydns, invalid n')
|
|
46
46
|
|
|
47
47
|
return new DNAME({
|
|
48
48
|
type: 'DNAME',
|
package/rr/dnskey.js
CHANGED
|
@@ -13,8 +13,7 @@ export default class DNSKEY extends RR {
|
|
|
13
13
|
this.is16bitInt('DNSKEY', 'flags', val)
|
|
14
14
|
|
|
15
15
|
// the possible values are: 0, 256, and 257; RFC 4034
|
|
16
|
-
if (![0, 256, 257].includes(val))
|
|
17
|
-
throw new Error(`DNSKEY: flags invalid, ${this.citeRFC()}`)
|
|
16
|
+
if (![0, 256, 257].includes(val)) this.throwHelp(`DNSKEY: flags invalid`)
|
|
18
17
|
|
|
19
18
|
this.set('flags', val)
|
|
20
19
|
}
|
|
@@ -24,8 +23,7 @@ export default class DNSKEY extends RR {
|
|
|
24
23
|
this.is8bitInt('DNSKEY', 'protocol', val)
|
|
25
24
|
|
|
26
25
|
// The Protocol Field MUST be represented as an unsigned decimal integer with a value of 3.
|
|
27
|
-
if (![3].includes(val))
|
|
28
|
-
throw new Error(`DNSKEY: protocol invalid, ${this.citeRFC()}`)
|
|
26
|
+
if (![3].includes(val)) this.throwHelp(`DNSKEY: protocol invalid`)
|
|
29
27
|
|
|
30
28
|
this.set('protocol', val)
|
|
31
29
|
}
|
|
@@ -37,16 +35,13 @@ export default class DNSKEY extends RR {
|
|
|
37
35
|
// https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
|
|
38
36
|
// 1=RSA/MD5, 2=DH, 3=DSA/SHA-1, 4=EC, 5=RSA/SHA-1
|
|
39
37
|
if (![...Array(16).keys(), 253, 254].includes(val))
|
|
40
|
-
console.error(
|
|
41
|
-
`DNSKEY: algorithm (${val}) not recognized, ${this.citeRFC()}`,
|
|
42
|
-
)
|
|
38
|
+
console.error(`DNSKEY: algorithm (${val}) not recognized`)
|
|
43
39
|
|
|
44
40
|
this.set('algorithm', val)
|
|
45
41
|
}
|
|
46
42
|
|
|
47
43
|
setPublickey(val) {
|
|
48
|
-
if (!val)
|
|
49
|
-
throw new Error(`DNSKEY: publickey is required, ${this.citeRFC()}`)
|
|
44
|
+
if (!val) this.throwHelp(`DNSKEY: publickey is required`)
|
|
50
45
|
|
|
51
46
|
this.set('publickey', val)
|
|
52
47
|
}
|
|
@@ -74,7 +69,7 @@ export default class DNSKEY extends RR {
|
|
|
74
69
|
const match = opts.bindline.match(
|
|
75
70
|
/^([^\s]+)\s+([0-9]+)\s+(\w+)\s+(\w+)\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+\s*(.*?)\s*$/,
|
|
76
71
|
)
|
|
77
|
-
if (!match)
|
|
72
|
+
if (!match) this.throwHelp(`unable to parse DNSKEY: ${opts.bindline}`)
|
|
78
73
|
const [owner, ttl, c, type, flags, protocol, algorithm, publickey] =
|
|
79
74
|
match.slice(1)
|
|
80
75
|
|
|
@@ -92,7 +87,7 @@ export default class DNSKEY extends RR {
|
|
|
92
87
|
|
|
93
88
|
fromTinydns(opts) {
|
|
94
89
|
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
95
|
-
if (n != 48)
|
|
90
|
+
if (n != 48) this.throwHelp('DNSKEY fromTinydns, invalid n')
|
|
96
91
|
|
|
97
92
|
const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
98
93
|
|
package/rr/ds.js
CHANGED
|
@@ -10,9 +10,8 @@ export default class DS extends RR {
|
|
|
10
10
|
/****** Resource record specific setters *******/
|
|
11
11
|
setKeyTag(val) {
|
|
12
12
|
// a 2 octet Key Tag field...in network byte order
|
|
13
|
-
if (!val)
|
|
14
|
-
if (val.length > 2)
|
|
15
|
-
throw new Error(`DS: key tag is too long, ${this.citeRFC()}`)
|
|
13
|
+
if (!val) this.throwHelp(`DS: key tag is required`)
|
|
14
|
+
if (val.length > 2) this.throwHelp(`DS: key tag is too long`)
|
|
16
15
|
|
|
17
16
|
this.set('key tag', val)
|
|
18
17
|
}
|
|
@@ -20,20 +19,19 @@ export default class DS extends RR {
|
|
|
20
19
|
setAlgorithm(val) {
|
|
21
20
|
// 1=RSA/MD5, 2=DH, 3=DSA/SHA-1, 4=EC, 5=RSA/SHA-1
|
|
22
21
|
if (![1, 2, 3, 4, 5, 253, 254].includes(val))
|
|
23
|
-
|
|
22
|
+
this.throwHelp(`DS: algorithm invalid`)
|
|
24
23
|
|
|
25
24
|
this.set('algorithm', val)
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
setDigestType(val) {
|
|
29
|
-
if (![1, 2].includes(val))
|
|
30
|
-
throw new Error(`DS: digest type invalid, ${this.citeRFC()}`)
|
|
28
|
+
if (![1, 2].includes(val)) this.throwHelp(`DS: digest type invalid`)
|
|
31
29
|
|
|
32
30
|
this.set('digest type', val)
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
setDigest(val) {
|
|
36
|
-
if (!val)
|
|
34
|
+
if (!val) this.throwHelp(`DS: digest is required`)
|
|
37
35
|
|
|
38
36
|
this.set('digest', val)
|
|
39
37
|
}
|
|
@@ -74,7 +72,7 @@ export default class DS extends RR {
|
|
|
74
72
|
|
|
75
73
|
fromTinydns(opts) {
|
|
76
74
|
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
77
|
-
if (n != 43)
|
|
75
|
+
if (n != 43) this.throwHelp('DS fromTinydns, invalid n')
|
|
78
76
|
|
|
79
77
|
const binRdata = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
80
78
|
|
package/rr/hinfo.js
CHANGED
|
@@ -9,12 +9,12 @@ export default class HINFO extends RR {
|
|
|
9
9
|
|
|
10
10
|
/****** Resource record specific setters *******/
|
|
11
11
|
setCpu(val) {
|
|
12
|
-
if (val.length > 255)
|
|
12
|
+
if (val.length > 255) this.throwHelp('HINFO cpu cannot exceed 255 chars')
|
|
13
13
|
this.set('cpu', val.replace(/^["']|["']$/g, ''))
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
setOs(val) {
|
|
17
|
-
if (val.length > 255)
|
|
17
|
+
if (val.length > 255) this.throwHelp('HINFO os cannot exceed 255 chars')
|
|
18
18
|
this.set('os', val.replace(/^["']|["']$/g, ''))
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -44,7 +44,7 @@ export default class HINFO extends RR {
|
|
|
44
44
|
const match = opts.bindline.match(
|
|
45
45
|
/([^\s]+)\s+([0-9]+)\s+(IN)\s+(HINFO)\s+("[^"]+"|[^\s]+)\s+("[^"]+"|[^\s]+)/i,
|
|
46
46
|
)
|
|
47
|
-
if (!match)
|
|
47
|
+
if (!match) this.throwHelp(`unable to parse HINFO: ${opts.bindline}`)
|
|
48
48
|
const [owner, ttl, c, type, cpu, os] = match.slice(1)
|
|
49
49
|
|
|
50
50
|
return new HINFO({
|
package/rr/https.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import RR from '../rr.js'
|
|
2
|
+
|
|
3
|
+
export default class HTTPS extends RR {
|
|
4
|
+
constructor(opts) {
|
|
5
|
+
super(opts)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/****** Resource record specific setters *******/
|
|
9
|
+
setPriority(val) {
|
|
10
|
+
this.is16bitInt('HTTPS', 'priority', val)
|
|
11
|
+
|
|
12
|
+
this.set('priority', val)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
setTargetName(val) {
|
|
16
|
+
// this.isFullyQualified('HTTPS', 'target name', val)
|
|
17
|
+
// this.isValidHostname('HTTPS', 'target name', val)
|
|
18
|
+
|
|
19
|
+
// RFC 4034: letters in the DNS names are lower cased
|
|
20
|
+
this.set('target name', val.toLowerCase())
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
setParams(val) {
|
|
24
|
+
// if (!val) this.throwHelp(`HTTPS: params is required`)
|
|
25
|
+
|
|
26
|
+
this.set('params', val)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getDescription() {
|
|
30
|
+
return 'HTTP Semantics'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getRdataFields(arg) {
|
|
34
|
+
return ['priority', 'target name', 'params']
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getRFCs() {
|
|
38
|
+
return [9460]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getTypeId() {
|
|
42
|
+
return 65
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/****** IMPORTERS *******/
|
|
46
|
+
|
|
47
|
+
fromBind(opts) {
|
|
48
|
+
// test.example.com 3600 IN HTTPS Priority TargetName Params
|
|
49
|
+
const [owner, ttl, c, type, pri, fqdn] = opts.bindline.split(/\s+/)
|
|
50
|
+
return new HTTPS({
|
|
51
|
+
owner,
|
|
52
|
+
ttl: parseInt(ttl, 10),
|
|
53
|
+
class: c,
|
|
54
|
+
type,
|
|
55
|
+
priority: parseInt(pri, 10),
|
|
56
|
+
'target name': fqdn,
|
|
57
|
+
params: opts.bindline.split(/\s+/).slice(6).join(' ').trim(),
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/****** EXPORTERS *******/
|
|
62
|
+
}
|
package/rr/ipseckey.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import net from 'net'
|
|
1
|
+
import net from 'node:net'
|
|
2
2
|
|
|
3
3
|
import RR from '../rr.js'
|
|
4
4
|
|
|
@@ -20,23 +20,20 @@ export default class IPSECKEY extends RR {
|
|
|
20
20
|
setGatewayType(val) {
|
|
21
21
|
// 0 (none), 1 (4-byte IPv4), 2 (16-byte IPv6), 3 (wire encoded domain name)
|
|
22
22
|
if (![0, 1, 2, 3].includes(val))
|
|
23
|
-
|
|
23
|
+
this.throwHelp(`IPSECKEY: Gateway Type is invalid`)
|
|
24
24
|
|
|
25
25
|
this.set('gateway type', val)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
setAlgorithm(val) {
|
|
29
29
|
// unsigned int, 1 octet, values: 1=DSA, 2=RSA
|
|
30
|
-
if (![1, 2].includes(val))
|
|
31
|
-
throw new Error(`IPSECKEY: Algorithm invalid, ${this.citeRFC()}`)
|
|
30
|
+
if (![1, 2].includes(val)) this.throwHelp(`IPSECKEY: Algorithm invalid`)
|
|
32
31
|
|
|
33
32
|
this.set('algorithm', val)
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
setGateway(val) {
|
|
37
|
-
const gwErr = new Error(
|
|
38
|
-
`IPSECKEY: gateway invalid (${val}), ${this.citeRFC()}`,
|
|
39
|
-
)
|
|
36
|
+
const gwErr = new Error(`IPSECKEY: gateway invalid (${val})`)
|
|
40
37
|
switch (this.get('gateway type')) {
|
|
41
38
|
case 0:
|
|
42
39
|
if (val !== '.') throw gwErr
|
|
@@ -53,7 +50,7 @@ export default class IPSECKEY extends RR {
|
|
|
53
50
|
}
|
|
54
51
|
|
|
55
52
|
setPublickey(val) {
|
|
56
|
-
// if (val)
|
|
53
|
+
// if (val) this.throwHelp(`IPSECKEY: publickey is optional`)
|
|
57
54
|
|
|
58
55
|
this.set('publickey', val)
|
|
59
56
|
}
|
|
@@ -74,6 +71,20 @@ export default class IPSECKEY extends RR {
|
|
|
74
71
|
return 45
|
|
75
72
|
}
|
|
76
73
|
|
|
74
|
+
getCanonical() {
|
|
75
|
+
return {
|
|
76
|
+
owner: '38.2.0.192.in-addr.arpa.',
|
|
77
|
+
ttl: 7200,
|
|
78
|
+
class: 'IN',
|
|
79
|
+
type: 'IPSECKEY',
|
|
80
|
+
precedence: 10,
|
|
81
|
+
'gateway type': 1,
|
|
82
|
+
algorithm: 2,
|
|
83
|
+
gateway: '192.0.2.38',
|
|
84
|
+
publickey: 'AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==',
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
77
88
|
/****** IMPORTERS *******/
|
|
78
89
|
fromBind(opts) {
|
|
79
90
|
// FQDN TTL CLASS IPSECKEY Precedence GatewayType Algorithm Gateway PublicKey
|
|
@@ -94,7 +105,7 @@ export default class IPSECKEY extends RR {
|
|
|
94
105
|
|
|
95
106
|
fromTinydns(opts) {
|
|
96
107
|
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
97
|
-
if (n != 45)
|
|
108
|
+
if (n != 45) this.throwHelp('IPSECKEY fromTinydns, invalid n')
|
|
98
109
|
|
|
99
110
|
const precedence = TINYDNS.octalToUInt8(rdata.substring(0, 4))
|
|
100
111
|
const gwType = TINYDNS.octalToUInt8(rdata.substring(4, 8))
|
package/rr/key.js
CHANGED
|
@@ -24,13 +24,13 @@ export default class KEY extends RR {
|
|
|
24
24
|
// 1 octet
|
|
25
25
|
// 1=RSA/MD5, 2=DH, 3=DSA/SHA-1, 4=EC, 5=RSA/SHA-1
|
|
26
26
|
if (![1, 2, 3, 4, 5, 253, 254].includes(val))
|
|
27
|
-
|
|
27
|
+
this.throwHelp(`KEY: algorithm invalid`)
|
|
28
28
|
|
|
29
29
|
this.set('algorithm', val)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
setPublickey(val) {
|
|
33
|
-
if (!val)
|
|
33
|
+
if (!val) this.throwHelp(`KEY: publickey is required`)
|
|
34
34
|
|
|
35
35
|
this.set('publickey', val)
|
|
36
36
|
}
|
package/rr/loc.js
CHANGED
|
@@ -20,7 +20,7 @@ export default class LOC extends RR {
|
|
|
20
20
|
|
|
21
21
|
/****** Resource record specific setters *******/
|
|
22
22
|
setAddress(val) {
|
|
23
|
-
if (!val)
|
|
23
|
+
if (!val) this.throwHelp('LOC: address is required')
|
|
24
24
|
|
|
25
25
|
/*
|
|
26
26
|
... LOC ( d1 [m1 [s1]] {"N"|"S"} d2 [m2 [s2]]
|
|
@@ -59,7 +59,7 @@ export default class LOC extends RR {
|
|
|
59
59
|
// put them all together
|
|
60
60
|
const locRe = new RegExp(`^${dms}(N|S)\\s+${dms}(E|W)\\s+${alt}`, 'i')
|
|
61
61
|
const r = string.match(locRe)
|
|
62
|
-
if (!r)
|
|
62
|
+
if (!r) this.throwHelp('LOC address: invalid format, see RFC 1876')
|
|
63
63
|
|
|
64
64
|
const loc = {
|
|
65
65
|
latitude: {
|
|
@@ -89,7 +89,7 @@ export default class LOC extends RR {
|
|
|
89
89
|
fromTinydns(opts) {
|
|
90
90
|
// LOC via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
91
91
|
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
92
|
-
if (n != 29)
|
|
92
|
+
if (n != 29) this.throwHelp('LOC fromTinydns, invalid n')
|
|
93
93
|
|
|
94
94
|
// divide by 100 is to convert cm to meters
|
|
95
95
|
const l = {
|
|
@@ -173,7 +173,7 @@ export default class LOC extends RR {
|
|
|
173
173
|
hem = rawmsec >= REF.LATLON ? 'E' : 'W'
|
|
174
174
|
break
|
|
175
175
|
default:
|
|
176
|
-
|
|
176
|
+
this.throwHelp('unknown or missing hemisphere')
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
return `${deg} ${min} ${sec}${msec ? '.' + msec : ''} ${hem}`
|
package/rr/mx.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import net from 'net'
|
|
1
|
+
import net from 'node:net'
|
|
2
2
|
|
|
3
3
|
import RR from '../rr.js'
|
|
4
4
|
|
|
@@ -10,15 +10,16 @@ export default class MX extends RR {
|
|
|
10
10
|
/****** Resource record specific setters *******/
|
|
11
11
|
setPreference(val) {
|
|
12
12
|
if (val === undefined) val = this?.default?.preference
|
|
13
|
+
if (val === undefined) this.throwHelp('MX: preference is required')
|
|
13
14
|
this.is16bitInt('MX', 'preference', val)
|
|
14
15
|
this.set('preference', val)
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
setExchange(val) {
|
|
18
|
-
if (!val)
|
|
19
|
+
if (!val) this.throwHelp('MX: exchange is required')
|
|
19
20
|
|
|
20
21
|
if (net.isIPv4(val) || net.isIPv6(val))
|
|
21
|
-
|
|
22
|
+
this.throwHelp(`MX: exchange must be a FQDN`)
|
|
22
23
|
|
|
23
24
|
this.isFullyQualified('MX', 'exchange', val)
|
|
24
25
|
this.isValidHostname('MX', 'exchange', val)
|
|
@@ -43,6 +44,17 @@ export default class MX extends RR {
|
|
|
43
44
|
return 15
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
getCanonical() {
|
|
48
|
+
return {
|
|
49
|
+
owner: 'example.com.',
|
|
50
|
+
ttl: 43200,
|
|
51
|
+
class: 'IN',
|
|
52
|
+
type: 'MX',
|
|
53
|
+
preference: 0,
|
|
54
|
+
exchange: 'mail.example.com.',
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
46
58
|
/****** IMPORTERS *******/
|
|
47
59
|
fromTinydns(opts) {
|
|
48
60
|
// @fqdn:ip:x:dist:ttl:timestamp:lo
|
package/rr/naptr.js
CHANGED
|
@@ -41,7 +41,7 @@ export default class NAPTR extends RR {
|
|
|
41
41
|
|
|
42
42
|
setFlags(val) {
|
|
43
43
|
if (!['', 'S', 'A', 'U', 'P'].includes(val.toUpperCase()))
|
|
44
|
-
|
|
44
|
+
this.throwHelp(`NAPTR flags are invalid`)
|
|
45
45
|
|
|
46
46
|
this.set('flags', val.toUpperCase())
|
|
47
47
|
}
|
|
@@ -62,7 +62,7 @@ export default class NAPTR extends RR {
|
|
|
62
62
|
fromTinydns(opts) {
|
|
63
63
|
// NAPTR via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
64
64
|
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
65
|
-
if (n != 35)
|
|
65
|
+
if (n != 35) this.throwHelp('NAPTR fromTinydns, invalid n')
|
|
66
66
|
|
|
67
67
|
const binRdata = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
68
68
|
|