@nictool/dns-resource-record 1.2.3 → 1.3.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/rr/rp.js ADDED
@@ -0,0 +1,78 @@
1
+ import RR from '../rr.js'
2
+
3
+ import * as TINYDNS from '../lib/tinydns.js'
4
+
5
+ export default class RP extends RR {
6
+ constructor(opts) {
7
+ super(opts)
8
+ }
9
+
10
+ /****** Resource record specific setters *******/
11
+ setMbox(val) {
12
+ if (!val) this.throwHelp('RP: mbox is required')
13
+
14
+ this.isFullyQualified('RP', 'mbox', val)
15
+
16
+ this.set('mbox', val.toLowerCase())
17
+ }
18
+
19
+ setTxt(val) {
20
+ if (!val) this.throwHelp('RP: txt is required')
21
+
22
+ this.isFullyQualified('RP', 'txt', val)
23
+
24
+ this.set('txt', val.toLowerCase())
25
+ }
26
+
27
+ getDescription() {
28
+ return 'Responsible Person'
29
+ }
30
+
31
+ getRdataFields(arg) {
32
+ return ['mbox', 'txt']
33
+ }
34
+
35
+ getRFCs() {
36
+ return [1183]
37
+ }
38
+
39
+ getTypeId() {
40
+ return 17
41
+ }
42
+
43
+ getCanonical() {
44
+ return {
45
+ owner: 'example.com.',
46
+ ttl: 3600,
47
+ class: 'IN',
48
+ type: 'RP',
49
+ mbox: 'admin.example.com.',
50
+ txt: 'info.example.com.',
51
+ }
52
+ }
53
+
54
+ /****** IMPORTERS *******/
55
+ fromBind(opts) {
56
+ // test.example.com 3600 IN RP mbox txt
57
+ const [owner, ttl, c, type, mbox, txt] = opts.bindline.split(/\s+/)
58
+ return new RP({
59
+ owner,
60
+ ttl: parseInt(ttl, 10),
61
+ class: c,
62
+ type,
63
+ mbox,
64
+ txt,
65
+ })
66
+ }
67
+
68
+ /****** EXPORTERS *******/
69
+ toBind(zone_opts) {
70
+ return `${this.getPrefix(zone_opts)}\t${this.getFQDN('mbox', zone_opts)}\t${this.getFQDN('txt', zone_opts)}\n`
71
+ }
72
+
73
+ toTinydns() {
74
+ return this.getTinydnsGeneric(
75
+ TINYDNS.packDomainName(this.get('mbox')) + TINYDNS.packDomainName(this.get('txt')),
76
+ )
77
+ }
78
+ }
package/rr/rrsig.js CHANGED
@@ -16,13 +16,23 @@ export default class RRSIG extends RR {
16
16
 
17
17
  setAlgorithm(val) {
18
18
  // a 1 octet Algorithm field
19
- // 1=RSA/MD5, 2=DH, 3=RRSIGA/SHA-1, 4=EC, 5=RSA/SHA-1
20
- if (![1, 2, 3, 4, 5, 253, 254].includes(val))
21
- this.throwHelp(`RRSIG: algorithm invalid`)
19
+ if (!this.getAlgorithmOptions().has(val)) this.throwHelp(`RRSIG: algorithm invalid`)
22
20
 
23
21
  this.set('algorithm', val)
24
22
  }
25
23
 
24
+ getAlgorithmOptions() {
25
+ return new Map([
26
+ [1, 'RSA/MD5'],
27
+ [2, 'DH'],
28
+ [3, 'RRSIGA/SHA-1'],
29
+ [4, 'EC'],
30
+ [5, 'RSA/SHA-1'],
31
+ [253],
32
+ [254],
33
+ ])
34
+ }
35
+
26
36
  setLabels(val) {
27
37
  // a 1 octet Labels field
28
38
  this.is8bitInt('RRSIG', 'labels', val)
package/rr/smimea.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 SMIMEA extends RR {
4
6
  constructor(opts) {
5
7
  super(opts)
@@ -7,24 +9,47 @@ export default class SMIMEA extends RR {
7
9
 
8
10
  /****** Resource record specific setters *******/
9
11
  setCertificateUsage(val) {
10
- if (![0, 1, 2, 3].includes(val))
11
- this.throwHelp(`SMIMEA: certificate usage invalid`)
12
+ if (!this.getCertificateUsageOptions().has(val)) this.throwHelp(`SMIMEA: certificate usage invalid`)
12
13
 
13
14
  this.set('certificate usage', val)
14
15
  }
15
16
 
17
+ getCertificateUsageOptions() {
18
+ return new Map([
19
+ [0, 'CA certificate'],
20
+ [1, 'an end entity certificate'],
21
+ [2, 'the trust anchor'],
22
+ [3, 'domain-issued certificate'],
23
+ ])
24
+ }
25
+
16
26
  setSelector(val) {
17
- if (![0, 1].includes(val)) this.throwHelp(`SMIMEA: selector invalid`)
27
+ if (!this.getSelectorOptions().has(val)) this.throwHelp(`SMIMEA: selector invalid`)
18
28
 
19
29
  this.set('selector', val)
20
30
  }
21
31
 
32
+ getSelectorOptions() {
33
+ return new Map([
34
+ [0, 'Full certificate'],
35
+ [1, 'SubjectPublicKeyInfo'],
36
+ ])
37
+ }
38
+
22
39
  setMatchingType(val) {
23
- if (![0, 1, 2].includes(val)) this.throwHelp(`SMIMEA: matching type`)
40
+ if (!this.getMatchingTypeOptions().has(val)) this.throwHelp(`SMIMEA: matching type`)
24
41
 
25
42
  this.set('matching type', val)
26
43
  }
27
44
 
45
+ getMatchingTypeOptions() {
46
+ return new Map([
47
+ [0, 'Exact match'],
48
+ [1, 'SHA-256 hash'],
49
+ [2, 'SHA-512 hash'],
50
+ ])
51
+ }
52
+
28
53
  setCertificateAssociationData(val) {
29
54
  this.set('certificate association data', val)
30
55
  }
@@ -34,12 +59,7 @@ export default class SMIMEA extends RR {
34
59
  }
35
60
 
36
61
  getRdataFields(arg) {
37
- return [
38
- 'certificate usage',
39
- 'selector',
40
- 'matching type',
41
- 'certificate association data',
42
- ]
62
+ return ['certificate usage', 'selector', 'matching type', 'certificate association data']
43
63
  }
44
64
 
45
65
  getRFCs() {
@@ -58,8 +78,7 @@ export default class SMIMEA extends RR {
58
78
 
59
79
  fromBind(opts) {
60
80
  // test.example.com 3600 IN SMIMEA, usage, selector, match, data
61
- const [owner, ttl, c, type, usage, selector, match] =
62
- opts.bindline.split(/\s+/)
81
+ const [owner, ttl, c, type, usage, selector, match] = opts.bindline.split(/\s+/)
63
82
  return new SMIMEA({
64
83
  owner,
65
84
  ttl: parseInt(ttl, 10),
@@ -68,11 +87,19 @@ export default class SMIMEA extends RR {
68
87
  'certificate usage': parseInt(usage, 10),
69
88
  selector: parseInt(selector, 10),
70
89
  'matching type': parseInt(match, 10),
71
- 'certificate association data': opts.bindline
72
- .split(/\s+/)
73
- .slice(7)
74
- .join(' ')
75
- .trim(),
90
+ 'certificate association data': opts.bindline.split(/\s+/).slice(7).join(' ').trim(),
76
91
  })
77
92
  }
93
+
94
+ /****** EXPORTERS *******/
95
+ toTinydns() {
96
+ const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
97
+
98
+ return this.getTinydnsGeneric(
99
+ TINYDNS.UInt8toOctal(this.get('certificate usage')) +
100
+ TINYDNS.UInt8toOctal(this.get('selector')) +
101
+ TINYDNS.UInt8toOctal(this.get('matching type')) +
102
+ TINYDNS.escapeOctal(dataRe, this.get('certificate association data')),
103
+ )
104
+ }
78
105
  }
package/rr/soa.js CHANGED
@@ -86,19 +86,8 @@ export default class SOA extends RR {
86
86
  /****** IMPORTERS *******/
87
87
  fromBind(opts) {
88
88
  // example.com TTL IN SOA mname rname serial refresh retry expire minimum
89
- const [
90
- owner,
91
- ttl,
92
- c,
93
- type,
94
- mname,
95
- rname,
96
- serial,
97
- refresh,
98
- retry,
99
- expire,
100
- minimum,
101
- ] = opts.bindline.split(/[\s+]/)
89
+ const [owner, ttl, c, type, mname, rname, serial, refresh, retry, expire, minimum] =
90
+ opts.bindline.split(/[\s+]/)
102
91
 
103
92
  return new SOA({
104
93
  owner,
@@ -117,8 +106,7 @@ export default class SOA extends RR {
117
106
 
118
107
  fromTinydns(opts) {
119
108
  // Zfqdn:mname:rname:ser:ref:ret:exp:min:ttl:time:lo
120
- const [fqdn, mname, rname, ser, ref, ret, exp, min, ttl, ts, loc] =
121
- opts.tinyline.substring(1).split(':')
109
+ const [fqdn, mname, rname, ser, ref, ret, exp, min, ttl, ts, loc] = opts.tinyline.substring(1).split(':')
122
110
 
123
111
  return new SOA({
124
112
  owner: this.fullyQualify(fqdn),
package/rr/spf.js CHANGED
@@ -48,10 +48,7 @@ export default class SPF extends TXT {
48
48
 
49
49
  /****** EXPORTERS *******/
50
50
  toTinydns() {
51
- const rdata = TINYDNS.escapeOctal(
52
- new RegExp(/[\r\n\t:\\/]/, 'g'),
53
- this.get('data'),
54
- )
51
+ const rdata = TINYDNS.escapeOctal(new RegExp(/[\r\n\t:\\/]/, 'g'), this.get('data'))
55
52
  return this.getTinydnsGeneric(rdata)
56
53
  }
57
54
  }
package/rr/srv.js CHANGED
@@ -28,8 +28,7 @@ export default class SRV extends RR {
28
28
  setTarget(val) {
29
29
  if (!val) this.throwHelp(`SRV: target is required`)
30
30
 
31
- if (this.isIPv4(val) || this.isIPv6(val))
32
- this.throwHelp(`SRV: target must be a FQDN`)
31
+ if (this.isIPv4(val) || this.isIPv6(val)) this.throwHelp(`SRV: target must be a FQDN`)
33
32
 
34
33
  this.isFullyQualified('SRV', 'target', val)
35
34
  this.isValidHostname('SRV', 'target', val)
@@ -61,9 +60,7 @@ export default class SRV extends RR {
61
60
 
62
61
  if (str[0] === 'S') {
63
62
  // patched tinydns with S records
64
- ;[fqdn, addr, port, pri, weight, ttl, ts, loc] = str
65
- .substring(1)
66
- .split(':')
63
+ ;[fqdn, addr, port, pri, weight, ttl, ts, loc] = str.substring(1).split(':')
67
64
  } else {
68
65
  // tinydns generic record format
69
66
  ;[fqdn, n, rdata, ttl, ts, loc] = str.substring(1).split(':')
@@ -90,8 +87,7 @@ export default class SRV extends RR {
90
87
 
91
88
  fromBind(opts) {
92
89
  // test.example.com 3600 IN SRV Priority Weight Port Target
93
- const [owner, ttl, c, type, pri, weight, port, target] =
94
- opts.bindline.split(/\s+/)
90
+ const [owner, ttl, c, type, pri, weight, port, target] = opts.bindline.split(/\s+/)
95
91
  return new SRV({
96
92
  owner: owner,
97
93
  ttl: parseInt(ttl, 10),
package/rr/sshfp.js CHANGED
@@ -8,19 +8,36 @@ export default class SSHFP extends RR {
8
8
 
9
9
  /****** Resource record specific setters *******/
10
10
  setAlgorithm(val) {
11
- // 0: reserved 1: RSA 2: DSA 3: ECDSA 4: Ed25519 6: Ed448
12
11
  this.is8bitInt('SSHFP', 'algorithm', val)
13
12
 
14
13
  this.set('algorithm', val)
15
14
  }
16
15
 
16
+ getAlgorithmOptions() {
17
+ return new Map([
18
+ [0, 'reserved'],
19
+ [1, 'RSA'],
20
+ [2, 'DSA'],
21
+ [3, 'ECDSA'],
22
+ [4, 'Ed25519'],
23
+ [6, 'Ed448'],
24
+ ])
25
+ }
26
+
17
27
  setFptype(val) {
18
- // 0: reserved, 1: SHA-1, 2: SHA-256
19
- this.is8bitInt('SSHFP', 'type', val)
28
+ this.is8bitInt('SSHFP', 'fptype', val)
20
29
 
21
30
  this.set('fptype', val)
22
31
  }
23
32
 
33
+ getFptypeOptions() {
34
+ return new Map([
35
+ [0, 'reserved'],
36
+ [1, 'SHA-1'],
37
+ [2, 'SHA-256'],
38
+ ])
39
+ }
40
+
24
41
  setFingerprint(val) {
25
42
  this.set('fingerprint', val)
26
43
  }
package/rr/svcb.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 SVCB extends RR {
4
6
  constructor(opts) {
5
7
  super(opts)
@@ -61,4 +63,14 @@ export default class SVCB extends RR {
61
63
  }
62
64
 
63
65
  /****** EXPORTERS *******/
66
+
67
+ toTinydns() {
68
+ const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
69
+
70
+ return this.getTinydnsGeneric(
71
+ TINYDNS.UInt16toOctal(this.get('priority')) +
72
+ TINYDNS.packDomainName(this.get('target name')) +
73
+ TINYDNS.escapeOctal(dataRe, this.get('params')),
74
+ )
75
+ }
64
76
  }
package/rr/tlsa.js CHANGED
@@ -9,24 +9,47 @@ export default class TLSA extends RR {
9
9
 
10
10
  /****** Resource record specific setters *******/
11
11
  setCertificateUsage(val) {
12
- if (![0, 1, 2, 3].includes(val))
13
- this.throwHelp(`TLSA: certificate usage invalid`)
12
+ if (!this.getCertificateUsageOptions().has(val)) this.throwHelp(`TLSA: certificate usage invalid`)
14
13
 
15
14
  this.set('certificate usage', val)
16
15
  }
17
16
 
17
+ getCertificateUsageOptions() {
18
+ return new Map([
19
+ [0, 'CA certificate'],
20
+ [1, 'an end entity certificate'],
21
+ [2, 'the trust anchor'],
22
+ [3, 'domain-issued certificate'],
23
+ ])
24
+ }
25
+
18
26
  setSelector(val) {
19
- if (![0, 1].includes(val)) this.throwHelp(`TLSA: selector invalid`)
27
+ if (!this.getSelectorOptions().has(val)) this.throwHelp(`TLSA: selector invalid`)
20
28
 
21
29
  this.set('selector', val)
22
30
  }
23
31
 
32
+ getSelectorOptions() {
33
+ return new Map([
34
+ [0, 'Full certificate'],
35
+ [1, 'SubjectPublicKeyInfo'],
36
+ ])
37
+ }
38
+
24
39
  setMatchingType(val) {
25
- if (![0, 1, 2].includes(val)) this.throwHelp(`TLSA: matching type`)
40
+ if (!this.getMatchingTypeOptions().has(val)) this.throwHelp(`TLSA: matching type`)
26
41
 
27
42
  this.set('matching type', val)
28
43
  }
29
44
 
45
+ getMatchingTypeOptions() {
46
+ return new Map([
47
+ [0, 'Exact match'],
48
+ [1, 'SHA-256 hash'],
49
+ [2, 'SHA-512 hash'],
50
+ ])
51
+ }
52
+
30
53
  setCertificateAssociationData(val) {
31
54
  this.set('certificate association data', val)
32
55
  }
@@ -36,12 +59,7 @@ export default class TLSA extends RR {
36
59
  }
37
60
 
38
61
  getRdataFields(arg) {
39
- return [
40
- 'certificate usage',
41
- 'selector',
42
- 'matching type',
43
- 'certificate association data',
44
- ]
62
+ return ['certificate usage', 'selector', 'matching type', 'certificate association data']
45
63
  }
46
64
 
47
65
  getRFCs() {
@@ -60,19 +78,17 @@ export default class TLSA extends RR {
60
78
 
61
79
  fromBind(opts) {
62
80
  // test.example.com 3600 IN TLSA, usage, selector, match, data
63
- const match = opts.bindline
64
- .trim()
65
- .split(
66
- /^([^\s]+)\s+([0-9]{1,10})\s+(IN)\s+(TLSA)\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+(.*?)$/,
67
- )
81
+ const regex =
82
+ /^(?<owner>\S+)\s+(?<ttl>\d{1,10})\s+(?<cls>IN)\s+(?<type>TLSA)\s+(?<usage>\d+)\s+(?<selector>\d+)\s+(?<matchtype>\d+)\s+(?<cad>.+)$/i
83
+ const match = opts.bindline.trim().match(regex)
68
84
  if (!match) this.throwHelp(`unable to parse TLSA: ${opts.bindline}`)
69
- const [owner, ttl, c, type, usage, selector, matchtype, cad] =
70
- match.slice(1)
85
+ const { owner, ttl, cls, type, usage, selector, matchtype, cad } = match.groups
86
+
71
87
  return new TLSA({
72
88
  owner: this.fullyQualify(owner),
73
89
  ttl: parseInt(ttl, 10),
74
- class: c,
75
- type,
90
+ class: cls.toUpperCase(),
91
+ type: type.toUpperCase(),
76
92
  'certificate usage': parseInt(usage, 10),
77
93
  selector: parseInt(selector, 10),
78
94
  'matching type': parseInt(matchtype, 10),
package/rr/tsig.js CHANGED
@@ -13,15 +13,7 @@ export default class TSIG extends RR {
13
13
  }
14
14
 
15
15
  getRdataFields(arg) {
16
- return [
17
- 'algorithm name',
18
- 'time signed',
19
- 'fudge',
20
- 'mac',
21
- 'original id',
22
- 'error',
23
- 'other',
24
- ]
16
+ return ['algorithm name', 'time signed', 'fudge', 'mac', 'original id', 'error', 'other']
25
17
  }
26
18
 
27
19
  getRFCs() {
package/rr/txt.js CHANGED
@@ -70,17 +70,18 @@ export default class TXT extends RR {
70
70
 
71
71
  fromBind(opts) {
72
72
  // test.example.com 3600 IN TXT "..."
73
- const match = opts.bindline
74
- .trim()
75
- .split(/^([\S]{1,255})\s+([0-9]{1,10})\s+(IN)\s+(\w{3})\s+?\s*(.*?)$/i)
73
+ const regex =
74
+ /^(?<owner>[\S]{1,255})\s+(?<ttl>\d{1,10})\s+(?<cls>IN)\s+(?<type>\w{3})\s+?\s*(?<rdata>.+?)$/i
75
+ const match = opts.bindline.trim().match(regex)
76
76
  if (!match) this.throwHelp(`unable to parse TXT: ${opts.bindline}`)
77
- const [owner, ttl, c, type, rdata] = match.slice(1)
77
+
78
+ const { owner, ttl, cls, type, rdata } = match.groups
78
79
 
79
80
  return new this.constructor({
80
81
  owner,
81
82
  ttl: parseInt(ttl, 10),
82
- class: c,
83
- type,
83
+ class: cls,
84
+ type: type.toUpperCase(),
84
85
  data: rdata
85
86
  .match(/"([^"]+?)"/g)
86
87
  .map((s) => s.replace(/^"|"$/g, ''))
package/rr/uri.js CHANGED
@@ -46,8 +46,7 @@ export default class URI extends RR {
46
46
 
47
47
  fromBind(opts) {
48
48
  // test.example.com 3600 IN URI priority, weight, target
49
- const [owner, ttl, c, type, priority, weight, target] =
50
- opts.bindline.split(/\s+/)
49
+ const [owner, ttl, c, type, priority, weight, target] = opts.bindline.split(/\s+/)
51
50
  return new URI({
52
51
  class: c,
53
52
  type: type,
package/rr/wks.js CHANGED
@@ -1,19 +1,36 @@
1
1
  import RR from '../rr.js'
2
2
 
3
+ import * as TINYDNS from '../lib/tinydns.js'
4
+
3
5
  export default class WKS extends RR {
4
6
  constructor(opts) {
5
7
  super(opts)
6
- if (opts === null) return
7
8
  }
8
9
 
9
10
  /****** Resource record specific setters *******/
11
+ setAddress(val) {
12
+ if (!val) this.throwHelp('WKS: address is required')
13
+ if (!this.isIPv4(val)) this.throwHelp('WKS address must be IPv4')
14
+ this.set('address', val)
15
+ }
16
+
17
+ setProtocol(val) {
18
+ if (!val) this.throwHelp('WKS: protocol is required')
19
+ const upper = typeof val === 'string' ? val.toUpperCase() : val
20
+ if (!['TCP', 'UDP', 6, 17].includes(upper)) this.throwHelp('WKS protocol must be TCP or UDP')
21
+ this.set('protocol', upper)
22
+ }
23
+
24
+ setBitMap(val) {
25
+ this.set('bit map', val ?? '')
26
+ }
10
27
 
11
28
  getDescription() {
12
29
  return 'Well Known Service'
13
30
  }
14
31
 
15
32
  getRdataFields(arg) {
16
- return ['bit map']
33
+ return ['address', 'protocol', 'bit map']
17
34
  }
18
35
 
19
36
  getRFCs() {
@@ -27,19 +44,31 @@ export default class WKS extends RR {
27
44
  /****** IMPORTERS *******/
28
45
 
29
46
  fromBind(opts) {
30
- // test.example.com 3600 IN WKS 192.168.1.1 TCP 25
31
- const [owner, ttl, c, type, address, protocol, bitmap] =
32
- opts.bindline.split(/\s+/)
47
+ // test.example.com 3600 IN WKS 192.168.1.1 TCP ftp smtp
48
+ const parts = opts.bindline.split(/\s+/)
49
+ const [owner, ttl, c, type, address, protocol] = parts
33
50
  return new WKS({
34
51
  owner,
35
52
  ttl: parseInt(ttl, 10),
36
53
  class: c,
37
54
  type,
38
- address, // 32-bit int
39
- protocol, // 8-bit int, 6=TCP, 17=UDP
40
- bitmap, // var len bit map, must be multiple of 8
55
+ address,
56
+ protocol,
57
+ 'bit map': parts.slice(6).join(' ').trim(),
41
58
  })
42
59
  }
43
60
 
44
61
  /****** EXPORTERS *******/
62
+
63
+ toTinydns() {
64
+ const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
65
+ const protoMap = { TCP: 6, UDP: 17, 6: 6, 17: 17 }
66
+ const protoNum = protoMap[this.get('protocol')]
67
+
68
+ return this.getTinydnsGeneric(
69
+ TINYDNS.ipv4toOctal(this.get('address')) +
70
+ TINYDNS.UInt8toOctal(protoNum) +
71
+ TINYDNS.escapeOctal(dataRe, this.get('bit map')),
72
+ )
73
+ }
45
74
  }