Replacement dns module in pure javascript for node.js
Pull request Compare This branch is 228 commits behind tjfontaine:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



 * TCP
 * Tests, tests, tests
 * Documentation



Designed to be a drop in replacement for the builtin node.js dns module. Every
function and constant that the core currently exports is also exported by this
module. It also passes the existing test-suite found in node.js for the dns

Beyond the core functionality the resolv* functions return an object that
facilitate cancelling an active request.


This module also adds a rudimentary server, currently only available over udp.
One simply calls createServer(type), the type can either be udp4 or udp6. The
result will wrap common socket operations, like bind, close, and address. It
will also re-emit the socket events of listen and close. It does not bind by
default, the user is responsible for that.

The main interface with the server comes via the 'message' event, which passes
two similar objects. The first is a representation of the dns request sent to
the server, the second is the same type, but has the header query response bit
set, the proper request id, and a copy of the same questions found in the
request. There are 4 arrays: question, answer, authority, and additional found
in this type, for your response you push resource records into the proper
category, and then call .send() to finalize the response.

Several base types are exported through the module, for instance: A, AAAA, PTR,
TXT, SRV, MX and others are already defined. You can instantiate instances of
these types by calling dns.A(initializing_properties), all resources require
name and ttl to be defined in the initializing object. The rest of the
properties vary by type.

One can define more types externally by using the registerType interface. Which
expects a type name, and an array of fields (described below) which represent
how the rdata of a specific type is laid out.

Underlying Design

There are 3 operations common to most types:

 * pack -- Based on the fields in the type (or the fields type) return a Buffer
           with the binary representation of the type (or field).
  - The limitation to this is it isn't flexible enough for label compression.
    For that to work name.pack needs to know the location of other labels, or
    compression would need to be a second pass. 
  - We could pass a pre-allocated Buffer, and offset to begin encoding the
    fields, and return the size written to the Buffer. Then theoretically we
    know the length that should actually be sent.
 * unpack -- Accepts a Buffer and absolute position in the Buffer to begin
             decoding the binary representation, return the amount read and
             potentially value when unpacking fields.
  - Messages have a member that keeps the Buffer and the records location in
    that buffer, beacuse labels may be compressed name.unpack needs to unpack
    relative to the entire message.
 * promote -- ResourceRecord or Packet method, returns the descendent type,
              like A/AAAA or an EDNS packet

The base type is Message, which when initialized expects a member _fields that
is an array of objects that adhere to the following pattern:

  name: // This will result in a propety defined on the type
  value: // During initialization the default value for the field, otherwise
         // the actual value of the field for this instance
  position: // This is populated during unpack, it is not required during
            // initialization
  pack: // a function that takes a value and returns it in binary via Buffer
  unpack: // given a buffer and position, properly unpack and return the following
          // {
          //   read:  // The amount read by this operation
          //   value: // The actual field value
          //   field_position: // optional, used for absolution position of rdata
          // }
  // if the following are defined, then its presumed they operate on a previous
  // field
  get: // a function that accepts the containing type, and returns the field value
  set: // a function that accepts the containing type and value to be set


When a Message object is instantiated the _fields array is iterated and then
for each field a property getter and setter is defined. Actual field values are
stored along with the field definition in the array.

ResourceRecords also define the _rdata_fields array, which is a set of type
specific fields, these are unpacked when .promote() is called. The registerType
interface expects an array of these fields as well.

The following are the available base field types:

 * Struct -- Takes a field name and format type, similar to python's struct
             module, everything is assumed big endian
 * Label -- Requires only a field name
 * IPAddress -- Requires a field name and address family (4 or 6)
 * BufferField -- Requires a field name, and format for how the length of the
                  buffer should be encoded, the length is located before the
                  actual data

The following are the types that depend on a previous field type:

 * SubField -- Requires a field name, parent field name, the offset in bits
               to the field, and the mask indicating the size of field
 * CharString -- Requires a field name, assumes the data is packed in an rdata
                 field in the parent, and is the entirety of the rdata