@nictool/dns-resource-record 1.6.0 → 1.7.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +45 -6
  2. package/README.md +328 -198
  3. package/dist/dns-rr.min.js +26 -0
  4. package/dist/dns-rr.min.js.map +7 -0
  5. package/index.js +12 -11
  6. package/lib/binary.js +108 -0
  7. package/lib/bind.js +94 -0
  8. package/lib/dns-query.js +67 -0
  9. package/lib/tinydns.js +128 -44
  10. package/lib/wire.js +519 -0
  11. package/package.json +29 -10
  12. package/rr/TEMPLATE.js +124 -0
  13. package/rr/a.js +8 -48
  14. package/rr/aaaa.js +13 -80
  15. package/rr/apl.js +123 -27
  16. package/rr/caa.js +27 -50
  17. package/rr/cert.js +58 -87
  18. package/rr/cname.js +7 -63
  19. package/rr/dhcid.js +20 -30
  20. package/rr/dname.js +9 -36
  21. package/rr/dnskey.js +38 -32
  22. package/rr/ds.js +43 -57
  23. package/rr/hinfo.js +21 -40
  24. package/rr/hip.js +88 -26
  25. package/rr/https.js +28 -40
  26. package/rr/ipseckey.js +97 -18
  27. package/rr/key.js +39 -29
  28. package/rr/kx.js +16 -27
  29. package/rr/loc.js +42 -12
  30. package/rr/mx.js +16 -51
  31. package/rr/naptr.js +58 -33
  32. package/rr/ns.js +8 -36
  33. package/rr/nsec.js +89 -18
  34. package/rr/nsec3.js +62 -26
  35. package/rr/nsec3param.js +56 -53
  36. package/rr/nxt.js +57 -18
  37. package/rr/openpgpkey.js +24 -30
  38. package/rr/ptr.js +7 -47
  39. package/rr/rp.js +17 -32
  40. package/rr/rrsig.js +80 -85
  41. package/rr/sig.js +70 -45
  42. package/rr/smimea.js +33 -33
  43. package/rr/soa.js +31 -49
  44. package/rr/spf.js +10 -17
  45. package/rr/srv.js +22 -62
  46. package/rr/sshfp.js +25 -53
  47. package/rr/svcb.js +27 -40
  48. package/rr/tlsa.js +34 -34
  49. package/rr/tsig.js +87 -24
  50. package/rr/txt.js +40 -59
  51. package/rr/uri.js +19 -29
  52. package/rr/wks.js +154 -22
  53. package/rr.js +290 -109
  54. package/lib/readme.js +0 -84
package/rr/ptr.js CHANGED
@@ -1,6 +1,13 @@
1
1
  import RR from '../rr.js'
2
2
 
3
3
  export default class PTR extends RR {
4
+ static typeName = 'PTR'
5
+ static typeId = 12
6
+ static RFCs = [1035]
7
+ static tinydnsType = '^'
8
+ static rdataFields = [['dname', 'fqdn']]
9
+ static tags = ['common']
10
+
4
11
  constructor(opts) {
5
12
  super(opts)
6
13
  }
@@ -18,22 +25,6 @@ export default class PTR extends RR {
18
25
  return 'Pointer'
19
26
  }
20
27
 
21
- getTags() {
22
- return ['common']
23
- }
24
-
25
- getRdataFields(arg) {
26
- return ['dname']
27
- }
28
-
29
- getRFCs() {
30
- return [1035]
31
- }
32
-
33
- getTypeId() {
34
- return 12
35
- }
36
-
37
28
  getCanonical() {
38
29
  return {
39
30
  owner: '2.2.0.192.in-addr.arpa.',
@@ -44,39 +35,8 @@ export default class PTR extends RR {
44
35
  }
45
36
  }
46
37
 
47
- /****** IMPORTERS *******/
48
- fromTinydns({ tinyline }) {
49
- // ^fqdn:p:ttl:timestamp:lo
50
- const [fqdn, p, ttl, ts, loc] = tinyline.slice(1).split(':')
51
-
52
- return new PTR({
53
- owner: this.fullyQualify(fqdn),
54
- ttl: parseInt(ttl, 10),
55
- type: 'PTR',
56
- dname: this.fullyQualify(p),
57
- timestamp: ts,
58
- location: loc?.trim() ?? '',
59
- })
60
- }
61
-
62
- fromBind({ bindline }) {
63
- // test.example.com 3600 IN PTR dname
64
- const [owner, ttl, c, type, dname] = bindline.split(/\s+/)
65
- return new PTR({
66
- owner,
67
- ttl: parseInt(ttl, 10),
68
- class: c,
69
- type: type,
70
- dname: dname,
71
- })
72
- }
73
-
74
38
  /****** EXPORTERS *******/
75
39
  getWireRdata() {
76
40
  return this.wirePackDomain(this.get('dname'))
77
41
  }
78
-
79
- toTinydns() {
80
- return `^${this.getTinyFQDN('owner')}:${this.getTinyFQDN('dname')}:${this.getTinydnsPostamble()}\n`
81
- }
82
42
  }
package/rr/rp.js CHANGED
@@ -3,6 +3,12 @@ import RR from '../rr.js'
3
3
  import * as TINYDNS from '../lib/tinydns.js'
4
4
 
5
5
  export default class RP extends RR {
6
+ static typeName = 'RP'
7
+ static rdataFields = [
8
+ ['mbox', 'fqdn'],
9
+ ['txt', 'fqdn'],
10
+ ]
11
+
6
12
  constructor(opts) {
7
13
  super(opts)
8
14
  }
@@ -27,23 +33,9 @@ export default class RP extends RR {
27
33
  getDescription() {
28
34
  return 'Responsible Person'
29
35
  }
30
-
31
- getTags() {
32
- return ['obsolete']
33
- }
34
-
35
- getRdataFields(arg) {
36
- return ['mbox', 'txt']
37
- }
38
-
39
- getRFCs() {
40
- return [1183]
41
- }
42
-
43
- getTypeId() {
44
- return 17
45
- }
46
-
36
+ static tags = ['obsolete']
37
+ static RFCs = [1183]
38
+ static typeId = 17
47
39
  getCanonical() {
48
40
  return {
49
41
  owner: 'example.com.',
@@ -56,19 +48,6 @@ export default class RP extends RR {
56
48
  }
57
49
 
58
50
  /****** IMPORTERS *******/
59
- fromBind({ bindline }) {
60
- // test.example.com 3600 IN RP mbox txt
61
- const [owner, ttl, c, type, mbox, txt] = bindline.split(/\s+/)
62
- return new RP({
63
- owner,
64
- ttl: parseInt(ttl, 10),
65
- class: c,
66
- type,
67
- mbox,
68
- txt,
69
- })
70
- }
71
-
72
51
  fromTinydns({ tinyline }) {
73
52
  const [owner, _typeId, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
74
53
 
@@ -87,8 +66,14 @@ export default class RP extends RR {
87
66
  }
88
67
 
89
68
  /****** EXPORTERS *******/
90
- toBind(zone_opts) {
91
- return `${this.getPrefix(zone_opts)}\t${this.getFQDN('mbox', zone_opts)}\t${this.getFQDN('txt', zone_opts)}\n`
69
+
70
+ getWireRdata() {
71
+ const mbox = this.wirePackDomain(this.get('mbox'))
72
+ const txt = this.wirePackDomain(this.get('txt'))
73
+ const result = new Uint8Array(mbox.length + txt.length)
74
+ result.set(mbox, 0)
75
+ result.set(txt, mbox.length)
76
+ return result
92
77
  }
93
78
 
94
79
  toTinydns() {
package/rr/rrsig.js CHANGED
@@ -1,17 +1,44 @@
1
1
  import RR from '../rr.js'
2
2
  import * as TINYDNS from '../lib/tinydns.js'
3
+ import * as WIRE from '../lib/binary.js'
4
+ import * as WIRELIB from '../lib/wire.js'
3
5
 
4
6
  export default class RRSIG extends RR {
7
+ static typeName = 'RRSIG'
8
+ static typeId = 46
9
+ static RFCs = [4034]
10
+ static rdataFields = [
11
+ ['type covered', 'u16'],
12
+ ['algorithm', 'u8'],
13
+ ['labels', 'u8'],
14
+ ['original ttl', 'u32'],
15
+ ['signature expiration', 'u32'],
16
+ ['signature inception', 'u32'],
17
+ ['key tag', 'u16'],
18
+ ['signers name', 'fqdn'],
19
+ ['signature', 'str'],
20
+ ]
21
+ static tags = ['dnssec']
22
+
5
23
  constructor(opts) {
6
24
  super(opts)
7
25
  }
8
26
 
9
27
  /****** Resource record specific setters *******/
10
28
  setTypeCovered(val) {
11
- // a 2 octet Type Covered field
12
- if (!val) this.throwHelp(`RRSIG: 'type covered' is required`)
13
- if (val.length > 2) this.throwHelp(`RRSIG: 'type covered' is too long`)
14
-
29
+ // a 16-bit Type Covered field (RFC 4034 §3.1.1)
30
+ if (!val && val !== 0) this.throwHelp(`RRSIG: 'type covered' is required`)
31
+ if (typeof val === 'string') {
32
+ const typeNN = val.match(/^TYPE(\d+)$/i)
33
+ if (typeNN) {
34
+ val = parseInt(typeNN[1], 10)
35
+ } else {
36
+ const id = WIRE.DNS_TYPE_IDS[val.toUpperCase()]
37
+ if (id === undefined) this.throwHelp(`RRSIG: 'type covered' is not a recognized type name`)
38
+ val = id
39
+ }
40
+ }
41
+ this.is16bitInt('RRSIG', 'type covered', val)
15
42
  this.set('type covered', val)
16
43
  }
17
44
 
@@ -34,76 +61,10 @@ export default class RRSIG extends RR {
34
61
  ])
35
62
  }
36
63
 
37
- setLabels(val) {
38
- // a 1 octet Labels field
39
- this.is8bitInt('RRSIG', 'labels', val)
40
-
41
- this.set('labels', val)
42
- }
43
-
44
- setOriginalTtl(val) {
45
- // a 4 octet Original TTL field
46
- this.is32bitInt('RRSIG', 'original ttl', val)
47
-
48
- this.set('original ttl', val)
49
- }
50
-
51
- setSignatureExpiration(val) {
52
- // a 4 octet Signature Expiration field
53
- this.set('signature expiration', val)
54
- }
55
-
56
- setSignatureInception(val) {
57
- // a 4 octet Signature Inception field
58
- this.set('signature inception', val)
59
- }
60
-
61
- setKeyTag(val) {
62
- // a 2 octet Key tag
63
- this.set('key tag', val)
64
- }
65
-
66
- setSignersName(val) {
67
- // the Signer's Name field
68
- this.set('signers name', val)
69
- }
70
-
71
- setSignature(val) {
72
- // the Signature field.
73
-
74
- this.set('signature', val)
75
- }
76
-
77
64
  getDescription() {
78
65
  return 'Resource Record Signature'
79
66
  }
80
67
 
81
- getTags() {
82
- return ['dnssec']
83
- }
84
-
85
- getRdataFields(arg) {
86
- return [
87
- 'type covered',
88
- 'algorithm',
89
- 'labels',
90
- 'original ttl',
91
- 'signature expiration',
92
- 'signature inception',
93
- 'key tag',
94
- 'signers name',
95
- 'signature',
96
- ]
97
- }
98
-
99
- getRFCs() {
100
- return [4034]
101
- }
102
-
103
- getTypeId() {
104
- return 46
105
- }
106
-
107
68
  getCanonical() {
108
69
  return {
109
70
  owner: 'example.com.',
@@ -127,12 +88,20 @@ export default class RRSIG extends RR {
127
88
  fromBind({ bindline }) {
128
89
  // example.com. 3600 IN RRSIG typecovered algorithm labels origttl sigexp siginc keytag signersname ( signature )
129
90
  const parts = bindline.trim().split(/\s+/)
91
+ const typeCoveredStr = parts[4]
92
+ // type covered may be a type name ('A', 'MX'), TYPEnn (RFC 3597), or a numeric ID
93
+ const typeNN = typeCoveredStr.match(/^TYPE(\d+)$/i)
94
+ const typeCovered = /^\d+$/.test(typeCoveredStr)
95
+ ? parseInt(typeCoveredStr, 10)
96
+ : typeNN
97
+ ? parseInt(typeNN[1], 10)
98
+ : (WIRE.DNS_TYPE_IDS[typeCoveredStr.toUpperCase()] ?? parseInt(typeCoveredStr, 10))
130
99
  return new RRSIG({
131
100
  owner: parts[0],
132
101
  ttl: parseInt(parts[1], 10),
133
102
  class: parts[2],
134
103
  type: 'RRSIG',
135
- 'type covered': parseInt(parts[4], 10),
104
+ 'type covered': typeCovered,
136
105
  algorithm: parseInt(parts[5], 10),
137
106
  labels: parseInt(parts[6], 10),
138
107
  'original ttl': parseInt(parts[7], 10),
@@ -152,25 +121,26 @@ export default class RRSIG extends RR {
152
121
  const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
153
122
  if (parseInt(n, 10) !== this.getTypeId()) this.throwHelp('RRSIG fromTinydns, invalid n')
154
123
 
155
- const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
156
- const typeCovered = bytes.readUInt16BE(0)
157
- const algorithm = bytes.readUInt8(2)
158
- const labels = bytes.readUInt8(3)
159
- const originalTtl = bytes.readUInt32BE(4)
160
- const signatureExpiration = bytes.readUInt32BE(8)
161
- const signatureInception = bytes.readUInt32BE(12)
162
- const keyTag = bytes.readUInt16BE(16)
124
+ const bytes = Uint8Array.from(TINYDNS.octalToChar(rdata), (c) => c.charCodeAt(0))
125
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)
126
+ const typeCovered = dv.getUint16(0)
127
+ const algorithm = bytes[2]
128
+ const labels = bytes[3]
129
+ const originalTtl = dv.getUint32(4)
130
+ const signatureExpiration = dv.getUint32(8)
131
+ const signatureInception = dv.getUint32(12)
132
+ const keyTag = dv.getUint16(16)
163
133
 
164
134
  let pos = 18
165
135
  const labelArr = []
166
136
  while (pos < bytes.length) {
167
- const len = bytes.readUInt8(pos++)
137
+ const len = bytes[pos++]
168
138
  if (len === 0) break
169
- labelArr.push(bytes.slice(pos, pos + len).toString())
139
+ labelArr.push(new TextDecoder().decode(bytes.subarray(pos, pos + len)))
170
140
  pos += len
171
141
  }
172
142
  const signersName = `${labelArr.join('.')}.`
173
- const signature = bytes.slice(pos).toString()
143
+ const signature = new TextDecoder().decode(bytes.subarray(pos))
174
144
 
175
145
  return new RRSIG({
176
146
  owner: this.fullyQualify(fqdn),
@@ -191,9 +161,6 @@ export default class RRSIG extends RR {
191
161
  }
192
162
 
193
163
  /****** EXPORTERS *******/
194
- toBind(zone_opts) {
195
- return `${this.getPrefix(zone_opts)}\t${this.get('type covered')}\t${this.get('algorithm')}\t${this.get('labels')}\t${this.get('original ttl')}\t${this.get('signature expiration')}\t${this.get('signature inception')}\t${this.get('key tag')}\t${this.getFQDN('signers name', zone_opts)}\t${this.get('signature')}\n`
196
- }
197
164
 
198
165
  toTinydns() {
199
166
  const dataRe = new RegExp(/[\r\n\t:]/, 'g')
@@ -209,4 +176,32 @@ export default class RRSIG extends RR {
209
176
  TINYDNS.escapeOctal(dataRe, this.get('signature')),
210
177
  )
211
178
  }
179
+
180
+ getWireRdata() {
181
+ const signerBytes = WIRELIB.wirePackDomain(this.get('signers name'))
182
+ const sigBytes = new TextEncoder().encode(this.get('signature'))
183
+
184
+ const totalLen = 2 + 1 + 1 + 4 + 4 + 4 + 2 + signerBytes.length + sigBytes.length
185
+ const bytes = new Uint8Array(totalLen)
186
+ const dv = new DataView(bytes.buffer, bytes.byteOffset)
187
+
188
+ let pos = 0
189
+ dv.setUint16(pos, this.get('type covered'))
190
+ pos += 2
191
+ bytes[pos++] = this.get('algorithm')
192
+ bytes[pos++] = this.get('labels')
193
+ dv.setUint32(pos, this.get('original ttl'))
194
+ pos += 4
195
+ dv.setUint32(pos, this.get('signature expiration'))
196
+ pos += 4
197
+ dv.setUint32(pos, this.get('signature inception'))
198
+ pos += 4
199
+ dv.setUint16(pos, this.get('key tag'))
200
+ pos += 2
201
+ bytes.set(signerBytes, pos)
202
+ pos += signerBytes.length
203
+ bytes.set(sigBytes, pos)
204
+
205
+ return bytes
206
+ }
212
207
  }
package/rr/sig.js CHANGED
@@ -1,8 +1,26 @@
1
1
  import RR from '../rr.js'
2
2
 
3
3
  import * as TINYDNS from '../lib/tinydns.js'
4
+ import * as WIRE from '../lib/binary.js'
5
+ import * as WIRELIB from '../lib/wire.js'
4
6
 
5
7
  export default class SIG extends RR {
8
+ static typeName = 'SIG'
9
+ static typeId = 24
10
+ static RFCs = [2535, 3755]
11
+ static rdataFields = [
12
+ ['type covered', 'u16'],
13
+ ['algorithm', 'u8'],
14
+ ['labels', 'u8'],
15
+ ['original ttl', 'u32'],
16
+ ['signature expiration', 'u32'],
17
+ ['signature inception', 'u32'],
18
+ ['key tag', 'u16'],
19
+ ['signers name', 'fqdn'],
20
+ ['signature', 'str'],
21
+ ]
22
+ static tags = ['obsolete']
23
+
6
24
  constructor(opts) {
7
25
  super(opts)
8
26
  }
@@ -68,32 +86,6 @@ export default class SIG extends RR {
68
86
  return 'Signature'
69
87
  }
70
88
 
71
- getTags() {
72
- return ['obsolete']
73
- }
74
-
75
- getRdataFields(arg) {
76
- return [
77
- 'type covered',
78
- 'algorithm',
79
- 'labels',
80
- 'original ttl',
81
- 'signature expiration',
82
- 'signature inception',
83
- 'key tag',
84
- 'signers name',
85
- 'signature',
86
- ]
87
- }
88
-
89
- getRFCs() {
90
- return [2535, 3755]
91
- }
92
-
93
- getTypeId() {
94
- return 24
95
- }
96
-
97
89
  getCanonical() {
98
90
  return {
99
91
  owner: 'example.com.',
@@ -117,13 +109,17 @@ export default class SIG extends RR {
117
109
  fromBind({ bindline }) {
118
110
  // example.com. 3600 IN SIG TypeCovered Algorithm Labels OrigTTL SigExpiration SigInception KeyTag SignersName ( Signature )
119
111
  const parts = bindline.trim().split(/\s+/)
112
+ const typeCoveredStr = parts[4]
113
+ const typeCovered = /^\d+$/.test(typeCoveredStr)
114
+ ? parseInt(typeCoveredStr, 10)
115
+ : (WIRE.DNS_TYPE_IDS[typeCoveredStr.toUpperCase()] ?? parseInt(typeCoveredStr, 10))
120
116
 
121
117
  return new SIG({
122
118
  owner: parts[0],
123
119
  ttl: parseInt(parts[1], 10),
124
120
  class: parts[2],
125
121
  type: 'SIG',
126
- 'type covered': parseInt(parts[4], 10),
122
+ 'type covered': typeCovered,
127
123
  algorithm: parseInt(parts[5], 10),
128
124
  labels: parseInt(parts[6], 10),
129
125
  'original ttl': parseInt(parts[7], 10),
@@ -156,36 +152,65 @@ export default class SIG extends RR {
156
152
  )
157
153
  }
158
154
 
155
+ getWireRdata() {
156
+ const signerBytes = WIRELIB.wirePackDomain(this.get('signers name'))
157
+ const sigBytes = new TextEncoder().encode(this.get('signature'))
158
+
159
+ const totalLen = 2 + 1 + 1 + 4 + 4 + 4 + 2 + signerBytes.length + sigBytes.length
160
+ const bytes = new Uint8Array(totalLen)
161
+ const dv = new DataView(bytes.buffer, bytes.byteOffset)
162
+
163
+ let pos = 0
164
+ dv.setUint16(pos, this.get('type covered'))
165
+ pos += 2
166
+ bytes[pos++] = this.get('algorithm')
167
+ bytes[pos++] = this.get('labels')
168
+ dv.setUint32(pos, this.get('original ttl'))
169
+ pos += 4
170
+ dv.setUint32(pos, this.get('signature expiration'))
171
+ pos += 4
172
+ dv.setUint32(pos, this.get('signature inception'))
173
+ pos += 4
174
+ dv.setUint16(pos, this.get('key tag'))
175
+ pos += 2
176
+ bytes.set(signerBytes, pos)
177
+ pos += signerBytes.length
178
+ bytes.set(sigBytes, pos)
179
+
180
+ return bytes
181
+ }
182
+
159
183
  fromTinydns({ tinyline }) {
160
- const [fqdn, n, rdata, ttl, ts, loc] = tinyline.substring(1).split(':')
161
- if (parseInt(n, 10) !== this.getTypeId()) this.throwHelp('SIG fromTinydns, invalid n')
184
+ const { owner, typeId, rdata, ttl, timestamp, location } = this.parseTinydnsLine(tinyline)
185
+ if (parseInt(typeId, 10) !== this.getTypeId()) this.throwHelp('SIG fromTinydns, invalid n')
162
186
 
163
- const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
187
+ const bytes = TINYDNS.octalRdataToBytes(rdata)
188
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)
164
189
 
165
- const typeCovered = bytes.readUInt16BE(0)
166
- const algorithm = bytes.readUInt8(2)
167
- const labels = bytes.readUInt8(3)
168
- const originalTtl = bytes.readUInt32BE(4)
169
- const signatureExpiration = bytes.readUInt32BE(8)
170
- const signatureInception = bytes.readUInt32BE(12)
171
- const keyTag = bytes.readUInt16BE(16)
190
+ const typeCovered = dv.getUint16(0)
191
+ const algorithm = bytes[2]
192
+ const labels = bytes[3]
193
+ const originalTtl = dv.getUint32(4)
194
+ const signatureExpiration = dv.getUint32(8)
195
+ const signatureInception = dv.getUint32(12)
196
+ const keyTag = dv.getUint16(16)
172
197
 
173
- // parse signers name from binary buffer starting at offset 18
198
+ // parse signers name from binary starting at offset 18
174
199
  let pos = 18
175
200
  const labelsArr = []
176
201
  while (pos < bytes.length) {
177
- const len = bytes.readUInt8(pos++)
202
+ const len = bytes[pos++]
178
203
  if (len === 0) break
179
- labelsArr.push(bytes.slice(pos, pos + len).toString())
204
+ labelsArr.push(new TextDecoder().decode(bytes.subarray(pos, pos + len)))
180
205
  pos += len
181
206
  }
182
207
  const signersName = `${labelsArr.join('.')}.`
183
208
 
184
- const signature = bytes.slice(pos).toString()
209
+ const signature = new TextDecoder().decode(bytes.subarray(pos))
185
210
 
186
211
  return new SIG({
187
- owner: this.fullyQualify(fqdn),
188
- ttl: parseInt(ttl, 10),
212
+ owner,
213
+ ttl,
189
214
  type: 'SIG',
190
215
  'type covered': typeCovered,
191
216
  algorithm,
@@ -196,8 +221,8 @@ export default class SIG extends RR {
196
221
  'key tag': keyTag,
197
222
  'signers name': signersName,
198
223
  signature,
199
- timestamp: ts,
200
- location: loc?.trim() ?? '',
224
+ timestamp,
225
+ location,
201
226
  })
202
227
  }
203
228
 
package/rr/smimea.js CHANGED
@@ -1,8 +1,20 @@
1
1
  import RR from '../rr.js'
2
2
 
3
3
  import * as TINYDNS from '../lib/tinydns.js'
4
+ import * as BINARY from '../lib/binary.js'
4
5
 
5
6
  export default class SMIMEA extends RR {
7
+ static typeName = 'SMIMEA'
8
+ static typeId = 53
9
+ static RFCs = [8162]
10
+ static rdataFields = [
11
+ ['certificate usage', 'u8'],
12
+ ['selector', 'u8'],
13
+ ['matching type', 'u8'],
14
+ ['certificate association data', 'hex'],
15
+ ]
16
+ static tags = ['security']
17
+
6
18
  constructor(opts) {
7
19
  super(opts)
8
20
  }
@@ -58,22 +70,6 @@ export default class SMIMEA extends RR {
58
70
  return 'S/MIME cert association'
59
71
  }
60
72
 
61
- getTags() {
62
- return ['security']
63
- }
64
-
65
- getRdataFields(arg) {
66
- return ['certificate usage', 'selector', 'matching type', 'certificate association data']
67
- }
68
-
69
- getRFCs() {
70
- return [8162]
71
- }
72
-
73
- getTypeId() {
74
- return 53
75
- }
76
-
77
73
  getCanonical() {
78
74
  return {
79
75
  owner: '_443._tcp.www.example.com.',
@@ -87,10 +83,6 @@ export default class SMIMEA extends RR {
87
83
  }
88
84
  }
89
85
 
90
- getQuotedFields() {
91
- return []
92
- }
93
-
94
86
  /****** IMPORTERS *******/
95
87
 
96
88
  fromBind({ bindline }) {
@@ -109,31 +101,39 @@ export default class SMIMEA extends RR {
109
101
  }
110
102
 
111
103
  fromTinydns({ tinyline }) {
112
- const [owner, _typeId, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
113
- const binaryRdata = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
104
+ const { owner, rdata, ttl, timestamp, location } = this.parseTinydnsLine(tinyline)
105
+ const binaryRdata = TINYDNS.octalRdataToBytes(rdata)
114
106
 
115
107
  return new SMIMEA({
116
- owner: this.fullyQualify(owner),
117
- ttl: parseInt(ttl, 10),
108
+ owner,
109
+ ttl,
118
110
  type: 'SMIMEA',
119
- 'certificate usage': binaryRdata.readUInt8(0),
120
- selector: binaryRdata.readUInt8(1),
121
- 'matching type': binaryRdata.readUInt8(2),
122
- 'certificate association data': binaryRdata.slice(3).toString(),
123
- timestamp: ts,
124
- location: loc?.trim() ?? '',
111
+ 'certificate usage': binaryRdata[0],
112
+ selector: binaryRdata[1],
113
+ 'matching type': binaryRdata[2],
114
+ 'certificate association data': BINARY.bytesToHex(binaryRdata.subarray(3)),
115
+ timestamp,
116
+ location,
125
117
  })
126
118
  }
127
119
 
128
120
  /****** EXPORTERS *******/
129
121
  toTinydns() {
130
- const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
131
-
132
122
  return this.getTinydnsGeneric(
133
123
  TINYDNS.UInt8toOctal(this.get('certificate usage')) +
134
124
  TINYDNS.UInt8toOctal(this.get('selector')) +
135
125
  TINYDNS.UInt8toOctal(this.get('matching type')) +
136
- TINYDNS.escapeOctal(dataRe, this.get('certificate association data')),
126
+ TINYDNS.packHex(this.get('certificate association data').replace(/[\s()]/g, '')),
137
127
  )
138
128
  }
129
+
130
+ getWireRdata() {
131
+ const cadBytes = BINARY.hexToBytes(this.get('certificate association data').replace(/[\s()]/g, ''))
132
+ const bytes = new Uint8Array(3 + cadBytes.length)
133
+ bytes[0] = this.get('certificate usage')
134
+ bytes[1] = this.get('selector')
135
+ bytes[2] = this.get('matching type')
136
+ bytes.set(cadBytes, 3)
137
+ return bytes
138
+ }
139
139
  }