@nictool/dns-resource-record 1.6.1 → 1.8.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 (55) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +356 -199
  3. package/dist/dns-rr.cjs +7050 -0
  4. package/dist/dns-rr.min.js +26 -0
  5. package/dist/dns-rr.min.js.map +7 -0
  6. package/index.js +12 -11
  7. package/lib/binary.js +108 -0
  8. package/lib/bind.js +96 -0
  9. package/lib/dns-query.js +67 -0
  10. package/lib/tinydns.js +128 -44
  11. package/lib/wire.js +629 -0
  12. package/package.json +28 -8
  13. package/rr/TEMPLATE.js +124 -0
  14. package/rr/a.js +8 -48
  15. package/rr/aaaa.js +13 -80
  16. package/rr/apl.js +123 -27
  17. package/rr/caa.js +27 -50
  18. package/rr/cert.js +60 -81
  19. package/rr/cname.js +8 -59
  20. package/rr/dhcid.js +20 -30
  21. package/rr/dname.js +10 -32
  22. package/rr/dnskey.js +38 -32
  23. package/rr/ds.js +59 -54
  24. package/rr/hinfo.js +21 -40
  25. package/rr/hip.js +88 -26
  26. package/rr/https.js +28 -40
  27. package/rr/ipseckey.js +97 -18
  28. package/rr/key.js +39 -29
  29. package/rr/kx.js +16 -27
  30. package/rr/loc.js +42 -12
  31. package/rr/mx.js +17 -48
  32. package/rr/naptr.js +58 -33
  33. package/rr/ns.js +8 -36
  34. package/rr/nsec.js +89 -18
  35. package/rr/nsec3.js +62 -26
  36. package/rr/nsec3param.js +56 -53
  37. package/rr/nxt.js +57 -18
  38. package/rr/openpgpkey.js +24 -30
  39. package/rr/ptr.js +7 -47
  40. package/rr/rp.js +17 -32
  41. package/rr/rrsig.js +108 -75
  42. package/rr/sig.js +70 -45
  43. package/rr/smimea.js +33 -33
  44. package/rr/soa.js +31 -49
  45. package/rr/spf.js +15 -18
  46. package/rr/srv.js +28 -51
  47. package/rr/sshfp.js +35 -48
  48. package/rr/svcb.js +27 -40
  49. package/rr/tlsa.js +34 -34
  50. package/rr/tsig.js +87 -24
  51. package/rr/txt.js +77 -68
  52. package/rr/uri.js +19 -29
  53. package/rr/wks.js +154 -22
  54. package/rr.js +290 -109
  55. package/lib/readme.js +0 -84
package/rr/ds.js CHANGED
@@ -1,19 +1,26 @@
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 DS extends RR {
7
+ static typeName = 'DS'
8
+ static typeId = 43
9
+ static RFCs = [4034, 4509, 9619]
10
+ static rdataFields = [['key tag', 'u16'], 'algorithm', 'digest type', ['digest', 'str']]
11
+ static tags = ['dnssec']
12
+
6
13
  constructor(opts) {
7
14
  super(opts)
8
15
  }
9
16
 
10
17
  /****** Resource record specific setters *******/
11
18
  setKeyTag(val) {
12
- // a 2 octet Key Tag field...in network byte order
13
- if (!val) this.throwHelp(`DS: key tag is required`)
14
- if (val.length > 2) this.throwHelp(`DS: key tag is too long`)
19
+ this.setTypedValue('u16', 'key tag', val)
20
+ }
15
21
 
16
- this.set('key tag', val)
22
+ setDigest(val) {
23
+ this.setTypedValue('str', 'digest', val)
17
24
  }
18
25
 
19
26
  setAlgorithm(val) {
@@ -23,49 +30,38 @@ export default class DS extends RR {
23
30
  }
24
31
 
25
32
  getAlgorithmOptions() {
33
+ // IANA DNSSEC Algorithm Numbers
34
+ // https://www.iana.org/assignments/dns-sec-alg-numbers/
26
35
  return new Map([
27
36
  [1, 'RSA/MD5'],
28
37
  [2, 'DH'],
29
38
  [3, 'DSA/SHA-1'],
30
39
  [4, 'EC'],
31
40
  [5, 'RSA/SHA-1'],
41
+ [6, 'DSA-NSEC3-SHA1'],
42
+ [7, 'RSASHA1-NSEC3-SHA1'],
43
+ [8, 'RSA/SHA-256'],
44
+ [10, 'RSA/SHA-512'],
45
+ [13, 'ECDSA P-256/SHA-256'],
46
+ [14, 'ECDSA P-384/SHA-384'],
47
+ [15, 'Ed25519'],
48
+ [16, 'Ed448'],
32
49
  [253, ''],
33
50
  [254, ''],
34
51
  ])
35
52
  }
36
53
 
37
54
  setDigestType(val) {
38
- if (![1, 2].includes(val)) this.throwHelp(`DS: digest type invalid`)
55
+ // 1=SHA-1 (RFC 4034), 2=SHA-256 (RFC 4509), 4=SHA-384 (RFC 6605)
56
+ if (![1, 2, 4].includes(val)) this.throwHelp(`DS: digest type invalid`)
39
57
 
40
58
  this.set('digest type', val)
41
59
  }
42
60
 
43
- setDigest(val) {
44
- if (!val) this.throwHelp(`DS: digest is required`)
45
-
46
- this.set('digest', val)
47
- }
48
-
49
61
  getDescription() {
50
62
  return 'Delegation Signer'
51
63
  }
52
64
 
53
- getTags() {
54
- return ['dnssec']
55
- }
56
-
57
- getRdataFields(arg) {
58
- return ['key tag', 'algorithm', 'digest type', 'digest']
59
- }
60
-
61
- getRFCs() {
62
- return [4034, 4509]
63
- }
64
-
65
- getTypeId() {
66
- return 43
67
- }
68
-
69
65
  getCanonical() {
70
66
  return {
71
67
  owner: 'example.com.',
@@ -81,50 +77,59 @@ export default class DS extends RR {
81
77
 
82
78
  /****** IMPORTERS *******/
83
79
 
84
- fromBind({ bindline }) {
85
- // test.example.com 3600 IN DS Key Tag Algorithm, Digest Type, Digest
86
- const [owner, ttl, c, type, keytag, algorithm, digesttype] = bindline.split(/\s+/)
80
+ fromTinydns(opts) {
81
+ const { tinyline } = opts
82
+ const { owner, typeId, rdata, ttl, timestamp, location } = this.parseTinydnsLine(tinyline)
83
+ if (typeId != this.getTypeId()) this.throwHelp('DS fromTinydns, invalid n')
84
+
85
+ const binRdata = TINYDNS.octalRdataToBytes(rdata)
86
+
87
87
  return new DS({
88
88
  owner,
89
- ttl: parseInt(ttl, 10),
90
- class: c,
91
- type,
92
- 'key tag': parseInt(keytag, 10),
93
- algorithm: parseInt(algorithm, 10),
94
- 'digest type': parseInt(digesttype, 10),
95
- digest: bindline.split(/\s+/).slice(7).join(' ').trim(),
89
+ ttl,
90
+ type: 'DS',
91
+ 'key tag': (binRdata[0] << 8) | binRdata[1],
92
+ algorithm: binRdata[2],
93
+ 'digest type': binRdata[3],
94
+ digest: BINARY.bytesToHex(binRdata.subarray(4)).toUpperCase(),
95
+ timestamp,
96
+ location,
96
97
  })
97
98
  }
98
99
 
99
- fromTinydns({ tinyline }) {
100
- const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
101
- if (n != 43) this.throwHelp('DS fromTinydns, invalid n')
102
-
103
- const binRdata = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
104
-
100
+ fromWire({ owner, cls, ttl, rdata }) {
101
+ const dv = new DataView(rdata.buffer, rdata.byteOffset)
105
102
  return new DS({
106
- owner: this.fullyQualify(fqdn),
107
- ttl: parseInt(ttl, 10),
103
+ owner,
104
+ ttl,
105
+ class: cls,
108
106
  type: 'DS',
109
- 'key tag': binRdata.readUInt16BE(0),
110
- algorithm: binRdata.readUInt8(2),
111
- 'digest type': binRdata.readUInt8(3),
112
- digest: binRdata.slice(4).toString(),
113
- timestamp: ts,
114
- location: loc?.trim() ?? '',
107
+ 'key tag': dv.getUint16(0),
108
+ algorithm: rdata[2],
109
+ 'digest type': rdata[3],
110
+ digest: BINARY.bytesToHex(rdata.subarray(4)).toUpperCase(),
115
111
  })
116
112
  }
117
113
 
118
114
  /****** EXPORTERS *******/
119
115
 
120
116
  toTinydns() {
121
- const rdataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
122
-
123
117
  return this.getTinydnsGeneric(
124
118
  TINYDNS.UInt16toOctal(this.get('key tag')) +
125
119
  TINYDNS.UInt8toOctal(this.get('algorithm')) +
126
120
  TINYDNS.UInt8toOctal(this.get('digest type')) +
127
- TINYDNS.escapeOctal(rdataRe, this.get('digest')),
121
+ TINYDNS.packHex(this.get('digest').replace(/\s+/g, '')),
128
122
  )
129
123
  }
124
+
125
+ getWireRdata() {
126
+ const digestBytes = BINARY.hexToBytes(this.get('digest').replace(/\s+/g, ''))
127
+ const bytes = new Uint8Array(4 + digestBytes.length)
128
+ const dv = new DataView(bytes.buffer, bytes.byteOffset)
129
+ dv.setUint16(0, this.get('key tag'))
130
+ bytes[2] = this.get('algorithm')
131
+ bytes[3] = this.get('digest type')
132
+ bytes.set(digestBytes, 4)
133
+ return bytes
134
+ }
130
135
  }
package/rr/hinfo.js CHANGED
@@ -3,6 +3,15 @@ import RR from '../rr.js'
3
3
  import * as TINYDNS from '../lib/tinydns.js'
4
4
 
5
5
  export default class HINFO extends RR {
6
+ static typeName = 'HINFO'
7
+ static typeId = 13
8
+ static RFCs = [1034, 1035, 8482]
9
+ static rdataFields = [
10
+ ['cpu', 'qcharstr'],
11
+ ['os', 'qcharstr'],
12
+ ]
13
+ static tags = ['obsolete']
14
+
6
15
  constructor(opts) {
7
16
  super(opts)
8
17
  }
@@ -22,22 +31,6 @@ export default class HINFO extends RR {
22
31
  return 'Host Info'
23
32
  }
24
33
 
25
- getTags() {
26
- return ['obsolete']
27
- }
28
-
29
- getRdataFields(arg) {
30
- return ['cpu', 'os']
31
- }
32
-
33
- getRFCs() {
34
- return [1034, 1035, 8482]
35
- }
36
-
37
- getTypeId() {
38
- return 13
39
- }
40
-
41
34
  getCanonical() {
42
35
  return {
43
36
  owner: 'test.example.com.',
@@ -49,31 +42,7 @@ export default class HINFO extends RR {
49
42
  }
50
43
  }
51
44
 
52
- getQuotedFields() {
53
- return ['cpu', 'os']
54
- }
55
-
56
45
  /****** IMPORTERS *******/
57
- fromBind({ bindline }) {
58
- // test.example.com 3600 IN HINFO DEC-2060 TOPS20
59
- const regex =
60
- /^(?<owner>\S+)\s+(?<ttl>\d{1,10})\s+(?<class>IN)\s+(?<type>HINFO)\s+(?:"(?<qCPU>[^"]*)"|(?<uCPU>\S+))\s+(?:"(?<qOS>[^"]*)"|(?<uOS>\S+))$/i
61
-
62
- const match = bindline.trim().match(regex)
63
- if (!match) this.throwHelp(`unable to parse HINFO: ${bindline}`)
64
-
65
- const { owner, ttl, class: c, type, qCPU, uCPU, qOS, uOS } = match.groups
66
-
67
- return new HINFO({
68
- owner,
69
- ttl: parseInt(ttl, 10),
70
- class: c,
71
- type,
72
- cpu: qCPU ?? uCPU,
73
- os: qOS ?? uOS,
74
- })
75
- }
76
-
77
46
  fromTinydns({ tinyline }) {
78
47
  // HINFO via generic, :fqdn:n:rdata:ttl:timestamp:lo
79
48
  const [fqdn, , rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
@@ -91,6 +60,18 @@ export default class HINFO extends RR {
91
60
  }
92
61
 
93
62
  /****** EXPORTERS *******/
63
+
64
+ getWireRdata() {
65
+ const cpu = new TextEncoder().encode(this.get('cpu'))
66
+ const os = new TextEncoder().encode(this.get('os'))
67
+ const result = new Uint8Array(2 + cpu.length + os.length)
68
+ result[0] = cpu.length
69
+ result.set(cpu, 1)
70
+ result[1 + cpu.length] = os.length
71
+ result.set(os, 2 + cpu.length)
72
+ return result
73
+ }
74
+
94
75
  toTinydns() {
95
76
  return this.getTinydnsGeneric(
96
77
  [TINYDNS.packString(this.get('cpu')), TINYDNS.packString(this.get('os'))].join(''),
package/rr/hip.js CHANGED
@@ -1,8 +1,15 @@
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'
5
+ import * as WIRE from '../lib/wire.js'
4
6
 
5
7
  export default class HIP extends RR {
8
+ static typeName = 'HIP'
9
+ static typeId = 55
10
+ static RFCs = [8005]
11
+ static rdataFields = ['pk algorithm', 'hit', 'public key', 'rendezvous servers']
12
+
6
13
  constructor(opts) {
7
14
  super(opts)
8
15
  }
@@ -32,18 +39,6 @@ export default class HIP extends RR {
32
39
  return 'Host Identity Protocol'
33
40
  }
34
41
 
35
- getRdataFields(arg) {
36
- return ['pk algorithm', 'hit', 'public key', 'rendezvous servers']
37
- }
38
-
39
- getRFCs() {
40
- return [8005]
41
- }
42
-
43
- getTypeId() {
44
- return 55
45
- }
46
-
47
42
  getCanonical() {
48
43
  return {
49
44
  owner: 'example.com.',
@@ -64,22 +59,19 @@ export default class HIP extends RR {
64
59
  const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
65
60
  if (n != 55) this.throwHelp('HIP fromTinydns, invalid n')
66
61
 
67
- const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
68
- const hitLen = bytes.readUInt8(0)
69
- const pkAlgorithm = bytes.readUInt8(1)
70
- const pkLen = bytes.readUInt16BE(2)
62
+ const bytes = Uint8Array.from(TINYDNS.octalToChar(rdata), (c) => c.charCodeAt(0))
63
+ const hitLen = bytes[0]
64
+ const pkAlgorithm = bytes[1]
65
+ const pkLen = (bytes[2] << 8) | bytes[3]
71
66
 
72
- const hit = bytes
73
- .slice(4, 4 + hitLen)
74
- .toString('hex')
75
- .toUpperCase()
76
- const publicKey = bytes.slice(4 + hitLen, 4 + hitLen + pkLen).toString('base64')
67
+ const hit = BINARY.bytesToHex(bytes.subarray(4, 4 + hitLen)).toUpperCase()
68
+ const publicKey = BINARY.bytesToBase64(bytes.subarray(4 + hitLen, 4 + hitLen + pkLen))
77
69
 
78
70
  const rvsNames = []
79
71
  let pos = 4 + hitLen + pkLen
80
72
  while (pos < bytes.length) {
81
73
  const [name, newPos] = TINYDNS.unpackDomainName(
82
- [...bytes.slice(pos)]
74
+ [...bytes.subarray(pos)]
83
75
  .map((b) => (b < 32 || b > 126 ? TINYDNS.UInt8toOctal(b) : String.fromCharCode(b)))
84
76
  .join(''),
85
77
  )
@@ -102,8 +94,20 @@ export default class HIP extends RR {
102
94
 
103
95
  fromBind({ bindline }) {
104
96
  // owner ttl IN HIP pk-algorithm HIT public-key [rendezvous-server...]
97
+ // The public key may be split across multiple lines and joined with spaces
98
+ // by the zone parser. Base64 chars are [A-Za-z0-9+/=]; domain names contain '.'.
105
99
  const parts = bindline.split(/\s+/)
106
- const [owner, ttl, c, type, pkAlgorithm, hit, publicKey] = parts
100
+ const [owner, ttl, c, type, pkAlgorithm, hit] = parts
101
+ const rest = parts.slice(6)
102
+ const keyParts = []
103
+ const rvsParts = []
104
+ for (const token of rest) {
105
+ if (/^[A-Za-z0-9+/=]+$/.test(token)) {
106
+ keyParts.push(token)
107
+ } else {
108
+ rvsParts.push(token)
109
+ }
110
+ }
107
111
  return new HIP({
108
112
  owner,
109
113
  ttl: parseInt(ttl, 10),
@@ -111,8 +115,34 @@ export default class HIP extends RR {
111
115
  type,
112
116
  'pk algorithm': parseInt(pkAlgorithm, 10),
113
117
  hit,
118
+ 'public key': keyParts.join(''),
119
+ 'rendezvous servers': rvsParts.join(' ').trim(),
120
+ })
121
+ }
122
+
123
+ fromWire({ owner, cls, ttl, rdata }) {
124
+ const dv = new DataView(rdata.buffer, rdata.byteOffset)
125
+ const hitLen = rdata[0]
126
+ const pkAlgorithm = rdata[1]
127
+ const pkLen = dv.getUint16(2)
128
+ const hit = BINARY.bytesToHex(rdata.subarray(4, 4 + hitLen)).toUpperCase()
129
+ const publicKey = BINARY.bytesToBase64(rdata.subarray(4 + hitLen, 4 + hitLen + pkLen))
130
+ const rvsNames = []
131
+ let pos = 4 + hitLen + pkLen
132
+ while (pos < rdata.length) {
133
+ const { fqdn, end } = this.wireUnpackDomain(rdata, pos)
134
+ rvsNames.push(fqdn)
135
+ pos = end
136
+ }
137
+ return new HIP({
138
+ owner,
139
+ ttl,
140
+ class: cls,
141
+ type: 'HIP',
142
+ 'pk algorithm': pkAlgorithm,
143
+ hit,
114
144
  'public key': publicKey,
115
- 'rendezvous servers': parts.slice(7).join(' ').trim(),
145
+ 'rendezvous servers': rvsNames.join(' '),
116
146
  })
117
147
  }
118
148
 
@@ -124,8 +154,9 @@ export default class HIP extends RR {
124
154
  }
125
155
 
126
156
  toTinydns() {
127
- const hitBytes = Buffer.from(this.get('hit'), 'hex')
128
- const pkBytes = Buffer.from(this.get('public key'), 'base64')
157
+ const hitHex = this.get('hit')
158
+ const hitBytes = BINARY.hexToBytes(hitHex)
159
+ const pkBytes = BINARY.base64ToBytes(this.get('public key'))
129
160
  const rs = this.get('rendezvous servers')
130
161
 
131
162
  let rdata = ''
@@ -140,4 +171,35 @@ export default class HIP extends RR {
140
171
 
141
172
  return this.getTinydnsGeneric(rdata)
142
173
  }
174
+
175
+ getWireRdata() {
176
+ const hitHex = this.get('hit')
177
+ const hitBytes = BINARY.hexToBytes(hitHex)
178
+ const pkBytes = BINARY.base64ToBytes(this.get('public key'))
179
+ const rs = this.get('rendezvous servers')
180
+
181
+ const rsNames = rs ? rs.split(/\s+/) : []
182
+ const rsDomains = rsNames.map((name) => WIRE.wirePackDomain(name))
183
+ const rsTotalLen = rsDomains.reduce((sum, b) => sum + b.length, 0)
184
+
185
+ const totalLen = 1 + 1 + 2 + hitBytes.length + pkBytes.length + rsTotalLen
186
+ const bytes = new Uint8Array(totalLen)
187
+ const dv = new DataView(bytes.buffer, bytes.byteOffset)
188
+
189
+ let pos = 0
190
+ bytes[pos++] = hitBytes.length
191
+ bytes[pos++] = this.get('pk algorithm')
192
+ dv.setUint16(pos, pkBytes.length)
193
+ pos += 2
194
+ bytes.set(hitBytes, pos)
195
+ pos += hitBytes.length
196
+ bytes.set(pkBytes, pos)
197
+ pos += pkBytes.length
198
+ for (const rdomain of rsDomains) {
199
+ bytes.set(rdomain, pos)
200
+ pos += rdomain.length
201
+ }
202
+
203
+ return bytes
204
+ }
143
205
  }
package/rr/https.js CHANGED
@@ -1,8 +1,19 @@
1
1
  import RR from '../rr.js'
2
2
 
3
3
  import * as TINYDNS from '../lib/tinydns.js'
4
+ import * as WIRE from '../lib/wire.js'
4
5
 
5
6
  export default class HTTPS extends RR {
7
+ static typeName = 'HTTPS'
8
+ static typeId = 65
9
+ static RFCs = [9460]
10
+ static tags = ['common']
11
+ static rdataFields = [
12
+ ['priority', 'u16'],
13
+ ['target name', 'fqdn'],
14
+ ['params', 'svcparams'],
15
+ ]
16
+
6
17
  constructor(opts) {
7
18
  super(opts)
8
19
  }
@@ -32,22 +43,6 @@ export default class HTTPS extends RR {
32
43
  return 'HTTP Semantics'
33
44
  }
34
45
 
35
- getTags() {
36
- return ['common']
37
- }
38
-
39
- getRdataFields(arg) {
40
- return ['priority', 'target name', 'params']
41
- }
42
-
43
- getRFCs() {
44
- return [9460]
45
- }
46
-
47
- getTypeId() {
48
- return 65
49
- }
50
-
51
46
  getCanonical() {
52
47
  return {
53
48
  owner: 'example.com.',
@@ -77,36 +72,19 @@ export default class HTTPS extends RR {
77
72
  }
78
73
 
79
74
  fromTinydns({ tinyline }) {
80
- const [owner, _typeId, rd, ttl, ts, loc] = tinyline.slice(1).split(':')
81
-
82
- if (rd.length < 6) {
83
- this.throwHelp(`HTTPS: RDATA too short: ${rd}`)
84
- }
85
-
86
- const binary = Buffer.from(TINYDNS.octalToChar(rd), 'binary')
87
- const priority = binary.readUInt16BE(0)
88
-
89
- let pos = 2
90
- const labels = []
91
- while (true) {
92
- const len = binary.readUInt8(pos)
93
- pos += 1
94
- if (len === 0) break
95
- labels.push(binary.slice(pos, pos + len).toString())
96
- pos += len
97
- }
98
- const targetName = `${labels.join('.')}.`
99
- const params = binary.slice(pos).toString()
75
+ const { owner, typeId, rdata, ttl, timestamp, location } = this.parseTinydnsLine(tinyline)
76
+ if (typeId != this.getTypeId()) this.throwHelp('HTTPS fromTinydns, invalid n')
77
+ const { priority, targetName, params } = TINYDNS.parseSvcbLikeRdata(rdata, 'HTTPS')
100
78
 
101
79
  return new HTTPS({
102
- owner: this.fullyQualify(owner),
103
- ttl: parseInt(ttl, 10),
80
+ owner,
81
+ ttl,
104
82
  type: 'HTTPS',
105
83
  priority,
106
84
  'target name': targetName,
107
85
  params,
108
- timestamp: ts,
109
- location: loc?.trim() ?? '',
86
+ timestamp,
87
+ location,
110
88
  })
111
89
  }
112
90
 
@@ -121,4 +99,14 @@ export default class HTTPS extends RR {
121
99
  TINYDNS.escapeOctal(dataRe, this.get('params')),
122
100
  )
123
101
  }
102
+
103
+ getWireRdata() {
104
+ const targetBytes = this.wirePackDomain(this.get('target name'))
105
+ const paramsBytes = WIRE.svcParamsToWire(this.get('params'))
106
+ const result = new Uint8Array(2 + targetBytes.length + paramsBytes.length)
107
+ new DataView(result.buffer).setUint16(0, this.get('priority'))
108
+ result.set(targetBytes, 2)
109
+ result.set(paramsBytes, 2 + targetBytes.length)
110
+ return result
111
+ }
124
112
  }
package/rr/ipseckey.js CHANGED
@@ -1,8 +1,16 @@
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'
5
+ import * as WIRE from '../lib/wire.js'
4
6
 
5
7
  export default class IPSECKEY extends RR {
8
+ static typeName = 'IPSECKEY'
9
+ static typeId = 45
10
+ static RFCs = [4025]
11
+ static rdataFields = ['precedence', 'gateway type', 'algorithm', 'gateway', 'publickey']
12
+ static tags = ['security']
13
+
6
14
  constructor(opts) {
7
15
  super(opts)
8
16
  }
@@ -62,8 +70,7 @@ export default class IPSECKEY extends RR {
62
70
  }
63
71
 
64
72
  setPublickey(val) {
65
- // if (val) this.throwHelp(`IPSECKEY: publickey is optional`)
66
-
73
+ if (val) this.isBase64('IPSECKEY', 'publickey', val)
67
74
  this.set('publickey', val)
68
75
  }
69
76
 
@@ -71,22 +78,6 @@ export default class IPSECKEY extends RR {
71
78
  return 'IPsec Keying'
72
79
  }
73
80
 
74
- getTags() {
75
- return ['security']
76
- }
77
-
78
- getRdataFields(arg) {
79
- return ['precedence', 'gateway type', 'algorithm', 'gateway', 'publickey']
80
- }
81
-
82
- getRFCs() {
83
- return [4025]
84
- }
85
-
86
- getTypeId() {
87
- return 45
88
- }
89
-
90
81
  getCanonical() {
91
82
  return {
92
83
  owner: '38.2.0.192.in-addr.arpa.',
@@ -161,6 +152,49 @@ export default class IPSECKEY extends RR {
161
152
  })
162
153
  }
163
154
 
155
+ fromWire({ owner, cls, ttl, rdata }) {
156
+ const precedence = rdata[0]
157
+ const gwType = rdata[1]
158
+ const algorithm = rdata[2]
159
+ let gateway, keyStart
160
+ switch (gwType) {
161
+ case 0:
162
+ gateway = '.'
163
+ keyStart = 3
164
+ break
165
+ case 1:
166
+ gateway = [...rdata.subarray(3, 7)].join('.')
167
+ keyStart = 7
168
+ break
169
+ case 2: {
170
+ const dv = new DataView(rdata.buffer, rdata.byteOffset + 3)
171
+ const groups = []
172
+ for (let i = 0; i < 16; i += 2) groups.push(dv.getUint16(i).toString(16).padStart(4, '0'))
173
+ gateway = groups.join(':')
174
+ keyStart = 19
175
+ break
176
+ }
177
+ case 3: {
178
+ const { fqdn, end } = this.wireUnpackDomain(rdata, 3)
179
+ gateway = fqdn
180
+ keyStart = end
181
+ break
182
+ }
183
+ }
184
+ const publickey = BINARY.bytesToBase64(rdata.subarray(keyStart))
185
+ return new IPSECKEY({
186
+ owner,
187
+ ttl,
188
+ class: cls,
189
+ type: 'IPSECKEY',
190
+ precedence,
191
+ 'gateway type': gwType,
192
+ algorithm,
193
+ gateway,
194
+ publickey,
195
+ })
196
+ }
197
+
164
198
  /****** EXPORTERS *******/
165
199
 
166
200
  toTinydns() {
@@ -190,4 +224,49 @@ export default class IPSECKEY extends RR {
190
224
 
191
225
  return this.getTinydnsGeneric(rdata)
192
226
  }
227
+
228
+ getWireRdata() {
229
+ const pubkeyBytes = BINARY.base64ToBytes(this.get('publickey'))
230
+ const gwType = this.get('gateway type')
231
+
232
+ let gwBytes
233
+ switch (gwType) {
234
+ case 0:
235
+ gwBytes = new Uint8Array(0)
236
+ break
237
+ case 1:
238
+ gwBytes = new Uint8Array(4)
239
+ this.get('gateway')
240
+ .split('.')
241
+ .forEach((part, i) => {
242
+ gwBytes[i] = parseInt(part, 10)
243
+ })
244
+ break
245
+ case 2:
246
+ gwBytes = new Uint8Array(16)
247
+ {
248
+ const parts = this.get('gateway').split(':')
249
+ let pos = 0
250
+ for (const part of parts) {
251
+ if (part === '') continue
252
+ const val = parseInt(part, 16)
253
+ gwBytes[pos++] = (val >>> 8) & 0xff
254
+ gwBytes[pos++] = val & 0xff
255
+ }
256
+ }
257
+ break
258
+ case 3:
259
+ gwBytes = WIRE.wirePackDomain(this.get('gateway'))
260
+ break
261
+ }
262
+
263
+ const bytes = new Uint8Array(3 + gwBytes.length + pubkeyBytes.length)
264
+ bytes[0] = this.get('precedence')
265
+ bytes[1] = gwType
266
+ bytes[2] = this.get('algorithm')
267
+ bytes.set(gwBytes, 3)
268
+ bytes.set(pubkeyBytes, 3 + gwBytes.length)
269
+
270
+ return bytes
271
+ }
193
272
  }