diff --git a/dns.unpack-labels.js b/dns.unpack-labels.js index ca791e2..0956fc0 100644 --- a/dns.unpack-labels.js +++ b/dns.unpack-labels.js @@ -29,18 +29,19 @@ exports.DNS_UNPACK_LABELS = function (ui8, ptr, q) { break; } - if (0xc0 === len) { - var cpptr = ui8[total + 1]; + // Handle message compression pointers. See 4.1.4 of RFC1035 for details. + if (len >= 0xc0) { + var cpptr = ((ui8[total] & 0x3f) << 8) | ui8[total + 1]; - // we're not coming back! - ptr = 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.cpcount += 1; // recursion - return exports.DNS_UNPACK_LABELS(ui8, ptr, q); + return exports.DNS_UNPACK_LABELS(ui8, cpptr, q); } //str.length = 0; // fast empty array @@ -51,27 +52,28 @@ exports.DNS_UNPACK_LABELS = function (ui8, ptr, q) { ); } + // Advance the pointer to after the length indicator, then read the string in. + total += 1; for (i = 0; i < len; i += 1) { - total += 1; // TODO check url-allowable characters label.push(String.fromCharCode(ui8[total])); + total += 1; } if (label.length) { q.labels.push(label.join('')); } - total += 1; - + // 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('.'); - if (0 === q.cpcount) { - q.byteLength = total - ptr; - } - return q; }; diff --git a/test/fixtures/canone30522.local.bin b/test/fixtures/canone30522.local.bin new file mode 100644 index 0000000..0fccbcf Binary files /dev/null and b/test/fixtures/canone30522.local.bin differ diff --git a/test/fixtures/canone30522.local.js b/test/fixtures/canone30522.local.js new file mode 100644 index 0000000..169ca3f --- /dev/null +++ b/test/fixtures/canone30522.local.js @@ -0,0 +1,59 @@ +module.exports = { + "header": { + "id": 0, + "qr": 1, + "opcode": 0, + "aa": 0, + "tc": 0, + "rd": 0, + "ra": 0, + "res1": 0, + "res2": 0, + "res3": 0, + "rcode": 0 + }, + "question": [], + "answer": [ + { + "name": "_pdl-datastream._tcp.local", + "type": 12, + "class": 1, + "ttl": 255, + "data": "Canon MF620C Series._pdl-datastream._tcp.local" + } + ], + "additional": [ + { + "name": "Canone30522.local", + "type": 1, + "class": 32769, + "ttl": 255, + }, + { + "name": "Canon MF620C Series._pdl-datastream._tcp.local", + "type": 33, + "class": 32769, + "ttl": 255, + }, + { + "name": "Canon MF620C Series._pdl-datastream._tcp.local", + "type": 16, + "class": 32769, + "ttl": 255, + }, + { + "name": "Canone30522.local", + "type": 47, + "class": 32769, + "ttl": 255, + }, + { + "name": "Canon MF620C Series._pdl-datastream._tcp.local", + "type": 47, + "class": 32769, + "ttl": 255, + } + ], + "authority": [], + "edns_options": [] +};