(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: '' } // // NOTE: // "NAME"s are terminated with 0x00 // "RDATA" is terminated by its length, but its labels may null-terminated 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]; if (len === undefined){ // RDATA is terminated by undefined, not len === 0 q.trunc = true; break; } // Handle message compression pointers. See 4.1.4 of RFC1035 for details. // 0xc0 // 192 // parseInt('11000000', 2).toString(16) if (len >= 0xc0) { // Only the two highest bits are used to signify the pointer. // The remaining bits may be used to specify the address of the pointer // (it would seem that only 1 extra bit is actually used since the message size is 512 bytes) var cpptr = ((ui8[total] & 0x3f) << 8) | ui8[total + 1]; if (cpptr >= total) { throw new Error( "Compression pointer at" + " 0x" + total.toString() + " (" + total + ")" + " points forward to" + " 0x" + cpptr.toString(16) + " (" + cpptr + ")" ); } // 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 if (!q.cpcount) { q.byteLength += 2; // cp and len //q.cps = []; } q.cpcount += 1; //q.cps.push(cpptr); // recursion return exports.DNS_UNPACK_LABELS(ui8, cpptr, q); } //str.length = 0; // fast empty array if (ui8.byteLength - total < len) { //console.error('-1', ui8[total - 1]); //console.error(' 0', ui8[total]); //console.error(' 1', ui8[total + 1]); //console.error(' 1', ui8[total + 2]); throw new Error( "Expected a string of length " + len + " but packet itself has " + (ui8.byteLength - total) + " bytes remaining" ); } // Advance the pointer to after the length indicator, then read the string in. total += 1; for (i = 0; i < len; i += 1) { // TODO check url-allowable characters label.push(String.fromCharCode(ui8[total])); total += 1; } if (label.length) { q.labels.push(label.join('')); } // 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; } } while (0 !== len && undefined !== len); //str.pop(); // remove trailing '.' q.name = q.labels.join('.'); return q; }; }('undefined' !== typeof window ? window : exports));