@nictool/dns-resource-record 1.1.7 → 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 +26 -43
- package/README.md +48 -48
- package/index.js +83 -29
- package/lib/tinydns.js +68 -61
- package/package.json +1 -2
- package/rr/a.js +32 -23
- package/rr/aaaa.js +49 -35
- package/rr/caa.js +56 -44
- package/rr/cert.js +21 -19
- package/rr/cname.js +22 -23
- package/rr/dname.js +23 -23
- package/rr/dnskey.js +45 -43
- package/rr/ds.js +40 -40
- package/rr/hinfo.js +29 -28
- package/rr/https.js +62 -0
- package/rr/ipseckey.js +69 -50
- package/rr/key.js +23 -23
- package/rr/loc.js +71 -58
- package/rr/mx.js +41 -27
- package/rr/naptr.js +52 -53
- package/rr/ns.js +26 -23
- package/rr/nsec.js +24 -20
- package/rr/nsec3.js +59 -46
- package/rr/nsec3param.js +24 -26
- package/rr/nxt.js +65 -0
- package/rr/openpgpkey.js +18 -15
- package/rr/ptr.js +20 -21
- package/rr/rrsig.js +28 -23
- package/rr/sig.js +25 -20
- package/rr/smimea.js +36 -31
- package/rr/soa.js +56 -42
- package/rr/spf.js +21 -18
- package/rr/srv.js +45 -45
- package/rr/sshfp.js +30 -31
- package/rr/svcb.js +64 -0
- package/rr/tlsa.js +50 -45
- package/rr/tsig.js +56 -0
- package/rr/txt.js +42 -35
- package/rr/uri.js +33 -33
- package/rr/wks.js +45 -0
- package/rr.js +133 -87
- package/.codeclimate.yml +0 -25
- package/DEVELOP.md +0 -23
- package/test/a.js +0 -76
- package/test/aaaa.js +0 -79
- package/test/base.js +0 -138
- package/test/caa.js +0 -104
- package/test/cert.js +0 -48
- package/test/cname.js +0 -41
- package/test/dname.js +0 -53
- package/test/dnskey.js +0 -44
- package/test/ds.js +0 -44
- package/test/fake.js +0 -26
- package/test/hinfo.js +0 -75
- package/test/ipseckey.js +0 -115
- package/test/key.js +0 -37
- package/test/loc.js +0 -71
- package/test/mx.js +0 -75
- package/test/naptr.js +0 -40
- package/test/ns.js +0 -53
- package/test/nsec.js +0 -38
- package/test/nsec3.js +0 -40
- package/test/nsec3param.js +0 -26
- package/test/openpgpkey.js +0 -35
- package/test/ptr.js +0 -54
- package/test/rr.js +0 -196
- package/test/smimea.js +0 -45
- package/test/soa.js +0 -77
- package/test/spf.js +0 -48
- package/test/srv.js +0 -81
- package/test/sshfp.js +0 -62
- package/test/tinydns.js +0 -140
- package/test/tlsa.js +0 -54
- package/test/txt.js +0 -70
- package/test/uri.js +0 -61
package/rr/caa.js
CHANGED
|
@@ -1,110 +1,122 @@
|
|
|
1
|
-
|
|
2
1
|
import RR from '../rr.js'
|
|
3
2
|
import * as TINYDNS from '../lib/tinydns.js'
|
|
4
3
|
|
|
5
4
|
export default class CAA extends RR {
|
|
6
|
-
constructor
|
|
5
|
+
constructor(opts) {
|
|
7
6
|
super(opts)
|
|
8
7
|
}
|
|
9
8
|
|
|
10
9
|
/****** Resource record specific setters *******/
|
|
11
|
-
setFlags
|
|
10
|
+
setFlags(val) {
|
|
12
11
|
this.is8bitInt('CAA', 'flags', val)
|
|
13
12
|
|
|
14
|
-
if (![
|
|
15
|
-
|
|
13
|
+
if (![0, 128].includes(val)) {
|
|
14
|
+
this.throwHelp(`CAA flags ${val} not recognized`)
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
this.set('flags', val)
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
setTag
|
|
22
|
-
if (typeof val !== 'string'
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
setTag(val) {
|
|
21
|
+
if (typeof val !== 'string' || val.length < 1 || /[^a-z0-9]/.test(val))
|
|
22
|
+
this.throwHelp(
|
|
23
|
+
`CAA tag must be a sequence of ASCII letters and numbers in lowercase`,
|
|
24
|
+
)
|
|
26
25
|
|
|
27
|
-
if (![
|
|
28
|
-
|
|
26
|
+
if (!['issue', 'issuewild', 'iodef'].includes(val)) {
|
|
27
|
+
this.throwHelp(`CAA tag ${val} not recognized`)
|
|
29
28
|
}
|
|
30
29
|
this.set('tag', val)
|
|
31
30
|
}
|
|
32
31
|
|
|
33
|
-
setValue
|
|
32
|
+
setValue(val) {
|
|
34
33
|
// either (2) a quoted string or
|
|
35
34
|
// (1) a contiguous set of characters without interior spaces
|
|
36
35
|
if (this.isQuoted(val)) {
|
|
37
36
|
val = val.replace(/^["']|["']$/g, '') // strip quotes
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// if (/\s/.test(val)) throw new Error(`CAA value may not have spaces unless quoted: RFC 8659`)
|
|
37
|
+
} else {
|
|
38
|
+
// if (/\s/.test(val)) this.throwHelp(`CAA value may not have spaces unless quoted`)
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
// check if val starts with one of iodefSchemes
|
|
44
42
|
if (this.get('tag') === 'iodef') {
|
|
45
|
-
const iodefSchemes = [
|
|
46
|
-
if (!iodefSchemes.filter(s => val.startsWith(s)).length) {
|
|
47
|
-
|
|
43
|
+
const iodefSchemes = ['mailto:', 'http:', 'https:']
|
|
44
|
+
if (!iodefSchemes.filter((s) => val.startsWith(s)).length) {
|
|
45
|
+
this.throwHelp(`CAA value must have valid iodefScheme prefix`)
|
|
48
46
|
}
|
|
49
47
|
}
|
|
50
48
|
|
|
51
49
|
this.set('value', val)
|
|
52
50
|
}
|
|
53
51
|
|
|
54
|
-
getDescription
|
|
52
|
+
getDescription() {
|
|
55
53
|
return 'Certification Authority Authorization'
|
|
56
54
|
}
|
|
57
55
|
|
|
58
|
-
getQuotedFields
|
|
59
|
-
return [
|
|
56
|
+
getQuotedFields() {
|
|
57
|
+
return ['value']
|
|
60
58
|
}
|
|
61
59
|
|
|
62
|
-
getRdataFields
|
|
63
|
-
return [
|
|
60
|
+
getRdataFields(arg) {
|
|
61
|
+
return ['flags', 'tag', 'value']
|
|
64
62
|
}
|
|
65
63
|
|
|
66
|
-
getRFCs
|
|
67
|
-
return [
|
|
64
|
+
getRFCs() {
|
|
65
|
+
return [6844, 8659]
|
|
68
66
|
}
|
|
69
67
|
|
|
70
|
-
getTypeId
|
|
68
|
+
getTypeId() {
|
|
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
|
-
fromTinydns
|
|
85
|
+
fromTinydns(opts) {
|
|
76
86
|
// CAA via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
77
|
-
const [
|
|
78
|
-
if (n != 257)
|
|
87
|
+
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
88
|
+
if (n != 257) this.throwHelp('CAA fromTinydns, invalid n')
|
|
79
89
|
|
|
80
|
-
const flags
|
|
90
|
+
const flags = TINYDNS.octalToUInt8(rdata.substring(0, 4))
|
|
81
91
|
const taglen = TINYDNS.octalToUInt8(rdata.substring(4, 8))
|
|
82
92
|
|
|
83
|
-
const unescaped
|
|
84
|
-
const tag
|
|
93
|
+
const unescaped = TINYDNS.octalToChar(rdata.substring(8))
|
|
94
|
+
const tag = unescaped.substring(0, taglen)
|
|
85
95
|
const fingerprint = unescaped.substring(taglen)
|
|
86
96
|
|
|
87
97
|
return new CAA({
|
|
88
|
-
owner
|
|
89
|
-
ttl
|
|
90
|
-
type
|
|
98
|
+
owner: this.fullyQualify(fqdn),
|
|
99
|
+
ttl: parseInt(ttl, 10),
|
|
100
|
+
type: 'CAA',
|
|
91
101
|
flags,
|
|
92
102
|
tag,
|
|
93
|
-
value
|
|
103
|
+
value: fingerprint,
|
|
94
104
|
timestamp: ts,
|
|
95
|
-
location
|
|
105
|
+
location: loc !== '' && loc !== '\n' ? loc : '',
|
|
96
106
|
})
|
|
97
107
|
}
|
|
98
108
|
|
|
99
|
-
fromBind
|
|
109
|
+
fromBind(opts) {
|
|
100
110
|
// test.example.com 3600 IN CAA flags, tags, value
|
|
101
|
-
const fields = opts.bindline.match(
|
|
102
|
-
|
|
111
|
+
const fields = opts.bindline.match(
|
|
112
|
+
/^([^\s]+)\s+([0-9]+)\s+(\w+)\s+(\w+)\s+([0-9]+)\s+(\w+)\s+("[^"]+"|[^\s]+?)\s*$/i,
|
|
113
|
+
)
|
|
114
|
+
if (!fields) this.throwHelp(`unable to parse: ${opts.bindline}`)
|
|
103
115
|
|
|
104
|
-
const [
|
|
116
|
+
const [owner, ttl, c, type, flags, tag, value] = fields.slice(1)
|
|
105
117
|
return new CAA({
|
|
106
118
|
owner,
|
|
107
|
-
ttl
|
|
119
|
+
ttl: parseInt(ttl, 10),
|
|
108
120
|
class: c,
|
|
109
121
|
type,
|
|
110
122
|
flags: parseInt(flags, 10),
|
|
@@ -115,7 +127,7 @@ export default class CAA extends RR {
|
|
|
115
127
|
|
|
116
128
|
/****** EXPORTERS *******/
|
|
117
129
|
|
|
118
|
-
toTinydns
|
|
130
|
+
toTinydns() {
|
|
119
131
|
let rdata = ''
|
|
120
132
|
rdata += TINYDNS.UInt8toOctal(this.get('flags'))
|
|
121
133
|
|
package/rr/cert.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
|
|
2
1
|
import RR from '../rr.js'
|
|
3
2
|
|
|
4
3
|
export default class CERT extends RR {
|
|
5
|
-
constructor
|
|
4
|
+
constructor(opts) {
|
|
6
5
|
super(opts)
|
|
7
6
|
}
|
|
8
7
|
|
|
9
8
|
/****** Resource record specific setters *******/
|
|
10
|
-
setCertType
|
|
9
|
+
setCertType(val) {
|
|
11
10
|
// The type field is the certificate type
|
|
12
11
|
// the type field as an unsigned decimal integer or as a mnemonic symbol
|
|
13
12
|
// this.is16bitInt('CERT', 'type', val)
|
|
@@ -15,7 +14,7 @@ export default class CERT extends RR {
|
|
|
15
14
|
this.set('cert type', val)
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
setKeyTag
|
|
17
|
+
setKeyTag(val) {
|
|
19
18
|
// The key tag field is the 16-bit value
|
|
20
19
|
// The key tag field is represented as an unsigned decimal integer.
|
|
21
20
|
|
|
@@ -24,7 +23,7 @@ export default class CERT extends RR {
|
|
|
24
23
|
this.set('key tag', val)
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
setAlgorithm
|
|
26
|
+
setAlgorithm(val) {
|
|
28
27
|
// The algorithm field has the same meaning as the algorithm field in DNSKEY
|
|
29
28
|
// The algorithm field is represented as an unsigned decimal integer
|
|
30
29
|
this.is8bitInt('CERT', 'algorithm', val)
|
|
@@ -32,41 +31,44 @@ export default class CERT extends RR {
|
|
|
32
31
|
this.set('algorithm', val)
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
setCertificate
|
|
34
|
+
setCertificate(val) {
|
|
36
35
|
// certificate/CRL portion is represented in base 64 [16] and may be
|
|
37
36
|
// divided into any number of white-space-separated substrings
|
|
38
37
|
this.set('certificate', val)
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
getDescription
|
|
40
|
+
getDescription() {
|
|
42
41
|
return 'Certificate'
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
getRdataFields
|
|
46
|
-
return [
|
|
44
|
+
getRdataFields() {
|
|
45
|
+
return ['cert type', 'key tag', 'algorithm', 'certificate']
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
getRFCs
|
|
50
|
-
return [
|
|
48
|
+
getRFCs() {
|
|
49
|
+
return [2538, 4398]
|
|
51
50
|
}
|
|
52
51
|
|
|
53
|
-
getTypeId
|
|
52
|
+
getTypeId() {
|
|
54
53
|
return 37
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
/****** IMPORTERS *******/
|
|
58
57
|
|
|
59
|
-
fromBind
|
|
58
|
+
fromBind(opts) {
|
|
60
59
|
// test.example.com 3600 IN CERT certtype, keytag, algo, cert
|
|
61
|
-
const [
|
|
60
|
+
const [owner, ttl, c, type, certtype, keytag, algo, certificate] =
|
|
61
|
+
opts.bindline.split(/\s+/)
|
|
62
62
|
return new CERT({
|
|
63
63
|
owner,
|
|
64
|
-
ttl
|
|
65
|
-
class
|
|
64
|
+
ttl: parseInt(ttl, 10),
|
|
65
|
+
class: c,
|
|
66
66
|
type,
|
|
67
|
-
'cert type': /^[0-9]+$/.test(certtype)
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
'cert type': /^[0-9]+$/.test(certtype)
|
|
68
|
+
? parseInt(certtype, 10)
|
|
69
|
+
: certtype,
|
|
70
|
+
'key tag': parseInt(keytag, 10),
|
|
71
|
+
algorithm: parseInt(algo, 10),
|
|
70
72
|
certificate,
|
|
71
73
|
})
|
|
72
74
|
}
|
package/rr/cname.js
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
import net from 'net'
|
|
1
|
+
import net from 'node:net'
|
|
3
2
|
|
|
4
3
|
import RR from '../rr.js'
|
|
5
4
|
|
|
6
5
|
export default class CNAME extends RR {
|
|
7
|
-
constructor
|
|
6
|
+
constructor(opts) {
|
|
8
7
|
super(opts)
|
|
9
8
|
}
|
|
10
9
|
|
|
11
10
|
/****** Resource record specific setters *******/
|
|
12
|
-
setCname
|
|
11
|
+
setCname(val) {
|
|
13
12
|
// A <domain-name> which specifies the canonical or primary
|
|
14
13
|
// name for the owner. The owner name is an alias.
|
|
15
14
|
|
|
16
|
-
if (!val)
|
|
15
|
+
if (!val) this.throwHelp('CNAME: cname is required')
|
|
17
16
|
|
|
18
17
|
if (net.isIPv4(val) || net.isIPv6(val))
|
|
19
|
-
|
|
18
|
+
this.throwHelp(`CNAME: cname must be a FQDN: RFC 2181`)
|
|
20
19
|
|
|
21
20
|
if (!this.isFullyQualified('CNAME', 'cname', val)) return
|
|
22
21
|
if (!this.isValidHostname('CNAME', 'cname', val)) return
|
|
@@ -25,43 +24,43 @@ export default class CNAME extends RR {
|
|
|
25
24
|
this.set('cname', val.toLowerCase())
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
getDescription
|
|
27
|
+
getDescription() {
|
|
29
28
|
return 'Canonical Name'
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
getRdataFields
|
|
33
|
-
return [
|
|
31
|
+
getRdataFields(arg) {
|
|
32
|
+
return ['cname']
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
getRFCs
|
|
37
|
-
return [
|
|
35
|
+
getRFCs() {
|
|
36
|
+
return [1035, 2181]
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
getTypeId
|
|
39
|
+
getTypeId() {
|
|
41
40
|
return 5
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
/****** IMPORTERS *******/
|
|
45
|
-
fromTinydns
|
|
44
|
+
fromTinydns(opts) {
|
|
46
45
|
// Cfqdn:p:ttl:timestamp:lo
|
|
47
|
-
const [
|
|
46
|
+
const [fqdn, p, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
48
47
|
|
|
49
48
|
return new CNAME({
|
|
50
|
-
owner
|
|
51
|
-
ttl
|
|
52
|
-
type
|
|
53
|
-
cname
|
|
49
|
+
owner: this.fullyQualify(fqdn),
|
|
50
|
+
ttl: parseInt(ttl, 10),
|
|
51
|
+
type: 'CNAME',
|
|
52
|
+
cname: this.fullyQualify(p),
|
|
54
53
|
timestamp: ts,
|
|
55
|
-
location
|
|
54
|
+
location: loc !== '' && loc !== '\n' ? loc : '',
|
|
56
55
|
})
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
fromBind
|
|
58
|
+
fromBind(opts) {
|
|
60
59
|
// test.example.com 3600 IN CNAME ...
|
|
61
|
-
const [
|
|
60
|
+
const [owner, ttl, c, type, cname] = opts.bindline.split(/\s+/)
|
|
62
61
|
return new CNAME({
|
|
63
62
|
owner,
|
|
64
|
-
ttl
|
|
63
|
+
ttl: parseInt(ttl, 10),
|
|
65
64
|
class: c,
|
|
66
65
|
type,
|
|
67
66
|
cname,
|
|
@@ -70,7 +69,7 @@ export default class CNAME extends RR {
|
|
|
70
69
|
|
|
71
70
|
/****** EXPORTERS *******/
|
|
72
71
|
|
|
73
|
-
toTinydns
|
|
72
|
+
toTinydns() {
|
|
74
73
|
return `C${this.getTinyFQDN('owner')}:${this.get('cname')}:${this.getTinydnsPostamble()}\n`
|
|
75
74
|
}
|
|
76
75
|
}
|
package/rr/dname.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
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'
|
|
5
5
|
|
|
6
6
|
export default class DNAME extends RR {
|
|
7
|
-
constructor
|
|
7
|
+
constructor(opts) {
|
|
8
8
|
super(opts)
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/****** Resource record specific setters *******/
|
|
12
|
-
setTarget
|
|
13
|
-
if (!val)
|
|
12
|
+
setTarget(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)
|
|
@@ -22,44 +22,44 @@ export default class DNAME extends RR {
|
|
|
22
22
|
this.set('target', val.toLowerCase())
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
getDescription
|
|
25
|
+
getDescription() {
|
|
26
26
|
return 'Delegation Name'
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
getRdataFields
|
|
30
|
-
return [
|
|
29
|
+
getRdataFields(arg) {
|
|
30
|
+
return ['target']
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
getRFCs
|
|
34
|
-
return [
|
|
33
|
+
getRFCs() {
|
|
34
|
+
return [2672, 6672]
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
getTypeId
|
|
37
|
+
getTypeId() {
|
|
38
38
|
return 39
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/****** IMPORTERS *******/
|
|
42
|
-
fromTinydns
|
|
42
|
+
fromTinydns(opts) {
|
|
43
43
|
// DNAME via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
44
|
-
const [
|
|
45
|
-
if (n != 39)
|
|
44
|
+
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
45
|
+
if (n != 39) this.throwHelp('DNAME fromTinydns, invalid n')
|
|
46
46
|
|
|
47
47
|
return new DNAME({
|
|
48
|
-
type
|
|
49
|
-
owner
|
|
50
|
-
target
|
|
51
|
-
ttl
|
|
48
|
+
type: 'DNAME',
|
|
49
|
+
owner: this.fullyQualify(fqdn),
|
|
50
|
+
target: TINYDNS.unpackDomainName(rdata)[0],
|
|
51
|
+
ttl: parseInt(ttl, 10),
|
|
52
52
|
timestamp: ts,
|
|
53
|
-
location
|
|
53
|
+
location: loc !== '' && loc !== '\n' ? loc : '',
|
|
54
54
|
})
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
fromBind
|
|
57
|
+
fromBind(opts) {
|
|
58
58
|
// test.example.com 3600 IN DNAME ...
|
|
59
|
-
const [
|
|
59
|
+
const [owner, ttl, c, type, target] = opts.bindline.split(/\s+/)
|
|
60
60
|
return new DNAME({
|
|
61
61
|
owner,
|
|
62
|
-
ttl
|
|
62
|
+
ttl: parseInt(ttl, 10),
|
|
63
63
|
class: c,
|
|
64
64
|
type,
|
|
65
65
|
target,
|
|
@@ -67,7 +67,7 @@ export default class DNAME extends RR {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
/****** EXPORTERS *******/
|
|
70
|
-
toTinydns
|
|
70
|
+
toTinydns() {
|
|
71
71
|
const rdata = TINYDNS.packDomainName(this.get('target'))
|
|
72
72
|
return this.getTinydnsGeneric(rdata)
|
|
73
73
|
}
|
package/rr/dnskey.js
CHANGED
|
@@ -1,117 +1,119 @@
|
|
|
1
|
-
|
|
2
1
|
import RR from '../rr.js'
|
|
3
2
|
|
|
4
3
|
import * as TINYDNS from '../lib/tinydns.js'
|
|
5
4
|
|
|
6
5
|
export default class DNSKEY extends RR {
|
|
7
|
-
constructor
|
|
6
|
+
constructor(opts) {
|
|
8
7
|
super(opts)
|
|
9
8
|
}
|
|
10
9
|
|
|
11
10
|
/****** Resource record specific setters *******/
|
|
12
|
-
setFlags
|
|
11
|
+
setFlags(val) {
|
|
13
12
|
// a 2 octet Flags Field
|
|
14
13
|
this.is16bitInt('DNSKEY', 'flags', val)
|
|
15
14
|
|
|
16
15
|
// the possible values are: 0, 256, and 257; RFC 4034
|
|
17
|
-
if (![
|
|
16
|
+
if (![0, 256, 257].includes(val)) this.throwHelp(`DNSKEY: flags invalid`)
|
|
18
17
|
|
|
19
18
|
this.set('flags', val)
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
setProtocol
|
|
21
|
+
setProtocol(val) {
|
|
23
22
|
// 1 octet
|
|
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 (![
|
|
26
|
+
if (![3].includes(val)) this.throwHelp(`DNSKEY: protocol invalid`)
|
|
28
27
|
|
|
29
28
|
this.set('protocol', val)
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
setAlgorithm
|
|
31
|
+
setAlgorithm(val) {
|
|
33
32
|
// 1 octet
|
|
34
33
|
this.is8bitInt('DNSKEY', 'algorithm', val)
|
|
35
34
|
|
|
36
35
|
// https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
|
|
37
36
|
// 1=RSA/MD5, 2=DH, 3=DSA/SHA-1, 4=EC, 5=RSA/SHA-1
|
|
38
|
-
if (![
|
|
39
|
-
console.error(`DNSKEY: algorithm (${val}) not recognized
|
|
37
|
+
if (![...Array(16).keys(), 253, 254].includes(val))
|
|
38
|
+
console.error(`DNSKEY: algorithm (${val}) not recognized`)
|
|
40
39
|
|
|
41
40
|
this.set('algorithm', val)
|
|
42
41
|
}
|
|
43
42
|
|
|
44
|
-
setPublickey
|
|
45
|
-
if (!val)
|
|
43
|
+
setPublickey(val) {
|
|
44
|
+
if (!val) this.throwHelp(`DNSKEY: publickey is required`)
|
|
46
45
|
|
|
47
46
|
this.set('publickey', val)
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
getDescription
|
|
49
|
+
getDescription() {
|
|
51
50
|
return 'DNS Public Key'
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
getRdataFields
|
|
55
|
-
return [
|
|
53
|
+
getRdataFields(arg) {
|
|
54
|
+
return ['flags', 'protocol', 'algorithm', 'publickey']
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
getRFCs
|
|
59
|
-
return [
|
|
57
|
+
getRFCs() {
|
|
58
|
+
return [4034, 6014, 8624]
|
|
60
59
|
}
|
|
61
60
|
|
|
62
|
-
getTypeId
|
|
61
|
+
getTypeId() {
|
|
63
62
|
return 48
|
|
64
63
|
}
|
|
65
64
|
|
|
66
65
|
/****** IMPORTERS *******/
|
|
67
66
|
|
|
68
|
-
fromBind
|
|
67
|
+
fromBind(opts) {
|
|
69
68
|
// test.example.com 3600 IN DNSKEY Flags Protocol Algorithm PublicKey
|
|
70
|
-
const match = opts.bindline.match(
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
const match = opts.bindline.match(
|
|
70
|
+
/^([^\s]+)\s+([0-9]+)\s+(\w+)\s+(\w+)\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+\s*(.*?)\s*$/,
|
|
71
|
+
)
|
|
72
|
+
if (!match) this.throwHelp(`unable to parse DNSKEY: ${opts.bindline}`)
|
|
73
|
+
const [owner, ttl, c, type, flags, protocol, algorithm, publickey] =
|
|
74
|
+
match.slice(1)
|
|
73
75
|
|
|
74
76
|
return new DNSKEY({
|
|
75
77
|
owner,
|
|
76
|
-
ttl
|
|
77
|
-
class
|
|
78
|
-
type
|
|
79
|
-
flags
|
|
80
|
-
protocol
|
|
81
|
-
algorithm: parseInt(algorithm,
|
|
78
|
+
ttl: parseInt(ttl, 10),
|
|
79
|
+
class: c,
|
|
80
|
+
type: type,
|
|
81
|
+
flags: parseInt(flags, 10),
|
|
82
|
+
protocol: parseInt(protocol, 10),
|
|
83
|
+
algorithm: parseInt(algorithm, 10),
|
|
82
84
|
publickey: publickey,
|
|
83
85
|
})
|
|
84
86
|
}
|
|
85
87
|
|
|
86
|
-
fromTinydns
|
|
87
|
-
const [
|
|
88
|
-
if (n != 48)
|
|
88
|
+
fromTinydns(opts) {
|
|
89
|
+
const [fqdn, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
|
|
90
|
+
if (n != 48) this.throwHelp('DNSKEY fromTinydns, invalid n')
|
|
89
91
|
|
|
90
92
|
const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
91
93
|
|
|
92
94
|
return new DNSKEY({
|
|
93
|
-
owner
|
|
94
|
-
ttl
|
|
95
|
-
type
|
|
96
|
-
flags
|
|
97
|
-
protocol
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
timestamp
|
|
101
|
-
location
|
|
95
|
+
owner: this.fullyQualify(fqdn),
|
|
96
|
+
ttl: parseInt(ttl, 10),
|
|
97
|
+
type: 'DNSKEY',
|
|
98
|
+
flags: bytes.readUInt16BE(0),
|
|
99
|
+
protocol: bytes.readUInt8(2),
|
|
100
|
+
algorithm: bytes.readUInt8(3),
|
|
101
|
+
publickey: bytes.slice(4).toString(),
|
|
102
|
+
timestamp: ts,
|
|
103
|
+
location: loc !== '' && loc !== '\n' ? loc : '',
|
|
102
104
|
})
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
/****** EXPORTERS *******/
|
|
106
108
|
|
|
107
|
-
toTinydns
|
|
109
|
+
toTinydns() {
|
|
108
110
|
const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
|
|
109
111
|
|
|
110
112
|
return this.getTinydnsGeneric(
|
|
111
113
|
TINYDNS.UInt16toOctal(this.get('flags')) +
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
114
|
+
TINYDNS.UInt8toOctal(this.get('protocol')) +
|
|
115
|
+
TINYDNS.UInt8toOctal(this.get('algorithm')) +
|
|
116
|
+
TINYDNS.escapeOctal(dataRe, this.get('publickey')),
|
|
115
117
|
)
|
|
116
118
|
}
|
|
117
119
|
}
|