@nictool/dns-resource-record 1.2.0 → 1.2.2
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/.codeclimate.yml +25 -0
- package/.github/FUNDING.yml +3 -0
- package/.github/workflows/ci.yml +43 -0
- package/.github/workflows/codeql.yml +14 -0
- package/.github/workflows/publish.yml +16 -0
- package/.gitmodules +3 -0
- package/CHANGELOG.md +18 -0
- package/DEVELOP.md +9 -0
- package/README.md +6 -2
- package/eslint.config.mjs +41 -0
- package/index.js +6 -0
- package/package.json +12 -3
- package/rr/a.js +13 -3
- package/rr/aaaa.js +14 -4
- package/rr/caa.js +25 -13
- 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 +8 -6
- 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 +10 -10
- package/rr/tsig.js +10 -2
- package/rr/txt.js +5 -5
- package/rr/uri.js +2 -2
- package/rr/wks.js +4 -3
- package/rr.js +32 -20
- package/test/a.js +75 -0
- package/test/aaaa.js +86 -0
- package/test/base.js +148 -0
- package/test/caa.js +111 -0
- package/test/cert.js +48 -0
- package/test/cname.js +40 -0
- package/test/dname.js +57 -0
- package/test/dnskey.js +45 -0
- package/test/ds.js +45 -0
- package/test/fake.js +34 -0
- package/test/hinfo.js +80 -0
- package/test/https.js +56 -0
- package/test/ipseckey.js +141 -0
- package/test/key.js +36 -0
- package/test/loc.js +75 -0
- package/test/mx.js +78 -0
- package/test/naptr.js +47 -0
- package/test/ns.js +56 -0
- package/test/nsec.js +37 -0
- package/test/nsec3.js +47 -0
- package/test/nsec3param.js +23 -0
- package/test/nxt.js +37 -0
- package/test/openpgpkey.js +85 -0
- package/test/ptr.js +56 -0
- package/test/rr.js +212 -0
- package/test/smimea.js +51 -0
- package/test/soa.js +99 -0
- package/test/spf.js +51 -0
- package/test/srv.js +101 -0
- package/test/sshfp.js +69 -0
- package/test/svcb.js +56 -0
- package/test/tinydns.js +163 -0
- package/test/tlsa.js +63 -0
- package/test/txt.js +82 -0
- package/test/uri.js +65 -0
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
|
|
package/rr/ns.js
CHANGED
|
@@ -8,7 +8,7 @@ export default class NS extends RR {
|
|
|
8
8
|
|
|
9
9
|
/****** Resource record specific setters *******/
|
|
10
10
|
setDname(val) {
|
|
11
|
-
if (!val)
|
|
11
|
+
if (!val) this.throwHelp(`NS: dname is required`)
|
|
12
12
|
|
|
13
13
|
this.isFullyQualified('NS', 'dname', val)
|
|
14
14
|
this.isValidHostname('NS', 'dname', val)
|
package/rr/nsec.js
CHANGED
|
@@ -8,8 +8,7 @@ export default class NSEC extends RR {
|
|
|
8
8
|
|
|
9
9
|
/****** Resource record specific setters *******/
|
|
10
10
|
setNextDomain(val) {
|
|
11
|
-
if (!val)
|
|
12
|
-
throw new Error(`NSEC: 'next domain' is required:, ${this.citeRFC()}`)
|
|
11
|
+
if (!val) this.throwHelp(`NSEC: 'next domain' is required:`)
|
|
13
12
|
|
|
14
13
|
this.isFullyQualified('NSEC', 'next domain', val)
|
|
15
14
|
this.isValidHostname('NSEC', 'next domain', val)
|
|
@@ -19,8 +18,7 @@ export default class NSEC extends RR {
|
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
setTypeBitMaps(val) {
|
|
22
|
-
if (!val)
|
|
23
|
-
throw new Error(`NSEC: 'type bit maps' is required, ${this.citeRFC()}`)
|
|
21
|
+
if (!val) this.throwHelp(`NSEC: 'type bit maps' is required`)
|
|
24
22
|
|
|
25
23
|
this.set('type bit maps', val)
|
|
26
24
|
}
|
package/rr/nsec3.js
CHANGED
|
@@ -12,8 +12,7 @@ export default class NSEC3 extends RR {
|
|
|
12
12
|
setHashAlgorithm(val) {
|
|
13
13
|
// Hash Algorithm is a single octet.
|
|
14
14
|
// The Hash Algorithm field is represented as an unsigned decimal integer.
|
|
15
|
-
if (!val)
|
|
16
|
-
throw new Error(`NSEC3: 'hash algorithm' is required, ${this.citeRFC()}`)
|
|
15
|
+
if (!val) this.throwHelp(`NSEC3: 'hash algorithm' is required`)
|
|
17
16
|
|
|
18
17
|
this.is8bitInt('NSEC3', 'hash algorithm', val)
|
|
19
18
|
|
|
@@ -22,7 +21,7 @@ export default class NSEC3 extends RR {
|
|
|
22
21
|
|
|
23
22
|
setFlags(val) {
|
|
24
23
|
// The Flags field is represented as an unsigned decimal integer.
|
|
25
|
-
if (!val)
|
|
24
|
+
if (!val) this.throwHelp(`NSEC3: 'flags' is required`)
|
|
26
25
|
|
|
27
26
|
this.is8bitInt('NSEC3', 'flags', val)
|
|
28
27
|
|
|
@@ -31,8 +30,7 @@ export default class NSEC3 extends RR {
|
|
|
31
30
|
|
|
32
31
|
setIterations(val) {
|
|
33
32
|
// The Iterations field is represented as an unsigned decimal integer. 0-65535
|
|
34
|
-
if (!val)
|
|
35
|
-
throw new Error(`NSEC3: 'iterations' is required, ${this.citeRFC()}`)
|
|
33
|
+
if (!val) this.throwHelp(`NSEC3: 'iterations' is required`)
|
|
36
34
|
|
|
37
35
|
this.is16bitInt('NSEC3', 'flags', val)
|
|
38
36
|
|
|
@@ -50,18 +48,14 @@ export default class NSEC3 extends RR {
|
|
|
50
48
|
setNextHashedOwnerName(val) {
|
|
51
49
|
// The Next Hashed Owner Name field is represented as an unpadded
|
|
52
50
|
// sequence of case-insensitive base32 digits, without whitespace
|
|
53
|
-
if (!val)
|
|
54
|
-
throw new Error(
|
|
55
|
-
`NSEC3: 'next hashed owner name' is required, ${this.citeRFC()}`,
|
|
56
|
-
)
|
|
51
|
+
if (!val) this.throwHelp(`NSEC3: 'next hashed owner name' is required`)
|
|
57
52
|
|
|
58
53
|
this.set('next hashed owner name', val)
|
|
59
54
|
}
|
|
60
55
|
|
|
61
56
|
setTypeBitMaps(val) {
|
|
62
57
|
// The Type Bit Maps field is represented as a sequence of RR type mnemonics.
|
|
63
|
-
if (!val)
|
|
64
|
-
throw new Error(`NSEC3: 'type bit maps' is required, ${this.citeRFC()}`)
|
|
58
|
+
if (!val) this.throwHelp(`NSEC3: 'type bit maps' is required`)
|
|
65
59
|
|
|
66
60
|
this.set('type bit maps', val)
|
|
67
61
|
}
|
|
@@ -113,7 +107,7 @@ export default class NSEC3 extends RR {
|
|
|
113
107
|
|
|
114
108
|
fromTinydns(opts) {
|
|
115
109
|
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
116
|
-
if (n != 50)
|
|
110
|
+
if (n != 50) this.throwHelp('NSEC3 fromTinydns, invalid n')
|
|
117
111
|
|
|
118
112
|
const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
119
113
|
|
package/rr/nsec3param.js
CHANGED
|
@@ -7,13 +7,10 @@ export default class NSEC3PARAM extends RR {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
/****** Resource record specific setters *******/
|
|
10
|
-
|
|
10
|
+
setHashAlgorithm(val) {
|
|
11
11
|
// Hash Algorithm is a single octet.
|
|
12
12
|
// The Hash Algorithm field is represented as an unsigned decimal integer.
|
|
13
|
-
if (!val)
|
|
14
|
-
throw new Error(
|
|
15
|
-
`NSEC3PARAM: 'hash algorithm' is required, ${this.citeRFC()}`,
|
|
16
|
-
)
|
|
13
|
+
if (!val) this.throwHelp(`NSEC3PARAM: 'hash algorithm' is required`)
|
|
17
14
|
|
|
18
15
|
this.is8bitInt('NSEC3PARAM', 'hash algorithm', val)
|
|
19
16
|
|
|
@@ -22,8 +19,7 @@ export default class NSEC3PARAM extends RR {
|
|
|
22
19
|
|
|
23
20
|
setFlags(val) {
|
|
24
21
|
// The Flags field is represented as an unsigned decimal integer.
|
|
25
|
-
if (!val)
|
|
26
|
-
throw new Error(`NSEC3PARAM: 'flags' is required, ${this.citeRFC()}`)
|
|
22
|
+
if (!val) this.throwHelp(`NSEC3PARAM: 'flags' is required`)
|
|
27
23
|
|
|
28
24
|
this.is8bitInt('NSEC3PARAM', 'flags', val)
|
|
29
25
|
|
|
@@ -32,8 +28,7 @@ export default class NSEC3PARAM extends RR {
|
|
|
32
28
|
|
|
33
29
|
setIterations(val) {
|
|
34
30
|
// The Iterations field is represented as an unsigned decimal integer. 0-65535
|
|
35
|
-
if (!val)
|
|
36
|
-
throw new Error(`NSEC3PARAM: 'iterations' is required, ${this.citeRFC()}`)
|
|
31
|
+
if (!val) this.throwHelp(`NSEC3PARAM: 'iterations' is required`)
|
|
37
32
|
|
|
38
33
|
this.is16bitInt('NSEC3PARAM', 'iterations', val)
|
|
39
34
|
|
package/rr/nxt.js
CHANGED
|
@@ -8,8 +8,7 @@ export default class NXT extends RR {
|
|
|
8
8
|
|
|
9
9
|
/****** Resource record specific setters *******/
|
|
10
10
|
setNextDomain(val) {
|
|
11
|
-
if (!val)
|
|
12
|
-
throw new Error(`NXT: 'next domain' is required:, ${this.citeRFC()}`)
|
|
11
|
+
if (!val) this.throwHelp(`NXT: 'next domain' is required`)
|
|
13
12
|
|
|
14
13
|
this.isFullyQualified('NXT', 'next domain', val)
|
|
15
14
|
this.isValidHostname('NXT', 'next domain', val)
|
|
@@ -19,8 +18,7 @@ export default class NXT extends RR {
|
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
setTypeBitMap(val) {
|
|
22
|
-
if (!val)
|
|
23
|
-
throw new Error(`NXT: 'type bit map' is required, ${this.citeRFC()}`)
|
|
21
|
+
if (!val) this.throwHelp(`NXT: 'type bit map' is required`)
|
|
24
22
|
|
|
25
23
|
this.set('type bit map', val)
|
|
26
24
|
}
|
package/rr/openpgpkey.js
CHANGED
|
@@ -27,15 +27,19 @@ export default class OPENPGPKEY extends RR {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/****** IMPORTERS *******/
|
|
30
|
-
fromBind(
|
|
30
|
+
fromBind(obj) {
|
|
31
31
|
// test.example.com 3600 IN OPENPGPKEY <base64 public key>
|
|
32
|
-
|
|
32
|
+
// eslint-disable-next-line no-unused-vars
|
|
33
|
+
const [ignore, owner, ttl, c, type, publickey] = obj.bindline
|
|
34
|
+
.trim()
|
|
35
|
+
.match(/^([\S]+)\s+(\d{1,10})\s+(IN)\s+(OPENPGPKEY)\s+([\W\w]*)$/)
|
|
36
|
+
|
|
33
37
|
return new OPENPGPKEY({
|
|
34
38
|
owner,
|
|
35
39
|
ttl: parseInt(ttl, 10),
|
|
36
40
|
class: c,
|
|
37
41
|
type: type,
|
|
38
|
-
'
|
|
42
|
+
'public key': publickey.trim(),
|
|
39
43
|
})
|
|
40
44
|
}
|
|
41
45
|
|
package/rr/rrsig.js
CHANGED
|
@@ -8,9 +8,8 @@ export default class RRSIG extends RR {
|
|
|
8
8
|
/****** Resource record specific setters *******/
|
|
9
9
|
setTypeCovered(val) {
|
|
10
10
|
// a 2 octet Type Covered field
|
|
11
|
-
if (!val)
|
|
12
|
-
if (val.length > 2)
|
|
13
|
-
throw new Error(`RRSIG: 'type covered' is too long, ${this.citeRFC()}`)
|
|
11
|
+
if (!val) this.throwHelp(`RRSIG: 'type covered' is required`)
|
|
12
|
+
if (val.length > 2) this.throwHelp(`RRSIG: 'type covered' is too long`)
|
|
14
13
|
|
|
15
14
|
this.set('type covered', val)
|
|
16
15
|
}
|
|
@@ -19,7 +18,7 @@ export default class RRSIG extends RR {
|
|
|
19
18
|
// a 1 octet Algorithm field
|
|
20
19
|
// 1=RSA/MD5, 2=DH, 3=RRSIGA/SHA-1, 4=EC, 5=RSA/SHA-1
|
|
21
20
|
if (![1, 2, 3, 4, 5, 253, 254].includes(val))
|
|
22
|
-
|
|
21
|
+
this.throwHelp(`RRSIG: algorithm invalid`)
|
|
23
22
|
|
|
24
23
|
this.set('algorithm', val)
|
|
25
24
|
}
|
package/rr/sig.js
CHANGED
|
@@ -8,7 +8,7 @@ export default class SIG extends RR {
|
|
|
8
8
|
/****** Resource record specific setters *******/
|
|
9
9
|
setTypeCovered(val) {
|
|
10
10
|
// a 2 octet Type Covered field
|
|
11
|
-
if (!val)
|
|
11
|
+
if (!val) this.throwHelp(`SIG: 'type covered' is required`)
|
|
12
12
|
|
|
13
13
|
this.set('type covered', val)
|
|
14
14
|
}
|
package/rr/smimea.js
CHANGED
|
@@ -8,21 +8,19 @@ export default class SMIMEA extends RR {
|
|
|
8
8
|
/****** Resource record specific setters *******/
|
|
9
9
|
setCertificateUsage(val) {
|
|
10
10
|
if (![0, 1, 2, 3].includes(val))
|
|
11
|
-
|
|
11
|
+
this.throwHelp(`SMIMEA: certificate usage invalid`)
|
|
12
12
|
|
|
13
13
|
this.set('certificate usage', val)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
setSelector(val) {
|
|
17
|
-
if (![0, 1].includes(val))
|
|
18
|
-
throw new Error(`SMIMEA: selector invalid, ${this.citeRFC()}`)
|
|
17
|
+
if (![0, 1].includes(val)) this.throwHelp(`SMIMEA: selector invalid`)
|
|
19
18
|
|
|
20
19
|
this.set('selector', val)
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
setMatchingType(val) {
|
|
24
|
-
if (![0, 1, 2].includes(val))
|
|
25
|
-
throw new Error(`SMIMEA: matching type, ${this.citeRFC()}`)
|
|
23
|
+
if (![0, 1, 2].includes(val)) this.throwHelp(`SMIMEA: matching type`)
|
|
26
24
|
|
|
27
25
|
this.set('matching type', val)
|
|
28
26
|
}
|
package/rr/soa.js
CHANGED
|
@@ -28,8 +28,7 @@ export default class SOA extends RR {
|
|
|
28
28
|
// RNAME (email of admin) (escape . with \)
|
|
29
29
|
this.isValidHostname('SOA', 'RNAME', val)
|
|
30
30
|
this.isFullyQualified('SOA', 'RNAME', val)
|
|
31
|
-
if (/@/.test(val))
|
|
32
|
-
throw new Error(`SOA rname replaces @ with a . (dot), ${this.citeRFC()}`)
|
|
31
|
+
if (/@/.test(val)) this.throwHelp(`SOA rname replaces @ with a . (dot)`)
|
|
33
32
|
|
|
34
33
|
// RFC 4034: letters in the DNS names are lower cased
|
|
35
34
|
this.set('rname', val.toLowerCase())
|
package/rr/spf.js
CHANGED
|
@@ -34,7 +34,7 @@ export default class SPF extends TXT {
|
|
|
34
34
|
fromTinydns(opts) {
|
|
35
35
|
// SPF via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
36
36
|
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
37
|
-
if (n != 99)
|
|
37
|
+
if (n != 99) this.throwHelp('SPF fromTinydns, invalid n')
|
|
38
38
|
|
|
39
39
|
return new SPF({
|
|
40
40
|
type: 'SPF',
|
package/rr/srv.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'
|
|
@@ -28,10 +28,10 @@ export default class SRV extends RR {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
setTarget(val) {
|
|
31
|
-
if (!val)
|
|
31
|
+
if (!val) this.throwHelp(`SRV: target is required`)
|
|
32
32
|
|
|
33
33
|
if (net.isIPv4(val) || net.isIPv6(val))
|
|
34
|
-
|
|
34
|
+
this.throwHelp(`SRV: target must be a FQDN`)
|
|
35
35
|
|
|
36
36
|
this.isFullyQualified('SRV', 'target', val)
|
|
37
37
|
this.isValidHostname('SRV', 'target', val)
|
|
@@ -69,7 +69,7 @@ export default class SRV extends RR {
|
|
|
69
69
|
} else {
|
|
70
70
|
// tinydns generic record format
|
|
71
71
|
;[fqdn, n, rdata, ttl, ts, loc] = str.substring(1).split(':')
|
|
72
|
-
if (n != 33)
|
|
72
|
+
if (n != 33) this.throwHelp('SRV fromTinydns: invalid n')
|
|
73
73
|
|
|
74
74
|
pri = TINYDNS.octalToUInt16(rdata.substring(0, 8))
|
|
75
75
|
weight = TINYDNS.octalToUInt16(rdata.substring(8, 16))
|
package/rr/sshfp.js
CHANGED
|
@@ -45,7 +45,7 @@ export default class SSHFP extends RR {
|
|
|
45
45
|
fromTinydns(opts) {
|
|
46
46
|
// SSHFP via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
47
47
|
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
48
|
-
if (n != 44)
|
|
48
|
+
if (n != 44) this.throwHelp('SSHFP fromTinydns, invalid n')
|
|
49
49
|
|
|
50
50
|
return new SSHFP({
|
|
51
51
|
owner: this.fullyQualify(fqdn),
|
package/rr/svcb.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import RR from '../rr.js'
|
|
2
|
+
|
|
3
|
+
export default class SVCB extends RR {
|
|
4
|
+
constructor(opts) {
|
|
5
|
+
super(opts)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/****** Resource record specific setters *******/
|
|
9
|
+
setPriority(val) {
|
|
10
|
+
this.is16bitInt('SVCB', 'priority', val)
|
|
11
|
+
|
|
12
|
+
this.set('priority', val)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
setTargetName(val) {
|
|
16
|
+
// this.isFullyQualified('SVCB', 'target name', val)
|
|
17
|
+
// this.isValidHostname('SVCB', '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) throw new Error(`SVCB: params is required`)
|
|
25
|
+
|
|
26
|
+
this.set('params', val)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getDescription() {
|
|
30
|
+
return 'Service Binding'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getRdataFields(arg) {
|
|
34
|
+
return ['priority', 'target name', 'params']
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getRFCs() {
|
|
38
|
+
return [9460]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getTypeId() {
|
|
42
|
+
return 64
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/****** IMPORTERS *******/
|
|
46
|
+
|
|
47
|
+
fromBind(opts) {
|
|
48
|
+
// test.example.com 3600 IN SVCB Priority TargetName Params
|
|
49
|
+
// _8443._foo.api.example.com. 7200 IN SVCB 0 svc4.example.net.
|
|
50
|
+
// svc4.example.net. 7200 IN SVCB 3 svc4.example.net. ( alpn="bar" port="8004" )
|
|
51
|
+
const [owner, ttl, c, type, pri, fqdn] = opts.bindline.split(/\s+/)
|
|
52
|
+
return new SVCB({
|
|
53
|
+
owner,
|
|
54
|
+
ttl: parseInt(ttl, 10),
|
|
55
|
+
class: c,
|
|
56
|
+
type,
|
|
57
|
+
priority: parseInt(pri, 10),
|
|
58
|
+
'target name': fqdn,
|
|
59
|
+
params: opts.bindline.split(/\s+/).slice(6).join(' ').trim(),
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/****** EXPORTERS *******/
|
|
64
|
+
}
|
package/rr/tlsa.js
CHANGED
|
@@ -10,21 +10,19 @@ export default class TLSA extends RR {
|
|
|
10
10
|
/****** Resource record specific setters *******/
|
|
11
11
|
setCertificateUsage(val) {
|
|
12
12
|
if (![0, 1, 2, 3].includes(val))
|
|
13
|
-
|
|
13
|
+
this.throwHelp(`TLSA: certificate usage invalid`)
|
|
14
14
|
|
|
15
15
|
this.set('certificate usage', val)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
setSelector(val) {
|
|
19
|
-
if (![0, 1].includes(val))
|
|
20
|
-
throw new Error(`TLSA: selector invalid, ${this.citeRFC()}`)
|
|
19
|
+
if (![0, 1].includes(val)) this.throwHelp(`TLSA: selector invalid`)
|
|
21
20
|
|
|
22
21
|
this.set('selector', val)
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
setMatchingType(val) {
|
|
26
|
-
if (![0, 1, 2].includes(val))
|
|
27
|
-
throw new Error(`TLSA: matching type, ${this.citeRFC()}`)
|
|
25
|
+
if (![0, 1, 2].includes(val)) this.throwHelp(`TLSA: matching type`)
|
|
28
26
|
|
|
29
27
|
this.set('matching type', val)
|
|
30
28
|
}
|
|
@@ -62,10 +60,12 @@ export default class TLSA extends RR {
|
|
|
62
60
|
|
|
63
61
|
fromBind(opts) {
|
|
64
62
|
// test.example.com 3600 IN TLSA, usage, selector, match, data
|
|
65
|
-
const match = opts.bindline
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
const match = opts.bindline
|
|
64
|
+
.trim()
|
|
65
|
+
.split(
|
|
66
|
+
/^([^\s]+)\s+([0-9]{1,10})\s+(IN)\s+(TLSA)\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+(.*?)$/,
|
|
67
|
+
)
|
|
68
|
+
if (!match) this.throwHelp(`unable to parse TLSA: ${opts.bindline}`)
|
|
69
69
|
const [owner, ttl, c, type, usage, selector, matchtype, cad] =
|
|
70
70
|
match.slice(1)
|
|
71
71
|
return new TLSA({
|
|
@@ -82,7 +82,7 @@ export default class TLSA extends RR {
|
|
|
82
82
|
|
|
83
83
|
fromTinydns(opts) {
|
|
84
84
|
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
85
|
-
if (n != 52)
|
|
85
|
+
if (n != 52) this.throwHelp('TLSA fromTinydns, invalid n')
|
|
86
86
|
|
|
87
87
|
const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
88
88
|
|