@nictool/dns-resource-record 1.3.0 → 1.4.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 CHANGED
@@ -4,6 +4,21 @@ Notable changes to this project are documented in this file.
4
4
 
5
5
  #### Unreleased
6
6
 
7
+ ### [1.4.0] - 2026-03-21
8
+
9
+ #### Changed
10
+
11
+ - feat(toBind): added to nsec3param, rrsig
12
+ - feat(toTinydns): added to key, nsec3param, nxt, openpgpkey
13
+ - feat(fromTinydns): added to cert, https, key, nsec, nsec3param, nxt, openpgpkey, smimea, svcb
14
+ - fix(naptr): fixed flags calc in fromTinydns
15
+ - fix(tinydns): more robust unpackDomainName
16
+ - test: switch test runner to node --test
17
+
18
+ ### [1.3.1] - 2026-03-13
19
+
20
+ - ci: update workflow triggers
21
+
7
22
  ### [1.3.0] - 2026-03-01
8
23
 
9
24
  - feat: add toTinydns for CERT, HTTPS, NSEC, SMIMEA, SVCB, WKS #51
@@ -332,4 +347,6 @@ Notable changes to this project are documented in this file.
332
347
  [1.2.2]: https://github.com/NicTool/dns-resource-record/releases/tag/1.2.2
333
348
  [1.2.3]: https://github.com/NicTool/dns-resource-record/releases/tag/1.2.3
334
349
  [1.2.4]: https://github.com/NicTool/dns-resource-record/releases/tag/1.2.4
335
- [1.3.0]: https://github.com/NicTool/dns-resource-record/releases/tag/1.3.0
350
+ [1.3.0]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.3.0
351
+ [1.3.1]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.3.1
352
+ [1.4.0]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.4.0
package/lib/tinydns.js CHANGED
@@ -27,6 +27,10 @@ export function escapeOctal(re, str) {
27
27
  return escaped
28
28
  }
29
29
 
30
+ export function unescapeOctal(str) {
31
+ return this.octalToChar(str)
32
+ }
33
+
30
34
  export function octalToChar(str) {
31
35
  // relace instances of \NNN with ASCII
32
36
  return str.replace(octalRe, (o) => String.fromCharCode(parseInt(o.substring(1), 8)))
@@ -108,22 +112,39 @@ export function packDomainName(fqdn) {
108
112
  return packed
109
113
  }
110
114
 
111
- export function unpackDomainName(fqdn) {
112
- fqdn = Buffer.from(octalToChar(fqdn.toString()))
113
-
114
- const labels = []
115
+ export function unpackDomainName(escaped) {
115
116
  let pos = 0
116
- let len
117
- while ((len = fqdn.readUInt8(pos))) {
118
- // encoded length byte
119
- pos++
120
- labels.push(fqdn.slice(pos, pos + len).toString())
121
- pos = +(pos + len)
117
+ let binaryLen = 0
118
+ const labels = []
119
+
120
+ // consume the next logical "byte" (char or octal escape)
121
+ const getNextByte = () => {
122
+ if (pos >= escaped.length) return null
123
+
124
+ let value
125
+ if (escaped[pos] === '\\') {
126
+ value = parseInt(escaped.slice(pos + 1, pos + 4), 8)
127
+ pos += 4
128
+ } else {
129
+ value = escaped.charCodeAt(pos++)
130
+ }
131
+
132
+ binaryLen++
133
+ return value
122
134
  }
123
- const r = `${labels.join('.')}.`
124
- // char position + length of last label + label length chars + null byte
125
- const strLen = pos + len + labels.length * 4 + 1
126
- return [r, strLen]
135
+
136
+ let lengthByte
137
+ while ((lengthByte = getNextByte()) && lengthByte !== 0) {
138
+ let label = ''
139
+ for (let i = 0; i < lengthByte; i++) {
140
+ const char = getNextByte()
141
+ if (char === null) break
142
+ label += String.fromCharCode(char)
143
+ }
144
+ labels.push(label)
145
+ }
146
+
147
+ return [`${labels.join('.')}.`, pos, binaryLen]
127
148
  }
128
149
 
129
150
  export function packHex(str) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nictool/dns-resource-record",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "DNS Resource Records",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -17,10 +17,11 @@
17
17
  "lint:fix": "npm run lint -- --fix",
18
18
  "prettier": "npx prettier --ignore-path .gitignore --check .",
19
19
  "prettier:fix": "npx prettier --ignore-path .gitignore --write .",
20
- "test": "npx mocha",
21
- "versions": "npx dependency-version-checker check",
22
- "watch": "npm run test -- --watch",
23
- "versions:fix": "npx dependency-version-checker update"
20
+ "test": "node --test test/*.js",
21
+ "test:coverage": "npx c8 --reporter=text --reporter=text-summary npm test",
22
+ "versions": "npx npm-dep-mgr check",
23
+ "versions:fix": "npx npm-dep-mgr update",
24
+ "watch": "node --test --watch test/*.js"
24
25
  },
25
26
  "repository": {
26
27
  "type": "git",
@@ -47,9 +48,8 @@
47
48
  "homepage": "https://github.com/NicTool/dns-resource-record#readme",
48
49
  "devDependencies": {
49
50
  "@eslint/js": "^10.0.1",
50
- "eslint": "^10.0.2",
51
- "globals": "^17.4.0",
52
- "mocha": "^11.7.5"
51
+ "eslint": "^10.1.0",
52
+ "globals": "^17.4.0"
53
53
  },
54
54
  "prettier": {
55
55
  "printWidth": 110,
package/rr/cert.js CHANGED
@@ -75,6 +75,41 @@ export default class CERT extends RR {
75
75
 
76
76
  /****** IMPORTERS *******/
77
77
 
78
+ fromTinydns(opts) {
79
+ const [owner, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
80
+ if (n != 37) this.throwHelp('CERT fromTinydns, invalid n')
81
+
82
+ const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
83
+ const typeNum = bytes.readUInt16BE(0)
84
+ let certType = typeNum
85
+
86
+ const types = {
87
+ 1: 'PKIX',
88
+ 2: 'SPKI',
89
+ 3: 'PGP',
90
+ 4: 'IPKIX',
91
+ 5: 'ISPKI',
92
+ 6: 'IPGP',
93
+ 7: 'ACPKIX',
94
+ 8: 'IACPKIX',
95
+ 253: 'URI',
96
+ 254: 'OID',
97
+ }
98
+ if (types[typeNum]) certType = types[typeNum]
99
+
100
+ return new CERT({
101
+ owner: this.fullyQualify(owner),
102
+ ttl: parseInt(ttl, 10),
103
+ type: 'CERT',
104
+ 'cert type': certType,
105
+ 'key tag': bytes.readUInt16BE(2),
106
+ algorithm: bytes.readUInt8(4),
107
+ certificate: bytes.slice(5).toString(),
108
+ timestamp: ts,
109
+ location: loc !== '' && loc !== '\n' ? loc : '',
110
+ })
111
+ }
112
+
78
113
  fromBind(opts) {
79
114
  // test.example.com 3600 IN CERT certtype, keytag, algo, cert
80
115
  const [owner, ttl, c, type, certtype, keytag, algo, certificate] = opts.bindline.split(/\s+/)
package/rr/https.js CHANGED
@@ -60,6 +60,27 @@ export default class HTTPS extends RR {
60
60
  })
61
61
  }
62
62
 
63
+ fromTinydns({ rd, owner, ttl }) {
64
+ if (rd.length < 6) {
65
+ this.throwHelp(`HTTPS: RDATA too short: ${rd}`)
66
+ }
67
+
68
+ const priority = TINYDNS.octalToUInt16(rd.substring(0, 6))
69
+ const remaining = rd.slice(6)
70
+
71
+ const [targetName, consumed] = TINYDNS.unpackDomainName(remaining)
72
+ const params = TINYDNS.escapeOctal(remaining.slice(consumed))
73
+
74
+ return new HTTPS({
75
+ owner: this.fullyQualify(owner),
76
+ ttl: parseInt(ttl, 10),
77
+ type: 'HTTPS',
78
+ priority,
79
+ 'target name': targetName,
80
+ params,
81
+ })
82
+ }
83
+
63
84
  /****** EXPORTERS *******/
64
85
 
65
86
  toTinydns() {
package/rr/key.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import RR from '../rr.js'
2
+ import * as TINYDNS from '../lib/tinydns.js'
2
3
 
3
4
  export default class KEY extends RR {
4
5
  constructor(opts) {
@@ -79,5 +80,39 @@ export default class KEY extends RR {
79
80
  })
80
81
  }
81
82
 
83
+ fromTinydns(opts) {
84
+ const rd = opts.rd
85
+
86
+ // RDATA format: Flags (6 octal chars) + Protocol (3 octal chars) + Algorithm (3 octal chars) + Public Key (escaped data)
87
+ if (rd.length < 12) {
88
+ this.throwHelp(`KEY: RDATA too short: ${rd}`)
89
+ }
90
+
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
+ return new KEY({
97
+ owner: this.fullyQualify(opts.owner),
98
+ ttl: parseInt(opts.ttl, 10),
99
+ type: 'KEY',
100
+ flags: flags,
101
+ protocol: protocol,
102
+ algorithm: algorithm,
103
+ publickey: publicKeyData,
104
+ })
105
+ }
106
+
82
107
  /****** EXPORTERS *******/
108
+ toTinydns() {
109
+ const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
110
+
111
+ return this.getTinydnsGeneric(
112
+ TINYDNS.UInt16toOctal(this.get('flags')) +
113
+ TINYDNS.UInt8toOctal(this.get('protocol')) +
114
+ TINYDNS.UInt8toOctal(this.get('algorithm')) +
115
+ TINYDNS.escapeOctal(dataRe, this.get('publickey')),
116
+ )
117
+ }
83
118
  }
package/rr/naptr.js CHANGED
@@ -82,7 +82,7 @@ export default class NAPTR extends RR {
82
82
  let idx = 4
83
83
  const flagsLength = binRdata.readUInt8(idx)
84
84
  idx++
85
- rec.flags = binRdata.slice(idx, flagsLength).toString()
85
+ rec.flags = binRdata.slice(idx, idx + flagsLength).toString()
86
86
  idx += flagsLength
87
87
 
88
88
  const serviceLen = binRdata.readUInt8(idx)
package/rr/nsec.js CHANGED
@@ -43,6 +43,22 @@ export default class NSEC extends RR {
43
43
 
44
44
  /****** IMPORTERS *******/
45
45
 
46
+ fromTinydns(opts) {
47
+ const [owner, _typeId, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
48
+ const binaryRdata = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
49
+ const [nextDomain, _escapedLen, binaryLen] = TINYDNS.unpackDomainName(rdata)
50
+
51
+ return new NSEC({
52
+ owner: this.fullyQualify(owner),
53
+ ttl: parseInt(ttl, 10),
54
+ type: 'NSEC',
55
+ 'next domain': nextDomain,
56
+ 'type bit maps': binaryRdata.slice(binaryLen).toString(),
57
+ timestamp: ts,
58
+ location: loc !== '' && loc !== '\n' ? loc : '',
59
+ })
60
+ }
61
+
46
62
  fromBind(opts) {
47
63
  // test.example.com 3600 IN NSEC NextDomain TypeBitMaps
48
64
  const [owner, ttl, c, type, next] = opts.bindline.split(/\s+/)
package/rr/nsec3.js CHANGED
@@ -93,7 +93,7 @@ export default class NSEC3 extends RR {
93
93
  iterations: parseInt(iterations, 10),
94
94
  salt,
95
95
  'next hashed owner name': rdata.split(/\s+/)[0],
96
- 'type bit maps': rdata.split(/\s+/).slice(1).join('\t'),
96
+ 'type bit maps': rdata.split(/\s+/).slice(1).join(' '),
97
97
  })
98
98
  }
99
99
 
@@ -103,16 +103,27 @@ export default class NSEC3 extends RR {
103
103
 
104
104
  const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
105
105
 
106
+ const hashAlgorithm = bytes.readUInt8(0)
107
+ const flags = bytes.readUInt8(1)
108
+ const iterations = bytes.readUInt16BE(2)
109
+
110
+ // The remaining bytes in the buffer contain:
111
+ // Salt Length (1 octet)
112
+ // Salt (variable length based on Salt Length)
113
+ // Next Hashed Owner Name (variable length)
114
+ // Type Bit Maps (variable length)
115
+ const { salt, nextHashedOwnerName, typeBitMaps } = TINYDNS.parseNSEC3Buffer(bytes)
116
+
106
117
  return new NSEC3({
107
118
  owner: this.fullyQualify(fqdn),
108
119
  ttl: parseInt(ttl, 10),
109
120
  type: 'NSEC3',
110
- 'hash algorithm': bytes.readUInt8(0),
111
- flags: bytes.readUInt8(1),
112
- iterations: bytes.readUInt16BE(2),
113
- // salt : ,
114
- // 'next hashed owner name': ,
115
- // 'type bit maps' : ,
121
+ 'hash algorithm': hashAlgorithm,
122
+ flags: flags,
123
+ iterations: iterations,
124
+ salt: salt,
125
+ 'next hashed owner name': nextHashedOwnerName,
126
+ 'type bit maps': typeBitMaps,
116
127
  timestamp: ts,
117
128
  location: loc !== '' && loc !== '\n' ? loc : '',
118
129
  })
@@ -121,13 +132,14 @@ export default class NSEC3 extends RR {
121
132
  /****** EXPORTERS *******/
122
133
 
123
134
  toBind(zone_opts) {
124
- return `${this.getFQDN('owner', zone_opts)}\t${this.get('ttl')}\t${this.get('class')}\tNSEC3${this.getRdataFields()
135
+ return `${this.getFQDN('owner', zone_opts)} ${this.get('ttl')} ${this.get('class')} NSEC3${this.getRdataFields()
125
136
  .slice(0, 4)
126
- .map((f) => '\t' + this.get(f))
127
- .join('')}\t(${this.getRdataFields()
137
+ .map((f) => ' ' + this.get(f))
138
+ .join('')} (${this.getRdataFields()
128
139
  .slice(4)
129
140
  .map((f) => this.get(f))
130
- .join('\t')})\n`
141
+ .join(' ')})
142
+ `
131
143
  }
132
144
 
133
145
  toTinydns() {
package/rr/nsec3param.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import RR from '../rr.js'
2
+ import * as TINYDNS from '../lib/tinydns.js'
2
3
 
3
4
  export default class NSEC3PARAM extends RR {
4
5
  constructor(opts) {
@@ -62,21 +63,57 @@ export default class NSEC3PARAM extends RR {
62
63
  /****** IMPORTERS *******/
63
64
 
64
65
  fromBind(str) {
65
- // test.example.com 3600 IN NSEC3PARAM
66
- const [owner, ttl, c, type] = str.split(/\s+/)
66
+ // test.example.com 3600 IN NSEC3PARAM <hash> <flags> <iterations> <salt>
67
+ // Example: test.example.com. 3600 IN NSEC3PARAM 1 1 12 aabbccdd
68
+ const [owner, ttl, c, type, ha, flags, iterations, salt] = str.split(/\s+/)
67
69
  return new NSEC3PARAM({
68
70
  owner,
69
71
  ttl: parseInt(ttl, 10),
70
72
  class: c,
71
73
  type: type,
72
- 'hash algorithm': '',
73
- flags: '',
74
- iterations: '',
75
- salt: '',
76
- 'next hashed owner name': '',
77
- 'type bit maps': '',
74
+ 'hash algorithm': parseInt(ha, 10),
75
+ flags: parseInt(flags, 10),
76
+ iterations: parseInt(iterations, 10),
77
+ salt: salt,
78
+ })
79
+ }
80
+
81
+ fromTinydns(opts) {
82
+ const rd = opts.rd
83
+
84
+ // RDATA format: Hash Algorithm (3 octal chars) + Flags (3 octal chars) + Iterations (6 octal chars) + Salt (escaped hex string)
85
+ if (rd.length < 12) {
86
+ this.throwHelp(`NSEC3PARAM: RDATA too short: ${rd}`)
87
+ }
88
+
89
+ return new NSEC3PARAM({
90
+ owner: this.fullyQualify(opts.owner),
91
+ ttl: parseInt(opts.ttl, 10),
92
+ type: 'NSEC3PARAM',
93
+ 'hash algorithm': TINYDNS.octalToUInt8(rd.substring(0, 3)),
94
+ flags: TINYDNS.octalToUInt8(rd.substring(3, 6)),
95
+ iterations: TINYDNS.octalToUInt16(rd.substring(6, 12)),
96
+ salt: TINYDNS.unescapeOctal(rd.substring(12)),
78
97
  })
79
98
  }
80
99
 
81
100
  /****** EXPORTERS *******/
101
+
102
+ toBind(zone_opts) {
103
+ // Example: test.example.com. 3600 IN NSEC3PARAM 1 1 12 aabbccdd
104
+ return `${this.getFQDN('owner', zone_opts)} ${this.get('ttl')} ${this.get('class')} NSEC3PARAM ${this.get('hash algorithm')} ${this.get('flags')} ${this.get('iterations')} ${this.get('salt')}
105
+ `
106
+ }
107
+
108
+ toTinydns() {
109
+ const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
110
+
111
+ let rdata = ''
112
+ rdata += TINYDNS.UInt8toOctal(this.get('hash algorithm'))
113
+ rdata += TINYDNS.UInt8toOctal(this.get('flags'))
114
+ rdata += TINYDNS.UInt16toOctal(this.get('iterations'))
115
+ rdata += TINYDNS.escapeOctal(dataRe, this.get('salt'))
116
+
117
+ return this.getTinydnsGeneric(rdata)
118
+ }
82
119
  }
package/rr/nxt.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import RR from '../rr.js'
2
2
 
3
+ import * as TINYDNS from '../lib/tinydns.js'
4
+
3
5
  export default class NXT extends RR {
4
6
  constructor(opts) {
5
7
  super(opts)
@@ -41,6 +43,24 @@ export default class NXT extends RR {
41
43
 
42
44
  /****** IMPORTERS *******/
43
45
 
46
+ fromTinydns(opts) {
47
+ const [owner, n, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
48
+ if (n != 30) this.throwHelp('NXT fromTinydns, invalid n')
49
+
50
+ const binaryRdata = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
51
+ const [nextDomain, _escapedLen, binaryLen] = TINYDNS.unpackDomainName(rdata)
52
+
53
+ return new NXT({
54
+ owner: this.fullyQualify(owner),
55
+ ttl: parseInt(ttl, 10),
56
+ type: 'NXT',
57
+ 'next domain': nextDomain,
58
+ 'type bit map': binaryRdata.slice(binaryLen).toString(),
59
+ timestamp: ts,
60
+ location: loc !== '' && loc !== '\n' ? loc : '',
61
+ })
62
+ }
63
+
44
64
  fromBind(opts) {
45
65
  // test.example.com 3600 IN NXT NextDomain TypeBitMap
46
66
  const [owner, ttl, c, type, next] = opts.bindline.split(/\s+/)
@@ -55,6 +75,14 @@ export default class NXT extends RR {
55
75
  }
56
76
 
57
77
  /****** EXPORTERS *******/
78
+
79
+ toTinydns() {
80
+ const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
81
+
82
+ return this.getTinydnsGeneric(
83
+ TINYDNS.packDomainName(this.get('next domain')) + TINYDNS.escapeOctal(dataRe, this.get('type bit map')),
84
+ )
85
+ }
58
86
  }
59
87
 
60
88
  const removeParens = (a) => !['(', ')'].includes(a)
package/rr/openpgpkey.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import RR from '../rr.js'
2
+ import * as TINYDNS from '../lib/tinydns.js'
2
3
 
3
4
  export default class OPENPGPKEY extends RR {
4
5
  constructor(opts) {
@@ -42,5 +43,22 @@ export default class OPENPGPKEY extends RR {
42
43
  })
43
44
  }
44
45
 
46
+ fromTinydns(opts) {
47
+ return new OPENPGPKEY({
48
+ owner: this.fullyQualify(opts.owner),
49
+ ttl: parseInt(opts.ttl, 10),
50
+ type: 'OPENPGPKEY',
51
+ 'public key': Buffer.from(TINYDNS.unescapeOctal(opts.rd), 'base64').toString('utf-8'),
52
+ })
53
+ }
54
+
45
55
  /****** EXPORTERS *******/
56
+ toTinydns() {
57
+ const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
58
+ const escapedPublicKey = TINYDNS.escapeOctal(
59
+ dataRe,
60
+ Buffer.from(this.get('public key'), 'utf-8').toString('base64'),
61
+ )
62
+ return this.getTinydnsGeneric(escapedPublicKey)
63
+ }
46
64
  }
package/rr/sig.js CHANGED
@@ -102,4 +102,14 @@ export default class SIG extends RR {
102
102
  // }
103
103
 
104
104
  /****** EXPORTERS *******/
105
+
106
+ toBind(zone_opts) {
107
+ return `${this.getFQDN('owner', zone_opts)} ${this.get('ttl')} ${this.get('class')} SIG${this.getRdataFields()
108
+ .slice(0, 4)
109
+ .map((f) => ' ' + this.get(f))
110
+ .join('')} ${this.getRdataFields()
111
+ .slice(4, 8)
112
+ .map((f) => this.get(f))
113
+ .join(' ')} ( ${this.get('signature')} )`
114
+ }
105
115
  }
package/rr/smimea.js CHANGED
@@ -91,6 +91,23 @@ export default class SMIMEA extends RR {
91
91
  })
92
92
  }
93
93
 
94
+ fromTinydns(opts) {
95
+ const [owner, _typeId, rdata, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
96
+ const binaryRdata = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
97
+
98
+ return new SMIMEA({
99
+ owner: this.fullyQualify(owner),
100
+ ttl: parseInt(ttl, 10),
101
+ type: 'SMIMEA',
102
+ 'certificate usage': binaryRdata.readUInt8(0),
103
+ selector: binaryRdata.readUInt8(1),
104
+ 'matching type': binaryRdata.readUInt8(2),
105
+ 'certificate association data': binaryRdata.slice(3).toString(),
106
+ timestamp: ts,
107
+ location: loc !== '' && loc !== '\n' ? loc : '',
108
+ })
109
+ }
110
+
94
111
  /****** EXPORTERS *******/
95
112
  toTinydns() {
96
113
  const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
package/rr/svcb.js CHANGED
@@ -62,6 +62,29 @@ export default class SVCB extends RR {
62
62
  })
63
63
  }
64
64
 
65
+ fromTinydns({ rd, owner, ttl }) {
66
+ if (rd.length < 6) {
67
+ this.throwHelp(`SVCB: RDATA too short: ${rd}`)
68
+ }
69
+
70
+ const priority = TINYDNS.octalToUInt16(rd.substring(0, 6))
71
+ const remainingRdata = rd.slice(6)
72
+
73
+ const [targetName, consumedLength] = TINYDNS.unpackDomainName(remainingRdata)
74
+
75
+ const params = remainingRdata.slice(consumedLength)
76
+ const unescapedParams = TINYDNS.unescapeOctal(params)
77
+
78
+ return new SVCB({
79
+ owner: this.fullyQualify(owner),
80
+ ttl: parseInt(ttl, 10),
81
+ type: 'SVCB',
82
+ priority: priority,
83
+ 'target name': targetName,
84
+ params: unescapedParams,
85
+ })
86
+ }
87
+
65
88
  /****** EXPORTERS *******/
66
89
 
67
90
  toTinydns() {
package/rr/tlsa.js CHANGED
@@ -111,7 +111,7 @@ export default class TLSA extends RR {
111
111
  'matching type': bytes.readUInt8(2),
112
112
  'certificate association data': bytes.slice(3).toString(),
113
113
  timestamp: ts,
114
- location: loc !== '' && loc !== '\n' ? loc : '',
114
+ location: loc.trim() || '',
115
115
  })
116
116
  }
117
117
 
package/rr/uri.js CHANGED
@@ -40,7 +40,7 @@ export default class URI extends RR {
40
40
  target: TINYDNS.octalToChar(rdata.substring(16)),
41
41
  ttl: parseInt(ttl, 10),
42
42
  timestamp: ts,
43
- location: loc !== '' && loc !== '\n' ? loc : '',
43
+ location: loc.trim() || '',
44
44
  })
45
45
  }
46
46