@nictool/dns-resource-record 1.4.0 → 1.5.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 +18 -2
- package/README.md +20 -19
- package/lib/tinydns.js +10 -10
- package/package.json +2 -2
- package/rr/a.js +5 -5
- package/rr/aaaa.js +9 -9
- package/rr/apl.js +49 -2
- package/rr/caa.js +26 -23
- package/rr/cert.js +31 -7
- package/rr/cname.js +5 -5
- package/rr/dhcid.js +17 -2
- package/rr/dname.js +5 -5
- package/rr/dnskey.js +14 -8
- package/rr/ds.js +6 -6
- package/rr/hinfo.js +13 -10
- package/rr/hip.js +43 -2
- package/rr/https.js +22 -9
- package/rr/ipseckey.js +16 -16
- package/rr/key.js +13 -17
- package/rr/kx.js +18 -2
- package/rr/loc.js +14 -14
- package/rr/mx.js +5 -5
- package/rr/naptr.js +23 -19
- package/rr/ns.js +5 -5
- package/rr/nsec.js +6 -6
- package/rr/nsec3.js +52 -7
- package/rr/nsec3param.js +35 -22
- package/rr/nxt.js +7 -7
- package/rr/openpgpkey.js +14 -8
- package/rr/ptr.js +5 -5
- package/rr/rp.js +19 -2
- package/rr/rrsig.js +84 -10
- package/rr/sig.js +88 -12
- package/rr/smimea.js +6 -6
- package/rr/soa.js +6 -6
- package/rr/spf.js +3 -3
- package/rr/srv.js +11 -11
- package/rr/sshfp.js +8 -8
- package/rr/svcb.js +25 -10
- package/rr/tlsa.js +8 -8
- package/rr/tsig.js +139 -13
- package/rr/txt.js +10 -11
- package/rr/uri.js +8 -8
- package/rr/wks.js +26 -2
- package/rr.js +52 -7
package/rr/hinfo.js
CHANGED
|
@@ -39,26 +39,29 @@ export default class HINFO extends RR {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/****** IMPORTERS *******/
|
|
42
|
-
fromBind(
|
|
42
|
+
fromBind({ bindline }) {
|
|
43
43
|
// test.example.com 3600 IN HINFO DEC-2060 TOPS20
|
|
44
|
-
const regex =
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
44
|
+
const regex =
|
|
45
|
+
/^(?<owner>\S+)\s+(?<ttl>\d{1,10})\s+(?<class>IN)\s+(?<type>HINFO)\s+(?:"(?<qCPU>[^"]*)"|(?<uCPU>\S+))\s+(?:"(?<qOS>[^"]*)"|(?<uOS>\S+))$/i
|
|
46
|
+
|
|
47
|
+
const match = bindline.trim().match(regex)
|
|
48
|
+
if (!match) this.throwHelp(`unable to parse HINFO: ${bindline}`)
|
|
49
|
+
|
|
50
|
+
const { owner, ttl, class: c, type, qCPU, uCPU, qOS, uOS } = match.groups
|
|
48
51
|
|
|
49
52
|
return new HINFO({
|
|
50
53
|
owner,
|
|
51
54
|
ttl: parseInt(ttl, 10),
|
|
52
55
|
class: c,
|
|
53
56
|
type,
|
|
54
|
-
cpu,
|
|
55
|
-
os,
|
|
57
|
+
cpu: qCPU ?? uCPU,
|
|
58
|
+
os: qOS ?? uOS,
|
|
56
59
|
})
|
|
57
60
|
}
|
|
58
61
|
|
|
59
|
-
fromTinydns(
|
|
62
|
+
fromTinydns({ tinyline }) {
|
|
60
63
|
// HINFO via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
61
|
-
const [fqdn, , rdata, ttl, ts, loc] =
|
|
64
|
+
const [fqdn, , rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
62
65
|
const [cpu, os] = [...TINYDNS.unpackString(rdata)]
|
|
63
66
|
|
|
64
67
|
return new this.constructor({
|
|
@@ -68,7 +71,7 @@ export default class HINFO extends RR {
|
|
|
68
71
|
cpu,
|
|
69
72
|
os,
|
|
70
73
|
timestamp: ts,
|
|
71
|
-
location: loc
|
|
74
|
+
location: loc?.trim() ?? '',
|
|
72
75
|
})
|
|
73
76
|
}
|
|
74
77
|
|
package/rr/hip.js
CHANGED
|
@@ -59,9 +59,50 @@ export default class HIP extends RR {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/****** IMPORTERS *******/
|
|
62
|
-
|
|
62
|
+
fromTinydns({ tinyline }) {
|
|
63
|
+
// HIP via generic, :fqdn:55:rdata:ttl:timestamp:lo
|
|
64
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
65
|
+
if (n != 55) this.throwHelp('HIP fromTinydns, invalid n')
|
|
66
|
+
|
|
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)
|
|
71
|
+
|
|
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')
|
|
77
|
+
|
|
78
|
+
const rvsNames = []
|
|
79
|
+
let pos = 4 + hitLen + pkLen
|
|
80
|
+
while (pos < bytes.length) {
|
|
81
|
+
const [name, newPos] = TINYDNS.unpackDomainName(
|
|
82
|
+
[...bytes.slice(pos)]
|
|
83
|
+
.map((b) => (b < 32 || b > 126 ? TINYDNS.UInt8toOctal(b) : String.fromCharCode(b)))
|
|
84
|
+
.join(''),
|
|
85
|
+
)
|
|
86
|
+
pos += newPos
|
|
87
|
+
if (name !== '.') rvsNames.push(name)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return new HIP({
|
|
91
|
+
owner: this.fullyQualify(fqdn),
|
|
92
|
+
ttl: parseInt(ttl, 10),
|
|
93
|
+
type: 'HIP',
|
|
94
|
+
'pk algorithm': pkAlgorithm,
|
|
95
|
+
hit,
|
|
96
|
+
'public key': publicKey,
|
|
97
|
+
'rendezvous servers': rvsNames.join(' '),
|
|
98
|
+
timestamp: ts,
|
|
99
|
+
location: loc?.trim() ?? '',
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
fromBind({ bindline }) {
|
|
63
104
|
// owner ttl IN HIP pk-algorithm HIT public-key [rendezvous-server...]
|
|
64
|
-
const parts =
|
|
105
|
+
const parts = bindline.split(/\s+/)
|
|
65
106
|
const [owner, ttl, c, type, pkAlgorithm, hit, publicKey] = parts
|
|
66
107
|
return new HIP({
|
|
67
108
|
owner,
|
package/rr/https.js
CHANGED
|
@@ -46,9 +46,9 @@ export default class HTTPS extends RR {
|
|
|
46
46
|
|
|
47
47
|
/****** IMPORTERS *******/
|
|
48
48
|
|
|
49
|
-
fromBind(
|
|
49
|
+
fromBind({ bindline }) {
|
|
50
50
|
// test.example.com 3600 IN HTTPS Priority TargetName Params
|
|
51
|
-
const [owner, ttl, c, type, pri, fqdn] =
|
|
51
|
+
const [owner, ttl, c, type, pri, fqdn] = bindline.split(/\s+/)
|
|
52
52
|
return new HTTPS({
|
|
53
53
|
owner,
|
|
54
54
|
ttl: parseInt(ttl, 10),
|
|
@@ -56,20 +56,31 @@ export default class HTTPS extends RR {
|
|
|
56
56
|
type,
|
|
57
57
|
priority: parseInt(pri, 10),
|
|
58
58
|
'target name': fqdn,
|
|
59
|
-
params:
|
|
59
|
+
params: bindline.split(/\s+/).slice(6).join(' ').trim(),
|
|
60
60
|
})
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
fromTinydns({
|
|
63
|
+
fromTinydns({ tinyline }) {
|
|
64
|
+
const [owner, _typeId, rd, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
65
|
+
|
|
64
66
|
if (rd.length < 6) {
|
|
65
67
|
this.throwHelp(`HTTPS: RDATA too short: ${rd}`)
|
|
66
68
|
}
|
|
67
69
|
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
70
|
+
const binary = Buffer.from(TINYDNS.octalToChar(rd), 'binary')
|
|
71
|
+
const priority = binary.readUInt16BE(0)
|
|
72
|
+
|
|
73
|
+
let pos = 2
|
|
74
|
+
const labels = []
|
|
75
|
+
while (true) {
|
|
76
|
+
const len = binary.readUInt8(pos)
|
|
77
|
+
pos += 1
|
|
78
|
+
if (len === 0) break
|
|
79
|
+
labels.push(binary.slice(pos, pos + len).toString())
|
|
80
|
+
pos += len
|
|
81
|
+
}
|
|
82
|
+
const targetName = `${labels.join('.')}.`
|
|
83
|
+
const params = binary.slice(pos).toString()
|
|
73
84
|
|
|
74
85
|
return new HTTPS({
|
|
75
86
|
owner: this.fullyQualify(owner),
|
|
@@ -78,6 +89,8 @@ export default class HTTPS extends RR {
|
|
|
78
89
|
priority,
|
|
79
90
|
'target name': targetName,
|
|
80
91
|
params,
|
|
92
|
+
timestamp: ts,
|
|
93
|
+
location: loc?.trim() ?? '',
|
|
81
94
|
})
|
|
82
95
|
}
|
|
83
96
|
|
package/rr/ipseckey.js
CHANGED
|
@@ -98,9 +98,9 @@ export default class IPSECKEY extends RR {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/****** IMPORTERS *******/
|
|
101
|
-
fromBind(
|
|
101
|
+
fromBind({ bindline }) {
|
|
102
102
|
// FQDN TTL CLASS IPSECKEY Precedence GatewayType Algorithm Gateway PublicKey
|
|
103
|
-
const [owner, ttl, c, type, prec, gwt, algo, gateway, publickey] =
|
|
103
|
+
const [owner, ttl, c, type, prec, gwt, algo, gateway, publickey] = bindline.split(/\s+/)
|
|
104
104
|
return new IPSECKEY({
|
|
105
105
|
owner,
|
|
106
106
|
ttl: parseInt(ttl, 10),
|
|
@@ -114,32 +114,32 @@ export default class IPSECKEY extends RR {
|
|
|
114
114
|
})
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
fromTinydns(
|
|
118
|
-
const [fqdn, n, rdata, ttl, ts, loc] =
|
|
117
|
+
fromTinydns({ tinyline }) {
|
|
118
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
119
119
|
if (n != 45) this.throwHelp('IPSECKEY fromTinydns, invalid n')
|
|
120
120
|
|
|
121
|
-
const precedence = TINYDNS.octalToUInt8(rdata.
|
|
122
|
-
const gwType = TINYDNS.octalToUInt8(rdata.
|
|
123
|
-
const algorithm = TINYDNS.octalToUInt8(rdata.
|
|
121
|
+
const precedence = TINYDNS.octalToUInt8(rdata.slice(0, 4))
|
|
122
|
+
const gwType = TINYDNS.octalToUInt8(rdata.slice(4, 8))
|
|
123
|
+
const algorithm = TINYDNS.octalToUInt8(rdata.slice(8, 12))
|
|
124
124
|
|
|
125
125
|
let len, gateway, octalKey
|
|
126
126
|
|
|
127
127
|
switch (gwType) {
|
|
128
128
|
case 0: // no gateway
|
|
129
|
-
gateway = rdata.
|
|
130
|
-
octalKey = rdata.
|
|
129
|
+
gateway = rdata.slice(12, 13) // should always be: '.'
|
|
130
|
+
octalKey = rdata.slice(13)
|
|
131
131
|
break
|
|
132
132
|
case 1: // 4-byte IPv4 address
|
|
133
|
-
gateway = TINYDNS.octalToIPv4(rdata.
|
|
134
|
-
octalKey = rdata.
|
|
133
|
+
gateway = TINYDNS.octalToIPv4(rdata.slice(12, 28))
|
|
134
|
+
octalKey = rdata.slice(28)
|
|
135
135
|
break
|
|
136
136
|
case 2: // 16-byte IPv6
|
|
137
|
-
gateway = TINYDNS.octalToHex(rdata.
|
|
138
|
-
octalKey = rdata.
|
|
137
|
+
gateway = TINYDNS.octalToHex(rdata.slice(12, 76))
|
|
138
|
+
octalKey = rdata.slice(76)
|
|
139
139
|
break
|
|
140
140
|
case 3: // wire encoded domain name
|
|
141
|
-
;[gateway, len] = TINYDNS.unpackDomainName(rdata.
|
|
142
|
-
octalKey = rdata.
|
|
141
|
+
;[gateway, len] = TINYDNS.unpackDomainName(rdata.slice(12))
|
|
142
|
+
octalKey = rdata.slice(12 + len)
|
|
143
143
|
break
|
|
144
144
|
}
|
|
145
145
|
|
|
@@ -153,7 +153,7 @@ export default class IPSECKEY extends RR {
|
|
|
153
153
|
gateway,
|
|
154
154
|
publickey: TINYDNS.octalToBase64(octalKey),
|
|
155
155
|
timestamp: ts,
|
|
156
|
-
location: loc
|
|
156
|
+
location: loc?.trim() ?? '',
|
|
157
157
|
})
|
|
158
158
|
}
|
|
159
159
|
|
package/rr/key.js
CHANGED
|
@@ -65,9 +65,9 @@ export default class KEY extends RR {
|
|
|
65
65
|
|
|
66
66
|
/****** IMPORTERS *******/
|
|
67
67
|
|
|
68
|
-
fromBind(
|
|
68
|
+
fromBind({ bindline }) {
|
|
69
69
|
// test.example.com 3600 IN KEY Flags Protocol Algorithm PublicKey
|
|
70
|
-
const [owner, ttl, c, type, flags, protocol, algorithm] =
|
|
70
|
+
const [owner, ttl, c, type, flags, protocol, algorithm] = bindline.split(/\s+/)
|
|
71
71
|
return new KEY({
|
|
72
72
|
owner,
|
|
73
73
|
ttl: parseInt(ttl, 10),
|
|
@@ -76,31 +76,27 @@ export default class KEY extends RR {
|
|
|
76
76
|
flags: parseInt(flags, 10),
|
|
77
77
|
protocol: parseInt(protocol, 10),
|
|
78
78
|
algorithm: parseInt(algorithm, 10),
|
|
79
|
-
publickey:
|
|
79
|
+
publickey: bindline.split(/\s+/).slice(7).join(' ').trim(),
|
|
80
80
|
})
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
fromTinydns(
|
|
84
|
-
const rd = opts.rd
|
|
85
|
-
|
|
83
|
+
fromTinydns({ tinyline }) {
|
|
86
84
|
// RDATA format: Flags (6 octal chars) + Protocol (3 octal chars) + Algorithm (3 octal chars) + Public Key (escaped data)
|
|
85
|
+
const [owner, _typeId, rd, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
87
86
|
if (rd.length < 12) {
|
|
88
87
|
this.throwHelp(`KEY: RDATA too short: ${rd}`)
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
const flags = TINYDNS.octalToUInt16(rd.substring(0, 6))
|
|
92
|
-
const protocol = TINYDNS.octalToUInt8(rd.substring(6, 9))
|
|
93
|
-
const algorithm = TINYDNS.octalToUInt8(rd.substring(9, 12))
|
|
94
|
-
const publicKeyData = TINYDNS.unescapeOctal(rd.substring(12))
|
|
95
|
-
|
|
96
90
|
return new KEY({
|
|
97
|
-
owner: this.fullyQualify(
|
|
98
|
-
ttl: parseInt(
|
|
91
|
+
owner: this.fullyQualify(owner),
|
|
92
|
+
ttl: parseInt(ttl, 10),
|
|
99
93
|
type: 'KEY',
|
|
100
|
-
flags:
|
|
101
|
-
protocol:
|
|
102
|
-
algorithm:
|
|
103
|
-
publickey:
|
|
94
|
+
flags: TINYDNS.octalToUInt16(rd.slice(0, 6)),
|
|
95
|
+
protocol: TINYDNS.octalToUInt8(rd.slice(6, 9)),
|
|
96
|
+
algorithm: TINYDNS.octalToUInt8(rd.slice(9, 12)),
|
|
97
|
+
publickey: TINYDNS.unescapeOctal(rd.slice(12)),
|
|
98
|
+
timestamp: ts,
|
|
99
|
+
location: loc?.trim() ?? '',
|
|
104
100
|
})
|
|
105
101
|
}
|
|
106
102
|
|
package/rr/kx.js
CHANGED
|
@@ -51,9 +51,25 @@ export default class KX extends RR {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/****** IMPORTERS *******/
|
|
54
|
-
|
|
54
|
+
fromTinydns({ tinyline }) {
|
|
55
|
+
// KX via generic, :fqdn:36:rdata:ttl:timestamp:lo
|
|
56
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
57
|
+
if (n != 36) this.throwHelp('KX fromTinydns, invalid n')
|
|
58
|
+
|
|
59
|
+
return new KX({
|
|
60
|
+
owner: this.fullyQualify(fqdn),
|
|
61
|
+
ttl: parseInt(ttl, 10),
|
|
62
|
+
type: 'KX',
|
|
63
|
+
preference: TINYDNS.octalToUInt16(rdata.slice(0, 8)),
|
|
64
|
+
exchanger: TINYDNS.unpackDomainName(rdata.slice(8))[0],
|
|
65
|
+
timestamp: ts,
|
|
66
|
+
location: loc?.trim() ?? '',
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fromBind({ bindline }) {
|
|
55
71
|
// test.example.com 3600 IN KX preference exchanger
|
|
56
|
-
const [owner, ttl, c, type, preference, exchanger] =
|
|
72
|
+
const [owner, ttl, c, type, preference, exchanger] = bindline.split(/\s+/)
|
|
57
73
|
return new KX({
|
|
58
74
|
owner,
|
|
59
75
|
ttl: parseInt(ttl, 10),
|
package/rr/loc.js
CHANGED
|
@@ -85,22 +85,22 @@ export default class LOC extends RR {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/****** IMPORTERS *******/
|
|
88
|
-
fromTinydns(
|
|
88
|
+
fromTinydns({ tinyline }) {
|
|
89
89
|
// LOC via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
90
|
-
const [fqdn, n, rdata, ttl, ts, loc] =
|
|
90
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
91
91
|
if (n != 29) this.throwHelp('LOC fromTinydns, invalid n')
|
|
92
92
|
|
|
93
93
|
// divide by 100 is to convert cm to meters
|
|
94
94
|
const l = {
|
|
95
|
-
version: TINYDNS.octalToUInt8(rdata.
|
|
96
|
-
size: this.fromExponent(TINYDNS.octalToUInt8(rdata.
|
|
95
|
+
version: TINYDNS.octalToUInt8(rdata.slice(0, 4)),
|
|
96
|
+
size: this.fromExponent(TINYDNS.octalToUInt8(rdata.slice(4, 8))),
|
|
97
97
|
precision: {
|
|
98
|
-
horizontal: this.fromExponent(TINYDNS.octalToUInt8(rdata.
|
|
99
|
-
vertical: this.fromExponent(TINYDNS.octalToUInt8(rdata.
|
|
98
|
+
horizontal: this.fromExponent(TINYDNS.octalToUInt8(rdata.slice(8, 12))),
|
|
99
|
+
vertical: this.fromExponent(TINYDNS.octalToUInt8(rdata.slice(12, 16))),
|
|
100
100
|
},
|
|
101
|
-
latitude: this.arcSecToDMS(TINYDNS.octalToUInt32(rdata.
|
|
102
|
-
longitude: this.arcSecToDMS(TINYDNS.octalToUInt32(rdata.
|
|
103
|
-
altitude: TINYDNS.octalToUInt32(rdata.
|
|
101
|
+
latitude: this.arcSecToDMS(TINYDNS.octalToUInt32(rdata.slice(16, 32)), 'lat'),
|
|
102
|
+
longitude: this.arcSecToDMS(TINYDNS.octalToUInt32(rdata.slice(32, 48)), 'lon'),
|
|
103
|
+
altitude: TINYDNS.octalToUInt32(rdata.slice(48, 64)) - REF.ALTITUDE,
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
return new LOC({
|
|
@@ -109,24 +109,24 @@ export default class LOC extends RR {
|
|
|
109
109
|
address: this.toHuman(l),
|
|
110
110
|
ttl: parseInt(ttl, 10),
|
|
111
111
|
timestamp: ts,
|
|
112
|
-
location: loc
|
|
112
|
+
location: loc?.trim() ?? '',
|
|
113
113
|
})
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
fromBind(
|
|
117
|
-
const [owner, ttl, c, type] =
|
|
116
|
+
fromBind({ bindline }) {
|
|
117
|
+
const [owner, ttl, c, type] = bindline.split(/\s+/)
|
|
118
118
|
|
|
119
119
|
return new LOC({
|
|
120
120
|
owner,
|
|
121
121
|
ttl: parseInt(ttl, 10),
|
|
122
122
|
class: c,
|
|
123
123
|
type: type,
|
|
124
|
-
address:
|
|
124
|
+
address: bindline.split(/\s+/).slice(4).join(' ').trim(),
|
|
125
125
|
})
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
dmsToArcSec(obj) {
|
|
129
|
-
let retval = obj.degrees * CONV.deg + (obj.minutes
|
|
129
|
+
let retval = obj.degrees * CONV.deg + (obj.minutes ?? 0) * CONV.min + (obj.seconds ?? 0) * CONV.sec
|
|
130
130
|
switch (obj.hemisphere.toUpperCase()) {
|
|
131
131
|
case 'W':
|
|
132
132
|
case 'S':
|
package/rr/mx.js
CHANGED
|
@@ -53,10 +53,10 @@ export default class MX extends RR {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/****** IMPORTERS *******/
|
|
56
|
-
fromTinydns(
|
|
56
|
+
fromTinydns({ tinyline }) {
|
|
57
57
|
// @fqdn:ip:x:dist:ttl:timestamp:lo
|
|
58
58
|
// eslint-disable-next-line no-unused-vars
|
|
59
|
-
const [owner, ip, x, preference, ttl, ts, loc] =
|
|
59
|
+
const [owner, ip, x, preference, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
60
60
|
|
|
61
61
|
return new MX({
|
|
62
62
|
type: 'MX',
|
|
@@ -65,13 +65,13 @@ export default class MX extends RR {
|
|
|
65
65
|
preference: parseInt(preference, 10) || 0,
|
|
66
66
|
ttl: parseInt(ttl, 10),
|
|
67
67
|
timestamp: ts,
|
|
68
|
-
location: loc
|
|
68
|
+
location: loc?.trim() ?? '',
|
|
69
69
|
})
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
fromBind(
|
|
72
|
+
fromBind({ bindline }) {
|
|
73
73
|
// test.example.com 3600 IN MX preference exchange
|
|
74
|
-
const [owner, ttl, c, type, preference, exchange] =
|
|
74
|
+
const [owner, ttl, c, type, preference, exchange] = bindline.split(/\s+/)
|
|
75
75
|
|
|
76
76
|
return new MX({
|
|
77
77
|
owner,
|
package/rr/naptr.js
CHANGED
|
@@ -62,9 +62,9 @@ export default class NAPTR extends RR {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/****** IMPORTERS *******/
|
|
65
|
-
fromTinydns(
|
|
65
|
+
fromTinydns({ tinyline }) {
|
|
66
66
|
// NAPTR via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
67
|
-
const [fqdn, n, rdata, ttl, ts, loc] =
|
|
67
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
68
68
|
if (n != 35) this.throwHelp('NAPTR fromTinydns, invalid n')
|
|
69
69
|
|
|
70
70
|
const binRdata = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
@@ -74,7 +74,7 @@ export default class NAPTR extends RR {
|
|
|
74
74
|
owner: this.fullyQualify(fqdn),
|
|
75
75
|
ttl: parseInt(ttl, 10),
|
|
76
76
|
timestamp: ts,
|
|
77
|
-
location: loc
|
|
77
|
+
location: loc?.trim() ?? '',
|
|
78
78
|
order: binRdata.readUInt16BE(0, 2),
|
|
79
79
|
preference: binRdata.readUInt16BE(2, 4),
|
|
80
80
|
}
|
|
@@ -102,26 +102,30 @@ export default class NAPTR extends RR {
|
|
|
102
102
|
return new NAPTR(rec)
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
fromBind(
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
const [owner, ttl, c, type, order, preference] = str.split(/\s+/)
|
|
109
|
-
const [flags, service, regexp] = str.match(/(?:").*?(?:"\s)/g)
|
|
110
|
-
const replacement = str.trim().split(/\s+/).pop()
|
|
105
|
+
fromBind({ bindline }) {
|
|
106
|
+
const regex =
|
|
107
|
+
/^(?<owner>\S+)\s+(?<ttl>\d+)\s+(?<class>\S+)\s+(?<type>NAPTR)\s+(?<order>\d+)\s+(?<preference>\d+)\s+["'](?<flags>[^"']*)["']\s+["'](?<service>[^"']*)["']\s+["'](?<regexp>[^"']*)["']\s+(?<replacement>\S+)$/
|
|
111
108
|
|
|
112
|
-
const
|
|
113
|
-
|
|
109
|
+
const match = bindline.trim().match(regex)
|
|
110
|
+
|
|
111
|
+
if (!match) {
|
|
112
|
+
throw new Error(`Invalid NAPTR BIND line: ${bindline}`)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const { owner, ttl, type, order, preference, flags, service, regexp, replacement } = match.groups
|
|
116
|
+
|
|
117
|
+
return new NAPTR({
|
|
118
|
+
owner: this.fullyQualify(owner),
|
|
114
119
|
ttl: parseInt(ttl, 10),
|
|
115
|
-
class:
|
|
116
|
-
type
|
|
120
|
+
class: match.groups.class,
|
|
121
|
+
type,
|
|
117
122
|
order: parseInt(order, 10),
|
|
118
123
|
preference: parseInt(preference, 10),
|
|
119
|
-
flags
|
|
120
|
-
service
|
|
121
|
-
regexp
|
|
122
|
-
replacement
|
|
123
|
-
}
|
|
124
|
-
return new NAPTR(bits)
|
|
124
|
+
flags,
|
|
125
|
+
service,
|
|
126
|
+
regexp,
|
|
127
|
+
replacement,
|
|
128
|
+
})
|
|
125
129
|
}
|
|
126
130
|
|
|
127
131
|
/****** EXPORTERS *******/
|
package/rr/ns.js
CHANGED
|
@@ -34,10 +34,10 @@ export default class NS extends RR {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/****** IMPORTERS *******/
|
|
37
|
-
fromTinydns(
|
|
37
|
+
fromTinydns({ tinyline }) {
|
|
38
38
|
// &fqdn:ip:x:ttl:timestamp:lo
|
|
39
39
|
// eslint-disable-next-line no-unused-vars
|
|
40
|
-
const [fqdn, ip, dname, ttl, ts, loc] =
|
|
40
|
+
const [fqdn, ip, dname, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
41
41
|
|
|
42
42
|
return new NS({
|
|
43
43
|
type: 'NS',
|
|
@@ -45,13 +45,13 @@ export default class NS extends RR {
|
|
|
45
45
|
dname: this.fullyQualify(/\./.test(dname) ? dname : `${dname}.ns.${fqdn}`),
|
|
46
46
|
ttl: parseInt(ttl, 10),
|
|
47
47
|
timestamp: ts,
|
|
48
|
-
location: loc
|
|
48
|
+
location: loc?.trim() ?? '',
|
|
49
49
|
})
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
fromBind(
|
|
52
|
+
fromBind({ bindline }) {
|
|
53
53
|
// test.example.com 3600 IN NS dname
|
|
54
|
-
const [owner, ttl, c, type, dname] =
|
|
54
|
+
const [owner, ttl, c, type, dname] = bindline.split(/\s+/)
|
|
55
55
|
|
|
56
56
|
return new NS({
|
|
57
57
|
owner,
|
package/rr/nsec.js
CHANGED
|
@@ -43,8 +43,8 @@ export default class NSEC extends RR {
|
|
|
43
43
|
|
|
44
44
|
/****** IMPORTERS *******/
|
|
45
45
|
|
|
46
|
-
fromTinydns(
|
|
47
|
-
const [owner, _typeId, rdata, ttl, ts, loc] =
|
|
46
|
+
fromTinydns({ tinyline }) {
|
|
47
|
+
const [owner, _typeId, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
48
48
|
const binaryRdata = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
49
49
|
const [nextDomain, _escapedLen, binaryLen] = TINYDNS.unpackDomainName(rdata)
|
|
50
50
|
|
|
@@ -55,20 +55,20 @@ export default class NSEC extends RR {
|
|
|
55
55
|
'next domain': nextDomain,
|
|
56
56
|
'type bit maps': binaryRdata.slice(binaryLen).toString(),
|
|
57
57
|
timestamp: ts,
|
|
58
|
-
location: loc
|
|
58
|
+
location: loc?.trim() ?? '',
|
|
59
59
|
})
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
fromBind(
|
|
62
|
+
fromBind({ bindline }) {
|
|
63
63
|
// test.example.com 3600 IN NSEC NextDomain TypeBitMaps
|
|
64
|
-
const [owner, ttl, c, type, next] =
|
|
64
|
+
const [owner, ttl, c, type, next] = bindline.split(/\s+/)
|
|
65
65
|
return new NSEC({
|
|
66
66
|
owner,
|
|
67
67
|
ttl: parseInt(ttl, 10),
|
|
68
68
|
class: c,
|
|
69
69
|
type: type,
|
|
70
70
|
'next domain': next,
|
|
71
|
-
'type bit maps':
|
|
71
|
+
'type bit maps': bindline.split(/\s+/).slice(5).filter(removeParens).join(' ').trim(),
|
|
72
72
|
})
|
|
73
73
|
}
|
|
74
74
|
|
package/rr/nsec3.js
CHANGED
|
@@ -78,10 +78,10 @@ export default class NSEC3 extends RR {
|
|
|
78
78
|
|
|
79
79
|
/****** IMPORTERS *******/
|
|
80
80
|
|
|
81
|
-
fromBind(
|
|
81
|
+
fromBind({ bindline }) {
|
|
82
82
|
// test.example.com. 3600 IN NSEC3 1 1 12 aabbccdd (2vptu5timamqttgl4luu9kg21e0aor3s A RRSIG)
|
|
83
|
-
const [owner, ttl, c, type, ha, flags, iterations, salt] =
|
|
84
|
-
const rdata =
|
|
83
|
+
const [owner, ttl, c, type, ha, flags, iterations, salt] = bindline.split(/\s+/)
|
|
84
|
+
const rdata = bindline.split(/\(|\)/)[1]
|
|
85
85
|
|
|
86
86
|
return new NSEC3({
|
|
87
87
|
owner,
|
|
@@ -97,8 +97,8 @@ export default class NSEC3 extends RR {
|
|
|
97
97
|
})
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
fromTinydns(
|
|
101
|
-
const [fqdn, n, rdata, ttl, ts, loc] =
|
|
100
|
+
fromTinydns({ tinyline }) {
|
|
101
|
+
const [fqdn, n, rdata, ttl, ts, loc] = tinyline.slice(1).split(':')
|
|
102
102
|
if (n != 50) this.throwHelp('NSEC3 fromTinydns, invalid n')
|
|
103
103
|
|
|
104
104
|
const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
@@ -112,7 +112,7 @@ export default class NSEC3 extends RR {
|
|
|
112
112
|
// Salt (variable length based on Salt Length)
|
|
113
113
|
// Next Hashed Owner Name (variable length)
|
|
114
114
|
// Type Bit Maps (variable length)
|
|
115
|
-
const { salt, nextHashedOwnerName, typeBitMaps } =
|
|
115
|
+
const { salt, nextHashedOwnerName, typeBitMaps } = parseNSEC3Buffer(bytes)
|
|
116
116
|
|
|
117
117
|
return new NSEC3({
|
|
118
118
|
owner: this.fullyQualify(fqdn),
|
|
@@ -125,7 +125,7 @@ export default class NSEC3 extends RR {
|
|
|
125
125
|
'next hashed owner name': nextHashedOwnerName,
|
|
126
126
|
'type bit maps': typeBitMaps,
|
|
127
127
|
timestamp: ts,
|
|
128
|
-
location: loc
|
|
128
|
+
location: loc?.trim() ?? '',
|
|
129
129
|
})
|
|
130
130
|
}
|
|
131
131
|
|
|
@@ -155,3 +155,48 @@ export default class NSEC3 extends RR {
|
|
|
155
155
|
)
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
|
+
|
|
159
|
+
function parseNSEC3Buffer(bytes) {
|
|
160
|
+
// bytes is a Buffer containing the full RDATA binary (hash alg, flags, iterations, then ASCII salt + next-hashed + type bit maps)
|
|
161
|
+
// Start after the first 4 bytes (hash alg, flags, iterations)
|
|
162
|
+
const rest = bytes.slice(4).toString('utf8')
|
|
163
|
+
|
|
164
|
+
// determine expected next hashed owner name length from hash algorithm
|
|
165
|
+
const hashAlgorithm = bytes.readUInt8(0)
|
|
166
|
+
// common mapping: algorithm 1 => SHA-1 => 20 bytes => base32 length 32
|
|
167
|
+
const expectedLen = hashAlgorithm === 1 ? 32 : hashAlgorithm === 2 ? 52 : 32
|
|
168
|
+
|
|
169
|
+
// salt length is ambiguous in this representation; try to find a split where
|
|
170
|
+
// the following segment matches expected base32 length
|
|
171
|
+
let salt = ''
|
|
172
|
+
let nextHashedOwnerName = ''
|
|
173
|
+
let typeBitMaps = ''
|
|
174
|
+
|
|
175
|
+
const maxSl = Math.min(64, rest.length)
|
|
176
|
+
for (let sl = maxSl; sl >= 1; sl--) {
|
|
177
|
+
const candNext = rest.slice(sl, sl + expectedLen)
|
|
178
|
+
if (candNext.length !== expectedLen) continue
|
|
179
|
+
if (!/^[0-9a-z]+$/.test(candNext)) continue
|
|
180
|
+
// candidate looks like a base32 name; accept and treat remainder as type bit maps
|
|
181
|
+
const saltCandidate = rest.slice(0, sl)
|
|
182
|
+
if (!/^[0-9A-Fa-f]+$/.test(saltCandidate)) continue
|
|
183
|
+
salt = saltCandidate
|
|
184
|
+
nextHashedOwnerName = candNext
|
|
185
|
+
typeBitMaps = rest.slice(sl + expectedLen)
|
|
186
|
+
break
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// fallback: if we couldn't find a split, treat everything up to first non-hex as salt
|
|
190
|
+
if (!nextHashedOwnerName) {
|
|
191
|
+
const saltMatch = rest.match(/^([0-9A-Fa-f]*)/)
|
|
192
|
+
salt = saltMatch ? saltMatch[1] : ''
|
|
193
|
+
nextHashedOwnerName = rest.slice(salt.length)
|
|
194
|
+
typeBitMaps = ''
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
salt,
|
|
199
|
+
nextHashedOwnerName,
|
|
200
|
+
typeBitMaps,
|
|
201
|
+
}
|
|
202
|
+
}
|