From eb8eeca4db8f573e6eb97c99e5bff60809e5a4c4 Mon Sep 17 00:00:00 2001 From: Matt Simerson Date: Sun, 10 Mar 2024 23:45:19 -0700 Subject: [PATCH] feat(zrs): test every type of zone record --- lib/test/rrs/https.json | 10 +++ lib/test/rrs/ipseckey.json | 12 ++++ lib/test/rrs/key.json | 11 +++ lib/test/rrs/loc.json | 8 +++ lib/test/rrs/naptr.json | 13 ++++ lib/test/rrs/nsec.json | 9 +++ lib/test/rrs/nsec3.json | 13 ++++ lib/test/rrs/nsec3param.json | 11 +++ lib/test/rrs/nxt.json | 9 +++ lib/test/rrs/openpgpkey.json | 8 +++ lib/test/rrs/ptr.json | 8 +++ lib/test/rrs/smimea.json | 11 +++ lib/test/rrs/soa.json | 14 ++++ lib/test/rrs/tlsa.json | 11 +++ lib/zone_record.js | 130 ++++++++++++++++++++++++++++++++++- lib/zone_record.test.js | 2 + test.js | 6 +- 17 files changed, 282 insertions(+), 4 deletions(-) create mode 100644 lib/test/rrs/https.json create mode 100644 lib/test/rrs/ipseckey.json create mode 100644 lib/test/rrs/key.json create mode 100644 lib/test/rrs/loc.json create mode 100644 lib/test/rrs/naptr.json create mode 100644 lib/test/rrs/nsec.json create mode 100644 lib/test/rrs/nsec3.json create mode 100644 lib/test/rrs/nsec3param.json create mode 100644 lib/test/rrs/nxt.json create mode 100644 lib/test/rrs/openpgpkey.json create mode 100644 lib/test/rrs/ptr.json create mode 100644 lib/test/rrs/smimea.json create mode 100644 lib/test/rrs/soa.json create mode 100644 lib/test/rrs/tlsa.json diff --git a/lib/test/rrs/https.json b/lib/test/rrs/https.json new file mode 100644 index 0000000..0d78492 --- /dev/null +++ b/lib/test/rrs/https.json @@ -0,0 +1,10 @@ +{ + "id": 4096, + "zid": 4096, + "owner": "_8443._foo.api.example.com.", + "priority": 0, + "target name": "svc4.example.net.", + "params": "alpn=\"bar\" port=\"8004\" ech=\"...\"", + "ttl": 86400, + "type": "HTTPS" +} diff --git a/lib/test/rrs/ipseckey.json b/lib/test/rrs/ipseckey.json new file mode 100644 index 0000000..bf6cceb --- /dev/null +++ b/lib/test/rrs/ipseckey.json @@ -0,0 +1,12 @@ +{ + "id": 4096, + "zid": 4096, + "owner": "38.2.0.192.in-addr.arpa.", + "ttl": 86400, + "type": "IPSECKEY", + "precedence": 10, + "gateway type": 1, + "algorithm": 2, + "gateway": "192.0.2.38", + "publickey": "AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==" +} diff --git a/lib/test/rrs/key.json b/lib/test/rrs/key.json new file mode 100644 index 0000000..7452fe7 --- /dev/null +++ b/lib/test/rrs/key.json @@ -0,0 +1,11 @@ +{ + "id": 4096, + "zid": 4096, + "owner": "example.com.", + "ttl": 86400, + "type": "KEY", + "flags": 256, + "protocol": 3, + "algorithm": 5, + "publickey": "( AQPSKmynfzW4kyBv015MUG2DeIQ3 Cbl+BBZH4b/0PY1kxkmvHjcZc8no kfzj31GajIQKY+5CptLr3buXA10h WqTkF7H6RfoRqXQeogmMHfpftf6z Mv1LyBUgia7za6ZEzOJBOztyvhjL 742iU/TpPSEDhm2SNKLijfUppn1U aNvv4w== )" +} diff --git a/lib/test/rrs/loc.json b/lib/test/rrs/loc.json new file mode 100644 index 0000000..4f3b7ea --- /dev/null +++ b/lib/test/rrs/loc.json @@ -0,0 +1,8 @@ +{ + "id": 4096, + "zid": 4096, + "owner": "loc.home.example.com.", + "ttl": 86400, + "type": "LOC", + "address": "47 43 47 N 122 21 35 W 132m 100m 100m 2m" +} diff --git a/lib/test/rrs/naptr.json b/lib/test/rrs/naptr.json new file mode 100644 index 0000000..95e406f --- /dev/null +++ b/lib/test/rrs/naptr.json @@ -0,0 +1,13 @@ +{ + "id": 4096, + "zid": 4096, + "ttl": 86400, + "type": "NAPTR", + "owner": "cid.urn.arpa.", + "order": 100, + "preference": 10, + "flags": "", + "service": "", + "regexp": "!^urn:cid:.+@([^\\.]+\\.)(.*)$!\\x02!i", + "replacement": "." +} diff --git a/lib/test/rrs/nsec.json b/lib/test/rrs/nsec.json new file mode 100644 index 0000000..60132ff --- /dev/null +++ b/lib/test/rrs/nsec.json @@ -0,0 +1,9 @@ +{ + "id": 4096, + "zid": 4096, + "ttl": 86400, + "type": "NSEC", + "owner": "alfa.example.com.", + "next domain": "host.example.com.", + "type bit maps": "A MX RRSIG NSEC TYPE1234" +} diff --git a/lib/test/rrs/nsec3.json b/lib/test/rrs/nsec3.json new file mode 100644 index 0000000..053d2a4 --- /dev/null +++ b/lib/test/rrs/nsec3.json @@ -0,0 +1,13 @@ +{ + "id": 4096, + "zid": 4096, + "ttl": 86400, + "type": "NSEC3", + "owner": "test.example.com.", + "hash algorithm": 1, + "flags": 1, + "iterations": 12, + "salt": "aabbccdd", + "type bit maps": "A\tRRSIG", + "next hashed owner name": "2vptu5timamqttgl4luu9kg21e0aor3s" +} diff --git a/lib/test/rrs/nsec3param.json b/lib/test/rrs/nsec3param.json new file mode 100644 index 0000000..4951995 --- /dev/null +++ b/lib/test/rrs/nsec3param.json @@ -0,0 +1,11 @@ +{ + "id": 4096, + "zid": 4096, + "ttl": 86400, + "type": "NSEC3PARAM", + "owner": "test.example.com.", + "hash algorithm": 1, + "flags": 1, + "iterations": 12, + "salt": "aabbccdd" +} diff --git a/lib/test/rrs/nxt.json b/lib/test/rrs/nxt.json new file mode 100644 index 0000000..2a1a5d3 --- /dev/null +++ b/lib/test/rrs/nxt.json @@ -0,0 +1,9 @@ +{ + "id": 4096, + "zid": 4096, + "ttl": 86400, + "type": "NXT", + "owner": "big.example.com.", + "next domain": "medium.example.com.", + "type bit map": "A SIG NXT" +} diff --git a/lib/test/rrs/openpgpkey.json b/lib/test/rrs/openpgpkey.json new file mode 100644 index 0000000..0908e1f --- /dev/null +++ b/lib/test/rrs/openpgpkey.json @@ -0,0 +1,8 @@ +{ + "id": 4096, + "zid": 4096, + "owner": "matt.example.com.", + "ttl": 86400, + "type": "OPENPGPKEY", + "public key": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nxsBNBGXucegBCAD+FLaLfH4QsU2DS2gkbI3QktOg27I2LQvdEI4mvR+nHGev1KK7\n...\n0VFBNRBmWIMXRAtmrzPyNp/nD7BymAQ=\n=kezp\n-----END PGP PUBLIC KEY BLOCK-----" +} diff --git a/lib/test/rrs/ptr.json b/lib/test/rrs/ptr.json new file mode 100644 index 0000000..0902e60 --- /dev/null +++ b/lib/test/rrs/ptr.json @@ -0,0 +1,8 @@ +{ + "id": 4096, + "zid": 4096, + "owner": "2.2.0.192.in-addr.arpa.", + "ttl": 86400, + "type": "PTR", + "dname": "dhcp.example.com." +} diff --git a/lib/test/rrs/smimea.json b/lib/test/rrs/smimea.json new file mode 100644 index 0000000..893faf1 --- /dev/null +++ b/lib/test/rrs/smimea.json @@ -0,0 +1,11 @@ +{ + "id": 4096, + "zid": 4096, + "owner": "_443._tcp.www.example.com.", + "ttl": 86400, + "type": "SMIMEA", + "certificate usage": 0, + "selector": 0, + "matching type": 1, + "certificate association data": "( d2abde240d7cd3ee6b4b28c54df034b9 7983a1d16e8a410e4561cb106618e971 )" +} diff --git a/lib/test/rrs/soa.json b/lib/test/rrs/soa.json new file mode 100644 index 0000000..bafdf9c --- /dev/null +++ b/lib/test/rrs/soa.json @@ -0,0 +1,14 @@ +{ + "id": 4096, + "zid": 4096, + "owner": "example.com.", + "ttl": 86400, + "type": "SOA", + "mname": "ns1.example.com.", + "rname": "matt.example.com.", + "serial": 1, + "refresh": 7200, + "retry": 3600, + "expire": 1209600, + "minimum": 3600 +} diff --git a/lib/test/rrs/tlsa.json b/lib/test/rrs/tlsa.json new file mode 100644 index 0000000..84d5a3c --- /dev/null +++ b/lib/test/rrs/tlsa.json @@ -0,0 +1,11 @@ +{ + "id": 4096, + "zid": 4096, + "owner": "_443._tcp.www.example.com.", + "ttl": 86400, + "type": "TLSA", + "certificate usage": 0, + "selector": 0, + "matching type": 1, + "certificate association data": "d2abde240d7cd3ee6b4b28c54df034b9 7983a1d16e8a410e4561cb106618e971" +} diff --git a/lib/zone_record.js b/lib/zone_record.js index ef17953..4d67e79 100644 --- a/lib/zone_record.js +++ b/lib/zone_record.js @@ -135,17 +135,77 @@ function objectToDb(obj) { } function applyMap(obj, map) { + // map dns-r-r (RFC/IETF) field names to NicTool 2.0 DB fields + for (const [key, value] of Object.entries(map)) { - obj[key] = obj[value] + if (Array.isArray(value)) { + obj[key] = `'${value.map((a) => obj[a]).join("','")}'` + for (const f of value) { + delete obj[f] + } + } else { + obj[key] = obj[value] + } + delete obj[value] } } function unApplyMap(obj, map) { + // map NicTool 2.0 DB fields to dns-r-r (RFC/IETF) field names + if (obj.type === 'NAPTR') { + const [flags, service, regexp] = obj.address.slice(1, -1).split("','") + obj.flags = flags ?? '' + obj.service = service ?? '' + obj.regexp = regexp ?? '' + delete obj.address + delete map.address + } + if (obj.type === 'NSEC3') { + const [algo, flags, iters, salt, bitmaps, next] = obj.address + .slice(1, -1) + .split("','") + obj['hash algorithm'] = /^\d+$/.test(algo) ? parseInt(algo) : algo ?? '' + obj.flags = /^\d+$/.test(flags) ? parseInt(flags) : flags ?? '' + obj.iterations = /^\d+$/.test(iters) ? parseInt(iters) : iters ?? '' + obj.salt = salt + obj['type bit maps'] = bitmaps + obj['next hashed owner name'] = next + delete obj.address + delete map.address + } + if (obj.type === 'NSEC3PARAM') { + const [algo, flags, iters, salt] = obj.address.slice(1, -1).split("','") + obj['hash algorithm'] = /^\d+$/.test(algo) ? parseInt(algo) : algo ?? '' + obj.flags = /^\d+$/.test(flags) ? parseInt(flags) : flags ?? '' + obj.iterations = /^\d+$/.test(iters) ? parseInt(iters) : iters ?? '' + obj.salt = salt + delete obj.address + delete map.address + } + if (obj.type === 'SOA') { + const [one, two, three, four, five, six, seven] = obj.address + .slice(1, -1) + .split("','") + obj.mname = one + obj.rname = two + obj.serial = parseInt(three) + obj.refresh = parseInt(four) + obj.retry = parseInt(five) + obj.expire = parseInt(six) + obj.minimum = parseInt(seven) + delete obj.address + delete map.address + } + for (const [key, value] of Object.entries(map)) { switch (value) { case 'key tag': // DS record case 'port': // SRV + case 'certificate usage': // SMIMEA + case 'algorithm': // IPSECKEY + case 'flags': // KEY + case 'matching type': // TLSA obj[value] = parseInt(obj[key]) break default: @@ -190,6 +250,11 @@ function getMap(rrType) { } case 'HINFO': return { address: 'os', other: 'cpu' } + case 'HTTPS': + return { + address: 'target name', + other: 'params', + } case 'IPSECKEY': return { address: 'gateway', @@ -198,16 +263,72 @@ function getMap(rrType) { priority: 'gateway type', other: 'algorithm', } + case 'KEY': + return { + address: 'publickey', + weight: 'protocol', + priority: 'algorithm', + other: 'flags', + } case 'MX': return { weight: 'preference', address: 'exchange' } case 'NAPTR': return { weight: 'order', priority: 'preference', + address: ['flags', 'service', 'regexp'], description: 'replacement', } case 'NS': return { address: 'dname' } + case 'NSEC': + return { + address: 'next domain', + description: 'type bit maps', + } + case 'NSEC3': + return { + address: [ + 'hash algorithm', + 'flags', + 'iterations', + 'salt', + 'type bit maps', + 'next hashed owner name', + ], + } + case 'NSEC3PARAM': + return { + address: ['hash algorithm', 'flags', 'iterations', 'salt'], + } + case 'NXT': + return { + address: 'next domain', + description: 'type bit map', + } + case 'OPENPGPKEY': + return { address: 'public key' } + case 'PTR': + return { address: 'dname' } + case 'SMIMEA': + return { + address: 'certificate association data', + weight: 'matching type', + priority: 'selector', + other: 'certificate usage', + } + case 'SOA': + return { + address: [ + 'mname', + 'rname', + 'serial', + 'refresh', + 'retry', + 'expire', + 'minimum', + ], + } case 'SPF': return { address: 'data' } case 'SSHFP': @@ -223,6 +344,13 @@ function getMap(rrType) { address: 'target name', other: 'params', } + case 'TLSA': + return { + weight: 'certificate usage', + priority: 'selector', + address: 'certificate association data', + other: 'matching type', + } case 'TXT': return { address: 'data' } case 'URI': diff --git a/lib/zone_record.test.js b/lib/zone_record.test.js index 4519a65..3184bf0 100644 --- a/lib/zone_record.test.js +++ b/lib/zone_record.test.js @@ -13,6 +13,8 @@ after(async () => { describe('zone_record', function () { for (const rrType of fs.readdirSync('./lib/test/rrs')) { + // console.log(rrType) + // if (rrType !== 'tlsa.json') continue describe(`${path.basename(rrType, '.json').toUpperCase()}`, function () { let testCase diff --git a/test.js b/test.js index 9de6e22..8d599df 100644 --- a/test.js +++ b/test.js @@ -8,12 +8,12 @@ import Session from './lib/session.js' import Permission from './lib/permission.js' import Nameserver from './lib/nameserver.js' import Zone from './lib/zone.js' -import ZoneRecord from './lib/zone_record.js' +// import ZoneRecord from './lib/zone_record.js' import groupCase from './lib/test/group.json' with { type: 'json' } import userCase from './lib/test/user.json' with { type: 'json' } import zoneCase from './lib/test/zone.json' with { type: 'json' } -import zrCase from './lib/test/zone_record.json' with { type: 'json' } +// import zrCase from './lib/test/zone_record.json' with { type: 'json' } import groupCaseR from './routes/test/group.json' with { type: 'json' } import userCaseR from './routes/test/user.json' with { type: 'json' } import nsCaseR from './routes/test/nameserver.json' with { type: 'json' } @@ -51,7 +51,7 @@ async function setup() { // } async function teardown() { - await ZoneRecord.destroy({ id: zrCase.id }) + // await ZoneRecord.destroy({ id: zrCase.id }) await Zone.destroy({ id: zoneCase.id }) await Nameserver.destroy({ id: nsCaseR.id }) await Nameserver.destroy({ id: nsCaseR.id - 1 })