diff --git a/ChangeLog b/ChangeLog index 79e1f83..1056b02 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 2013-03-23 Timothy J Fontaine * Add SPF record type, same as TXT * Emit platform ready on windows (Oleg Elifantiev) + * Split packet parsing into its own library 2013-03-03 Timothy J Fontaine * Assert missing fields diff --git a/dns.js b/dns.js index ab20ef2..1b7a8c6 100644 --- a/dns.js +++ b/dns.js @@ -38,7 +38,7 @@ exports.resolveNs = client.resolveNs; exports.resolveCname = client.resolveCname; exports.reverse = client.reverse; -var consts = require('./lib/consts'); +var consts = require('native-dns-packet').consts; exports.BADNAME = consts.BADNAME; exports.BADRESP = consts.BADRESP; exports.CONNREFUSED = consts.CONNREFUSED; diff --git a/examples/client.js b/examples/client.js index 590c86d..3f92e5c 100644 --- a/examples/client.js +++ b/examples/client.js @@ -42,7 +42,7 @@ request = dns.resolveNs('linode.com', function (err, results) { }); }); -request = dns.resolveCname('www.google.com', function (err, results) { +request = dns.resolveCname('www.nodejs.org', function (err, results) { results.forEach(function (result) { console.log('www.google.com -->', result); }); diff --git a/lib/client.js b/lib/client.js index dc7c031..edabf63 100644 --- a/lib/client.js +++ b/lib/client.js @@ -26,7 +26,7 @@ var ipaddr = require('ipaddr.js'), EventEmitter = require('events').EventEmitter, PendingRequests = require('./pending'), Packet = require('./packet'), - consts = require('./consts'), + consts = require('native-dns-packet').consts, utils = require('./utils'), platform = require('./platform'); @@ -109,7 +109,7 @@ Request.prototype.handleTimeout = function() { Request.prototype.error = function(err) { if (!this.fired) { - debug('request error', this.id, this.question); + debug('request error', err, this.id, this.question); this.emit('error', err); this.done(); } @@ -179,7 +179,20 @@ var Resolve = function(opts) { this._started = false; this._current_server = undefined; + this._server_list = []; + if (opts.remote) { + this._server_list.push({ + address: opts.remote, + port: 53, + type: 'tcp', + }); + this._server_list.push({ + address: opts.remote, + port: 53, + type: 'udp', + }); + } this._request = undefined; this._type = 'getHostByName'; @@ -258,7 +271,8 @@ Resolve.prototype._preStart = function() { this._started = new Date().getTime(); this.try_edns = platform.edns; - this._fillServers(); + if (!this._server_list.length) + this._fillServers(); } }; @@ -376,15 +390,20 @@ Resolve.prototype._handleTimeout = function() { } }; -var resolve = function(domain, rrtype, callback) { +var resolve = function(domain, rrtype, ip, callback) { var res; + if (!callback) { + callback = ip; + ip = undefined; + } + if (!callback) { callback = rrtype; rrtype = undefined; } - rrtype = consts.NAME_TO_QTYPE[rrtype || A]; + rrtype = consts.NAME_TO_QTYPE[rrtype || 'A']; if (rrtype === PTR) { return reverse(domain, callback); @@ -392,7 +411,8 @@ var resolve = function(domain, rrtype, callback) { var opts = { domain: domain, - rrtype: rrtype + rrtype: rrtype, + remote: ip, }; res = new Resolve(opts); diff --git a/lib/consts.js b/lib/consts.js deleted file mode 100644 index 792d5b3..0000000 --- a/lib/consts.js +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2011 Timothy J Fontaine -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE - -'use strict'; - -function reverse_map(src) { - var dst = {}, - k; - - for (k in src) { - if (src.hasOwnProperty(k)) { - dst[src[k]] = k; - } - } - return dst; -} - -/* http://www.iana.org/assignments/dns-parameters */ -var NAME_TO_QTYPE = exports.NAME_TO_QTYPE = { - A: 1, - NS: 2, - MD: 3, - MF: 4, - CNAME: 5, - SOA: 6, - MB: 7, - MG: 8, - MR: 9, - 'NULL': 10, - WKS: 11, - PTR: 12, - HINFO: 13, - MINFO: 14, - MX: 15, - TXT: 16, - RP: 17, - AFSDB: 18, - X25: 19, - ISDN: 20, - RT: 21, - NSAP: 22, - 'NSAP-PTR': 23, - SIG: 24, - KEY: 25, - PX: 26, - GPOS: 27, - AAAA: 28, - LOC: 29, - NXT: 30, - EID: 31, - NIMLOC: 32, - SRV: 33, - ATMA: 34, - NAPTR: 35, - KX: 36, - CERT: 37, - A6: 38, - DNAME: 39, - SINK: 40, - OPT: 41, - APL: 42, - DS: 43, - SSHFP: 44, - IPSECKEY: 45, - RRSIG: 46, - NSEC: 47, - DNSKEY: 48, - DHCID: 49, - NSEC3: 50, - NSEC3PARAM: 51, - HIP: 55, - NINFO: 56, - RKEY: 57, - TALINK: 58, - CDS: 59, - SPF: 99, - UINFO: 100, - UID: 101, - GID: 102, - UNSPEC: 103, - TKEY: 249, - TSIG: 250, - IXFR: 251, - AXFR: 252, - MAILB: 253, - MAILA: 254, - ANY: 255, - URI: 256, - CAA: 257, - TA: 32768, - DLV: 32769 -}; -exports.QTYPE_TO_NAME = reverse_map(NAME_TO_QTYPE); - -exports.nameToQtype = function(n) { - return NAME_TO_QTYPE[n.toUpperCase()]; -}; - -exports.qtypeToName = function(t) { - return exports.QTYPE_TO_NAME[t]; -}; - -var NAME_TO_QCLASS = exports.NAME_TO_QCLASS = { - IN: 1 -}; -exports.QCLASS_TO_NAME = reverse_map(NAME_TO_QCLASS); - -exports.FAMILY_TO_QTYPE = { - 4: NAME_TO_QTYPE.A, - 6: NAME_TO_QTYPE.AAAA -}; -exports.QTYPE_TO_FAMILY = {}; -exports.QTYPE_TO_FAMILY[exports.NAME_TO_QTYPE.A] = 4; -exports.QTYPE_TO_FAMILY[exports.NAME_TO_QTYPE.AAAA] = 6; - -exports.NAME_TO_RCODE = { - NOERROR: 0, - FORMERR: 1, - SERVFAIL: 2, - NOTFOUND: 3, - NOTIMP: 4, - REFUSED: 5, - YXDOMAIN: 6, //Name Exists when it should not - YXRRSET: 7, //RR Set Exists when it should not - NXRRSET: 8, //RR Set that should exist does not - NOTAUTH: 9, - NOTZONE: 10, - BADVERS: 16, - BADSIG: 16, // really? - BADKEY: 17, - BADTIME: 18, - BADMODE: 19, - BADNAME: 20, - BADALG: 21, - BADTRUNC: 22 -}; -exports.RCODE_TO_NAME = reverse_map(exports.NAME_TO_RCODE); - -exports.BADNAME = 'EBADNAME'; -exports.BADRESP = 'EBADRESP'; -exports.CONNREFUSED = 'ECONNREFUSED'; -exports.DESTRUCTION = 'EDESTRUCTION'; -exports.REFUSED = 'EREFUSED'; -exports.FORMERR = 'EFORMERR'; -exports.NODATA = 'ENODATA'; -exports.NOMEM = 'ENOMEM'; -exports.NOTFOUND = 'ENOTFOUND'; -exports.NOTIMP = 'ENOTIMP'; -exports.SERVFAIL = 'ESERVFAIL'; -exports.TIMEOUT = 'ETIMEOUT'; diff --git a/lib/packet.js b/lib/packet.js index ec16757..df9621c 100644 --- a/lib/packet.js +++ b/lib/packet.js @@ -20,41 +20,15 @@ 'use strict'; -var consts = require('./consts'), - BufferCursor = require('buffercursor'), - BufferCursorOverflow = BufferCursor.BufferCursorOverflow, - ipaddr = require('ipaddr.js'), - assert = require('assert'), +var NDP = require('native-dns-packet'), util = require('util'); -function assertUndefined(val, msg) { - assert(typeof val != 'undefined', msg); -} - var Packet = module.exports = function(socket) { - this.header = { - id: 0, - qr: 0, - opcode: 0, - aa: 0, - tc: 0, - rd: 1, - ra: 0, - res1: 0, - res2: 0, - res3: 0, - rcode: 0 - }; - this.question = []; - this.answer = []; - this.authority = []; - this.additional = []; - this.edns_options = []; - this.payload = undefined; + NDP.call(this); this.address = undefined; - this._socket = socket; }; +util.inherits(Packet, NDP); Packet.prototype.send = function() { var buff, len, size; @@ -70,540 +44,10 @@ Packet.prototype.send = function() { this._socket.send(len); }; -var LABEL_POINTER = 0xC0; - -var isPointer = function(len) { - return (len & LABEL_POINTER) === LABEL_POINTER; -}; - -var name_unpack = function(buff, index) { - var parts, len, start, pos, i, part, combine = []; - - start = buff.tell(); - - parts = []; - len = buff.readUInt8(); - - while (len !== 0) { - if (isPointer(len)) { - len -= LABEL_POINTER; - len = len << 8; - pos = len + buff.readUInt8(); - parts.push({ - pos: pos, - value: index[pos] - }); - len = 0; - } else { - parts.push({ - pos: buff.tell() - 1, - value: buff.toString('ascii', len) - }); - len = buff.readUInt8(); - } - } - - for (i = parts.length - 1; i >= 0; i--) { - part = parts[i]; - combine.splice(0, 0, part.value); - index[part.pos] = combine.join('.'); - } - - return combine.join('.'); -}; - -var name_pack = function(str, buff, index) { - var offset, dot, part; - - while (str) { - if (index[str]) { - offset = (LABEL_POINTER << 8) + index[str]; - buff.writeUInt16BE(offset); - break; - } else { - index[str] = buff.tell(); - dot = str.indexOf('.'); - if (dot > -1) { - part = str.slice(0, dot); - str = str.slice(dot + 1); - } else { - part = str; - str = undefined; - } - buff.writeUInt8(part.length); - buff.write(part, part.length, 'ascii'); - } - } - - if (!str) { - buff.writeUInt8(0); - } -}; - -Packet.write = function(buff, packet) { - var state, - next, - name, - val, - section, - count, - pos, - rdata_pos, - last_resource, - label_index = {}; - - buff = BufferCursor(buff); - - if (typeof(packet.edns_version) !== 'undefined') { - state = 'EDNS'; - } else { - state = 'HEADER'; - } - - while (true) { - try { - switch (state) { - case 'EDNS': - val = { - name: '', - type: consts.NAME_TO_QTYPE.OPT, - class: packet.payload - }; - pos = packet.header.rcode; - val.ttl = packet.header.rcode >> 4; - packet.header.rcode = pos - (val.ttl << 4); - val.ttl = (val.ttl << 8) + packet.edns_version; - val.ttl = (val.ttl << 16) + (packet.do << 15) & 0x8000; - packet.additional.splice(0, 0, val); - state = 'HEADER'; - break; - case 'HEADER': - assert(packet.header, 'Packet requires "header"'); - buff.writeUInt16BE(packet.header.id & 0xFFFF); - val = 0; - val += (packet.header.qr << 15) & 0x8000; - val += (packet.header.opcode << 11) & 0x7800; - val += (packet.header.aa << 10) & 0x400; - val += (packet.header.tc << 9) & 0x200; - val += (packet.header.rd << 8) & 0x100; - val += (packet.header.ra << 7) & 0x80; - val += (packet.header.res1 << 6) & 0x40; - val += (packet.header.res1 << 5) & 0x20; - val += (packet.header.res1 << 4) & 0x10; - val += packet.header.rcode & 0xF; - buff.writeUInt16BE(val & 0xFFFF); - // TODO assert on question.length > 1, in practice multiple questions - // aren't used - buff.writeUInt16BE(1); - // answer offset 6 - buff.writeUInt16BE(packet.answer.length & 0xFFFF); - // authority offset 8 - buff.writeUInt16BE(packet.authority.length & 0xFFFF); - // additional offset 10 - buff.writeUInt16BE(packet.additional.length & 0xFFFF); - state = 'QUESTION'; - break; - case 'TRUNCATE': - buff.seek(2); - val = buff.readUInt16BE(); - val |= (1 << 9) & 0x200; - buff.seek(2); - buff.writeUInt16BE(val); - switch (section) { - case 'answer': - pos = 6; - // seek to authority and clear it and additional out - buff.seek(8); - buff.writeUInt16BE(0); - buff.writeUInt16BE(0); - break; - case 'authority': - pos = 8; - // seek to additional and clear it out - buff.seek(10); - buff.writeUInt16BE(0); - break; - case 'additional': - pos = 10; - break; - } - buff.seek(pos); - buff.writeUInt16BE(count - 1); - buff.seek(last_resource); - state = 'END'; - break; - case 'NAME_PACK': - name_pack(name, buff, label_index); - state = next; - break; - case 'QUESTION': - val = packet.question[0]; - assert(val, 'Packet requires a question'); - assertUndefined(val.name, 'Question requires a "name"'); - name = val.name; - state = 'NAME_PACK'; - next = 'QUESTION_NEXT'; - break; - case 'QUESTION_NEXT': - assertUndefined(val.type, 'Question requires a "type"'); - assertUndefined(val.class, 'Questionn requires a "class"'); - buff.writeUInt16BE(val.type & 0xFFFF); - buff.writeUInt16BE(val.class & 0xFFFF); - state = 'RESOURCE_RECORD'; - section = 'answer'; - count = 0; - break; - case 'RESOURCE_RECORD': - last_resource = buff.tell(); - if (packet[section].length == count) { - switch (section) { - case 'answer': - section = 'authority'; - state = 'RESOURCE_RECORD'; - break; - case 'authority': - section = 'additional'; - state = 'RESOURCE_RECORD'; - break; - case 'additional': - state = 'END'; - break; - } - count = 0; - } else { - state = 'RESOURCE_WRITE'; - } - break; - case 'RESOURCE_WRITE': - val = packet[section][count]; - assertUndefined(val.name, 'Resource record requires "name"'); - name = val.name; - state = 'NAME_PACK'; - next = 'RESOURCE_WRITE_NEXT'; - break; - case 'RESOURCE_WRITE_NEXT': - assertUndefined(val.type, 'Resource record requires "type"'); - assertUndefined(val.class, 'Resource record requires "class"'); - assertUndefined(val.ttl, 'Resource record requires "ttl"'); - buff.writeUInt16BE(val.type & 0xFFFF); - buff.writeUInt16BE(val.class & 0xFFFF); - buff.writeUInt32BE(val.ttl & 0xFFFFFFFF); - - // where the rdata length goes - rdata_pos = buff.tell(); - buff.writeUInt16BE(0); - - state = consts.QTYPE_TO_NAME[val.type]; - break; - case 'RESOURCE_DONE': - pos = buff.tell(); - buff.seek(rdata_pos); - buff.writeUInt16BE(pos - rdata_pos - 2); - buff.seek(pos); - count += 1; - state = 'RESOURCE_RECORD'; - break; - case 'A': - case 'AAAA': - //TODO XXX FIXME -- assert that address is of proper type - assertUndefined(val.address, 'A/AAAA record requires "address"'); - val = ipaddr.parse(val.address).toByteArray(); - val.forEach(function(b) { - buff.writeUInt8(b); - }); - state = 'RESOURCE_DONE'; - break; - case 'NS': - case 'CNAME': - case 'PTR': - assertUndefined(val.data, 'NS/CNAME/PTR record requires "data"'); - name = val.data; - state = 'NAME_PACK'; - next = 'RESOURCE_DONE'; - break; - case 'SPF': - case 'TXT': - //TODO XXX FIXME -- split on max char string and loop - assertUndefined(val.data, 'TXT record requires "data"'); - buff.writeUInt8(val.data.length); - buff.write(val.data, val.data.length, 'ascii'); - state = 'RESOURCE_DONE'; - break; - case 'MX': - assertUndefined(val.priority, 'MX record requires "priority"'); - assertUndefined(val.exchange, 'MX record requires "exchange"'); - buff.writeUInt16BE(val.priority & 0xFFFF); - name = val.exchange; - state = 'NAME_PACK'; - next = 'RESOURCE_DONE'; - break; - case 'SRV': - assertUndefined(val.priority, 'SRV record requires "priority"'); - assertUndefined(val.weight, 'SRV record requires "weight"'); - assertUndefined(val.port, 'SRV record requires "port"'); - assertUndefined(val.target, 'SRV record requires "target"'); - buff.writeUInt16BE(val.priority & 0xFFFF); - buff.writeUInt16BE(val.weight & 0xFFFF); - buff.writeUInt16BE(val.port & 0xFFFF); - name = val.target; - state = 'NAME_PACK'; - next = 'RESOURCE_DONE'; - break; - case 'SOA': - assertUndefined(val.primary, 'SOA record requires "primary"'); - name = val.primary; - state = 'NAME_PACK'; - next = 'SOA_ADMIN'; - break; - case 'SOA_ADMIN': - assertUndefined(val.admin, 'SOA record requires "admin"'); - name = val.admin; - state = 'NAME_PACK'; - next = 'SOA_NEXT'; - break; - case 'SOA_NEXT': - assertUndefined(val.serial, 'SOA record requires "serial"'); - assertUndefined(val.refresh, 'SOA record requires "refresh"'); - assertUndefined(val.retry, 'SOA record requires "retry"'); - assertUndefined(val.expiration, 'SOA record requires "expiration"'); - assertUndefined(val.minimum, 'SOA record requires "minimum"'); - buff.writeUInt32BE(val.serial & 0xFFFFFFFF); - buff.writeInt32BE(val.refresh & 0xFFFFFFFF); - buff.writeInt32BE(val.retry & 0xFFFFFFFF); - buff.writeInt32BE(val.expiration & 0xFFFFFFFF); - buff.writeInt32BE(val.minimum & 0xFFFFFFFF); - state = 'RESOURCE_DONE'; - break; - case 'OPT': - while (packet.edns_options.length) { - val = packet.edns_options.pop(); - buff.writeUInt16BE(val.code); - buff.writeUInt16BE(val.data.length); - for (pos = 0; pos < val.data.length; pos++) { - buff.writeUInt8(val.data.readUInt8(pos)); - } - } - state = 'RESOURCE_DONE'; - break; - case 'NAPTR': - assertUndefined(val.order, 'NAPTR record requires "order"'); - assertUndefined(val.preference, 'NAPTR record requires "preference"'); - assertUndefined(val.flags, 'NAPTR record requires "flags"'); - assertUndefined(val.service, 'NAPTR record requires "service"'); - assertUndefined(val.regexp, 'NAPTR record requires "regexp"'); - assertUndefined(val.replacement, 'NAPTR record requires "replacement"'); - buff.writeUInt16BE(val.order & 0xFFFF); - buff.writeUInt16BE(val.preference & 0xFFFF); - buff.writeUInt8(val.flags.length); - buff.write(val.flags, val.flags.length, 'ascii'); - buff.writeUInt8(val.service.length); - buff.write(val.service, val.service.length, 'ascii'); - buff.writeUInt8(val.regexp.length); - buff.write(val.regexp, val.regexp.length, 'ascii'); - buff.writeUInt8(val.replacement.length); - buff.write(val.replacement, val.replacement.length, 'ascii'); - state = 'RESOURCE_DONE'; - break; - case 'END': - return buff.tell(); - break; - default: - throw new Error('WTF No State While Writing'); - break; - } - } catch (e) { - if (e instanceof BufferCursorOverflow) { - state = 'TRUNCATE'; - } else { - throw e; - } - } - } -}; - -Packet.parse = function(msg, socket) { - var state, - len, - pos, - val, - rdata_len, - rdata, - label_index = {}, - counts = {}, - section, - count; - - var packet = new Packet(socket); - - pos = 0; - state = 'HEADER'; - - msg = BufferCursor(msg); - len = msg.length; +Packet.parse = function (msg, socket) { + var p = NDP.parse(msg); + p._socket = socket; + return p; +} - while (true) { - switch (state) { - case 'HEADER': - packet.header.id = msg.readUInt16BE(); - val = msg.readUInt16BE(); - packet.header.qr = (val & 0x8000) >> 15; - packet.header.opcode = (val & 0x7800) >> 11; - packet.header.aa = (val & 0x400) >> 10; - packet.header.tc = (val & 0x200) >> 9; - packet.header.rd = (val & 0x100) >> 8; - packet.header.ra = (val & 0x80) >> 7; - packet.header.res1 = (val & 0x40) >> 6; - packet.header.res2 = (val & 0x20) >> 5; - packet.header.res3 = (val & 0x10) >> 4; - packet.header.rcode = (val & 0xF); - counts.qdcount = msg.readUInt16BE(); - counts.ancount = msg.readUInt16BE(); - counts.nscount = msg.readUInt16BE(); - counts.arcount = msg.readUInt16BE(); - state = 'QUESTION'; - break; - case 'QUESTION': - val = {}; - val.name = name_unpack(msg, label_index); - val.type = msg.readUInt16BE(); - val.class = msg.readUInt16BE(); - packet.question.push(val); - // TODO handle qdcount > 0 in practice no one sends this - state = 'RESOURCE_RECORD'; - section = 'answer'; - count = 'ancount'; - break; - case 'RESOURCE_RECORD': - if (counts[count] === packet[section].length) { - switch (section) { - case 'answer': - section = 'authority'; - count = 'nscount'; - break; - case 'authority': - section = 'additional'; - count = 'arcount'; - break; - case 'additional': - state = 'END'; - break; - } - } else { - state = 'RR_UNPACK'; - } - break; - case 'RR_UNPACK': - val = {}; - val.name = name_unpack(msg, label_index); - val.type = msg.readUInt16BE(); - val.class = msg.readUInt16BE(); - val.ttl = msg.readUInt32BE(); - rdata_len = msg.readUInt16BE(); - rdata = msg.slice(rdata_len); - state = consts.QTYPE_TO_NAME[val.type]; - break; - case 'RESOURCE_DONE': - packet[section].push(val); - state = 'RESOURCE_RECORD'; - break; - case 'A': - val.address = new ipaddr.IPv4(rdata.toByteArray()); - val.address = val.address.toString(); - state = 'RESOURCE_DONE'; - break; - case 'AAAA': - val.address = new ipaddr.IPv6(rdata.toByteArray('readUInt16BE')); - val.address = val.address.toString(); - state = 'RESOURCE_DONE'; - break; - case 'NS': - case 'CNAME': - case 'PTR': - pos = msg.tell(); - msg.seek(pos - rdata_len); - val.data = name_unpack(msg, label_index); - msg.seek(pos); - state = 'RESOURCE_DONE'; - break; - case 'SPF': - case 'TXT': - val.data = ''; - while (!rdata.eof()) { - val.data += rdata.toString('ascii', rdata.readUInt8()); - } - state = 'RESOURCE_DONE'; - break; - case 'MX': - val.priority = rdata.readUInt16BE(); - pos = msg.tell(); - msg.seek(pos - rdata_len + rdata.tell()); - val.exchange = name_unpack(msg, label_index); - msg.seek(pos); - state = 'RESOURCE_DONE'; - break; - case 'SRV': - val.priority = rdata.readUInt16BE(); - val.weight = rdata.readUInt16BE(); - val.port = rdata.readUInt16BE(); - pos = msg.tell(); - msg.seek(pos - rdata_len + rdata.tell()); - val.target = name_unpack(msg, label_index); - msg.seek(pos); - state = 'RESOURCE_DONE'; - break; - case 'SOA': - pos = msg.tell(); - msg.seek(pos - rdata_len + rdata.tell()); - val.primary = name_unpack(msg, label_index); - val.admin = name_unpack(msg, label_index); - rdata.seek(msg.tell() - (pos - rdata_len + rdata.tell())); - msg.seek(pos); - val.serial = rdata.readUInt32BE(); - val.refresh = rdata.readInt32BE(); - val.retry = rdata.readInt32BE(); - val.expiration = rdata.readInt32BE(); - val.minimum = rdata.readInt32BE(); - state = 'RESOURCE_DONE'; - break; - case 'OPT': - // assert first entry in additional - counts[count] -= 1; - packet.payload = val.class; - pos = msg.tell(); - msg.seek(pos - 6); - packet.header.rcode = (msg.readUInt8() << 4) + packet.header.rcode; - packet.edns_version = msg.readUInt8(); - val = msg.readUInt16BE(); - msg.seek(pos); - packet.do = (val & 0x8000) << 15; - while (!rdata.eof()) { - packet.edns_options.push({ - code: rdata.readUInt16BE(), - data: rdata.slice(rdata.readUInt16BE()).buffer - }); - } - state = 'RESOURCE_RECORD'; - break; - case 'NAPTR': - val.order = rdata.readUInt16BE(); - val.preference = rdata.readUInt16BE(); - pos = rdata.readUInt8(); - val.flags = rdata.toString('ascii', pos); - pos = rdata.readUInt8(); - val.service = rdata.toString('ascii', pos); - pos = rdata.readUInt8(); - val.regexp = rdata.toString('ascii', pos); - pos = rdata.readUInt8(); - val.replacement = rdata.toString('ascii', pos); - state = 'RESOURCE_DONE'; - break; - case 'END': - return packet; - break; - default: - //console.log(state, val); - state = 'RESOURCE_DONE'; - break; - } - } -}; +Packet.write = NDP.write; diff --git a/lib/pending.js b/lib/pending.js index 7409c56..e6c0c06 100644 --- a/lib/pending.js +++ b/lib/pending.js @@ -24,7 +24,7 @@ var net = require('net'), util = require('util'), EventEmitter = require('events').EventEmitter, Packet = require('./packet'), - consts = require('./consts'), + consts = require('native-dns-packet').consts, UDPSocket = require('./utils').UDPSocket, TCPSocket = require('./utils').TCPSocket; diff --git a/lib/platform.js b/lib/platform.js index d397010..d59ce1d 100644 --- a/lib/platform.js +++ b/lib/platform.js @@ -26,7 +26,7 @@ var fs = require('fs'), os = require('os'), util = require('util'), Cache = require('./cache'), - consts = require('./consts'), + consts = require('native-dns-packet').consts, path = require('path'), utils = require('./utils'); diff --git a/lib/utils.js b/lib/utils.js index 8d479c9..a0d748e 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -208,7 +208,7 @@ var ensure_absolute = exports.ensure_absolute = function (f) { return f; }; -var CNAME = require('./consts').NAME_TO_QTYPE.CNAME; +var CNAME = require('native-dns-packet').consts.NAME_TO_QTYPE.CNAME; var Lookup = exports.Lookup = function (store, zone, question, cb) { if (!(this instanceof Lookup)) diff --git a/package.json b/package.json index f3bb53f..9ac46a5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "native-dns", - "version": "0.4.1", + "version": "0.5.0", "author": "Timothy J Fontaine (http://atxconsulting.com)", "description": "Replacement for the core DNS module, includes server implementation", "keywords": [ @@ -24,9 +24,9 @@ "test": "nodeunit test" }, "dependencies": { - "buffercursor": ">= 0.0.5", "binaryheap": ">= 0.0.2", - "ipaddr.js": ">= 0.1.1" + "ipaddr.js": ">= 0.1.1", + "native-dns-packet": ">= 0.0.1" }, "devDependencies": { "optimist": "",