コード例 #1
0
ファイル: packet.js プロジェクト: avimar/node-dns
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;

  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 '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;
    }
  }
};
コード例 #2
0
ファイル: dnsrecord.js プロジェクト: Saigneur/fathom.addon
exports.parse = function(msg) {
  var state,
      pos,
      val,
      rdata,
      counts = {},
      section,
      count;

  var packet = new DNSRecord();

  pos = 0;
  state = PARSE_HEADER;

    if (typeof msg !== 'Buffer') {
	msg = new Buffer(msg,'binary');
    }
  msg = BufferCursor(msg, true);

  while (true) {
    switch (state) {
      case PARSE_HEADER:
        state = parseHeader(msg, packet, counts);
        break;
      case PARSE_QUESTION:
        state = parseQuestion(msg, packet);
        section = 'answer';
        count = 0;
        break;
      case PARSE_RESOURCE_RECORD:
        if (count === packet[section].length) {
          switch (section) {
            case 'answer':
              section = 'authority';
              count = 0;
              break;
            case 'authority':
              section = 'additional';
              count = 0;
              break;
            case 'additional':
              state = PARSE_END;
              break;
          }
        } else {
          state = PARSE_RR_UNPACK;
        }
        break;
      case PARSE_RR_UNPACK:
        val = {};
        rdata = {};
        state = parseRR(msg, val, rdata);
        break;
      case PARSE_RESOURCE_DONE:
        packet[section][count] = val;
        count++;
        state = PARSE_RESOURCE_RECORD;
        break;
      case PARSE_A:
        state = parseA(val, msg);
        break;
      case PARSE_AAAA:
        state = parseAAAA(val, msg);
        break;
      case PARSE_NS:
      case PARSE_CNAME:
      case PARSE_PTR:
        state = parseCname(val, msg);
        break;
      case PARSE_SPF:
      case PARSE_TXT:
        state = parseTxt(val, msg, rdata);
        break;
      case PARSE_MX:
        state = parseMx(val, msg);
        break;
      case PARSE_SRV:
        state = parseSrv(val, msg);
        break;
      case PARSE_SOA:
        state = parseSoa(val, msg);
        break;
      case PARSE_OPT:
        // assert first entry in additional
        rdata.buf = msg.slice(rdata.len);
        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.buf.eof()) {
          packet.edns_options.push({
            code: rdata.buf.readUInt16BE(),
            data: rdata.buf.slice(rdata.buf.readUInt16BE()).buffer
          });
        }
        state = PARSE_RESOURCE_RECORD;
        break;
      case PARSE_NAPTR:
        state = parseNaptr(val, msg);
        break;
      case PARSE_END:
        return packet;
        break;
      default:
        //console.log(state, val);
        val.data = msg.slice(rdata.len);
        state = PARSE_RESOURCE_DONE;
        break;
    }
  }
};
コード例 #3
0
ファイル: packet.js プロジェクト: avimar/node-dns
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':
          buff.writeUInt16BE(packet.header.id);
          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);
          // TODO assert on question.length > 1, in practice multiple questions
          // aren't used
          buff.writeUInt16BE(1);
          // answer offset 6
          buff.writeUInt16BE(packet.answer.length);
          // authority offset 8
          buff.writeUInt16BE(packet.authority.length);
          // additional offset 10
          buff.writeUInt16BE(packet.additional.length);
          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];
          name = val.name;
          state = 'NAME_PACK';
          next = 'QUESTION_NEXT';
          break;
        case 'QUESTION_NEXT':
          buff.writeUInt16BE(val.type);
          buff.writeUInt16BE(val.class);
          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];
          name = val.name;
          state = 'NAME_PACK';
          next = 'RESOURCE_WRITE_NEXT';
          break;
        case 'RESOURCE_WRITE_NEXT':
          buff.writeUInt16BE(val.type);
          buff.writeUInt16BE(val.class);
          buff.writeUInt32BE(val.ttl);

          // 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':
          val = ipaddr.parse(val.address).toByteArray();
          val.forEach(function(b) {
            buff.writeUInt8(b);
          });
          state = 'RESOURCE_DONE';
          break;
        case 'AAAA':
          val = ipaddr.parse(val.address).toByteArray();
          val.forEach(function(b) {
            buff.writeUInt16BE(b);
          });
          state = 'RESOURCE_DONE';
          break;
        case 'NS':
        case 'CNAME':
        case 'PTR':
          name = val.data;
          state = 'NAME_PACK';
          next = 'RESOURCE_DONE';
          break;
        case 'TXT':
          //TODO XXX FIXME -- split on max char string and loop
          buff.writeUInt8(val.data.length);
          buff.write(val.data, val.data.length, 'ascii');
          state = 'RESOURCE_DONE';
          break;
        case 'MX':
          buff.writeUInt16BE(val.priority);
          name = val.exchange;
          state = 'NAME_PACK';
          next = 'RESOURCE_DONE';
          break;
        case 'SRV':
          buff.writeUInt16BE(val.priority);
          buff.writeUInt16BE(val.weight);
          buff.writeUInt16BE(val.port);
          name = val.target;
          state = 'NAME_PACK';
          next = 'RESOURCE_DONE';
          break;
        case 'SOA':
          name = val.primary;
          state = 'NAME_PACK';
          next = 'SOA_ADMIN';
          break;
        case 'SOA_ADMIN':
          name = val.admin;
          state = 'NAME_PACK';
          next = 'SOA_NEXT';
          break;
        case 'SOA_NEXT':
          buff.writeUInt32BE(val.serial);
          buff.writeInt32BE(val.refresh);
          buff.writeInt32BE(val.retry);
          buff.writeInt32BE(val.expiration);
          buff.writeInt32BE(val.minimum);
          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':
          buff.writeUInt16BE(val.order);
          buff.writeUInt16BE(val.preference);
          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;
      }
    }
  }
};
コード例 #4
0
ファイル: dnsrecord.js プロジェクト: Saigneur/fathom.addon
exports.write = function(buff, packet) {
  var state,
      val,
      section,
      count,
      rdata,
      last_resource,
      label_index = {};

  buff = BufferCursor(buff, true);

  if (typeof(packet.edns_version) !== 'undefined') {
    state = WRITE_EDNS;
  } else {
    state = WRITE_HEADER;
  }

  while (true) {
    try {
      switch (state) {
        case WRITE_EDNS:
          state = writeEns(packet);
          break;
        case WRITE_HEADER:
          state = writeHeader(buff, packet);
          break;
        case WRITE_TRUNCATE:
          state = writeTruncate(buff, packet, section, last_resource);
          break;
        case WRITE_QUESTION:
          state = writeQuestion(buff, packet.question[0], label_index);
          section = 'answer';
          count = 0;
          break;
        case WRITE_RESOURCE_RECORD:
          last_resource = buff.tell();
          if (packet[section].length == count) {
            switch (section) {
              case 'answer':
                section = 'authority';
                state = WRITE_RESOURCE_RECORD;
                break;
              case 'authority':
                section = 'additional';
                state = WRITE_RESOURCE_RECORD;
                break;
              case 'additional':
                state = WRITE_END;
                break;
            }
            count = 0;
          } else {
            state = WRITE_RESOURCE_WRITE;
          }
          break;
        case WRITE_RESOURCE_WRITE:
          rdata = {}
          val = packet[section][count];
          state = writeResource(buff, val, label_index, rdata);
          break;
        case WRITE_RESOURCE_DONE:
          count += 1;
          state = writeResourceDone(buff, rdata);
          break;
        case WRITE_A:
        case WRITE_AAAA:
          state = writeIp(buff, val);
          break;
        case WRITE_NS:
        case WRITE_CNAME:
        case WRITE_PTR:
          state = writeCname(buff, val, label_index);
          break;
        case WRITE_SPF:
        case WRITE_TXT:
          state = writeTxt(buff, val);
          break;
        case WRITE_MX:
          state = writeMx(buff, val, label_index);
          break;
        case WRITE_SRV:
          state = writeSrv(buff, val, label_index);
          break;
        case WRITE_SOA:
          state = writeSoa(buff, val, label_index);
          break;
        case WRITE_OPT:
          state = writeOpt(buff, packet);
          break;
        case WRITE_NAPTR:
          state = writeNaptr(buff, val);
          break;
        case WRITE_END:
          return buff.tell();
          break;
        default:
          throw new Error('WTF No State While Writing');
          break;
      }
    } catch (e) {
      if (e instanceof BufferCursorOverflow) {
        state = WRITE_TRUNCATE;
      } else {
        throw e;
      }
    }
  }
};