@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/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.match(
|
|
34
|
+
/^([\S]+)\s+(\d+)\s+(\w+)\s+(\w+)\s+([\W\w]*)$/,
|
|
35
|
+
)
|
|
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
|
}
|
|
@@ -65,7 +63,7 @@ export default class TLSA extends RR {
|
|
|
65
63
|
const match = opts.bindline.split(
|
|
66
64
|
/^([^\s]+)\s+([0-9]+)\s+(\w+)\s+(\w+)\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+(.*?)\s*$/,
|
|
67
65
|
)
|
|
68
|
-
if (!match)
|
|
66
|
+
if (!match) this.throwHelp(`unable to parse TLSA: ${opts.bindline}`)
|
|
69
67
|
const [owner, ttl, c, type, usage, selector, matchtype, cad] =
|
|
70
68
|
match.slice(1)
|
|
71
69
|
return new TLSA({
|
|
@@ -82,7 +80,7 @@ export default class TLSA extends RR {
|
|
|
82
80
|
|
|
83
81
|
fromTinydns(opts) {
|
|
84
82
|
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
85
|
-
if (n != 52)
|
|
83
|
+
if (n != 52) this.throwHelp('TLSA fromTinydns, invalid n')
|
|
86
84
|
|
|
87
85
|
const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
88
86
|
|
package/rr/tsig.js
CHANGED
|
@@ -13,7 +13,15 @@ export default class TSIG extends RR {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
getRdataFields(arg) {
|
|
16
|
-
return [
|
|
16
|
+
return [
|
|
17
|
+
'algorithm name',
|
|
18
|
+
'time signed',
|
|
19
|
+
'fudge',
|
|
20
|
+
'mac',
|
|
21
|
+
'original id',
|
|
22
|
+
'error',
|
|
23
|
+
'other',
|
|
24
|
+
]
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
getRFCs() {
|
|
@@ -34,7 +42,7 @@ export default class TSIG extends RR {
|
|
|
34
42
|
ttl: parseInt(ttl, 10),
|
|
35
43
|
class: c,
|
|
36
44
|
type: type,
|
|
37
|
-
|
|
45
|
+
algorithm: algorithm,
|
|
38
46
|
// 'time signed': opts.bindline,
|
|
39
47
|
// fudge
|
|
40
48
|
// mac
|
package/rr/txt.js
CHANGED
|
@@ -54,7 +54,7 @@ export default class TXT extends RR {
|
|
|
54
54
|
// generic: :fqdn:n:rdata:ttl:timestamp:location
|
|
55
55
|
// eslint-disable-next-line prefer-const
|
|
56
56
|
let [fqdn, n, rdata, ttl, ts, loc] = str.substring(1).split(':')
|
|
57
|
-
if (n != 16)
|
|
57
|
+
if (n != 16) this.throwHelp('TXT fromTinydns, invalid n')
|
|
58
58
|
|
|
59
59
|
rdata = TINYDNS.octalToChar(rdata)
|
|
60
60
|
let s = ''
|
|
@@ -73,7 +73,7 @@ export default class TXT extends RR {
|
|
|
73
73
|
const match = opts.bindline.split(
|
|
74
74
|
/^([^\s]+)\s+([0-9]+)\s+(\w+)\s+(\w+)\s+?\s*(.*?)\s*$/,
|
|
75
75
|
)
|
|
76
|
-
if (!match)
|
|
76
|
+
if (!match) this.throwHelp(`unable to parse TXT: ${opts.bindline}`)
|
|
77
77
|
const [owner, ttl, c, type, rdata] = match.slice(1)
|
|
78
78
|
|
|
79
79
|
return new this.constructor({
|
package/rr/uri.js
CHANGED
|
@@ -21,7 +21,7 @@ export default class URI extends RR {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
setTarget(val) {
|
|
24
|
-
if (!val)
|
|
24
|
+
if (!val) this.throwHelp(`URI: target is required`)
|
|
25
25
|
|
|
26
26
|
this.set('target', val)
|
|
27
27
|
}
|
|
@@ -30,7 +30,7 @@ export default class URI extends RR {
|
|
|
30
30
|
fromTinydns(opts) {
|
|
31
31
|
// URI via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
32
32
|
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
33
|
-
if (n != 256)
|
|
33
|
+
if (n != 256) this.throwHelp('URI fromTinydns, invalid n')
|
|
34
34
|
|
|
35
35
|
return new URI({
|
|
36
36
|
type: 'URI',
|
package/rr/wks.js
CHANGED
|
@@ -28,15 +28,16 @@ export default class WKS extends RR {
|
|
|
28
28
|
|
|
29
29
|
fromBind(opts) {
|
|
30
30
|
// test.example.com 3600 IN WKS 192.168.1.1 TCP 25
|
|
31
|
-
const [owner, ttl, c, type, address, protocol, bitmap] =
|
|
31
|
+
const [owner, ttl, c, type, address, protocol, bitmap] =
|
|
32
|
+
opts.bindline.split(/\s+/)
|
|
32
33
|
return new WKS({
|
|
33
34
|
owner,
|
|
34
35
|
ttl: parseInt(ttl, 10),
|
|
35
36
|
class: c,
|
|
36
37
|
type,
|
|
37
|
-
address,
|
|
38
|
+
address, // 32-bit int
|
|
38
39
|
protocol, // 8-bit int, 6=TCP, 17=UDP
|
|
39
|
-
bitmap,
|
|
40
|
+
bitmap, // var len bit map, must be multiple of 8
|
|
40
41
|
})
|
|
41
42
|
}
|
|
42
43
|
|
package/rr.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import util from 'node:util'
|
|
2
|
+
|
|
1
3
|
export default class RR extends Map {
|
|
2
4
|
constructor(opts) {
|
|
3
5
|
super()
|
|
@@ -21,7 +23,7 @@ export default class RR extends Map {
|
|
|
21
23
|
for (const f of this.getFields('rdata')) {
|
|
22
24
|
const fnName = `set${this.ucfirst(f)}`
|
|
23
25
|
if (this[fnName] === undefined)
|
|
24
|
-
|
|
26
|
+
this.throwHelp(`Missing ${fnName} in class ${this.get('type')}`)
|
|
25
27
|
this[fnName](opts[f])
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -51,7 +53,7 @@ export default class RR extends Map {
|
|
|
51
53
|
this.set('class', c)
|
|
52
54
|
break
|
|
53
55
|
default:
|
|
54
|
-
|
|
56
|
+
this.throwHelp(`invalid class ${c}`)
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
|
|
@@ -74,20 +76,20 @@ export default class RR extends Map {
|
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
setOwner(n) {
|
|
77
|
-
if (n === undefined)
|
|
79
|
+
if (n === undefined) this.throwHelp(`owner is required`)
|
|
78
80
|
|
|
79
81
|
if (n.length < 1 || n.length > 255)
|
|
80
|
-
|
|
82
|
+
this.throwHelp(
|
|
81
83
|
'Domain names must have 1-255 octets (characters): RFC 2181',
|
|
82
84
|
)
|
|
83
85
|
|
|
84
|
-
this.isFullyQualified(
|
|
86
|
+
this.isFullyQualified(this.constructor.name, 'owner', n)
|
|
85
87
|
this.hasValidLabels(n)
|
|
86
88
|
|
|
87
89
|
// wildcard records: RFC 1034, 4592
|
|
88
90
|
if (/\*/.test(n)) {
|
|
89
91
|
if (!/^\*\./.test(n) && !/\.\*\./.test(n))
|
|
90
|
-
|
|
92
|
+
this.throwHelp('only *.something or * (by itself) is a valid wildcard')
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
this.set('owner', n.toLowerCase())
|
|
@@ -97,11 +99,11 @@ export default class RR extends Map {
|
|
|
97
99
|
if (t === undefined) t = this?.default?.ttl
|
|
98
100
|
if (t === undefined) {
|
|
99
101
|
if (['SOA', 'SSHPF'].includes(this.get('type'))) return
|
|
100
|
-
|
|
102
|
+
this.throwHelp('TTL is required, no default available')
|
|
101
103
|
}
|
|
102
104
|
|
|
103
105
|
if (typeof t !== 'number')
|
|
104
|
-
|
|
106
|
+
this.throwHelp(`TTL must be numeric (${typeof t})`)
|
|
105
107
|
|
|
106
108
|
// RFC 1035, 2181
|
|
107
109
|
this.is32bitInt(this.owner, 'TTL', t)
|
|
@@ -113,17 +115,27 @@ export default class RR extends Map {
|
|
|
113
115
|
switch (t) {
|
|
114
116
|
case '':
|
|
115
117
|
case undefined:
|
|
116
|
-
|
|
118
|
+
this.throwHelp(`type is required`)
|
|
117
119
|
}
|
|
118
120
|
|
|
119
121
|
if (t.toUpperCase() !== this.constructor.name)
|
|
120
|
-
|
|
122
|
+
this.throwHelp(`type ${t} doesn't match ${this.constructor.name}`)
|
|
121
123
|
|
|
122
124
|
this.set('type', t.toUpperCase())
|
|
123
125
|
}
|
|
124
126
|
|
|
127
|
+
throwHelp(e) {
|
|
128
|
+
if (this.constructor.name === 'RR') throw new Error(e)
|
|
129
|
+
|
|
130
|
+
const example = this.getCanonical
|
|
131
|
+
? `Example ${this.constructor.name}:\n${util.inspect(this.getCanonical(), { depth: null })}\n\n`
|
|
132
|
+
: `${this.constructor.name} records have the fields: ${this.getFields().join(', ')}\n\n`
|
|
133
|
+
|
|
134
|
+
throw new Error(`${e}\n\n${example}${this.citeRFC()}\n`)
|
|
135
|
+
}
|
|
136
|
+
|
|
125
137
|
citeRFC() {
|
|
126
|
-
return `see RFC ${this.getRFCs()}`
|
|
138
|
+
return `see RFC${this.getRFCs().length > 1 ? 's' : ''} ${this.getRFCs()}`
|
|
127
139
|
}
|
|
128
140
|
|
|
129
141
|
fullyQualify(hostname, origin) {
|
|
@@ -194,7 +206,7 @@ export default class RR extends Map {
|
|
|
194
206
|
|
|
195
207
|
getFQDN(field, zone_opts = {}) {
|
|
196
208
|
let fqdn = this.get(field)
|
|
197
|
-
if (!fqdn)
|
|
209
|
+
if (!fqdn) this.throwHelp(`empty value for field ${field}`)
|
|
198
210
|
if (!fqdn.endsWith('.')) fqdn += '.'
|
|
199
211
|
|
|
200
212
|
if (zone_opts.hide?.origin && zone_opts.origin) {
|
|
@@ -235,7 +247,7 @@ export default class RR extends Map {
|
|
|
235
247
|
const fq = hostname.endsWith('.') ? hostname.slice(0, -1) : hostname
|
|
236
248
|
for (const label of fq.split('.')) {
|
|
237
249
|
if (label.length < 1 || label.length > 63)
|
|
238
|
-
|
|
250
|
+
this.throwHelp('Labels must have 1-63 octets (characters), RFC 2181')
|
|
239
251
|
}
|
|
240
252
|
}
|
|
241
253
|
|
|
@@ -248,7 +260,7 @@ export default class RR extends Map {
|
|
|
248
260
|
)
|
|
249
261
|
return true
|
|
250
262
|
|
|
251
|
-
|
|
263
|
+
this.throwHelp(
|
|
252
264
|
`${type} ${field} must be a 8-bit integer (in the range 0-255)`,
|
|
253
265
|
)
|
|
254
266
|
}
|
|
@@ -262,7 +274,7 @@ export default class RR extends Map {
|
|
|
262
274
|
)
|
|
263
275
|
return true
|
|
264
276
|
|
|
265
|
-
|
|
277
|
+
this.throwHelp(
|
|
266
278
|
`${type} ${field} must be a 16-bit integer (in the range 0-65535)`,
|
|
267
279
|
)
|
|
268
280
|
}
|
|
@@ -276,7 +288,7 @@ export default class RR extends Map {
|
|
|
276
288
|
)
|
|
277
289
|
return true
|
|
278
290
|
|
|
279
|
-
|
|
291
|
+
this.throwHelp(
|
|
280
292
|
`${type} ${field} must be a 32-bit integer (in the range 0-2147483647)`,
|
|
281
293
|
)
|
|
282
294
|
}
|
|
@@ -285,10 +297,10 @@ export default class RR extends Map {
|
|
|
285
297
|
return /^["']/.test(val) && /["']$/.test(val)
|
|
286
298
|
}
|
|
287
299
|
|
|
288
|
-
isFullyQualified(type,
|
|
300
|
+
isFullyQualified(type, field, hostname) {
|
|
289
301
|
if (hostname.endsWith('.')) return true
|
|
290
302
|
|
|
291
|
-
|
|
303
|
+
this.throwHelp(`${type}: ${field} must be fully qualified`)
|
|
292
304
|
}
|
|
293
305
|
|
|
294
306
|
isValidHostname(type, field, hostname) {
|
|
@@ -296,7 +308,7 @@ export default class RR extends Map {
|
|
|
296
308
|
if (!allowed.test(hostname)) return true
|
|
297
309
|
|
|
298
310
|
const matches = allowed.exec(hostname)
|
|
299
|
-
|
|
311
|
+
this.throwHelp(
|
|
300
312
|
`${type}, ${field} has invalid hostname character (${matches[0]})`,
|
|
301
313
|
)
|
|
302
314
|
}
|
|
@@ -320,7 +332,7 @@ export default class RR extends Map {
|
|
|
320
332
|
}
|
|
321
333
|
|
|
322
334
|
toMaraGeneric() {
|
|
323
|
-
//
|
|
335
|
+
// this.throwHelp(`\nMaraDNS does not support ${type} records yet and this package does not support MaraDNS generic records. Yet.\n`)
|
|
324
336
|
return `${this.get('owner')}\t+${this.get('ttl')}\tRAW ${this.getTypeId()}\t'${this.getRdataFields()
|
|
325
337
|
.map((f) => this.getQuoted(f))
|
|
326
338
|
.join(' ')}' ~\n`
|
package/.prettierrc.yml
DELETED