@nictool/dns-resource-record 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -1
- package/README.md +49 -42
- package/lib/readme.js +84 -0
- package/lib/tinydns.js +20 -10
- package/package.json +3 -2
- package/rr/a.js +13 -5
- package/rr/aaaa.js +19 -11
- package/rr/apl.js +49 -2
- package/rr/caa.js +30 -23
- package/rr/cert.js +44 -7
- package/rr/cname.js +22 -5
- package/rr/dhcid.js +17 -2
- package/rr/dname.js +15 -5
- package/rr/dnskey.js +31 -8
- package/rr/ds.js +23 -6
- package/rr/hinfo.js +28 -10
- package/rr/hip.js +43 -2
- package/rr/https.js +38 -9
- package/rr/ipseckey.js +20 -16
- package/rr/key.js +26 -17
- package/rr/kx.js +18 -2
- package/rr/loc.js +24 -14
- package/rr/mx.js +16 -6
- package/rr/naptr.js +39 -20
- package/rr/ns.js +23 -5
- package/rr/nsec.js +21 -6
- package/rr/nsec3.js +71 -7
- package/rr/nsec3param.js +52 -22
- package/rr/nxt.js +22 -7
- package/rr/openpgpkey.js +28 -8
- package/rr/ptr.js +23 -5
- package/rr/rp.js +23 -2
- package/rr/rrsig.js +106 -10
- package/rr/sig.js +111 -13
- package/rr/smimea.js +23 -6
- package/rr/soa.js +36 -6
- package/rr/spf.js +17 -3
- package/rr/srv.js +28 -11
- package/rr/sshfp.js +24 -8
- package/rr/svcb.js +37 -10
- package/rr/tlsa.js +26 -9
- package/rr/tsig.js +155 -13
- package/rr/txt.js +46 -12
- package/rr/uri.js +20 -8
- package/rr/wks.js +42 -2
- package/rr.js +109 -7
package/rr/smimea.js
CHANGED
|
@@ -58,6 +58,10 @@ export default class SMIMEA extends RR {
|
|
|
58
58
|
return 'S/MIME cert association'
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
getTags() {
|
|
62
|
+
return ['security']
|
|
63
|
+
}
|
|
64
|
+
|
|
61
65
|
getRdataFields(arg) {
|
|
62
66
|
return ['certificate usage', 'selector', 'matching type', 'certificate association data']
|
|
63
67
|
}
|
|
@@ -70,15 +74,28 @@ export default class SMIMEA extends RR {
|
|
|
70
74
|
return 53
|
|
71
75
|
}
|
|
72
76
|
|
|
77
|
+
getCanonical() {
|
|
78
|
+
return {
|
|
79
|
+
owner: '_443._tcp.www.example.com.',
|
|
80
|
+
ttl: 3600,
|
|
81
|
+
class: 'IN',
|
|
82
|
+
type: 'SMIMEA',
|
|
83
|
+
'certificate usage': 0,
|
|
84
|
+
selector: 0,
|
|
85
|
+
'matching type': 1,
|
|
86
|
+
'certificate association data': 'ABCDEF...',
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
73
90
|
getQuotedFields() {
|
|
74
91
|
return []
|
|
75
92
|
}
|
|
76
93
|
|
|
77
94
|
/****** IMPORTERS *******/
|
|
78
95
|
|
|
79
|
-
fromBind(
|
|
96
|
+
fromBind({ bindline }) {
|
|
80
97
|
// test.example.com 3600 IN SMIMEA, usage, selector, match, data
|
|
81
|
-
const [owner, ttl, c, type, usage, selector, match] =
|
|
98
|
+
const [owner, ttl, c, type, usage, selector, match] = bindline.split(/\s+/)
|
|
82
99
|
return new SMIMEA({
|
|
83
100
|
owner,
|
|
84
101
|
ttl: parseInt(ttl, 10),
|
|
@@ -87,12 +104,12 @@ export default class SMIMEA extends RR {
|
|
|
87
104
|
'certificate usage': parseInt(usage, 10),
|
|
88
105
|
selector: parseInt(selector, 10),
|
|
89
106
|
'matching type': parseInt(match, 10),
|
|
90
|
-
'certificate association data':
|
|
107
|
+
'certificate association data': bindline.split(/\s+/).slice(7).join(' ').trim(),
|
|
91
108
|
})
|
|
92
109
|
}
|
|
93
110
|
|
|
94
|
-
fromTinydns(
|
|
95
|
-
const [owner, _typeId, rdata, ttl, ts, loc] =
|
|
111
|
+
fromTinydns({ tinyline }) {
|
|
112
|
+
const [owner, _typeId, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
96
113
|
const binaryRdata = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
97
114
|
|
|
98
115
|
return new SMIMEA({
|
|
@@ -104,7 +121,7 @@ export default class SMIMEA extends RR {
|
|
|
104
121
|
'matching type': binaryRdata.readUInt8(2),
|
|
105
122
|
'certificate association data': binaryRdata.slice(3).toString(),
|
|
106
123
|
timestamp: ts,
|
|
107
|
-
location: loc
|
|
124
|
+
location: loc?.trim() ?? '',
|
|
108
125
|
})
|
|
109
126
|
}
|
|
110
127
|
|
package/rr/soa.js
CHANGED
|
@@ -83,11 +83,27 @@ export default class SOA extends RR {
|
|
|
83
83
|
return 6
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
getCanonical() {
|
|
87
|
+
return {
|
|
88
|
+
owner: 'example.com.',
|
|
89
|
+
ttl: 3600,
|
|
90
|
+
class: 'IN',
|
|
91
|
+
type: 'SOA',
|
|
92
|
+
mname: 'ns1.example.com.',
|
|
93
|
+
rname: 'admin.example.com.',
|
|
94
|
+
serial: 2023051001,
|
|
95
|
+
refresh: 7200,
|
|
96
|
+
retry: 3600,
|
|
97
|
+
expire: 1209600,
|
|
98
|
+
minimum: 3600,
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
86
102
|
/****** IMPORTERS *******/
|
|
87
|
-
fromBind(
|
|
103
|
+
fromBind({ bindline }) {
|
|
88
104
|
// example.com TTL IN SOA mname rname serial refresh retry expire minimum
|
|
89
105
|
const [owner, ttl, c, type, mname, rname, serial, refresh, retry, expire, minimum] =
|
|
90
|
-
|
|
106
|
+
bindline.split(/[\s+]/)
|
|
91
107
|
|
|
92
108
|
return new SOA({
|
|
93
109
|
owner,
|
|
@@ -104,9 +120,9 @@ export default class SOA extends RR {
|
|
|
104
120
|
})
|
|
105
121
|
}
|
|
106
122
|
|
|
107
|
-
fromTinydns(
|
|
123
|
+
fromTinydns({ tinyline }) {
|
|
108
124
|
// Zfqdn:mname:rname:ser:ref:ret:exp:min:ttl:time:lo
|
|
109
|
-
const [fqdn, mname, rname, ser, ref, ret, exp, min, ttl, ts, loc] =
|
|
125
|
+
const [fqdn, mname, rname, ser, ref, ret, exp, min, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
110
126
|
|
|
111
127
|
return new SOA({
|
|
112
128
|
owner: this.fullyQualify(fqdn),
|
|
@@ -114,13 +130,13 @@ export default class SOA extends RR {
|
|
|
114
130
|
type: 'SOA',
|
|
115
131
|
mname: this.fullyQualify(mname),
|
|
116
132
|
rname: this.fullyQualify(rname),
|
|
117
|
-
serial: parseInt(ser
|
|
133
|
+
serial: parseInt(ser ?? this.default?.serial, 10),
|
|
118
134
|
refresh: parseInt(ref, 10) || 16384,
|
|
119
135
|
retry: parseInt(ret, 10) || 2048,
|
|
120
136
|
expire: parseInt(exp, 10) || 1048576,
|
|
121
137
|
minimum: parseInt(min, 10) || 2560,
|
|
122
138
|
timestamp: parseInt(ts) || '',
|
|
123
|
-
location: loc
|
|
139
|
+
location: loc?.trim() ?? '',
|
|
124
140
|
})
|
|
125
141
|
}
|
|
126
142
|
|
|
@@ -136,6 +152,20 @@ export default class SOA extends RR {
|
|
|
136
152
|
.join('\t')} ~\n`
|
|
137
153
|
}
|
|
138
154
|
|
|
155
|
+
getWireRdata() {
|
|
156
|
+
const nums = Buffer.alloc(20)
|
|
157
|
+
nums.writeUInt32BE(this.get('serial'), 0)
|
|
158
|
+
nums.writeUInt32BE(this.get('refresh'), 4)
|
|
159
|
+
nums.writeUInt32BE(this.get('retry'), 8)
|
|
160
|
+
nums.writeUInt32BE(this.get('expire'), 12)
|
|
161
|
+
nums.writeUInt32BE(this.get('minimum'), 16)
|
|
162
|
+
return Buffer.concat([
|
|
163
|
+
this.wirePackDomain(this.get('mname')),
|
|
164
|
+
this.wirePackDomain(this.get('rname')),
|
|
165
|
+
nums,
|
|
166
|
+
])
|
|
167
|
+
}
|
|
168
|
+
|
|
139
169
|
toTinydns() {
|
|
140
170
|
return `Z${this.getTinyFQDN('owner')}:${this.getTinyFQDN('mname')}:${this.getTinyFQDN('rname')}:${this.getEmpty('serial')}:${this.getEmpty('refresh')}:${this.getEmpty('retry')}:${this.getEmpty('expire')}:${this.getEmpty('minimum')}:${this.getTinydnsPostamble()}\n`
|
|
141
171
|
}
|
package/rr/spf.js
CHANGED
|
@@ -18,6 +18,10 @@ export default class SPF extends TXT {
|
|
|
18
18
|
return 'Sender Policy Framework'
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
getTags() {
|
|
22
|
+
return ['deprecated']
|
|
23
|
+
}
|
|
24
|
+
|
|
21
25
|
getRdataFields(arg) {
|
|
22
26
|
return ['data']
|
|
23
27
|
}
|
|
@@ -30,10 +34,20 @@ export default class SPF extends TXT {
|
|
|
30
34
|
return 99
|
|
31
35
|
}
|
|
32
36
|
|
|
37
|
+
getCanonical() {
|
|
38
|
+
return {
|
|
39
|
+
owner: 'example.com.',
|
|
40
|
+
ttl: 3600,
|
|
41
|
+
class: 'IN',
|
|
42
|
+
type: 'SPF',
|
|
43
|
+
data: 'v=spf1 mx -all',
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
33
47
|
/****** IMPORTERS *******/
|
|
34
|
-
fromTinydns(
|
|
48
|
+
fromTinydns({ tinyline }) {
|
|
35
49
|
// SPF via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
36
|
-
const [fqdn, n, rdata, ttl, ts, loc] =
|
|
50
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
37
51
|
if (n != 99) this.throwHelp('SPF fromTinydns, invalid n')
|
|
38
52
|
|
|
39
53
|
return new SPF({
|
|
@@ -42,7 +56,7 @@ export default class SPF extends TXT {
|
|
|
42
56
|
data: TINYDNS.octalToChar(rdata),
|
|
43
57
|
ttl: parseInt(ttl, 10),
|
|
44
58
|
timestamp: ts,
|
|
45
|
-
location: loc
|
|
59
|
+
location: loc?.trim() ?? '',
|
|
46
60
|
})
|
|
47
61
|
}
|
|
48
62
|
|
package/rr/srv.js
CHANGED
|
@@ -41,6 +41,10 @@ export default class SRV extends RR {
|
|
|
41
41
|
return 'Service'
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
getTags() {
|
|
45
|
+
return ['common']
|
|
46
|
+
}
|
|
47
|
+
|
|
44
48
|
getRdataFields(arg) {
|
|
45
49
|
return ['priority', 'weight', 'port', 'target']
|
|
46
50
|
}
|
|
@@ -53,23 +57,36 @@ export default class SRV extends RR {
|
|
|
53
57
|
return 33
|
|
54
58
|
}
|
|
55
59
|
|
|
60
|
+
getCanonical() {
|
|
61
|
+
return {
|
|
62
|
+
owner: '_imaps._tcp.example.com.',
|
|
63
|
+
ttl: 3600,
|
|
64
|
+
class: 'IN',
|
|
65
|
+
type: 'SRV',
|
|
66
|
+
priority: 10,
|
|
67
|
+
weight: 10,
|
|
68
|
+
port: 993,
|
|
69
|
+
target: 'mail.example.com.',
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
56
73
|
/****** IMPORTERS *******/
|
|
57
|
-
fromTinydns(
|
|
58
|
-
const str =
|
|
74
|
+
fromTinydns({ tinyline }) {
|
|
75
|
+
const str = tinyline
|
|
59
76
|
let fqdn, addr, port, pri, weight, ttl, ts, loc, n, rdata
|
|
60
77
|
|
|
61
78
|
if (str[0] === 'S') {
|
|
62
79
|
// patched tinydns with S records
|
|
63
|
-
;[fqdn, addr, port, pri, weight, ttl, ts, loc] = str.
|
|
80
|
+
;[fqdn, addr, port, pri, weight, ttl, ts, loc] = str.slice(1).split(':')
|
|
64
81
|
} else {
|
|
65
82
|
// tinydns generic record format
|
|
66
|
-
;[fqdn, n, rdata, ttl, ts, loc] = str.
|
|
83
|
+
;[fqdn, n, rdata, ttl, ts, loc] = str.slice(1).split(':')
|
|
67
84
|
if (n != 33) this.throwHelp('SRV fromTinydns: invalid n')
|
|
68
85
|
|
|
69
|
-
pri = TINYDNS.octalToUInt16(rdata.
|
|
70
|
-
weight = TINYDNS.octalToUInt16(rdata.
|
|
71
|
-
port = TINYDNS.octalToUInt16(rdata.
|
|
72
|
-
addr = TINYDNS.unpackDomainName(rdata.
|
|
86
|
+
pri = TINYDNS.octalToUInt16(rdata.slice(0, 8))
|
|
87
|
+
weight = TINYDNS.octalToUInt16(rdata.slice(8, 16))
|
|
88
|
+
port = TINYDNS.octalToUInt16(rdata.slice(16, 24))
|
|
89
|
+
addr = TINYDNS.unpackDomainName(rdata.slice(24))[0]
|
|
73
90
|
}
|
|
74
91
|
|
|
75
92
|
return new SRV({
|
|
@@ -81,13 +98,13 @@ export default class SRV extends RR {
|
|
|
81
98
|
port: parseInt(port, 10),
|
|
82
99
|
target: this.fullyQualify(addr),
|
|
83
100
|
timestamp: ts,
|
|
84
|
-
location: loc
|
|
101
|
+
location: loc?.trim() ?? '',
|
|
85
102
|
})
|
|
86
103
|
}
|
|
87
104
|
|
|
88
|
-
fromBind(
|
|
105
|
+
fromBind({ bindline }) {
|
|
89
106
|
// test.example.com 3600 IN SRV Priority Weight Port Target
|
|
90
|
-
const [owner, ttl, c, type, pri, weight, port, target] =
|
|
107
|
+
const [owner, ttl, c, type, pri, weight, port, target] = bindline.split(/\s+/)
|
|
91
108
|
return new SRV({
|
|
92
109
|
owner: owner,
|
|
93
110
|
ttl: parseInt(ttl, 10),
|
package/rr/sshfp.js
CHANGED
|
@@ -46,6 +46,10 @@ export default class SSHFP extends RR {
|
|
|
46
46
|
return 'Secure Shell Key Fingerprints'
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
getTags() {
|
|
50
|
+
return ['security']
|
|
51
|
+
}
|
|
52
|
+
|
|
49
53
|
getRdataFields() {
|
|
50
54
|
return ['algorithm', 'fptype', 'fingerprint']
|
|
51
55
|
}
|
|
@@ -58,27 +62,39 @@ export default class SSHFP extends RR {
|
|
|
58
62
|
return 44
|
|
59
63
|
}
|
|
60
64
|
|
|
65
|
+
getCanonical() {
|
|
66
|
+
return {
|
|
67
|
+
owner: 'mail.example.com.',
|
|
68
|
+
ttl: 3600,
|
|
69
|
+
class: 'IN',
|
|
70
|
+
type: 'SSHFP',
|
|
71
|
+
algorithm: 2,
|
|
72
|
+
fptype: 1,
|
|
73
|
+
fingerprint: '123456789abcdef6789abcdf6789abdf6789abcd',
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
61
77
|
/****** IMPORTERS *******/
|
|
62
|
-
fromTinydns(
|
|
78
|
+
fromTinydns({ tinyline }) {
|
|
63
79
|
// SSHFP via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
64
|
-
const [fqdn, n, rdata, ttl, ts, loc] =
|
|
80
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
65
81
|
if (n != 44) this.throwHelp('SSHFP fromTinydns, invalid n')
|
|
66
82
|
|
|
67
83
|
return new SSHFP({
|
|
68
84
|
owner: this.fullyQualify(fqdn),
|
|
69
85
|
ttl: parseInt(ttl, 10),
|
|
70
86
|
type: 'SSHFP',
|
|
71
|
-
algorithm: TINYDNS.octalToUInt8(rdata.
|
|
72
|
-
fptype: TINYDNS.octalToUInt8(rdata.
|
|
73
|
-
fingerprint: TINYDNS.octalToHex(rdata.
|
|
87
|
+
algorithm: TINYDNS.octalToUInt8(rdata.slice(0, 4)),
|
|
88
|
+
fptype: TINYDNS.octalToUInt8(rdata.slice(4, 8)),
|
|
89
|
+
fingerprint: TINYDNS.octalToHex(rdata.slice(8)),
|
|
74
90
|
timestamp: ts,
|
|
75
|
-
location: loc
|
|
91
|
+
location: loc?.trim() ?? '',
|
|
76
92
|
})
|
|
77
93
|
}
|
|
78
94
|
|
|
79
|
-
fromBind(
|
|
95
|
+
fromBind({ bindline }) {
|
|
80
96
|
// test.example.com 3600 IN SSHFP algo fptype fp
|
|
81
|
-
const [owner, ttl, c, type, algo, fptype, fp] =
|
|
97
|
+
const [owner, ttl, c, type, algo, fptype, fp] = bindline.split(/\s+/)
|
|
82
98
|
return new SSHFP({
|
|
83
99
|
owner,
|
|
84
100
|
ttl: parseInt(ttl, 10),
|
package/rr/svcb.js
CHANGED
|
@@ -44,13 +44,25 @@ export default class SVCB extends RR {
|
|
|
44
44
|
return 64
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
getCanonical() {
|
|
48
|
+
return {
|
|
49
|
+
owner: '_8443._foo.api.example.com.',
|
|
50
|
+
ttl: 3600,
|
|
51
|
+
class: 'IN',
|
|
52
|
+
type: 'SVCB',
|
|
53
|
+
priority: 1,
|
|
54
|
+
'target name': 'svc4.example.net.',
|
|
55
|
+
params: 'alpn="h2,h3"',
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
47
59
|
/****** IMPORTERS *******/
|
|
48
60
|
|
|
49
|
-
fromBind(
|
|
61
|
+
fromBind({ bindline }) {
|
|
50
62
|
// test.example.com 3600 IN SVCB Priority TargetName Params
|
|
51
63
|
// _8443._foo.api.example.com. 7200 IN SVCB 0 svc4.example.net.
|
|
52
64
|
// svc4.example.net. 7200 IN SVCB 3 svc4.example.net. ( alpn="bar" port="8004" )
|
|
53
|
-
const [owner, ttl, c, type, pri, fqdn] =
|
|
65
|
+
const [owner, ttl, c, type, pri, fqdn] = bindline.split(/\s+/)
|
|
54
66
|
return new SVCB({
|
|
55
67
|
owner,
|
|
56
68
|
ttl: parseInt(ttl, 10),
|
|
@@ -58,22 +70,35 @@ export default class SVCB extends RR {
|
|
|
58
70
|
type,
|
|
59
71
|
priority: parseInt(pri, 10),
|
|
60
72
|
'target name': fqdn,
|
|
61
|
-
params:
|
|
73
|
+
params: bindline.split(/\s+/).slice(6).join(' ').trim(),
|
|
62
74
|
})
|
|
63
75
|
}
|
|
64
76
|
|
|
65
|
-
fromTinydns({
|
|
77
|
+
fromTinydns({ tinyline }) {
|
|
78
|
+
const [owner, _typeId, rd, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
79
|
+
|
|
66
80
|
if (rd.length < 6) {
|
|
67
81
|
this.throwHelp(`SVCB: RDATA too short: ${rd}`)
|
|
68
82
|
}
|
|
69
83
|
|
|
70
|
-
|
|
71
|
-
const
|
|
84
|
+
// Convert escaped octal RDATA into a binary buffer for reliable parsing
|
|
85
|
+
const binary = Buffer.from(TINYDNS.octalToChar(rd), 'binary')
|
|
72
86
|
|
|
73
|
-
const
|
|
87
|
+
const priority = binary.readUInt16BE(0)
|
|
74
88
|
|
|
75
|
-
|
|
76
|
-
|
|
89
|
+
// parse domain name from binary starting at offset 2
|
|
90
|
+
let pos = 2
|
|
91
|
+
const labels = []
|
|
92
|
+
while (true) {
|
|
93
|
+
const len = binary.readUInt8(pos)
|
|
94
|
+
pos += 1
|
|
95
|
+
if (len === 0) break
|
|
96
|
+
labels.push(binary.slice(pos, pos + len).toString())
|
|
97
|
+
pos += len
|
|
98
|
+
}
|
|
99
|
+
const targetName = `${labels.join('.')}.`
|
|
100
|
+
// remaining params are ASCII text after the domain
|
|
101
|
+
const params = binary.slice(pos).toString()
|
|
77
102
|
|
|
78
103
|
return new SVCB({
|
|
79
104
|
owner: this.fullyQualify(owner),
|
|
@@ -81,7 +106,9 @@ export default class SVCB extends RR {
|
|
|
81
106
|
type: 'SVCB',
|
|
82
107
|
priority: priority,
|
|
83
108
|
'target name': targetName,
|
|
84
|
-
params:
|
|
109
|
+
params: params,
|
|
110
|
+
timestamp: ts,
|
|
111
|
+
location: loc?.trim() ?? '',
|
|
85
112
|
})
|
|
86
113
|
}
|
|
87
114
|
|
package/rr/tlsa.js
CHANGED
|
@@ -58,30 +58,47 @@ export default class TLSA extends RR {
|
|
|
58
58
|
return 'TLSA certificate association'
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
getTags() {
|
|
62
|
+
return ['security']
|
|
63
|
+
}
|
|
64
|
+
|
|
61
65
|
getRdataFields(arg) {
|
|
62
66
|
return ['certificate usage', 'selector', 'matching type', 'certificate association data']
|
|
63
67
|
}
|
|
64
68
|
|
|
65
69
|
getRFCs() {
|
|
66
|
-
return [6698]
|
|
70
|
+
return [6698, 7671]
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
getTypeId() {
|
|
70
74
|
return 52
|
|
71
75
|
}
|
|
72
76
|
|
|
77
|
+
getCanonical() {
|
|
78
|
+
return {
|
|
79
|
+
owner: '_443._tcp.www.example.com.',
|
|
80
|
+
ttl: 3600,
|
|
81
|
+
class: 'IN',
|
|
82
|
+
type: 'TLSA',
|
|
83
|
+
'certificate usage': 3,
|
|
84
|
+
selector: 1,
|
|
85
|
+
'matching type': 1,
|
|
86
|
+
'certificate association data': 'ABCDEF...',
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
73
90
|
getQuotedFields() {
|
|
74
91
|
return []
|
|
75
92
|
}
|
|
76
93
|
|
|
77
94
|
/****** IMPORTERS *******/
|
|
78
95
|
|
|
79
|
-
fromBind(
|
|
96
|
+
fromBind({ bindline }) {
|
|
80
97
|
// test.example.com 3600 IN TLSA, usage, selector, match, data
|
|
81
98
|
const regex =
|
|
82
|
-
/^(?<owner>\S+)\s+(?<ttl>\d{1,10})\s+(?<cls>IN)\s+(?<type>TLSA)\s+(?<usage>\d+)\s+(?<selector>\d+)\s+(?<matchtype>\d+)\s+(?<cad
|
|
83
|
-
const match =
|
|
84
|
-
if (!match) this.throwHelp(`unable to parse TLSA: ${
|
|
99
|
+
/^(?<owner>\S+)\s+(?<ttl>\d{1,10})\s+(?<cls>IN)\s+(?<type>TLSA)\s+(?<usage>\d+)\s+(?<selector>\d+)\s+(?<matchtype>\d+)\s+(?<cad>\S.*)$/i
|
|
100
|
+
const match = bindline.trim().match(regex)
|
|
101
|
+
if (!match) this.throwHelp(`unable to parse TLSA: ${bindline}`)
|
|
85
102
|
const { owner, ttl, cls, type, usage, selector, matchtype, cad } = match.groups
|
|
86
103
|
|
|
87
104
|
return new TLSA({
|
|
@@ -92,12 +109,12 @@ export default class TLSA extends RR {
|
|
|
92
109
|
'certificate usage': parseInt(usage, 10),
|
|
93
110
|
selector: parseInt(selector, 10),
|
|
94
111
|
'matching type': parseInt(matchtype, 10),
|
|
95
|
-
'certificate association data': cad,
|
|
112
|
+
'certificate association data': cad.trim(),
|
|
96
113
|
})
|
|
97
114
|
}
|
|
98
115
|
|
|
99
|
-
fromTinydns(
|
|
100
|
-
const [fqdn, n, rdata, ttl, ts, loc] =
|
|
116
|
+
fromTinydns({ tinyline }) {
|
|
117
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
101
118
|
if (n != 52) this.throwHelp('TLSA fromTinydns, invalid n')
|
|
102
119
|
|
|
103
120
|
const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
@@ -111,7 +128,7 @@ export default class TLSA extends RR {
|
|
|
111
128
|
'matching type': bytes.readUInt8(2),
|
|
112
129
|
'certificate association data': bytes.slice(3).toString(),
|
|
113
130
|
timestamp: ts,
|
|
114
|
-
location: loc
|
|
131
|
+
location: loc?.trim() ?? '',
|
|
115
132
|
})
|
|
116
133
|
}
|
|
117
134
|
|
package/rr/tsig.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import RR from '../rr.js'
|
|
2
|
+
import * as TINYDNS from '../lib/tinydns.js'
|
|
2
3
|
|
|
3
4
|
export default class TSIG extends RR {
|
|
4
5
|
constructor(opts) {
|
|
@@ -17,32 +18,173 @@ export default class TSIG extends RR {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
getRFCs() {
|
|
20
|
-
return [2845]
|
|
21
|
+
return [2845, 8945]
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
getTypeId() {
|
|
24
25
|
return 250
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
getCanonical() {
|
|
29
|
+
return {
|
|
30
|
+
owner: 'test.example.',
|
|
31
|
+
ttl: 0,
|
|
32
|
+
class: 'ANY',
|
|
33
|
+
type: 'TSIG',
|
|
34
|
+
'algorithm name': 'hmac-sha256.',
|
|
35
|
+
'time signed': 1620650000,
|
|
36
|
+
fudge: 300,
|
|
37
|
+
mac: 'ABCDEF...',
|
|
38
|
+
'original id': 12345,
|
|
39
|
+
error: 0,
|
|
40
|
+
other: '',
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
setClass(t) {
|
|
45
|
+
if (t !== 'ANY') this.throwHelp('TSIG: Class is required to be ANY')
|
|
46
|
+
this.set('class', t)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
setTtl(t) {
|
|
50
|
+
if (t !== 0) this.throwHelp('TSIG: TTL is required to be 0')
|
|
51
|
+
this.set('ttl', t)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
setAlgorithmName(val) {
|
|
55
|
+
if (!val) this.throwHelp(`TSIG: 'algorithm name' is required`)
|
|
56
|
+
this.set('algorithm name', val)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
setTimeSigned(val) {
|
|
60
|
+
// a 48-bit unsigned integer, as seconds since the UNIX epoch
|
|
61
|
+
if (val === undefined) this.throwHelp(`TSIG: 'time signed' is required`)
|
|
62
|
+
this.set('time signed', val)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
setFudge(val) {
|
|
66
|
+
// 16-bit unsigned
|
|
67
|
+
this.is16bitInt('TSIG', 'fudge', val)
|
|
68
|
+
this.set('fudge', val)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
setMac(val) {
|
|
72
|
+
this.set('mac', val ?? '')
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
setOriginalId(val) {
|
|
76
|
+
this.is16bitInt('TSIG', 'original id', val)
|
|
77
|
+
this.set('original id', val)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
setError(val) {
|
|
81
|
+
this.is16bitInt('TSIG', 'error', val)
|
|
82
|
+
this.set('error', val)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
setOther(val) {
|
|
86
|
+
this.set('other', val ?? '')
|
|
87
|
+
}
|
|
88
|
+
|
|
27
89
|
/****** IMPORTERS *******/
|
|
28
90
|
|
|
29
|
-
fromBind(
|
|
30
|
-
//
|
|
31
|
-
const
|
|
91
|
+
fromBind({ bindline }) {
|
|
92
|
+
// owner ttl ANY TSIG alg time fudge mac_size mac original_id error other_len
|
|
93
|
+
const parts = bindline.trimEnd().split('\t')
|
|
94
|
+
const [owner, ttl, cls, type, alg, time, fudge, , mac, origId, error] = parts
|
|
95
|
+
|
|
32
96
|
return new TSIG({
|
|
33
97
|
owner,
|
|
34
98
|
ttl: parseInt(ttl, 10),
|
|
35
|
-
class:
|
|
36
|
-
type: type,
|
|
37
|
-
algorithm:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
99
|
+
class: cls,
|
|
100
|
+
type: type.toUpperCase(),
|
|
101
|
+
'algorithm name': alg,
|
|
102
|
+
'time signed': parseInt(time, 10),
|
|
103
|
+
fudge: parseInt(fudge, 10),
|
|
104
|
+
mac: mac || '',
|
|
105
|
+
'original id': parseInt(origId, 10),
|
|
106
|
+
error: parseInt(error, 10),
|
|
107
|
+
other: '',
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
fromTinydns({ tinyline }) {
|
|
112
|
+
const [owner, _typeId, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
113
|
+
|
|
114
|
+
const algUnpacked = TINYDNS.unpackDomainName(rdata)
|
|
115
|
+
const algBinaryLen = algUnpacked[2]
|
|
116
|
+
|
|
117
|
+
const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
118
|
+
let bpos = algBinaryLen
|
|
119
|
+
|
|
120
|
+
const timeSigned = bytes.readUInt32BE(bpos)
|
|
121
|
+
bpos += 4
|
|
122
|
+
const fudge = bytes.readUInt16BE(bpos)
|
|
123
|
+
bpos += 2
|
|
124
|
+
const macSize = bytes.readUInt16BE(bpos)
|
|
125
|
+
bpos += 2
|
|
126
|
+
const mac = macSize > 0 ? bytes.slice(bpos, bpos + macSize).toString('hex') : ''
|
|
127
|
+
bpos += macSize
|
|
128
|
+
const originalId = bytes.readUInt16BE(bpos)
|
|
129
|
+
bpos += 2
|
|
130
|
+
const error = bytes.readUInt16BE(bpos)
|
|
131
|
+
bpos += 2
|
|
132
|
+
const other = bpos < bytes.length ? bytes.slice(bpos).toString() : ''
|
|
133
|
+
|
|
134
|
+
return new TSIG({
|
|
135
|
+
owner: this.fullyQualify(owner),
|
|
136
|
+
ttl: parseInt(ttl, 10),
|
|
137
|
+
class: 'ANY',
|
|
138
|
+
type: 'TSIG',
|
|
139
|
+
'algorithm name': algUnpacked[0],
|
|
140
|
+
'time signed': timeSigned,
|
|
141
|
+
fudge,
|
|
142
|
+
mac,
|
|
143
|
+
'original id': originalId,
|
|
144
|
+
error,
|
|
145
|
+
other,
|
|
146
|
+
timestamp: ts,
|
|
147
|
+
location: loc?.trim() ?? '',
|
|
44
148
|
})
|
|
45
149
|
}
|
|
46
150
|
|
|
47
151
|
/****** EXPORTERS *******/
|
|
152
|
+
toBind(zone_opts) {
|
|
153
|
+
const mac = this.get('mac') ?? ''
|
|
154
|
+
const macSize = mac.length > 0 ? mac.length : ''
|
|
155
|
+
const other = this.get('other') ?? ''
|
|
156
|
+
const otherLen = other.length > 0 ? other.length : 0
|
|
157
|
+
return (
|
|
158
|
+
[
|
|
159
|
+
this.getFQDN('owner', zone_opts),
|
|
160
|
+
this.get('ttl'),
|
|
161
|
+
this.get('class'),
|
|
162
|
+
this.get('type'),
|
|
163
|
+
this.get('algorithm name'),
|
|
164
|
+
this.get('time signed'),
|
|
165
|
+
this.get('fudge'),
|
|
166
|
+
macSize,
|
|
167
|
+
mac,
|
|
168
|
+
this.get('original id'),
|
|
169
|
+
this.get('error'),
|
|
170
|
+
otherLen,
|
|
171
|
+
].join('\t') + '\n'
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
toTinydns() {
|
|
176
|
+
const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
|
|
177
|
+
const alg = this.get('algorithm name') || ''
|
|
178
|
+
|
|
179
|
+
return this.getTinydnsGeneric(
|
|
180
|
+
TINYDNS.packDomainName(alg) +
|
|
181
|
+
TINYDNS.UInt32toOctal(this.get('time signed') ?? 0) +
|
|
182
|
+
TINYDNS.UInt16toOctal(this.get('fudge')) +
|
|
183
|
+
TINYDNS.UInt16toOctal(this.get('mac size') ?? 0) +
|
|
184
|
+
(this.get('mac size') > 0 ? TINYDNS.escapeOctal(dataRe, this.get('mac')) : '') +
|
|
185
|
+
TINYDNS.UInt16toOctal(this.get('original id') ?? 0) +
|
|
186
|
+
TINYDNS.UInt16toOctal(this.get('error') ?? 0) +
|
|
187
|
+
(this.get('other').length > 0 ? TINYDNS.escapeOctal(dataRe, this.get('other')) : ''),
|
|
188
|
+
)
|
|
189
|
+
}
|
|
48
190
|
}
|