@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/CHANGELOG.md
CHANGED
|
@@ -4,10 +4,37 @@ Notable changes to this project are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
#### Unreleased
|
|
6
6
|
|
|
7
|
-
### [1.
|
|
7
|
+
### [1.6.0] - 2026-03-26
|
|
8
8
|
|
|
9
9
|
#### Changed
|
|
10
10
|
|
|
11
|
+
- feat(getCanonical): added to RRs where missing
|
|
12
|
+
- feat(toWire): added wire format export
|
|
13
|
+
- feat: add getTags() to all RR types
|
|
14
|
+
- values: common, obsolete, security, dnssec
|
|
15
|
+
- doc(README): categorize RR types.
|
|
16
|
+
- added RFCs to: AAAA 5952, NAPTR 4848, SIG 3755, TLSA 7671
|
|
17
|
+
- TXT: 4408, 6376, 7208
|
|
18
|
+
|
|
19
|
+
### [1.5.0] - 2026-03-22
|
|
20
|
+
|
|
21
|
+
- feat(RRSIG, SIG, TSIG): added toBind, toTinydns, fromTinydns
|
|
22
|
+
- feat(TSIG): added missing setters
|
|
23
|
+
- feat(fromTinydns): added to APL, DHCID, HIP, KX, RRSIG, RP, WKS
|
|
24
|
+
- feat(CERT): validate mnemonic values
|
|
25
|
+
- fix: hardened polynomial regexes #56
|
|
26
|
+
- fix(NAPTR): replace polynomial regexp
|
|
27
|
+
- test: coverage is at 98% 🎉
|
|
28
|
+
- test(NSEC3PARAM): added test cases, better binary parser, better salt
|
|
29
|
+
- test(AAAA, APL, CERT, KEY, NAPTR, NSEC3, NSEC3PARAM, RRSIG, SIG, SSHFP, TSIG, URL): added test coverage
|
|
30
|
+
- doc(README): updated RR table completion status
|
|
31
|
+
- style(es6): use ?. and ?? operators (nullish coalescing) #57
|
|
32
|
+
- style(es6): use argument expansion / destructured parameters
|
|
33
|
+
- style(es6): substring -> slice #55
|
|
34
|
+
- style(es6): use more trim() #55
|
|
35
|
+
|
|
36
|
+
### [1.4.0] - 2026-03-21
|
|
37
|
+
|
|
11
38
|
- feat(toBind): added to nsec3param, rrsig
|
|
12
39
|
- feat(toTinydns): added to key, nsec3param, nxt, openpgpkey
|
|
13
40
|
- feat(fromTinydns): added to cert, https, key, nsec, nsec3param, nxt, openpgpkey, smimea, svcb
|
|
@@ -350,3 +377,5 @@ Notable changes to this project are documented in this file.
|
|
|
350
377
|
[1.3.0]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.3.0
|
|
351
378
|
[1.3.1]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.3.1
|
|
352
379
|
[1.4.0]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.4.0
|
|
380
|
+
[1.5.0]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.5.0
|
|
381
|
+
[1.6.0]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.6.0
|
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@ This module is used to:
|
|
|
19
19
|
| **[Tinydns](https://cr.yp.to/djbdns/tinydns-data.html)** | :white_check_mark: | :white_check_mark: |
|
|
20
20
|
| **MaraDNS** | | :white_check_mark: |
|
|
21
21
|
| **JS** | :white_check_mark: | :white_check_mark: |
|
|
22
|
+
| **PowerDNS** | | |
|
|
22
23
|
|
|
23
24
|
This package intends to import and export RFC compliant DNS resource records. Please [raise an issue](https://github.com/NicTool/dns-resource-record/issues) if a valid resource record fails to pass or an invalid resource record passes.
|
|
24
25
|
|
|
@@ -185,48 +186,54 @@ This module intends to support all current (ie, not officially deprecated) DNS R
|
|
|
185
186
|
|
|
186
187
|
PRs are welcome, especially PRs with tests.
|
|
187
188
|
|
|
188
|
-
| **RR** |
|
|
189
|
-
| :------------: |
|
|
190
|
-
|
|
|
191
|
-
|
|
|
192
|
-
| **
|
|
193
|
-
|
|
|
194
|
-
|
|
|
195
|
-
|
|
|
196
|
-
|
|
|
197
|
-
|
|
|
198
|
-
|
|
|
199
|
-
|
|
|
200
|
-
|
|
|
201
|
-
| **
|
|
202
|
-
|
|
|
203
|
-
|
|
|
204
|
-
|
|
|
205
|
-
|
|
|
206
|
-
| **
|
|
207
|
-
| **
|
|
208
|
-
|
|
|
209
|
-
|
|
|
210
|
-
| **
|
|
211
|
-
|
|
|
212
|
-
|
|
|
213
|
-
| **
|
|
214
|
-
|
|
|
215
|
-
| **
|
|
216
|
-
|
|
|
217
|
-
|
|
|
218
|
-
|
|
|
219
|
-
| **
|
|
220
|
-
| **
|
|
221
|
-
|
|
|
222
|
-
|
|
|
223
|
-
|
|
|
224
|
-
| **
|
|
225
|
-
|
|
|
226
|
-
|
|
|
227
|
-
|
|
|
228
|
-
|
|
|
229
|
-
| **
|
|
189
|
+
| **RR** | **BIND / RFC 1035** | **Tinydns** |
|
|
190
|
+
| :------------: | :-----------------: | :----------------: |
|
|
191
|
+
| _Common_ |
|
|
192
|
+
| **A** | :white_check_mark: | :white_check_mark: |
|
|
193
|
+
| **AAAA** | :white_check_mark: | :white_check_mark: |
|
|
194
|
+
| **CNAME** | :white_check_mark: | :white_check_mark: |
|
|
195
|
+
| **HTTPS** | :white_check_mark: | :white_check_mark: |
|
|
196
|
+
| **MX** | :white_check_mark: | :white_check_mark: |
|
|
197
|
+
| **NS** | :white_check_mark: | :white_check_mark: |
|
|
198
|
+
| **PTR** | :white_check_mark: | :white_check_mark: |
|
|
199
|
+
| **SRV** | :white_check_mark: | :white_check_mark: |
|
|
200
|
+
| **TXT** | :white_check_mark: | :white_check_mark: |
|
|
201
|
+
| _Less Common_ |
|
|
202
|
+
| **APL** | :white_check_mark: | :white_check_mark: |
|
|
203
|
+
| **CERT** | :white_check_mark: | :white_check_mark: |
|
|
204
|
+
| **DHCID** | :white_check_mark: | :white_check_mark: |
|
|
205
|
+
| **DNAME** | :white_check_mark: | :white_check_mark: |
|
|
206
|
+
| **HIP** | :white_check_mark: | :white_check_mark: |
|
|
207
|
+
| **KEY** | :white_check_mark: | :white_check_mark: |
|
|
208
|
+
| **KX** | :white_check_mark: | :white_check_mark: |
|
|
209
|
+
| **LOC** | :white_check_mark: | :white_check_mark: |
|
|
210
|
+
| **NAPTR** | :white_check_mark: | :white_check_mark: |
|
|
211
|
+
| **SOA** | :white_check_mark: | :white_check_mark: |
|
|
212
|
+
| **SVCB** | :white_check_mark: | :white_check_mark: |
|
|
213
|
+
| **TSIG** | :white_check_mark: | :white_check_mark: |
|
|
214
|
+
| **URI** | :white_check_mark: | :white_check_mark: |
|
|
215
|
+
| _Security_ |
|
|
216
|
+
| **CAA** | :white_check_mark: | :white_check_mark: |
|
|
217
|
+
| **IPSECKEY** | :white_check_mark: | :white_check_mark: |
|
|
218
|
+
| **OPENPGPKEY** | :white_check_mark: | :white_check_mark: |
|
|
219
|
+
| **SMIMEA** | :white_check_mark: | :white_check_mark: |
|
|
220
|
+
| **SSHFP** | :white_check_mark: | :white_check_mark: |
|
|
221
|
+
| **TLSA** | :white_check_mark: | :white_check_mark: |
|
|
222
|
+
| _DNSSEC_ |
|
|
223
|
+
| **DNSKEY** | :white_check_mark: | :white_check_mark: |
|
|
224
|
+
| **DS** | :white_check_mark: | :white_check_mark: |
|
|
225
|
+
| **NSEC** | :white_check_mark: | :white_check_mark: |
|
|
226
|
+
| **NSEC3** | :white_check_mark: | :white_check_mark: |
|
|
227
|
+
| **NSEC3PARAM** | :white_check_mark: | :white_check_mark: |
|
|
228
|
+
| **RRSIG** | :white_check_mark: | :white_check_mark: |
|
|
229
|
+
| _Deprecated_ |
|
|
230
|
+
| **NXT** | :white_check_mark: | :white_check_mark: |
|
|
231
|
+
| **SPF** | :white_check_mark: | :white_check_mark: |
|
|
232
|
+
| _Obsolete_ |
|
|
233
|
+
| **HINFO** | :white_check_mark: | :white_check_mark: |
|
|
234
|
+
| **RP** | :white_check_mark: | :white_check_mark: |
|
|
235
|
+
| **SIG** | :white_check_mark: | :white_check_mark: |
|
|
236
|
+
| **WKS** | :white_check_mark: | :white_check_mark: |
|
|
230
237
|
|
|
231
238
|
## TIPS
|
|
232
239
|
|
package/lib/readme.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Regenerates the Supported Records table in README.md using getTags() from each RR class.
|
|
3
|
+
|
|
4
|
+
import { readFileSync, writeFileSync } from 'fs'
|
|
5
|
+
import { fileURLToPath } from 'url'
|
|
6
|
+
import { dirname, join } from 'path'
|
|
7
|
+
|
|
8
|
+
import * as RR from '../index.js'
|
|
9
|
+
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
11
|
+
|
|
12
|
+
const tagToGroup = {
|
|
13
|
+
common: 'Common',
|
|
14
|
+
security: 'Security',
|
|
15
|
+
dnssec: 'DNSSEC',
|
|
16
|
+
deprecated: 'Deprecated',
|
|
17
|
+
obsolete: 'Obsolete',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const groupOrder = ['Common', 'Less Common', 'Security', 'DNSSEC', 'Deprecated', 'Obsolete']
|
|
21
|
+
|
|
22
|
+
function getGroup(instance) {
|
|
23
|
+
const tags = instance.getTags()
|
|
24
|
+
for (const [tag, group] of Object.entries(tagToGroup)) {
|
|
25
|
+
if (tags.includes(tag)) return group
|
|
26
|
+
}
|
|
27
|
+
return 'Less Common'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const groups = {}
|
|
31
|
+
for (const name of groupOrder) groups[name] = []
|
|
32
|
+
|
|
33
|
+
for (const [name, cls] of Object.entries(RR)) {
|
|
34
|
+
if (name === 'typeMap' || name === 'default') continue
|
|
35
|
+
if (typeof cls !== 'function') continue
|
|
36
|
+
const instance = new cls(null)
|
|
37
|
+
const group = getGroup(instance)
|
|
38
|
+
groups[group].push(name)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const check = ':white_check_mark:'
|
|
42
|
+
const rows = []
|
|
43
|
+
for (const groupName of groupOrder) {
|
|
44
|
+
const names = groups[groupName]
|
|
45
|
+
if (!names.length) continue
|
|
46
|
+
rows.push(`| *${groupName}* |`)
|
|
47
|
+
for (const name of names.sort()) {
|
|
48
|
+
const cls = RR[name]
|
|
49
|
+
const hasToBind = typeof cls.prototype.toBind === 'function'
|
|
50
|
+
const hasFromBind = typeof cls.prototype.fromBind === 'function'
|
|
51
|
+
const hasToTinydns = typeof cls.prototype.toTinydns === 'function'
|
|
52
|
+
const hasFromTinydns = typeof cls.prototype.fromTinydns === 'function'
|
|
53
|
+
|
|
54
|
+
const bind = hasToBind && hasFromBind ? check : ''
|
|
55
|
+
const tinydns = hasToTinydns && hasFromTinydns ? check : ''
|
|
56
|
+
|
|
57
|
+
rows.push(`| **${name}** | ${bind} | ${tinydns} |`)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const table = [
|
|
62
|
+
`| **RR** | **BIND / RFC 1035** | **Tinydns** |`,
|
|
63
|
+
`| :------------: | :-------------------: | :-----------------: |`,
|
|
64
|
+
...rows,
|
|
65
|
+
].join('\n')
|
|
66
|
+
|
|
67
|
+
const readmePath = join(__dirname, '..', 'README.md')
|
|
68
|
+
const readme = readFileSync(readmePath, 'utf-8')
|
|
69
|
+
|
|
70
|
+
// Replace from the table header line up to (but not including) the ## TIPS section
|
|
71
|
+
const tableHeaderMarker = '\n| **RR** |'
|
|
72
|
+
const tipsSectionMarker = '\n\n## TIPS'
|
|
73
|
+
|
|
74
|
+
const tableStart = readme.indexOf(tableHeaderMarker)
|
|
75
|
+
const tipsStart = readme.indexOf(tipsSectionMarker)
|
|
76
|
+
|
|
77
|
+
if (tableStart === -1 || tipsStart === -1) {
|
|
78
|
+
console.error('Could not locate table boundaries in README.md')
|
|
79
|
+
process.exit(1)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const newReadme = readme.slice(0, tableStart + 1) + table + '\n' + readme.slice(tipsStart)
|
|
83
|
+
writeFileSync(readmePath, newReadme)
|
|
84
|
+
console.log('README.md updated successfully')
|
package/lib/tinydns.js
CHANGED
|
@@ -33,7 +33,7 @@ export function unescapeOctal(str) {
|
|
|
33
33
|
|
|
34
34
|
export function octalToChar(str) {
|
|
35
35
|
// relace instances of \NNN with ASCII
|
|
36
|
-
return str.replace(octalRe, (o) => String.fromCharCode(parseInt(o.
|
|
36
|
+
return str.replace(octalRe, (o) => String.fromCharCode(parseInt(o.slice(1), 8)))
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export function octalToHex(str) {
|
|
@@ -41,29 +41,29 @@ export function octalToHex(str) {
|
|
|
41
41
|
return str.replace(octalRe, (o) => {
|
|
42
42
|
// parseInt(n, 8) -> from octal to decimal
|
|
43
43
|
// .toString(16) -> decimal to hex
|
|
44
|
-
return parseInt(o.
|
|
44
|
+
return parseInt(o.slice(1), 8).toString(16).padStart(2, 0)
|
|
45
45
|
})
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export function octalToUInt8(str) {
|
|
49
49
|
const b = Buffer.alloc(1)
|
|
50
|
-
b.writeUInt8(parseInt(str.
|
|
50
|
+
b.writeUInt8(parseInt(str.slice(1, 4), 8), 0)
|
|
51
51
|
return b.readUInt8()
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
export function octalToUInt16(str) {
|
|
55
55
|
const b = Buffer.alloc(2)
|
|
56
|
-
b.writeUInt8(parseInt(str.
|
|
57
|
-
b.writeUInt8(parseInt(str.
|
|
56
|
+
b.writeUInt8(parseInt(str.slice(1, 4), 8), 0)
|
|
57
|
+
b.writeUInt8(parseInt(str.slice(5, 8), 8), 1)
|
|
58
58
|
return b.readUInt16BE()
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
export function octalToUInt32(str) {
|
|
62
62
|
const b = Buffer.alloc(4)
|
|
63
|
-
b.writeUInt8(parseInt(str.
|
|
64
|
-
b.writeUInt8(parseInt(str.
|
|
65
|
-
b.writeUInt8(parseInt(str.
|
|
66
|
-
b.writeUInt8(parseInt(str.
|
|
63
|
+
b.writeUInt8(parseInt(str.slice(1, 4), 8), 0)
|
|
64
|
+
b.writeUInt8(parseInt(str.slice(5, 8), 8), 1)
|
|
65
|
+
b.writeUInt8(parseInt(str.slice(9, 12), 8), 2)
|
|
66
|
+
b.writeUInt8(parseInt(str.slice(13, 16), 8), 3)
|
|
67
67
|
return b.readUInt32BE()
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -99,7 +99,7 @@ export function packDomainName(fqdn) {
|
|
|
99
99
|
// RFC 1035, 3.3 Standard RRs
|
|
100
100
|
// The standard wire format for DNS names. (1 octet length + octets)
|
|
101
101
|
let packed = ''
|
|
102
|
-
fqdn.split('.').
|
|
102
|
+
fqdn.split('.').forEach((label) => {
|
|
103
103
|
if (label === undefined || !label.length) return
|
|
104
104
|
|
|
105
105
|
const len = Buffer.alloc(1)
|
|
@@ -196,6 +196,16 @@ export function octalToIPv4(str) {
|
|
|
196
196
|
return [24, 16, 8, 0].map((n) => (asInt >> n) & 0xff).join('.')
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
+
export function ipv6toOctal(ip) {
|
|
200
|
+
return packHex(ip.replace(/:/g, ''))
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function octalToIPv6(str) {
|
|
204
|
+
return octalToHex(str)
|
|
205
|
+
.match(/(.{4})/g)
|
|
206
|
+
.join(':')
|
|
207
|
+
}
|
|
208
|
+
|
|
199
209
|
export function base64toOctal(str) {
|
|
200
210
|
const bytes = Buffer.from(str, 'base64')
|
|
201
211
|
let escaped = ''
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nictool/dns-resource-record",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "DNS Resource Records",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
],
|
|
12
12
|
"type": "module",
|
|
13
13
|
"scripts": {
|
|
14
|
+
"build": "node lib/readme.js",
|
|
14
15
|
"format:check": "npm run prettier; npm run lint",
|
|
15
|
-
"format": "npm run prettier -- --write && npm run lint
|
|
16
|
+
"format": "npm run prettier -- --write && npm run lint:fix",
|
|
16
17
|
"lint": "npx eslint **/*.js",
|
|
17
18
|
"lint:fix": "npm run lint -- --fix",
|
|
18
19
|
"prettier": "npx prettier --ignore-path .gitignore --check .",
|
package/rr/a.js
CHANGED
|
@@ -16,6 +16,10 @@ export default class A extends RR {
|
|
|
16
16
|
return 'Address'
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
getTags() {
|
|
20
|
+
return ['common']
|
|
21
|
+
}
|
|
22
|
+
|
|
19
23
|
getRdataFields(arg) {
|
|
20
24
|
return ['address']
|
|
21
25
|
}
|
|
@@ -39,9 +43,9 @@ export default class A extends RR {
|
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
/****** IMPORTERS *******/
|
|
42
|
-
fromTinydns(
|
|
46
|
+
fromTinydns({ tinyline }) {
|
|
43
47
|
// +fqdn:ip:ttl:timestamp:lo
|
|
44
|
-
const [owner, ip, ttl, ts, loc] =
|
|
48
|
+
const [owner, ip, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
45
49
|
|
|
46
50
|
return new A({
|
|
47
51
|
owner: this.fullyQualify(owner),
|
|
@@ -49,13 +53,13 @@ export default class A extends RR {
|
|
|
49
53
|
address: ip,
|
|
50
54
|
ttl: parseInt(ttl, 10),
|
|
51
55
|
timestamp: ts,
|
|
52
|
-
location: loc
|
|
56
|
+
location: loc?.trim() ?? '',
|
|
53
57
|
})
|
|
54
58
|
}
|
|
55
59
|
|
|
56
|
-
fromBind(
|
|
60
|
+
fromBind({ bindline }) {
|
|
57
61
|
// test.example.com 3600 IN A 192.0.2.127
|
|
58
|
-
const [owner, ttl, c, type, address] =
|
|
62
|
+
const [owner, ttl, c, type, address] = bindline.split(/\s+/)
|
|
59
63
|
return new A({
|
|
60
64
|
owner,
|
|
61
65
|
ttl: parseInt(ttl, 10),
|
|
@@ -66,6 +70,10 @@ export default class A extends RR {
|
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
/****** EXPORTERS *******/
|
|
73
|
+
getWireRdata() {
|
|
74
|
+
return Buffer.from(this.get('address').split('.').map(Number))
|
|
75
|
+
}
|
|
76
|
+
|
|
69
77
|
toTinydns() {
|
|
70
78
|
return `+${this.getTinyFQDN('owner')}:${this.get('address')}:${this.getTinydnsPostamble()}\n`
|
|
71
79
|
}
|
package/rr/aaaa.js
CHANGED
|
@@ -15,19 +15,23 @@ export default class AAAA extends RR {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
getCompressed(val) {
|
|
18
|
-
return this.compress(val
|
|
18
|
+
return this.compress(val ?? this.get('address'))
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
getDescription() {
|
|
22
22
|
return 'Address IPv6'
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
getTags() {
|
|
26
|
+
return ['common']
|
|
27
|
+
}
|
|
28
|
+
|
|
25
29
|
getRdataFields(arg) {
|
|
26
30
|
return ['address']
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
getRFCs() {
|
|
30
|
-
return [3596]
|
|
34
|
+
return [3596, 5952]
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
getTypeId() {
|
|
@@ -40,19 +44,19 @@ export default class AAAA extends RR {
|
|
|
40
44
|
address: '2001:0db8:0020:000a:0000:0000:0000:0004',
|
|
41
45
|
class: 'IN',
|
|
42
46
|
ttl: 3600,
|
|
43
|
-
type: '
|
|
47
|
+
type: 'AAAA',
|
|
44
48
|
}
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
/****** IMPORTERS *******/
|
|
48
|
-
fromTinydns(
|
|
49
|
-
const str =
|
|
52
|
+
fromTinydns({ tinyline }) {
|
|
53
|
+
const str = tinyline
|
|
50
54
|
let fqdn, ip, n, rdata, ttl, ts, loc
|
|
51
55
|
|
|
52
56
|
switch (str[0]) {
|
|
53
57
|
case ':':
|
|
54
58
|
// GENERIC => :fqdn:28:rdata:ttl:timestamp:lo
|
|
55
|
-
;[fqdn, n, rdata, ttl, ts, loc] = str.
|
|
59
|
+
;[fqdn, n, rdata, ttl, ts, loc] = str.slice(1).split(':')
|
|
56
60
|
if (n != 28) this.throwHelp('AAAA fromTinydns, invalid n')
|
|
57
61
|
ip = TINYDNS.octalToHex(rdata)
|
|
58
62
|
.match(/([0-9a-fA-F]{4})/g)
|
|
@@ -62,7 +66,7 @@ export default class AAAA extends RR {
|
|
|
62
66
|
case '6':
|
|
63
67
|
// AAAA => 3fqdn:ip:x:ttl:timestamp:lo
|
|
64
68
|
// AAAA,PTR => 6fqdn:ip:x:ttl:timestamp:lo
|
|
65
|
-
;[fqdn, rdata, ttl, ts, loc] = str.
|
|
69
|
+
;[fqdn, rdata, ttl, ts, loc] = str.slice(1).split(':')
|
|
66
70
|
ip = rdata.match(/(.{4})/g).join(':')
|
|
67
71
|
break
|
|
68
72
|
}
|
|
@@ -73,13 +77,13 @@ export default class AAAA extends RR {
|
|
|
73
77
|
type: 'AAAA',
|
|
74
78
|
address: ip,
|
|
75
79
|
timestamp: ts,
|
|
76
|
-
location: loc
|
|
80
|
+
location: loc?.trim() ?? '',
|
|
77
81
|
})
|
|
78
82
|
}
|
|
79
83
|
|
|
80
|
-
fromBind(
|
|
84
|
+
fromBind({ bindline }) {
|
|
81
85
|
// test.example.com 3600 IN AAAA ...
|
|
82
|
-
const [owner, ttl, c, type, ip] =
|
|
86
|
+
const [owner, ttl, c, type, ip] = bindline.split(/\s+/)
|
|
83
87
|
return new AAAA({
|
|
84
88
|
owner,
|
|
85
89
|
ttl: parseInt(ttl, 10),
|
|
@@ -124,7 +128,7 @@ export default class AAAA extends RR {
|
|
|
124
128
|
if (delimiter === undefined) delimiter = ':'
|
|
125
129
|
|
|
126
130
|
const colons = val.match(/:/g)
|
|
127
|
-
if (colons
|
|
131
|
+
if (colons?.length < 7) {
|
|
128
132
|
// console.log(`AAAA: restoring compressed colons`)
|
|
129
133
|
val = val.replace(/::/, ':'.repeat(9 - colons.length))
|
|
130
134
|
}
|
|
@@ -138,6 +142,10 @@ export default class AAAA extends RR {
|
|
|
138
142
|
}
|
|
139
143
|
|
|
140
144
|
/****** EXPORTERS *******/
|
|
145
|
+
getWireRdata() {
|
|
146
|
+
return Buffer.from(this.expand(this.get('address'), ''), 'hex')
|
|
147
|
+
}
|
|
148
|
+
|
|
141
149
|
toBind(zone_opts) {
|
|
142
150
|
return `${this.getPrefix(zone_opts)}\t${this.getCompressed()}\n`
|
|
143
151
|
}
|
package/rr/apl.js
CHANGED
|
@@ -42,9 +42,56 @@ export default class APL extends RR {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/****** IMPORTERS *******/
|
|
45
|
-
|
|
45
|
+
fromTinydns({ tinyline }) {
|
|
46
|
+
// APL via generic, :fqdn:42:rdata:ttl:timestamp:lo
|
|
47
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
48
|
+
if (n != 42) this.throwHelp('APL fromTinydns, invalid n')
|
|
49
|
+
|
|
50
|
+
const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
51
|
+
const items = []
|
|
52
|
+
let pos = 0
|
|
53
|
+
|
|
54
|
+
while (pos < bytes.length) {
|
|
55
|
+
const afi = bytes.readUInt16BE(pos)
|
|
56
|
+
pos += 2
|
|
57
|
+
const prefix = bytes.readUInt8(pos)
|
|
58
|
+
pos++
|
|
59
|
+
const adfLenByte = bytes.readUInt8(pos)
|
|
60
|
+
pos++
|
|
61
|
+
const neg = (adfLenByte & 0x80) !== 0
|
|
62
|
+
const addrLen = adfLenByte & 0x7f
|
|
63
|
+
const addrBytes = bytes.slice(pos, pos + addrLen)
|
|
64
|
+
pos += addrLen
|
|
65
|
+
|
|
66
|
+
let addr
|
|
67
|
+
if (afi === 1) {
|
|
68
|
+
const padded = Buffer.alloc(4)
|
|
69
|
+
addrBytes.copy(padded)
|
|
70
|
+
addr = [...padded].join('.')
|
|
71
|
+
} else {
|
|
72
|
+
const padded = Buffer.alloc(16)
|
|
73
|
+
addrBytes.copy(padded)
|
|
74
|
+
const groups = []
|
|
75
|
+
for (let i = 0; i < 16; i += 2) groups.push(padded.readUInt16BE(i).toString(16).padStart(4, '0'))
|
|
76
|
+
addr = this.compressIPv6(groups.join(':'))
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
items.push(`${neg ? '!' : ''}${afi}:${addr}/${prefix}`)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return new APL({
|
|
83
|
+
owner: this.fullyQualify(fqdn),
|
|
84
|
+
ttl: parseInt(ttl, 10),
|
|
85
|
+
type: 'APL',
|
|
86
|
+
'apl rdata': items.join(' '),
|
|
87
|
+
timestamp: ts,
|
|
88
|
+
location: loc?.trim() ?? '',
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
fromBind({ bindline }) {
|
|
46
93
|
// test.example.com 3600 IN APL {[!]afi:address/prefix}*
|
|
47
|
-
const parts =
|
|
94
|
+
const parts = bindline.split(/\s+/)
|
|
48
95
|
const [owner, ttl, c, type] = parts
|
|
49
96
|
return new APL({
|
|
50
97
|
owner,
|
package/rr/caa.js
CHANGED
|
@@ -62,6 +62,10 @@ export default class CAA extends RR {
|
|
|
62
62
|
return 'Certification Authority Authorization'
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
getTags() {
|
|
66
|
+
return ['security']
|
|
67
|
+
}
|
|
68
|
+
|
|
65
69
|
getQuotedFields() {
|
|
66
70
|
return ['value']
|
|
67
71
|
}
|
|
@@ -91,17 +95,17 @@ export default class CAA extends RR {
|
|
|
91
95
|
}
|
|
92
96
|
|
|
93
97
|
/****** IMPORTERS *******/
|
|
94
|
-
fromTinydns(
|
|
98
|
+
fromTinydns({ tinyline }) {
|
|
95
99
|
// CAA via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
96
|
-
const [fqdn, n, rdata, ttl, ts, loc] =
|
|
100
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
97
101
|
if (n != 257) this.throwHelp('CAA fromTinydns, invalid n')
|
|
98
102
|
|
|
99
|
-
const flags = TINYDNS.octalToUInt8(rdata.
|
|
100
|
-
const taglen = TINYDNS.octalToUInt8(rdata.
|
|
103
|
+
const flags = TINYDNS.octalToUInt8(rdata.slice(0, 4))
|
|
104
|
+
const taglen = TINYDNS.octalToUInt8(rdata.slice(4, 8))
|
|
101
105
|
|
|
102
|
-
const unescaped = TINYDNS.octalToChar(rdata.
|
|
103
|
-
const tag = unescaped.
|
|
104
|
-
const fingerprint = unescaped.
|
|
106
|
+
const unescaped = TINYDNS.octalToChar(rdata.slice(8))
|
|
107
|
+
const tag = unescaped.slice(0, taglen)
|
|
108
|
+
const fingerprint = unescaped.slice(taglen)
|
|
105
109
|
|
|
106
110
|
return new CAA({
|
|
107
111
|
owner: this.fullyQualify(fqdn),
|
|
@@ -111,17 +115,23 @@ export default class CAA extends RR {
|
|
|
111
115
|
tag,
|
|
112
116
|
value: fingerprint,
|
|
113
117
|
timestamp: ts,
|
|
114
|
-
location: loc
|
|
118
|
+
location: loc?.trim() ?? '',
|
|
115
119
|
})
|
|
116
120
|
}
|
|
117
121
|
|
|
118
|
-
fromBind(
|
|
122
|
+
fromBind({ bindline }) {
|
|
119
123
|
// test.example.com 3600 IN CAA flags, tags, value
|
|
120
|
-
const regex =
|
|
121
|
-
|
|
122
|
-
|
|
124
|
+
const regex =
|
|
125
|
+
/^(?<owner>\S+)\s+(?<ttl>\d{1,10})\s+(?<class>IN)\s+(?<type>CAA)\s+(?<flags>\d+)\s+(?<tag>\w+)\s+(?:"(?<quotedValue>[^"]+)"|(?<unquotedValue>\S+))$/i
|
|
126
|
+
|
|
127
|
+
const match = bindline.trim().match(regex)
|
|
128
|
+
|
|
129
|
+
if (!match) {
|
|
130
|
+
this.throwHelp(`unable to parse CAA: ${bindline}`)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const { owner, ttl, class: c, type, flags, tag, quotedValue, unquotedValue } = match.groups
|
|
123
134
|
|
|
124
|
-
const [owner, ttl, c, type, flags, tag, value] = fields.slice(1)
|
|
125
135
|
return new CAA({
|
|
126
136
|
owner,
|
|
127
137
|
ttl: parseInt(ttl, 10),
|
|
@@ -129,21 +139,18 @@ export default class CAA extends RR {
|
|
|
129
139
|
type,
|
|
130
140
|
flags: parseInt(flags, 10),
|
|
131
141
|
tag,
|
|
132
|
-
value,
|
|
142
|
+
value: quotedValue ?? unquotedValue,
|
|
133
143
|
})
|
|
134
144
|
}
|
|
135
145
|
|
|
136
146
|
/****** EXPORTERS *******/
|
|
137
147
|
|
|
138
148
|
toTinydns() {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
rdata += TINYDNS.escapeOctal(/[\r\n\t:\\/]/, this.getQuoted('value'))
|
|
146
|
-
|
|
147
|
-
return this.getTinydnsGeneric(rdata)
|
|
149
|
+
return this.getTinydnsGeneric(
|
|
150
|
+
TINYDNS.UInt8toOctal(this.get('flags')) +
|
|
151
|
+
TINYDNS.UInt8toOctal(this.get('tag').length) +
|
|
152
|
+
TINYDNS.escapeOctal(/[\r\n\t:\\/]/, this.get('tag')) +
|
|
153
|
+
TINYDNS.escapeOctal(/[\r\n\t:\\/]/, this.getQuoted('value')),
|
|
154
|
+
)
|
|
148
155
|
}
|
|
149
156
|
}
|