WIP Packer

This commit is contained in:
AJ ONeal 2017-02-16 14:16:21 -07:00
parent 367c0207d0
commit 12fef62e09
5 changed files with 125 additions and 6 deletions

View File

@ -43,6 +43,7 @@ Similar API to `dns.js` and `native-dns-packet`.
, "answer": [] , "answer": []
, "authority": [] , "authority": []
, "additional": [] , "additional": []
, "edns_options": []
, "byteLength": 44 , "byteLength": 44
} }
``` ```

View File

@ -1,15 +1,21 @@
(function (exports) { (function (exports) {
'use strict'; 'use strict';
var classes = exports.DNS_CLASSES || require('./dns.classes.js').DNS_CLASSES;
var types = exports.DNS_TYPES || require('./dns.types.js').DNS_TYPES;
var dnspack = exports.DNS_PACKER = { var dnspack = exports.DNS_PACKER = {
pack: function (packet) { pack: function (packet) {
// TODO update for edns payload size
var ab = new ArrayBuffer(576); // http://serverfault.com/a/587626/93930
var dv = new DataView(ab);
var labelsMap = {};
var total = 0; var total = 0;
var id = packet.header.id; // 2 bytes var id = packet.header.id; // 2 bytes
var header = dnspack.packHeader(packet.header); // 2 bytes var header = dnspack.packHeader(packet.header); // 2 bytes
total = 12; // 2+2+2+2 bytes ({qd,an,ns,ar}count) total = 12; // 2+2+2+2 bytes ({qd,an,ns,ar}count)
var ab = new ArrayBuffer(total);
var dv = new DataView(ab);
dv.setUint16(0, id, false); dv.setUint16(0, id, false);
dv.setUint16(2, header, false); dv.setUint16(2, header, false);
dv.setUint16(4, packet.question.length, false); dv.setUint16(4, packet.question.length, false);
@ -18,8 +24,112 @@ var dnspack = exports.DNS_PACKER = {
// EDNS is added as an additional with TYPE 41 (OPT, 0x29) // EDNS is added as an additional with TYPE 41 (OPT, 0x29)
dv.setUint16(10, packet.additional.length + (packet.payload ? 1 : 0), false); dv.setUint16(10, packet.additional.length + (packet.payload ? 1 : 0), false);
return ab; function lint(r) {
if (!r.name) {
throw new Error("missing name");
}
if (!r.class) {
if (!r.className) {
throw new Error("no className");
}
r.class = classes[r.className];
}
if (!r.type) {
if (!r.typeName) {
throw new Error("no typeName");
}
r.type = types[r.typeName];
if (!r.type) {
console.warn("ignoring invalid type '" + r.type + "' for '" + r.name + "', ignoring");
}
}
}
function packLabel(sequence, terminates) {
if (terminates) {
// we don't want non-terminating rdata cached, just terminating names
labelsMap[total] = { total: total, name: sequence };
labelsMap[sequence] = labelsMap[total];
}
sequence.split('.').forEach(function (label) {
dv.setUint8(total, label.length, false);
total += 1;
label.split('').forEach(function (ch) {
dv.setUint8(total, ch.charCodeAt(0), false);
total += 1;
});
});
}
function packQuestion(q) {
lint(q);
packLabel(q.name);
// trailing 0 (null) as label sequence terminator
dv.setUint8(total, 0, false);
total += 1;
dv.setUint16(total, q.type, false);
dv.setUint16(total + 2, q.class, false);
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);
if ('undefined' === typeof a.ttl) {
throw new Error("missing ttl");
}
// 32-bit ttl
dv.setUint32(total, a.ttl, false);
total += 4;
if (a.rdata) {
// 16-bit
dv.setUint16(total, a.rdata.byteLength, false);
total += 2;
(new Uint8Array(a.rdata)).forEach(function (b) {
dv.setUint8(total, b, false);
total += 1;
});
} else {
packRdata(a);
}
}
//console.log(packet);
// fixed size, other than labels
packet.question.forEach(packQuestion);
packet.answer.forEach(packAnswer);
packet.authority.forEach(packAnswer);
packet.additional.forEach(packAnswer);
// TODO handle compression pointers
// TODO handle edns
return ab.slice(0, total);
} }
/*
, packLabels: function(map, labels) {
}
*/
, packHeader: function(h) { , packHeader: function(h) {
var val = 0; var val = 0;
@ -36,6 +146,7 @@ var dnspack = exports.DNS_PACKER = {
return val; return val;
} }
}; };
}('undefined' !== typeof window ? window : exports)); }('undefined' !== typeof window ? window : exports));

View File

@ -232,6 +232,7 @@ pdns.unpack = function (ab) {
packet.authority.push(rec); packet.authority.push(rec);
} }
packet.edns_options = [];
packet.additional = []; packet.additional = [];
for (i = 0; i < packet.arcount; i += 1) { for (i = 0; i < packet.arcount; i += 1) {
rec = unpackAnswer(ab, dv, ui8, total); rec = unpackAnswer(ab, dv, ui8, total);

View File

@ -14,6 +14,7 @@ var types = exports.DNS_TYPES = {
, OPT: 0x29 // 41 , OPT: 0x29 // 41
, ANY: 0xff // 255 , ANY: 0xff // 255
}; };
// and in reverse // and in reverse
Object.keys(types).forEach(function (key) { Object.keys(types).forEach(function (key) {
types[types[key]] = key; types[types[key]] = key;

View File

@ -32,9 +32,9 @@
h = '0' + h; h = '0' + h;
} }
return h; return h;
}).join('').match(/.{1,2}/g).join(' ').match(/.{1,47}/g).map(function (str) { }).join('').match(/.{1,2}/g).join(' ').match(/.{1,48}/g).map(function (str) {
var lead = bytecount.toString(16); var lead = bytecount.toString(16);
bytecount += 10; bytecount += 16;
while (lead.length < 7) { while (lead.length < 7) {
lead = '0' + lead; lead = '0' + lead;
@ -51,10 +51,15 @@
console.log('DEBUG with hexdump: '); console.log('DEBUG with hexdump: ');
console.log('hexdump ' + onefile.replace(/\.[^\.]*$/, '.bin')); console.log('hexdump ' + onefile.replace(/\.[^\.]*$/, '.bin'));
console.log(''); console.log('');
console.log(' 0 1 2 3 4 5 6 7 8 9 A B C D E F');
console.log(str + '\n' + trail); console.log(str + '\n' + trail);
console.log(''); console.log('');
console.error('test implementation not complete'); console.error('');
console.error('!!!');
console.error('Test implementation not complete.');
console.error('!!!');
console.error('');
process.exit(1); process.exit(1);
}()); }());