WIP Packer
This commit is contained in:
parent
367c0207d0
commit
12fef62e09
|
@ -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
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
117
dns.packer.js
117
dns.packer.js
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
Loading…
Reference in New Issue