From 28b607857e5c16efe8a8f3dacc8ae6ef4fb4dca5 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Thu, 16 Feb 2017 15:52:07 -0700 Subject: [PATCH] WIP Packer --- dns.packer.js | 13 ++---------- dns.packer.type.a.js | 21 +++++++++++++++++++ dns.packer.type.aaaa.js | 34 ++++++++++++++++++++++++++++++ dns.rdata.pack.js | 45 ++++++++++++++++++++++++++++++++++++++++ dns.rdata.parse.js | 3 --- test/packer.type.a.js | 30 +++++++++++++++++++++++++++ test/packer.type.aaaa.js | 41 ++++++++++++++++++++++++++++++++++++ 7 files changed, 173 insertions(+), 14 deletions(-) create mode 100644 dns.packer.type.a.js create mode 100644 dns.packer.type.aaaa.js create mode 100644 dns.rdata.pack.js create mode 100644 test/packer.type.a.js create mode 100644 test/packer.type.aaaa.js diff --git a/dns.packer.js b/dns.packer.js index 210d076..ce65ae4 100644 --- a/dns.packer.js +++ b/dns.packer.js @@ -77,16 +77,6 @@ var dnspack = exports.DNS_PACKER = { total += 4; // two bytes type two bytes class } - function packRdata(a) { - dv.setUint16(total, 8, false); - total += 2; - dv.setUint32(total, 0xFFFFFFFF, false) - total += 4; - dv.setUint32(total, 0xFFFFFFFF, false) - total += 4; - //throw new Error('not implemented'); - } - function packAnswer(a) { packQuestion(a); @@ -107,7 +97,7 @@ var dnspack = exports.DNS_PACKER = { total += 1; }); } else { - packRdata(a); + dnspack.packRdata(ab, dv, total, a); } } @@ -148,5 +138,6 @@ var dnspack = exports.DNS_PACKER = { } }; +dnspack.packRdata = exports.DNS_RDATA_PACK || require('./dns.rdata.pack.js').DNS_RDATA_PACK; }('undefined' !== typeof window ? window : exports)); diff --git a/dns.packer.type.a.js b/dns.packer.type.a.js new file mode 100644 index 0000000..a4c24f3 --- /dev/null +++ b/dns.packer.type.a.js @@ -0,0 +1,21 @@ +(function (exports) { +'use strict'; + +// An 'A' record is a 32-bit value representing the IP address + +exports.DNS_PACKER_TYPE_A = function (ab, dv, total, record) { + if (!record.address) { + throw new Error("no address on A record"); + } + + // i.e. 127.0.0.1 => 0x7F, 0x00, 0x00, 0x01 + //record.rdlength = 4; + record.address.split('.').forEach(function (octet) { + dv.setUint8(total, parseInt(octet, 10), false); + total += 1; + }); + + return total; +}; + +}('undefined' !== typeof window ? window : exports)); diff --git a/dns.packer.type.aaaa.js b/dns.packer.type.aaaa.js new file mode 100644 index 0000000..307d17c --- /dev/null +++ b/dns.packer.type.aaaa.js @@ -0,0 +1,34 @@ +(function (exports) { +'use strict'; + +// 'AAAA' +// Value: IP Address +// Meaning:Use: 16 octets (8 sexdectets, 128 bits) represting the IP address + +exports.DNS_PACKER_TYPE_AAAA = function (ab, dv, total, record) { + if (!record.address) { + throw new Error("no address on A record"); + } + + // i.e. ::1 => 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001 + // i.e. FFFF:DDDD::1 => 0xFFFF, 0xDDDD, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001 + //record.rdlength = 16; + var address = '0' + record.address; // prevent case of two leading blanks, such as '::1' + var parts = address.split(':'); + parts.forEach(function (sedectet, i) { + if (!sedectet) { + parts[i] = '0'; + while (parts.length < 8) { + parts.splice(i + 1, 0, '0'); + } + } + }); + parts.forEach(function (sedectet) { + dv.setUint16(total, parseInt(sedectet, 16), false); + total += 2; + }); + + return total; +}; + +}('undefined' !== typeof window ? window : exports)); diff --git a/dns.rdata.pack.js b/dns.rdata.pack.js new file mode 100644 index 0000000..a26be4c --- /dev/null +++ b/dns.rdata.pack.js @@ -0,0 +1,45 @@ +(function (exports) { +'use strict'; + +var classes = exports.DNS_CLASSES || require('./dns.classes.js').DNS_CLASSES; +var types = exports.DNS_TYPES || require('./dns.types.js').DNS_TYPES; + +exports.DNS_RDATA_PACK = function (ab, dv, total, record) { + // ab is needed if the rdata makes use of compression pointers + // packet is given for convenience + var packer; + var className = classes[record.class]; + var typeName = types[record.type]; + + + if (!className) { + throw new Error("Support for DNS Class 0x" + record.class.toString(16) + " (" + record.class + ")" + + " is not implemented yet. Open an issue if you actually need support" + + " (i.e. you're not working with a malformed packet)" + ); + } + + if (!typeName) { + throw new Error("Support for DNS Type 0x" + record.type.toString(16) + " (" + record.type + ")" + + " is not implemented yet. Open an issue if you actually need support" + + " (i.e. you're not working with a malformed packet)" + ); + } + + try { + packer = exports['DNS_PACKER_TYPE_' + typeName] + || require('./dns.packer.type.' + typeName.toLowerCase())['DNS_PACKER_TYPE_' + typeName]; + } + catch (e) { /*console.error(e)*/ } + + if (!packer) { + throw new Error("Packer for DNS Type " + typeName + " could not be loaded." + + " Did you include ?" + + " (or perhaps we plan to implement it and haven't yet - in which case please open an issue)" + ); + } + + return packer(ab, dv, total, record); +}; + +}('undefined' !== typeof window ? window : exports)); diff --git a/dns.rdata.parse.js b/dns.rdata.parse.js index afd7bd9..edd9f9f 100644 --- a/dns.rdata.parse.js +++ b/dns.rdata.parse.js @@ -1,9 +1,6 @@ (function (exports) { 'use strict'; -var classes = exports.DNS_CLASSES || require('./dns.classes.js').DNS_CLASSES; -var types = exports.DNS_TYPES || require('./dns.types.js').DNS_TYPES; - exports.DNS_RDATA_PARSE = function (ab, packet, record) { // ab is needed if the rdata makes use of compression pointers // packet is given for convenience diff --git a/test/packer.type.a.js b/test/packer.type.a.js new file mode 100644 index 0000000..4198fea --- /dev/null +++ b/test/packer.type.a.js @@ -0,0 +1,30 @@ +'use strict'; + +var packer = require('../dns.packer.type.a.js').DNS_PACKER_TYPE_A; +var ab = new ArrayBuffer(4); +var dv = new DataView(ab); +var total; + +// just to see that bytes are changed as a marker +dv.setUint32(0x0, 0xDDDDDDDD, false); + +[ '0.0.0.0' +, '127.0.0.1' +, '192.168.1.100' +, '216.21.170.44' +, '255.255.255.255' +].forEach(function (ipv4) { + total = 0; + total = packer(ab, dv, total, { address: ipv4 }); + if (0x04 !== total) { + console.error('unexpected total ' + total); + process.exit(1); + } + if (ipv4 !== new Uint8Array(ab).join('.')) { + console.error("expected: ", ipv4); + console.error("actual: ", new Uint8Array(ab).join('.')); + process.exit(1); + } +}); + +console.log('PASS'); diff --git a/test/packer.type.aaaa.js b/test/packer.type.aaaa.js new file mode 100644 index 0000000..75404fd --- /dev/null +++ b/test/packer.type.aaaa.js @@ -0,0 +1,41 @@ +'use strict'; + +var packer = require('../dns.packer.type.aaaa.js').DNS_PACKER_TYPE_AAAA; +var ab = new ArrayBuffer(20); +var dv = new DataView(ab); +var total = 0; + +// just to see that bytes are changed as a marker +dv.setUint16(0x0, 0xDDDD, false); +dv.setUint16(0x2, 0xDDDD, false); +dv.setUint16(0x4, 0xDDDD, false); +dv.setUint16(0x6, 0xDDDD, false); +dv.setUint16(0x8, 0xDDDD, false); +dv.setUint16(0xA, 0xDDDD, false); +dv.setUint16(0xC, 0xDDDD, false); +dv.setUint16(0xE, 0xDDDD, false); +dv.setUint16(0x10, 0xDDDD, false); +dv.setUint16(0x12, 0xDDDD, false); + +[ [ '::1' + , [ 0xDD, 0xDD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0xDD, 0xDD ].join(' ') ] +, [ 'fe80::1' + , [ 0xDD, 0xDD, 0xFE, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0xDD, 0xDD ].join(' ') ] +, [ 'fd41:50ca:2169:f4e:5020:f756:ca4e:c3b5' + , [ 0xDD, 0xDD, 0xFD, 0x41, 0x50, 0xCA, 0x21, 0x69, 0x0F, 0x4E + , 0x50, 0x20, 0xF7, 0x56, 0xCA, 0x4E, 0xC3, 0xB5, 0xDD, 0xDD ].join(' ') ] +].forEach(function (ipv6) { + total = 2; // leave leading 0x00 + total = packer(ab, dv, total, { address: ipv6[0] }); + if (0x12 !== total) { + console.error('unexpected total ' + total); + process.exit(1); + } + if (ipv6[1] !== new Uint8Array(ab).join(' ')) { + console.error("expected: ", ipv6[1]); + console.error("actual: ", new Uint8Array(ab).join(' ')); + process.exit(1); + } +}); + +console.log('PASS');