@nictool/dns-resource-record 1.1.3

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 (71) hide show
  1. package/.codeclimate.yml +25 -0
  2. package/CHANGELOG.md +253 -0
  3. package/DEVELOP.md +23 -0
  4. package/LICENSE +29 -0
  5. package/README.md +267 -0
  6. package/index.js +67 -0
  7. package/lib/tinydns.js +186 -0
  8. package/package.json +40 -0
  9. package/rr/a.js +65 -0
  10. package/rr/aaaa.js +137 -0
  11. package/rr/caa.js +129 -0
  12. package/rr/cert.js +75 -0
  13. package/rr/cname.js +76 -0
  14. package/rr/dname.js +74 -0
  15. package/rr/dnskey.js +117 -0
  16. package/rr/ds.js +104 -0
  17. package/rr/hinfo.js +84 -0
  18. package/rr/ipseckey.js +159 -0
  19. package/rr/key.js +73 -0
  20. package/rr/loc.js +216 -0
  21. package/rr/mx.js +86 -0
  22. package/rr/naptr.js +146 -0
  23. package/rr/ns.js +74 -0
  24. package/rr/nsec.js +61 -0
  25. package/rr/nsec3.js +99 -0
  26. package/rr/nsec3param.js +84 -0
  27. package/rr/openpgpkey.js +44 -0
  28. package/rr/ptr.js +65 -0
  29. package/rr/rrsig.js +101 -0
  30. package/rr/sig.js +100 -0
  31. package/rr/smimea.js +73 -0
  32. package/rr/soa.js +140 -0
  33. package/rr/spf.js +54 -0
  34. package/rr/srv.js +122 -0
  35. package/rr/sshfp.js +86 -0
  36. package/rr/tlsa.js +106 -0
  37. package/rr/txt.js +122 -0
  38. package/rr/uri.js +95 -0
  39. package/rr.js +291 -0
  40. package/test/a.js +76 -0
  41. package/test/aaaa.js +79 -0
  42. package/test/base.js +138 -0
  43. package/test/caa.js +104 -0
  44. package/test/cert.js +48 -0
  45. package/test/cname.js +41 -0
  46. package/test/dname.js +53 -0
  47. package/test/dnskey.js +44 -0
  48. package/test/ds.js +44 -0
  49. package/test/fake.js +26 -0
  50. package/test/hinfo.js +75 -0
  51. package/test/ipseckey.js +115 -0
  52. package/test/key.js +37 -0
  53. package/test/loc.js +71 -0
  54. package/test/mx.js +75 -0
  55. package/test/naptr.js +40 -0
  56. package/test/ns.js +53 -0
  57. package/test/nsec.js +38 -0
  58. package/test/nsec3.js +26 -0
  59. package/test/nsec3param.js +26 -0
  60. package/test/openpgpkey.js +35 -0
  61. package/test/ptr.js +54 -0
  62. package/test/rr.js +196 -0
  63. package/test/smimea.js +45 -0
  64. package/test/soa.js +77 -0
  65. package/test/spf.js +48 -0
  66. package/test/srv.js +81 -0
  67. package/test/sshfp.js +62 -0
  68. package/test/tinydns.js +140 -0
  69. package/test/tlsa.js +54 -0
  70. package/test/txt.js +70 -0
  71. package/test/uri.js +61 -0
package/rr/loc.js ADDED
@@ -0,0 +1,216 @@
1
+
2
+ import RR from '../rr.js'
3
+ import * as TINYDNS from '../lib/tinydns.js'
4
+
5
+ const REF = { // RFC 1876
6
+ LATLON : 2**31, // LAT equator, LON prime meridian
7
+ ALTITUDE: 100000 * 100, // reference spheroid used by GPS, in cm
8
+ }
9
+
10
+ const CONV = {
11
+ sec: 1000,
12
+ min: 60 * 1000,
13
+ deg: 60 * 60 * 1000,
14
+ }
15
+
16
+ export default class LOC extends RR {
17
+ constructor (opts) {
18
+ super(opts)
19
+ }
20
+
21
+ /****** Resource record specific setters *******/
22
+ setAddress (val) {
23
+ if (!val) throw new Error('LOC: address is required')
24
+
25
+ /*
26
+ ... LOC ( d1 [m1 [s1]] {"N"|"S"} d2 [m2 [s2]]
27
+ {"E"|"W"} alt["m"] [siz["m"] [hp["m"]
28
+ [vp["m"]]]] )
29
+ */
30
+ this.parseLoc(val)
31
+
32
+ this.set('address', val)
33
+ }
34
+
35
+ getDescription () {
36
+ return 'Location'
37
+ }
38
+
39
+ getRdataFields (arg) {
40
+ return [ 'address' ]
41
+ }
42
+
43
+ getRFCs () {
44
+ return [ 1876 ]
45
+ }
46
+
47
+ getTypeId () {
48
+ return 29
49
+ }
50
+
51
+ parseLoc (string) {
52
+
53
+ // d1 [m1 [s1]]
54
+ const dms = '(\\d+)\\s+(?:(\\d+)\\s+)?(?:([\\d.]+)\\s+)?'
55
+
56
+ // alt["m"] [siz["m"] [hp["m"] [vp["m"]]]]
57
+ const alt = '(-?[\\d.]+)m?(?:\\s+([\\d.]+)m?)?(?:\\s+([\\d.]+)m?)?(?:\\s+([\\d.]+)m?)?'
58
+
59
+ // put them all together
60
+ const locRe = new RegExp(`^${dms}(N|S)\\s+${dms}(E|W)\\s+${alt}`, 'i')
61
+ const r = string.match(locRe)
62
+ if (!r) throw new Error('LOC address: invalid format, see RFC 1876')
63
+
64
+ const loc = {
65
+ latitude: {
66
+ degrees : r[1],
67
+ minutes : r[2],
68
+ seconds : r[3],
69
+ hemisphere: r[4].toUpperCase(),
70
+ },
71
+ longitude: {
72
+ degrees : r[5],
73
+ minutes : r[6],
74
+ seconds : r[7],
75
+ hemisphere: r[8].toUpperCase(),
76
+ },
77
+ altitude : r[9] * 100, // m -> cm
78
+ size : r[10] * 100,
79
+ precision: {
80
+ horizontal: r[11] * 100,
81
+ vertical : r[12] * 100,
82
+ },
83
+ }
84
+
85
+ return loc
86
+ }
87
+
88
+ /****** IMPORTERS *******/
89
+ fromTinydns (opts) {
90
+ // LOC via generic, :fqdn:n:rdata:ttl:timestamp:lo
91
+ const [ fqdn, n, rdata, ttl, ts, loc ] = opts.tinyline.substring(1).split(':')
92
+ if (n != 29) throw new Error('LOC fromTinydns, invalid n')
93
+
94
+ // divide by 100 is to convert cm to meters
95
+ const l = {
96
+ version : TINYDNS.octalToUInt8(rdata.substring(0, 4)),
97
+ size : this.fromExponent(TINYDNS.octalToUInt8(rdata.substring(4, 8))),
98
+ precision: {
99
+ horizontal: this.fromExponent(TINYDNS.octalToUInt8(rdata.substring( 8, 12))),
100
+ vertical : this.fromExponent(TINYDNS.octalToUInt8(rdata.substring(12, 16))),
101
+ },
102
+ latitude : this.arcSecToDMS(TINYDNS.octalToUInt32(rdata.substring(16, 32)), 'lat'),
103
+ longitude: this.arcSecToDMS(TINYDNS.octalToUInt32(rdata.substring(32, 48)), 'lon'),
104
+ altitude : TINYDNS.octalToUInt32(rdata.substring(48, 64)) - REF.ALTITUDE,
105
+ }
106
+
107
+ return new LOC({
108
+ type : 'LOC',
109
+ owner : this.fullyQualify(fqdn),
110
+ address : this.toHuman(l),
111
+ ttl : parseInt(ttl, 10),
112
+ timestamp: ts,
113
+ location : loc !== '' && loc !== '\n' ? loc : '',
114
+ })
115
+ }
116
+
117
+ fromBind (opts) {
118
+ const [ owner, ttl, c, type ] = opts.bindline.split(/\s+/)
119
+
120
+ return new LOC({
121
+ owner,
122
+ ttl : parseInt(ttl, 10),
123
+ class : c,
124
+ type : type,
125
+ address: opts.bindline.split(/\s+/).slice(4).join(' ').trim(),
126
+ })
127
+ }
128
+
129
+ dmsToArcSec (obj) {
130
+ let retval = (obj.degrees * CONV.deg) + ((obj.minutes || 0) * CONV.min) + ((obj.seconds || 0) * CONV.sec)
131
+ switch (obj.hemisphere.toUpperCase()) {
132
+ case 'W':
133
+ case 'S':
134
+ retval = -retval
135
+ break
136
+ }
137
+ retval += REF.LATLON
138
+ return retval
139
+ }
140
+
141
+ arcSecToDMS (rawmsec, latlon) {
142
+ let msec = Math.abs(rawmsec - REF.LATLON)
143
+ // console.log(`rawmsec: ${rawmsec}, abs msec: ${msec}`)
144
+
145
+ const deg = Math.floor(msec / CONV.deg)
146
+ msec -= deg * CONV.deg
147
+
148
+ const min = Math.floor(msec / CONV.min)
149
+ msec -= min * CONV.min
150
+
151
+ const sec = Math.floor(msec / CONV.sec)
152
+ msec -= sec * CONV.sec
153
+
154
+ let hem
155
+ switch (latlon) {
156
+ case 'lat':
157
+ hem = rawmsec >= REF.LATLON ? 'N' : 'S'
158
+ break
159
+ case 'lon':
160
+ hem = rawmsec >= REF.LATLON ? 'E' : 'W'
161
+ break
162
+ default:
163
+ throw new Error('unknown or missing hemisphere')
164
+ }
165
+
166
+ return `${deg} ${min} ${sec}${msec ? '.'+msec : ''} ${hem}`
167
+ }
168
+
169
+ fromExponent (prec) {
170
+ const mantissa = ((prec >> 4) & 0x0f) % 10
171
+ const exponent = ((prec >> 0) & 0x0f) % 10
172
+ return mantissa * Math.pow(10, exponent)
173
+ }
174
+
175
+ toExponent (val) {
176
+ /*
177
+ RFC 1876, ... expressed as a pair of four-bit unsigned
178
+ integers, each ranging from zero to nine, with the most
179
+ significant four bits representing the base and the second
180
+ number representing the power of ten by which to multiply
181
+ the base.
182
+ */
183
+ let exponent = 0
184
+ while (val >= 10) {
185
+ val /= 10
186
+ ++exponent
187
+ }
188
+ return (parseInt(val) << 4) | (exponent & 0x0f)
189
+ }
190
+
191
+ toHuman (obj) {
192
+ let r = `${obj.latitude} ${obj.longitude} ${(obj.altitude/100)}m`
193
+ if (obj.size) r += ` ${obj.size/100}m`
194
+ if (obj.precision.horizontal) r += ` ${obj.precision.horizontal / 100}m`
195
+ if (obj.precision.vertical ) r += ` ${obj.precision.vertical / 100}m`
196
+ return r
197
+ }
198
+
199
+ /****** EXPORTERS *******/
200
+
201
+ toTinydns () {
202
+ const loc = this.parseLoc(this.get('address'))
203
+
204
+ // LOC format declares in meters, tinydns uses cm (hence * 100)
205
+ let rdata = ''
206
+ rdata += TINYDNS.UInt8toOctal(0) // version
207
+ rdata += TINYDNS.UInt8toOctal(this.toExponent(loc.size))
208
+ rdata += TINYDNS.UInt8toOctal(this.toExponent(loc.precision.horizontal))
209
+ rdata += TINYDNS.UInt8toOctal(this.toExponent(loc.precision.vertical))
210
+ rdata += TINYDNS.UInt32toOctal(this.dmsToArcSec(loc.latitude))
211
+ rdata += TINYDNS.UInt32toOctal(this.dmsToArcSec(loc.longitude))
212
+ rdata += TINYDNS.UInt32toOctal(loc.altitude + REF.ALTITUDE)
213
+
214
+ return this.getTinydnsGeneric(rdata)
215
+ }
216
+ }
package/rr/mx.js ADDED
@@ -0,0 +1,86 @@
1
+
2
+ import net from 'net'
3
+
4
+ import RR from '../rr.js'
5
+
6
+ export default class MX extends RR {
7
+ constructor (opts) {
8
+ super(opts)
9
+ }
10
+
11
+ /****** Resource record specific setters *******/
12
+ setPreference (val) {
13
+ if (val === undefined) val = this?.default?.preference
14
+ this.is16bitInt('MX', 'preference', val)
15
+ this.set('preference', val)
16
+ }
17
+
18
+ setExchange (val) {
19
+ if (!val) throw new Error('MX: exchange is required')
20
+
21
+ if (net.isIPv4(val) || net.isIPv6(val))
22
+ throw new Error(`MX: exchange must be a FQDN, ${this.citeRFC()}`)
23
+
24
+ this.isFullyQualified('MX', 'exchange', val)
25
+ this.isValidHostname('MX', 'exchange', val)
26
+
27
+ // RFC 4034: letters in the DNS names ... are lower cased
28
+ this.set('exchange', val.toLowerCase())
29
+ }
30
+
31
+ getDescription () {
32
+ return 'Mail Exchanger'
33
+ }
34
+
35
+ getRdataFields (arg) {
36
+ return [ 'preference', 'exchange' ]
37
+ }
38
+
39
+ getRFCs () {
40
+ return [ 1035, 2181, 7505 ]
41
+ }
42
+
43
+ getTypeId () {
44
+ return 15
45
+ }
46
+
47
+ /****** IMPORTERS *******/
48
+ fromTinydns (opts) {
49
+ // @fqdn:ip:x:dist:ttl:timestamp:lo
50
+ // eslint-disable-next-line no-unused-vars
51
+ const [ owner, ip, x, preference, ttl, ts, loc ] = opts.tinyline.substring(1).split(':')
52
+
53
+ return new MX({
54
+ type : 'MX',
55
+ owner : this.fullyQualify(owner),
56
+ exchange : this.fullyQualify(/\./.test(x) ? x : `${x}.mx.${owner}`),
57
+ preference: parseInt(preference, 10) || 0,
58
+ ttl : parseInt(ttl, 10),
59
+ timestamp : ts,
60
+ location : loc !== '' && loc !== '\n' ? loc : '',
61
+ })
62
+ }
63
+
64
+ fromBind (opts) {
65
+ // test.example.com 3600 IN MX preference exchange
66
+ const [ owner, ttl, c, type, preference, exchange ] = opts.bindline.split(/\s+/)
67
+
68
+ return new MX({
69
+ owner,
70
+ ttl : parseInt(ttl, 10),
71
+ class : c,
72
+ type,
73
+ preference: parseInt(preference),
74
+ exchange,
75
+ })
76
+ }
77
+
78
+ /****** EXPORTERS *******/
79
+ toBind (zone_opts) {
80
+ return `${this.getPrefix(zone_opts)}\t${this.get('preference')}\t${this.getFQDN('exchange', zone_opts)}\n`
81
+ }
82
+
83
+ toTinydns () {
84
+ return `@${this.getTinyFQDN('owner')}::${this.getTinyFQDN('exchange')}:${this.get('preference')}:${this.getTinydnsPostamble()}\n`
85
+ }
86
+ }
package/rr/naptr.js ADDED
@@ -0,0 +1,146 @@
1
+
2
+ import RR from '../rr.js'
3
+ import * as TINYDNS from '../lib/tinydns.js'
4
+
5
+ const rdataRe = /[\r\n\t:\\/]/
6
+
7
+ export default class NAPTR extends RR {
8
+ constructor (opts) {
9
+ super(opts)
10
+ }
11
+
12
+ getDescription () {
13
+ return 'Naming Authority Pointer'
14
+ }
15
+
16
+ getQuotedFields () {
17
+ return [ 'flags', 'service', 'regexp' ]
18
+ }
19
+
20
+ getRdataFields (arg) {
21
+ return [ 'order', 'preference', 'flags', 'service', 'regexp', 'replacement' ]
22
+ }
23
+
24
+ getRFCs () {
25
+ return [ 2915, 3403 ]
26
+ }
27
+
28
+ getTypeId () {
29
+ return 35
30
+ }
31
+
32
+ /****** Resource record specific setters *******/
33
+ setOrder (val) {
34
+ this.is16bitInt('NAPTR', 'order', val)
35
+ this.set('order', val)
36
+ }
37
+
38
+ setPreference (val) {
39
+ this.is16bitInt('NAPTR', 'preference', val)
40
+ this.set('preference', val)
41
+ }
42
+
43
+ setFlags (val) {
44
+ if (![ '', 'S', 'A', 'U', 'P' ].includes(val.toUpperCase()))
45
+ throw new Error (`NAPTR flags are invalid, ${this.citeRFC()}`)
46
+
47
+ this.set('flags', val.toUpperCase())
48
+ }
49
+
50
+ setService (val) {
51
+ this.set('service', val)
52
+ }
53
+
54
+ setRegexp (val) {
55
+ this.set('regexp', val)
56
+ }
57
+
58
+ setReplacement (val) {
59
+ this.set('replacement', val)
60
+ }
61
+
62
+ /****** IMPORTERS *******/
63
+ fromTinydns (opts) {
64
+ // NAPTR via generic, :fqdn:n:rdata:ttl:timestamp:lo
65
+ const [ fqdn, n, rdata, ttl, ts, loc ] = opts.tinyline.substring(1).split(':')
66
+ if (n != 35) throw new Error('NAPTR fromTinydns, invalid n')
67
+
68
+ const binRdata = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
69
+
70
+ const rec = {
71
+ type : 'NAPTR',
72
+ owner : this.fullyQualify(fqdn),
73
+ ttl : parseInt(ttl, 10),
74
+ timestamp : ts,
75
+ location : loc !== '' && loc !== '\n' ? loc : '',
76
+ order : binRdata.readUInt16BE(0,2),
77
+ preference: binRdata.readUInt16BE(2,4),
78
+ }
79
+
80
+ let idx = 4
81
+ const flagsLength = binRdata.readUInt8(idx); idx++
82
+ rec.flags = binRdata.slice(idx, flagsLength).toString()
83
+ idx += flagsLength
84
+
85
+ const serviceLen = binRdata.readUInt8(idx); idx++
86
+ rec.service = binRdata.slice(idx, idx+serviceLen).toString()
87
+ idx += serviceLen
88
+
89
+ const regexpLen = binRdata.readUInt8(idx); idx++
90
+ rec.regexp = binRdata.slice(idx, idx+regexpLen).toString()
91
+ idx += regexpLen
92
+
93
+ const replaceLen = binRdata.readUInt8(idx); idx++
94
+ rec.replacement = binRdata.slice(idx, idx+replaceLen).toString()
95
+
96
+ return new NAPTR(rec)
97
+ }
98
+
99
+ fromBind (opts) {
100
+ const str = opts.bindline
101
+ // test.example.com 3600 IN NAPTR order, preference, "flags", "service", "regexp", replacement
102
+ const [ owner, ttl, c, type, order, preference ] = str.split(/\s+/)
103
+ const [ flags, service, regexp ] = str.match(/(?:").*?(?:"\s)/g)
104
+ const replacement = str.trim().split(/\s+/).pop()
105
+
106
+ const bits = {
107
+ owner : owner,
108
+ ttl : parseInt(ttl, 10),
109
+ class : c,
110
+ type : type,
111
+ order : parseInt(order, 10),
112
+ preference : parseInt(preference, 10),
113
+ flags : flags.trim().replace(/^['"]|['"]$/g, ''),
114
+ service : service.trim().replace(/^['"]|['"]$/g, ''),
115
+ regexp : regexp.trim().replace(/^['"]|['"]/g, ''),
116
+ replacement: replacement,
117
+ }
118
+ return new NAPTR(bits)
119
+ }
120
+
121
+ /****** EXPORTERS *******/
122
+ toTinydns () {
123
+
124
+ let rdata =
125
+ TINYDNS.UInt16toOctal(this.get('order')) +
126
+ TINYDNS.UInt16toOctal(this.get('preference')) +
127
+
128
+ TINYDNS.UInt8toOctal(this.get('flags').length) +
129
+ this.get('flags') +
130
+
131
+ TINYDNS.UInt8toOctal(this.get('service').length) +
132
+ TINYDNS.escapeOctal(rdataRe, this.get('service')) +
133
+
134
+ TINYDNS.UInt8toOctal(this.get('regexp').length) +
135
+ TINYDNS.escapeOctal(rdataRe, this.get('regexp'))
136
+
137
+ const replacement = this.get('replacement')
138
+ if (replacement !== '') {
139
+ rdata += TINYDNS.UInt8toOctal(replacement.length)
140
+ rdata += TINYDNS.escapeOctal(rdataRe, replacement)
141
+ }
142
+ rdata += '\\000'
143
+
144
+ return this.getTinydnsGeneric(rdata)
145
+ }
146
+ }
package/rr/ns.js ADDED
@@ -0,0 +1,74 @@
1
+
2
+ import RR from '../rr.js'
3
+
4
+ export default class NS extends RR {
5
+ constructor (opts) {
6
+ super(opts)
7
+ if (opts === null) return
8
+ }
9
+
10
+ /****** Resource record specific setters *******/
11
+ setDname (val) {
12
+ if (!val) throw new Error(`NS: dname is required, ${this.citeRFC()}`)
13
+
14
+ this.isFullyQualified('NS', 'dname', val)
15
+ this.isValidHostname('NS', 'dname', val)
16
+
17
+ // RFC 4034: letters in the DNS names are lower cased
18
+ this.set('dname', val.toLowerCase())
19
+ }
20
+
21
+ getDescription () {
22
+ return 'Name Server'
23
+ }
24
+
25
+ getRdataFields (arg) {
26
+ return [ 'dname' ]
27
+ }
28
+
29
+ getRFCs () {
30
+ return [ 1035 ]
31
+ }
32
+
33
+ getTypeId () {
34
+ return 2
35
+ }
36
+
37
+ /****** IMPORTERS *******/
38
+ fromTinydns (opts) {
39
+ // &fqdn:ip:x:ttl:timestamp:lo
40
+ // eslint-disable-next-line no-unused-vars
41
+ const [ fqdn, ip, dname, ttl, ts, loc ] = opts.tinyline.substring(1).split(':')
42
+
43
+ return new NS({
44
+ type : 'NS',
45
+ owner : this.fullyQualify(fqdn),
46
+ dname : this.fullyQualify(/\./.test(dname) ? dname : `${dname}.ns.${fqdn}`),
47
+ ttl : parseInt(ttl, 10),
48
+ timestamp: ts,
49
+ location : loc !== '' && loc !== '\n' ? loc : '',
50
+ })
51
+ }
52
+
53
+ fromBind (opts) {
54
+ // test.example.com 3600 IN NS dname
55
+ const [ owner, ttl, c, type, dname ] = opts.bindline.split(/\s+/)
56
+
57
+ return new NS({
58
+ owner,
59
+ ttl : parseInt(ttl, 10),
60
+ class: c,
61
+ type : type,
62
+ dname: dname,
63
+ })
64
+ }
65
+
66
+ /****** EXPORTERS *******/
67
+ toBind (zone_opts) {
68
+ return `${this.getPrefix(zone_opts)}\t${this.getFQDN('dname', zone_opts)}\n`
69
+ }
70
+
71
+ toTinydns () {
72
+ return `&${this.getTinyFQDN('owner')}::${this.getTinyFQDN('dname')}:${this.getTinydnsPostamble()}\n`
73
+ }
74
+ }
package/rr/nsec.js ADDED
@@ -0,0 +1,61 @@
1
+
2
+ import RR from '../rr.js'
3
+
4
+ export default class NSEC extends RR {
5
+ constructor (opts) {
6
+ super(opts)
7
+ if (opts === null) return
8
+ }
9
+
10
+ /****** Resource record specific setters *******/
11
+ setNextDomain (val) {
12
+ if (!val) throw new Error(`NSEC: 'next domain' is required:, ${this.citeRFC()}`)
13
+
14
+ this.isFullyQualified('NSEC', 'next domain', val)
15
+ this.isValidHostname('NSEC', 'next domain', val)
16
+
17
+ // RFC 4034: letters in the DNS names are lower cased
18
+ this.set('next domain', val.toLowerCase())
19
+ }
20
+
21
+ setTypeBitMaps (val) {
22
+ if (!val) throw new Error(`NSEC: 'type bit maps' is required, ${this.citeRFC()}`)
23
+
24
+ this.set('type bit maps', val)
25
+ }
26
+
27
+ getDescription () {
28
+ return 'Next Secure'
29
+ }
30
+
31
+ getRdataFields (arg) {
32
+ return [ 'next domain', 'type bit maps' ]
33
+ }
34
+
35
+ getRFCs () {
36
+ return [ 4034 ]
37
+ }
38
+
39
+ getTypeId () {
40
+ return 47
41
+ }
42
+
43
+ /****** IMPORTERS *******/
44
+
45
+ fromBind (opts) {
46
+ // test.example.com 3600 IN NSEC NextDomain TypeBitMaps
47
+ const [ owner, ttl, c, type, next ] = opts.bindline.split(/\s+/)
48
+ return new NSEC({
49
+ owner,
50
+ ttl : parseInt(ttl, 10),
51
+ class : c,
52
+ type : type,
53
+ 'next domain' : next,
54
+ 'type bit maps': opts.bindline.split(/\s+/).slice(5).filter(removeParens).join(' ').trim(),
55
+ })
56
+ }
57
+
58
+ /****** EXPORTERS *******/
59
+ }
60
+
61
+ const removeParens = a => ![ '(',')' ].includes(a)
package/rr/nsec3.js ADDED
@@ -0,0 +1,99 @@
1
+
2
+ import RR from '../rr.js'
3
+
4
+ export default class NSEC3 extends RR {
5
+ constructor (opts) {
6
+ super(opts)
7
+ if (opts === null) return
8
+ }
9
+
10
+ /****** Resource record specific setters *******/
11
+ setHashAlgoritm (val) {
12
+ // Hash Algorithm is a single octet.
13
+ // The Hash Algorithm field is represented as an unsigned decimal integer.
14
+ if (!val) throw new Error(`NSEC3: 'hash algorithm' is required, ${this.citeRFC()}`)
15
+
16
+ this.is8bitInt('NSEC3', 'hash algorithm', val)
17
+
18
+ this.set('hash algorithm', val)
19
+ }
20
+
21
+ setFlags (val) {
22
+ // The Flags field is represented as an unsigned decimal integer.
23
+ if (!val) throw new Error(`NSEC3: 'flags' is required, ${this.citeRFC()}`)
24
+
25
+ this.is8bitInt('NSEC3', 'flags', val)
26
+
27
+ this.set('flags', val)
28
+ }
29
+
30
+ setIterations (val) {
31
+ // The Iterations field is represented as an unsigned decimal integer. 0-65535
32
+ if (!val) throw new Error(`NSEC3: 'iterations' is required, ${this.citeRFC()}`)
33
+
34
+ this.is16bitInt('NSEC3', 'flags', val)
35
+
36
+ this.set('iterations', val)
37
+ }
38
+
39
+ setSalt (val) {
40
+ // The Salt field is represented as a sequence of case-insensitive
41
+ // hexadecimal digits. Whitespace is not allowed within the
42
+ // sequence. The Salt field is represented as "-" (without the
43
+ // quotes) when the Salt Length field has a value of 0
44
+ this.set('salt', val)
45
+ }
46
+
47
+ setNextHashedOwnerName (val) {
48
+ // The Next Hashed Owner Name field is represented as an unpadded
49
+ // sequence of case-insensitive base32 digits, without whitespace
50
+ if (!val) throw new Error(`NSEC3: 'next hashed owner name' is required, ${this.citeRFC()}`)
51
+
52
+ this.set('next hashed owner name', val)
53
+ }
54
+
55
+ setTypeBitMaps (val) {
56
+ // The Type Bit Maps field is represented as a sequence of RR type mnemonics.
57
+ if (!val) throw new Error(`NSEC3: 'type bit maps' is required, ${this.citeRFC()}`)
58
+
59
+ this.set('type bit maps', val)
60
+ }
61
+
62
+ getDescription () {
63
+ return 'Next Secure'
64
+ }
65
+
66
+ getRdataFields (arg) {
67
+ return [ 'hash algorithm', 'flags', 'iterations', 'salt', 'next hashed owner name', 'type bit maps' ]
68
+ }
69
+
70
+ getRFCs () {
71
+ return [ 5155, 9077 ]
72
+ }
73
+
74
+ getTypeId () {
75
+ return 50
76
+ }
77
+
78
+ /****** IMPORTERS *******/
79
+
80
+ fromBind (str) {
81
+ // test.example.com 3600 IN NSEC3
82
+ const [ owner, ttl, c, type ] = str.split(/\s+/)
83
+ return new NSEC3({
84
+ owner,
85
+ ttl : parseInt(ttl, 10),
86
+ class : c,
87
+ type : type,
88
+ 'hash algorithm' : '',
89
+ 'flags' : '',
90
+ 'iterations' : '',
91
+ 'salt' : '',
92
+ 'next hashed owner name': '',
93
+ 'type bit maps' : '',
94
+ })
95
+ }
96
+
97
+ /****** EXPORTERS *******/
98
+
99
+ }