@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.
- package/.codeclimate.yml +25 -0
- package/CHANGELOG.md +253 -0
- package/DEVELOP.md +23 -0
- package/LICENSE +29 -0
- package/README.md +267 -0
- package/index.js +67 -0
- package/lib/tinydns.js +186 -0
- package/package.json +40 -0
- package/rr/a.js +65 -0
- package/rr/aaaa.js +137 -0
- package/rr/caa.js +129 -0
- package/rr/cert.js +75 -0
- package/rr/cname.js +76 -0
- package/rr/dname.js +74 -0
- package/rr/dnskey.js +117 -0
- package/rr/ds.js +104 -0
- package/rr/hinfo.js +84 -0
- package/rr/ipseckey.js +159 -0
- package/rr/key.js +73 -0
- package/rr/loc.js +216 -0
- package/rr/mx.js +86 -0
- package/rr/naptr.js +146 -0
- package/rr/ns.js +74 -0
- package/rr/nsec.js +61 -0
- package/rr/nsec3.js +99 -0
- package/rr/nsec3param.js +84 -0
- package/rr/openpgpkey.js +44 -0
- package/rr/ptr.js +65 -0
- package/rr/rrsig.js +101 -0
- package/rr/sig.js +100 -0
- package/rr/smimea.js +73 -0
- package/rr/soa.js +140 -0
- package/rr/spf.js +54 -0
- package/rr/srv.js +122 -0
- package/rr/sshfp.js +86 -0
- package/rr/tlsa.js +106 -0
- package/rr/txt.js +122 -0
- package/rr/uri.js +95 -0
- package/rr.js +291 -0
- package/test/a.js +76 -0
- package/test/aaaa.js +79 -0
- package/test/base.js +138 -0
- package/test/caa.js +104 -0
- package/test/cert.js +48 -0
- package/test/cname.js +41 -0
- package/test/dname.js +53 -0
- package/test/dnskey.js +44 -0
- package/test/ds.js +44 -0
- package/test/fake.js +26 -0
- package/test/hinfo.js +75 -0
- package/test/ipseckey.js +115 -0
- package/test/key.js +37 -0
- package/test/loc.js +71 -0
- package/test/mx.js +75 -0
- package/test/naptr.js +40 -0
- package/test/ns.js +53 -0
- package/test/nsec.js +38 -0
- package/test/nsec3.js +26 -0
- package/test/nsec3param.js +26 -0
- package/test/openpgpkey.js +35 -0
- package/test/ptr.js +54 -0
- package/test/rr.js +196 -0
- package/test/smimea.js +45 -0
- package/test/soa.js +77 -0
- package/test/spf.js +48 -0
- package/test/srv.js +81 -0
- package/test/sshfp.js +62 -0
- package/test/tinydns.js +140 -0
- package/test/tlsa.js +54 -0
- package/test/txt.js +70 -0
- package/test/uri.js +61 -0
package/rr/srv.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
|
|
2
|
+
import net from 'net'
|
|
3
|
+
|
|
4
|
+
import RR from '../rr.js'
|
|
5
|
+
import * as TINYDNS from '../lib/tinydns.js'
|
|
6
|
+
|
|
7
|
+
export default class SRV extends RR {
|
|
8
|
+
constructor (opts) {
|
|
9
|
+
super(opts)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/****** Resource record specific setters *******/
|
|
13
|
+
setPriority (val) {
|
|
14
|
+
this.is16bitInt('SRV', 'priority', val)
|
|
15
|
+
|
|
16
|
+
this.set('priority', val)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
setPort (val) {
|
|
20
|
+
this.is16bitInt('SRV', 'port', val)
|
|
21
|
+
|
|
22
|
+
this.set('port', val)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
setWeight (val) {
|
|
26
|
+
this.is16bitInt('SRV', 'weight', val)
|
|
27
|
+
|
|
28
|
+
this.set('weight', val)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
setTarget (val) {
|
|
32
|
+
if (!val) throw new Error(`SRV: target is required, ${this.citeRFC()}`)
|
|
33
|
+
|
|
34
|
+
if (net.isIPv4(val) || net.isIPv6(val))
|
|
35
|
+
throw new Error(`SRV: target must be a FQDN, ${this.citeRFC()}`)
|
|
36
|
+
|
|
37
|
+
this.isFullyQualified('SRV', 'target', val)
|
|
38
|
+
this.isValidHostname('SRV', 'target', val)
|
|
39
|
+
|
|
40
|
+
// RFC 4034: letters in the DNS names are lower cased
|
|
41
|
+
this.set('target', val.toLowerCase())
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getDescription () {
|
|
45
|
+
return 'Service'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getRdataFields (arg) {
|
|
49
|
+
return [ 'priority', 'weight', 'port', 'target' ]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getRFCs () {
|
|
53
|
+
return [ 2782 ]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
getTypeId () {
|
|
57
|
+
return 33
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/****** IMPORTERS *******/
|
|
61
|
+
fromTinydns (opts) {
|
|
62
|
+
const str = opts.tinyline
|
|
63
|
+
let fqdn, addr, port, pri, weight, ttl, ts, loc, n, rdata
|
|
64
|
+
|
|
65
|
+
if (str[0] === 'S') {
|
|
66
|
+
// patched tinydns with S records
|
|
67
|
+
[ fqdn, addr, port, pri, weight, ttl, ts, loc ] = str.substring(1).split(':')
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// tinydns generic record format
|
|
71
|
+
[ fqdn, n, rdata, ttl, ts, loc ] = str.substring(1).split(':')
|
|
72
|
+
if (n != 33) throw new Error('SRV fromTinydns: invalid n')
|
|
73
|
+
|
|
74
|
+
pri = TINYDNS.octalToUInt16(rdata.substring(0, 8))
|
|
75
|
+
weight = TINYDNS.octalToUInt16(rdata.substring(8, 16))
|
|
76
|
+
port = TINYDNS.octalToUInt16(rdata.substring(16, 24))
|
|
77
|
+
addr = (TINYDNS.unpackDomainName(rdata.substring(24)))[0]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return new SRV({
|
|
81
|
+
owner : this.fullyQualify(fqdn),
|
|
82
|
+
ttl : parseInt(ttl, 10),
|
|
83
|
+
type : 'SRV',
|
|
84
|
+
priority : parseInt(pri, 10),
|
|
85
|
+
weight : parseInt(weight, 10),
|
|
86
|
+
port : parseInt(port, 10),
|
|
87
|
+
target : this.fullyQualify(addr),
|
|
88
|
+
timestamp: ts,
|
|
89
|
+
location : loc !== '' && loc !== '\n' ? loc : '',
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
fromBind (opts) {
|
|
94
|
+
// test.example.com 3600 IN SRV Priority Weight Port Target
|
|
95
|
+
const [ owner, ttl, c, type, pri, weight, port, target ] = opts.bindline.split(/\s+/)
|
|
96
|
+
return new SRV({
|
|
97
|
+
owner : owner,
|
|
98
|
+
ttl : parseInt(ttl, 10),
|
|
99
|
+
class : c,
|
|
100
|
+
type : type,
|
|
101
|
+
priority: parseInt(pri, 10),
|
|
102
|
+
weight : parseInt(weight, 10),
|
|
103
|
+
port : parseInt(port, 10),
|
|
104
|
+
target : target,
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/****** EXPORTERS *******/
|
|
109
|
+
|
|
110
|
+
toTinydns () {
|
|
111
|
+
|
|
112
|
+
let rdata = ''
|
|
113
|
+
|
|
114
|
+
for (const e of [ 'priority', 'weight', 'port' ]) {
|
|
115
|
+
rdata += TINYDNS.UInt16toOctal(this.get(e))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
rdata += TINYDNS.packDomainName(this.get('target'))
|
|
119
|
+
|
|
120
|
+
return this.getTinydnsGeneric(rdata)
|
|
121
|
+
}
|
|
122
|
+
}
|
package/rr/sshfp.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
|
|
2
|
+
import RR from '../rr.js'
|
|
3
|
+
import * as TINYDNS from '../lib/tinydns.js'
|
|
4
|
+
|
|
5
|
+
export default class SSHFP extends RR {
|
|
6
|
+
constructor (opts) {
|
|
7
|
+
super(opts)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/****** Resource record specific setters *******/
|
|
11
|
+
setAlgorithm (val) {
|
|
12
|
+
// 0: reserved; 1: RSA 2: DSA 3: ECDSA 4: Ed25519 6:Ed448
|
|
13
|
+
this.is8bitInt('SSHFP', 'algorithm', val)
|
|
14
|
+
|
|
15
|
+
this.set('algorithm', val)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
setFptype (val) {
|
|
19
|
+
// 0: reserved, 1: SHA-1, 2: SHA-256
|
|
20
|
+
this.is8bitInt('SSHFP', 'type', val)
|
|
21
|
+
|
|
22
|
+
this.set('fptype', val)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
setFingerprint (val) {
|
|
26
|
+
this.set('fingerprint', val)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getDescription () {
|
|
30
|
+
return 'Secure Shell Key Fingerprints'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getRdataFields () {
|
|
34
|
+
return [ 'algorithm', 'fptype', 'fingerprint' ]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getRFCs () {
|
|
38
|
+
return [ 4255 ]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getTypeId () {
|
|
42
|
+
return 44
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/****** IMPORTERS *******/
|
|
46
|
+
fromTinydns (opts) {
|
|
47
|
+
// SSHFP via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
48
|
+
const [ fqdn, n, rdata, ttl, ts, loc ] = opts.tinyline.substring(1).split(':')
|
|
49
|
+
if (n != 44) throw new Error('SSHFP fromTinydns, invalid n')
|
|
50
|
+
|
|
51
|
+
return new SSHFP({
|
|
52
|
+
owner : this.fullyQualify(fqdn),
|
|
53
|
+
ttl : parseInt(ttl, 10),
|
|
54
|
+
type : 'SSHFP',
|
|
55
|
+
algorithm : TINYDNS.octalToUInt8(rdata.substring(0, 4)),
|
|
56
|
+
fptype : TINYDNS.octalToUInt8(rdata.substring(4, 8)),
|
|
57
|
+
fingerprint: TINYDNS.octalToHex(rdata.substring(8)),
|
|
58
|
+
timestamp : ts,
|
|
59
|
+
location : loc !== '' && loc !== '\n' ? loc : '',
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fromBind (opts) {
|
|
64
|
+
// test.example.com 3600 IN SSHFP algo fptype fp
|
|
65
|
+
const [ owner, ttl, c, type, algo, fptype, fp ] = opts.bindline.split(/\s+/)
|
|
66
|
+
return new SSHFP({
|
|
67
|
+
owner,
|
|
68
|
+
ttl : parseInt(ttl, 10),
|
|
69
|
+
class : c,
|
|
70
|
+
type : type,
|
|
71
|
+
algorithm : parseInt(algo, 10),
|
|
72
|
+
fptype : parseInt(fptype, 10),
|
|
73
|
+
fingerprint: fp,
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/****** EXPORTERS *******/
|
|
78
|
+
|
|
79
|
+
toTinydns () {
|
|
80
|
+
return this.getTinydnsGeneric(
|
|
81
|
+
TINYDNS.UInt8toOctal(this.get('algorithm')) +
|
|
82
|
+
TINYDNS.UInt8toOctal(this.get('fptype')) +
|
|
83
|
+
TINYDNS.packHex(this.get('fingerprint'))
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
}
|
package/rr/tlsa.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
|
|
2
|
+
import RR from '../rr.js'
|
|
3
|
+
|
|
4
|
+
import * as TINYDNS from '../lib/tinydns.js'
|
|
5
|
+
|
|
6
|
+
export default class TLSA extends RR {
|
|
7
|
+
constructor (opts) {
|
|
8
|
+
super(opts)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/****** Resource record specific setters *******/
|
|
12
|
+
setCertificateUsage (val) {
|
|
13
|
+
if (![ 0,1,2,3 ].includes(val))
|
|
14
|
+
throw new Error(`TLSA: certificate usage invalid, ${this.citeRFC()}`)
|
|
15
|
+
|
|
16
|
+
this.set('certificate usage', val)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
setSelector (val) {
|
|
20
|
+
if (![ 0,1 ].includes(val))
|
|
21
|
+
throw new Error(`TLSA: selector invalid, ${this.citeRFC()}`)
|
|
22
|
+
|
|
23
|
+
this.set('selector', val)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
setMatchingType (val) {
|
|
27
|
+
if (![ 0,1,2 ].includes(val))
|
|
28
|
+
throw new Error(`TLSA: matching type, ${this.citeRFC()}`)
|
|
29
|
+
|
|
30
|
+
this.set('matching type', val)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
setCertificateAssociationData (val) {
|
|
34
|
+
this.set('certificate association data', val)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getDescription () {
|
|
38
|
+
return 'TLSA certificate association'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getRdataFields (arg) {
|
|
42
|
+
return [ 'certificate usage', 'selector', 'matching type', 'certificate association data' ]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
getRFCs () {
|
|
46
|
+
return [ 6698 ]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
getTypeId () {
|
|
50
|
+
return 52
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getQuotedFields () {
|
|
54
|
+
return [ ]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/****** IMPORTERS *******/
|
|
58
|
+
|
|
59
|
+
fromBind (opts) {
|
|
60
|
+
// test.example.com 3600 IN TLSA, usage, selector, match, data
|
|
61
|
+
const match = opts.bindline.split(/^([^\s]+)\s+([0-9]+)\s+(\w+)\s+(\w+)\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+(.*?)\s*$/)
|
|
62
|
+
if (!match) throw new Error(`unable to parse TLSA: ${opts.bindline}`)
|
|
63
|
+
const [ owner, ttl, c, type, usage, selector, matchtype, cad ] = match.slice(1)
|
|
64
|
+
return new TLSA({
|
|
65
|
+
owner : this.fullyQualify(owner),
|
|
66
|
+
ttl : parseInt(ttl, 10),
|
|
67
|
+
class : c,
|
|
68
|
+
type,
|
|
69
|
+
'certificate usage' : parseInt(usage, 10),
|
|
70
|
+
selector : parseInt(selector, 10),
|
|
71
|
+
'matching type' : parseInt(matchtype, 10),
|
|
72
|
+
'certificate association data': cad,
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fromTinydns (opts) {
|
|
77
|
+
const [ fqdn, n, rdata, ttl, ts, loc ] = opts.tinyline.substring(1).split(':')
|
|
78
|
+
if (n != 52) throw new Error('TLSA fromTinydns, invalid n')
|
|
79
|
+
|
|
80
|
+
const bytes = Buffer.from(TINYDNS.octalToChar(rdata), 'binary')
|
|
81
|
+
|
|
82
|
+
return new TLSA({
|
|
83
|
+
owner : this.fullyQualify(fqdn),
|
|
84
|
+
ttl : parseInt(ttl, 10),
|
|
85
|
+
type : 'TLSA',
|
|
86
|
+
'certificate usage' : bytes.readUInt8(0),
|
|
87
|
+
selector : bytes.readUInt8(1),
|
|
88
|
+
'matching type' : bytes.readUInt8(2),
|
|
89
|
+
'certificate association data': bytes.slice(3).toString(),
|
|
90
|
+
timestamp : ts,
|
|
91
|
+
location : loc !== '' && loc !== '\n' ? loc : '',
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/****** EXPORTERS *******/
|
|
96
|
+
toTinydns () {
|
|
97
|
+
const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
|
|
98
|
+
|
|
99
|
+
return this.getTinydnsGeneric(
|
|
100
|
+
TINYDNS.UInt8toOctal(this.get('certificate usage')) +
|
|
101
|
+
TINYDNS.UInt8toOctal(this.get('selector')) +
|
|
102
|
+
TINYDNS.UInt8toOctal(this.get('matching type')) +
|
|
103
|
+
TINYDNS.escapeOctal(dataRe, this.get('certificate association data'))
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
}
|
package/rr/txt.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
|
|
2
|
+
import RR from '../rr.js'
|
|
3
|
+
|
|
4
|
+
import * as TINYDNS from '../lib/tinydns.js'
|
|
5
|
+
|
|
6
|
+
export default class TXT extends RR {
|
|
7
|
+
constructor (opts) {
|
|
8
|
+
super(opts)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/****** Resource record specific setters *******/
|
|
12
|
+
setData (val) {
|
|
13
|
+
this.set('data', val)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
getDescription () {
|
|
17
|
+
return 'Text'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
getRdataFields (arg) {
|
|
21
|
+
return [ 'data' ]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getRFCs () {
|
|
25
|
+
return [ 1035 ]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getTypeId () {
|
|
29
|
+
return 16
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/****** IMPORTERS *******/
|
|
33
|
+
fromTinydns (opts) {
|
|
34
|
+
const str = opts.tinyline
|
|
35
|
+
let fqdn, rdata, s, ttl, ts, loc
|
|
36
|
+
// 'fqdn:s:ttl:timestamp:lo
|
|
37
|
+
if (str[0] === "'") {
|
|
38
|
+
[ fqdn, s, ttl, ts, loc ] = str.substring(1).split(':')
|
|
39
|
+
rdata = TINYDNS.octalToChar(s)
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
[ fqdn, rdata, ttl, ts, loc ] = this.fromTinydnsGeneric(str)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return new this.constructor({
|
|
46
|
+
owner : this.fullyQualify(fqdn),
|
|
47
|
+
ttl : parseInt(ttl, 10),
|
|
48
|
+
type : 'TXT',
|
|
49
|
+
data : rdata,
|
|
50
|
+
timestamp: ts,
|
|
51
|
+
location : loc !== '' && loc !== '\n' ? loc : '',
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
fromTinydnsGeneric (str) {
|
|
56
|
+
// generic: :fqdn:n:rdata:ttl:timestamp:location
|
|
57
|
+
// eslint-disable-next-line prefer-const
|
|
58
|
+
let [ fqdn, n, rdata, ttl, ts, loc ] = str.substring(1).split(':')
|
|
59
|
+
if (n != 16) throw new Error('TXT fromTinydns, invalid n')
|
|
60
|
+
|
|
61
|
+
rdata = TINYDNS.octalToChar(rdata)
|
|
62
|
+
let s = ''
|
|
63
|
+
let len = rdata[0].charCodeAt(0)
|
|
64
|
+
let pos = 1
|
|
65
|
+
while (pos < rdata.length) {
|
|
66
|
+
s += rdata.substring(pos, +(len + pos))
|
|
67
|
+
pos = len + pos
|
|
68
|
+
len = rdata.charCodeAt(pos + 1)
|
|
69
|
+
}
|
|
70
|
+
return [ fqdn, s, ttl, ts, loc ]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fromBind (opts) {
|
|
74
|
+
// test.example.com 3600 IN TXT "..."
|
|
75
|
+
const match = opts.bindline.split(/^([^\s]+)\s+([0-9]+)\s+(\w+)\s+(\w+)\s+?\s*(.*?)\s*$/)
|
|
76
|
+
if (!match) throw new Error(`unable to parse TXT: ${opts.bindline}`)
|
|
77
|
+
const [ owner, ttl, c, type, rdata ] = match.slice(1)
|
|
78
|
+
|
|
79
|
+
return new this.constructor({
|
|
80
|
+
owner,
|
|
81
|
+
ttl : parseInt(ttl, 10),
|
|
82
|
+
class: c,
|
|
83
|
+
type,
|
|
84
|
+
data : rdata.match(/"([^"]+?)"/g).map(s => s.replace(/^"|"$/g, '')).join(''),
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/****** EXPORTERS *******/
|
|
89
|
+
toBind (zone_opts) {
|
|
90
|
+
return `${this.getPrefix(zone_opts)}\t"${asQuotedStrings(this.get('data'))}"\n`
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
toMaraDNS () {
|
|
94
|
+
const data = asQuotedStrings(this.get('data')).replace(/"/g, "'")
|
|
95
|
+
return `${this.get('owner')}\t+${this.get('ttl')}\t${this.get('type')}\t'${data}' ~\n`
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
toTinydns () {
|
|
99
|
+
let data = this.get('data')
|
|
100
|
+
if (Array.isArray(data)) data = data.join('')
|
|
101
|
+
const rdata = TINYDNS.escapeOctal(new RegExp(/[\r\n\t:\\/]/, 'g'), data)
|
|
102
|
+
return `'${this.getTinyFQDN('owner')}:${rdata}:${this.getTinydnsPostamble()}\n`
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function asQuotedStrings (data) {
|
|
107
|
+
|
|
108
|
+
// BIND croaks when any string in the TXT RR data is longer than 255
|
|
109
|
+
if (Array.isArray(data)) {
|
|
110
|
+
let hasTooLong = false
|
|
111
|
+
for (const str of data) {
|
|
112
|
+
if (str.length > 255) hasTooLong = true
|
|
113
|
+
}
|
|
114
|
+
return hasTooLong ? data.join('').match(/(.{1,255})/g).join('" "') : data.join('" "')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (data.length > 255) {
|
|
118
|
+
return data.match(/(.{1,255})/g).join('" "')
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return data
|
|
122
|
+
}
|
package/rr/uri.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
|
|
2
|
+
import RR from '../rr.js'
|
|
3
|
+
|
|
4
|
+
import * as TINYDNS from '../lib/tinydns.js'
|
|
5
|
+
|
|
6
|
+
export default class URI extends RR {
|
|
7
|
+
constructor (opts) {
|
|
8
|
+
super(opts)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/****** Resource record specific setters *******/
|
|
12
|
+
setPriority (val) {
|
|
13
|
+
this.is16bitInt('URI', 'priority', val)
|
|
14
|
+
|
|
15
|
+
this.set('priority', val)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
setWeight (val) {
|
|
19
|
+
this.is16bitInt('URI', 'weight', val)
|
|
20
|
+
|
|
21
|
+
this.set('weight', val)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
setTarget (val) {
|
|
25
|
+
if (!val) throw new Error(`URI: target is required, ${this.citeRFC()}`)
|
|
26
|
+
|
|
27
|
+
this.set('target', val)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/****** IMPORTERS *******/
|
|
31
|
+
fromTinydns (opts) {
|
|
32
|
+
// URI via generic, :fqdn:n:rdata:ttl:timestamp:lo
|
|
33
|
+
const [ fqdn, n, rdata, ttl, ts, loc ] = opts.tinyline.substring(1).split(':')
|
|
34
|
+
if (n != 256) throw new Error('URI fromTinydns, invalid n')
|
|
35
|
+
|
|
36
|
+
return new URI({
|
|
37
|
+
type : 'URI',
|
|
38
|
+
owner : this.fullyQualify(fqdn),
|
|
39
|
+
priority : TINYDNS.octalToUInt16(rdata.substring(0, 8)),
|
|
40
|
+
weight : TINYDNS.octalToUInt16(rdata.substring(8, 16)),
|
|
41
|
+
target : TINYDNS.octalToChar(rdata.substring(16)),
|
|
42
|
+
ttl : parseInt(ttl, 10),
|
|
43
|
+
timestamp: ts,
|
|
44
|
+
location : loc !== '' && loc !== '\n' ? loc : '',
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fromBind (opts) {
|
|
49
|
+
// test.example.com 3600 IN URI priority, weight, target
|
|
50
|
+
const [ owner, ttl, c, type, priority, weight, target ] = opts.bindline.split(/\s+/)
|
|
51
|
+
return new URI({
|
|
52
|
+
class : c,
|
|
53
|
+
type : type,
|
|
54
|
+
owner,
|
|
55
|
+
priority: parseInt(priority, 10),
|
|
56
|
+
weight : parseInt(weight, 10),
|
|
57
|
+
target : target.replace(/^"|"$/g, ''),
|
|
58
|
+
ttl : parseInt(ttl, 10),
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/****** MISC *******/
|
|
63
|
+
getDescription () {
|
|
64
|
+
return 'URI'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
getRdataFields (arg) {
|
|
68
|
+
return [ 'priority', 'weight', 'target' ]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getRFCs () {
|
|
72
|
+
return [ 7553 ]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
getTypeId () {
|
|
76
|
+
return 256
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
getQuotedFields () {
|
|
80
|
+
return [ 'target' ]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/****** EXPORTERS *******/
|
|
84
|
+
toTinydns () {
|
|
85
|
+
const dataRe = new RegExp(/[\r\n\t:\\/]/, 'g')
|
|
86
|
+
let rdata = ''
|
|
87
|
+
|
|
88
|
+
for (const e of [ 'priority', 'weight' ]) {
|
|
89
|
+
rdata += TINYDNS.UInt16toOctal(this.get(e))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
rdata += TINYDNS.escapeOctal(dataRe, this.get('target'))
|
|
93
|
+
return this.getTinydnsGeneric(rdata)
|
|
94
|
+
}
|
|
95
|
+
}
|