Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

native-dns-packet

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

native-dns-packet - npm Package Compare versions

Comparing version 0.0.2 to 0.0.3

bench-raw-write.js

2

bench-raw.js

@@ -13,5 +13,5 @@ var fs = require('fs');

var T = 1000000;
var T = 100000;
for (var i = 0; i < T; i++)
var p = Packet.parse(packets[i % packets.length]);
{
"name": "native-dns-packet",
"version": "0.0.2",
"version": "0.0.3",
"author": "Timothy J Fontaine <tjfontaine@gmail.com> (http://atxconsulting.com)",

@@ -5,0 +5,0 @@ "description": "Raw DNS Packet Parsing and Writing",

@@ -62,3 +62,3 @@ // Copyright 2011 Timothy J Fontaine <tjfontaine@gmail.com>

var nameUnpack = function(buff) {
function nameUnpack(buff) {
var len, comp, end, pos, part, combine = '';

@@ -98,5 +98,5 @@

return combine;
};
}
var name_pack = function(str, buff, index) {
function namePack(str, buff, index) {
var offset, dot, part;

@@ -127,13 +127,250 @@

}
};
}
var
WRITE_HEADER = 100001,
WRITE_TRUNCATE = 100002,
WRITE_QUESTION = 100003,
WRITE_RESOURCE_RECORD = 100004,
WRITE_RESOURCE_WRITE = 100005,
WRITE_RESOURCE_DONE = 100006,
WRITE_RESOURCE_END = 100007,
WRITE_EDNS = 100008,
WRITE_END = 100009,
WRITE_A = consts.NAME_TO_QTYPE.A,
WRITE_AAAA = consts.NAME_TO_QTYPE.AAAA,
WRITE_NS = consts.NAME_TO_QTYPE.NS,
WRITE_CNAME = consts.NAME_TO_QTYPE.CNAME,
WRITE_PTR = consts.NAME_TO_QTYPE.PTR,
WRITE_SPF = consts.NAME_TO_QTYPE.SPF,
WRITE_MX = consts.NAME_TO_QTYPE.MX,
WRITE_SRV = consts.NAME_TO_QTYPE.SRV,
WRITE_TXT = consts.NAME_TO_QTYPE.TXT,
WRITE_SOA = consts.NAME_TO_QTYPE.SOA,
WRITE_OPT = consts.NAME_TO_QTYPE.OPT,
WRITE_NAPTR = consts.NAME_TO_QTYPE.NAPTR;
function writeHeader(buff, packet) {
assert(packet.header, 'Packet requires "header"');
buff.writeUInt16BE(packet.header.id & 0xFFFF);
var 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);
assert(packet.question.length == 1, 'DNS requires one question');
// 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);
return WRITE_QUESTION;
}
function writeTruncate(buff, packet, section, val) {
// XXX FIXME TODO truncation is currently done wrong.
// Quote rfc2181 section 9
// The TC bit should not be set merely because some extra information
// could have been included, but there was insufficient room. This
// includes the results of additional section processing. In such cases
// the entire RRSet that will not fit in the response should be omitted,
// and the reply sent as is, with the TC bit clear. If the recipient of
// the reply needs the omitted data, it can construct a query for that
// data and send that separately.
//
// TODO IOW only set TC if we hit it in ANSWERS otherwise make sure an
// entire RRSet is removed during a truncation.
var pos, val;
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);
return WRITE_END;
}
function writeQuestion(buff, val, label_index) {
assert(val, 'Packet requires a question');
assertUndefined(val.name, 'Question requires a "name"');
assertUndefined(val.type, 'Question requires a "type"');
assertUndefined(val.class, 'Questionn requires a "class"');
namePack(val.name, buff, label_index);
buff.writeUInt16BE(val.type & 0xFFFF);
buff.writeUInt16BE(val.class & 0xFFFF);
return WRITE_RESOURCE_RECORD;
}
function writeResource(buff, val, label_index, rdata) {
assert(val, 'Resource must be defined');
assertUndefined(val.name, 'Resource record requires "name"');
assertUndefined(val.type, 'Resource record requires "type"');
assertUndefined(val.class, 'Resource record requires "class"');
assertUndefined(val.ttl, 'Resource record requires "ttl"');
namePack(val.name, buff, label_index);
buff.writeUInt16BE(val.type & 0xFFFF);
buff.writeUInt16BE(val.class & 0xFFFF);
buff.writeUInt32BE(val.ttl & 0xFFFFFFFF);
rdata.pos = buff.tell();
buff.writeUInt16BE(0);
return val.type;
}
function writeResourceDone(buff, rdata) {
var pos = buff.tell();
buff.seek(rdata.pos);
buff.writeUInt16BE(pos - rdata.pos - 2);
buff.seek(pos);
return WRITE_RESOURCE_RECORD;
}
function writeIp(buff, val) {
//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);
});
return WRITE_RESOURCE_DONE;
}
function writeCname(buff, val, label_index) {
assertUndefined(val.data, 'NS/CNAME/PTR record requires "data"');
namePack(val.data, buff, label_index);
return WRITE_RESOURCE_DONE;
}
function writeTxt(buff, val) {
//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');
return WRITE_RESOURCE_DONE;
}
function writeMx(buff, val, label_index) {
assertUndefined(val.priority, 'MX record requires "priority"');
assertUndefined(val.exchange, 'MX record requires "exchange"');
buff.writeUInt16BE(val.priority & 0xFFFF);
namePack(val.exchange, buff, label_index);
return WRITE_RESOURCE_DONE;
}
function writeSrv(buff, val, label_index) {
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);
namePack(val.target, buff, label_index);
return WRITE_RESOURCE_DONE;
}
function writeSoa(buff, val, label_index) {
assertUndefined(val.primary, 'SOA record requires "primary"');
assertUndefined(val.admin, 'SOA record requires "admin"');
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"');
namePack(val.primary, buff, label_index);
namePack(val.admin, buff, label_index);
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);
return WRITE_RESOURCE_DONE;
}
function writeNaptr(buff, val) {
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');
return WRITE_RESOURCE_DONE;
}
function writeEnds(packet) {
var val = {
name: '',
type: consts.NAME_TO_QTYPE.OPT,
class: packet.payload
};
var 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);
return WRITE_HEADER;
}
function writeOpt(buff, packet) {
var pos;
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));
}
}
return WRITE_RESOURCE_DONE;
}
Packet.write = function(buff, packet) {
var state,
next,
name,
val,
section,
count,
pos,
rdata_pos,
rdata,
last_resource,

@@ -145,5 +382,5 @@ label_index = {};

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

@@ -154,93 +391,17 @@

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';
case WRITE_EDNS:
state = writeEns(packet);
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';
case WRITE_HEADER:
state = writeHeader(buff, packet);
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';
case WRITE_TRUNCATE:
state = writeTruncate(buff, packet, section, last_resource);
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';
case WRITE_QUESTION:
state = writeQuestion(buff, packet.question[0], label_index);
section = 'answer';
count = 0;
break;
case 'RESOURCE_RECORD':
case WRITE_RESOURCE_RECORD:
last_resource = buff.tell();

@@ -251,10 +412,10 @@ if (packet[section].length == count) {

section = 'authority';
state = 'RESOURCE_RECORD';
state = WRITE_RESOURCE_RECORD;
break;
case 'authority':
section = 'additional';
state = 'RESOURCE_RECORD';
state = WRITE_RESOURCE_RECORD;
break;
case 'additional':
state = 'END';
state = WRITE_END;
break;

@@ -264,136 +425,43 @@ }

} else {
state = 'RESOURCE_WRITE';
state = WRITE_RESOURCE_WRITE;
}
break;
case 'RESOURCE_WRITE':
case WRITE_RESOURCE_WRITE:
rdata = {}
val = packet[section][count];
assertUndefined(val.name, 'Resource record requires "name"');
name = val.name;
state = 'NAME_PACK';
next = 'RESOURCE_WRITE_NEXT';
state = writeResource(buff, val, label_index, rdata);
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);
case WRITE_RESOURCE_DONE:
count += 1;
state = 'RESOURCE_RECORD';
state = writeResourceDone(buff, rdata);
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';
case WRITE_A:
case WRITE_AAAA:
state = writeIp(buff, val);
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';
case WRITE_NS:
case WRITE_CNAME:
case WRITE_PTR:
state = writeCname(buff, val, label_index);
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';
case WRITE_SPF:
case WRITE_TXT:
state = writeTxt(buff, val);
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';
case WRITE_MX:
state = writeMx(buff, val, label_index);
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';
case WRITE_SRV:
state = writeSrv(buff, val, label_index);
break;
case 'SOA':
assertUndefined(val.primary, 'SOA record requires "primary"');
name = val.primary;
state = 'NAME_PACK';
next = 'SOA_ADMIN';
case WRITE_SOA:
state = writeSoa(buff, val, label_index);
break;
case 'SOA_ADMIN':
assertUndefined(val.admin, 'SOA record requires "admin"');
name = val.admin;
state = 'NAME_PACK';
next = 'SOA_NEXT';
case WRITE_OPT:
state = writeOpt(buff, packet);
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';
case WRITE_NAPTR:
state = writeNaptr(buff, val);
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':
case WRITE_END:
return buff.tell();

@@ -407,3 +475,3 @@ break;

if (e instanceof BufferCursorOverflow) {
state = 'TRUNCATE';
state = WRITE_TRUNCATE;
} else {

@@ -410,0 +478,0 @@ throw e;

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc