2017-01-28 22:15:27 +00:00
|
|
|
(function (exports) {
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
// unpack labels with 0x20 compression pointer support
|
|
|
|
|
|
|
|
// ui8 is the ArrayBuffer of the entire packet
|
|
|
|
// ptr is the current index of the packet
|
|
|
|
// q = { byteLength: 0, cpcount: 0, labels: [], name: '' }
|
2017-02-03 02:43:56 +00:00
|
|
|
//
|
|
|
|
// NOTE:
|
|
|
|
// "NAME"s are terminated with 0x00
|
|
|
|
// "RDATA" is terminated by its length
|
2017-01-28 22:15:27 +00:00
|
|
|
exports.DNS_UNPACK_LABELS = function (ui8, ptr, q) {
|
|
|
|
if (q.cpcount > 25) {
|
|
|
|
throw new Error("compression pointer loop detected (over 25 pointers seems like a loop)");
|
|
|
|
}
|
|
|
|
|
|
|
|
var total = ptr;
|
|
|
|
var i;
|
|
|
|
|
|
|
|
var len;
|
|
|
|
var label = [];
|
|
|
|
|
|
|
|
do {
|
|
|
|
label.length = 0;
|
|
|
|
len = ui8[total];
|
2017-02-03 01:39:32 +00:00
|
|
|
if (len === undefined){
|
2017-02-03 02:43:56 +00:00
|
|
|
// RDATA is terminated by undefined, not len === 0
|
|
|
|
break;
|
2017-02-03 01:39:32 +00:00
|
|
|
}
|
2017-02-03 02:43:56 +00:00
|
|
|
|
2017-05-30 22:18:48 +00:00
|
|
|
// Handle message compression pointers. See 4.1.4 of RFC1035 for details.
|
|
|
|
if (len >= 0xc0) {
|
|
|
|
var cpptr = ((ui8[total] & 0x3f) << 8) | ui8[total + 1];
|
2017-01-28 22:15:27 +00:00
|
|
|
|
2017-05-30 22:18:48 +00:00
|
|
|
// We're not coming back, so if this is the first time we're following one of
|
|
|
|
// these pointers we up the byteLength to mark the pointer as part of the label
|
2017-02-11 16:54:27 +00:00
|
|
|
if (!q.cpcount) {
|
|
|
|
q.byteLength += 2; // cp and len
|
|
|
|
}
|
2017-01-28 22:15:27 +00:00
|
|
|
q.cpcount += 1;
|
2017-02-03 01:39:32 +00:00
|
|
|
|
2017-02-03 02:43:56 +00:00
|
|
|
// recursion
|
2017-05-30 22:18:48 +00:00
|
|
|
return exports.DNS_UNPACK_LABELS(ui8, cpptr, q);
|
2017-01-28 22:15:27 +00:00
|
|
|
}
|
2017-02-03 02:43:56 +00:00
|
|
|
|
2017-01-28 22:15:27 +00:00
|
|
|
//str.length = 0; // fast empty array
|
|
|
|
if (ui8.byteLength - total < len) {
|
2017-09-28 19:13:18 +00:00
|
|
|
//console.error('-1', ui8[total - 1]);
|
|
|
|
//console.error(' 0', ui8[total]);
|
|
|
|
//console.error(' 1', ui8[total + 1]);
|
|
|
|
//console.error(' 1', ui8[total + 2]);
|
2017-01-28 22:15:27 +00:00
|
|
|
throw new Error(
|
|
|
|
"Expected a string of length " + len
|
|
|
|
+ " but packet itself has " + (ui8.byteLength - total) + " bytes remaining"
|
|
|
|
);
|
|
|
|
}
|
2017-02-03 02:43:56 +00:00
|
|
|
|
2017-05-30 22:18:48 +00:00
|
|
|
// Advance the pointer to after the length indicator, then read the string in.
|
|
|
|
total += 1;
|
2017-01-28 22:15:27 +00:00
|
|
|
for (i = 0; i < len; i += 1) {
|
|
|
|
// TODO check url-allowable characters
|
|
|
|
label.push(String.fromCharCode(ui8[total]));
|
2017-05-30 22:18:48 +00:00
|
|
|
total += 1;
|
2017-01-28 22:15:27 +00:00
|
|
|
}
|
2017-02-03 02:43:56 +00:00
|
|
|
|
2017-01-28 22:15:27 +00:00
|
|
|
if (label.length) {
|
|
|
|
q.labels.push(label.join(''));
|
|
|
|
}
|
2017-02-03 02:43:56 +00:00
|
|
|
|
2017-05-30 22:18:48 +00:00
|
|
|
// It is important this be done every time, so that if we run into a message compression
|
|
|
|
// pointer later we still have a record of what was consumed before that.
|
|
|
|
if (0 === q.cpcount) {
|
|
|
|
q.byteLength = total - ptr;
|
|
|
|
}
|
2017-02-03 02:43:56 +00:00
|
|
|
} while (0 !== len && undefined !== len);
|
2017-01-28 22:15:27 +00:00
|
|
|
|
|
|
|
//str.pop(); // remove trailing '.'
|
|
|
|
|
|
|
|
q.name = q.labels.join('.');
|
|
|
|
return q;
|
|
|
|
};
|
|
|
|
|
|
|
|
}('undefined' !== typeof window ? window : exports));
|