Socket
Socket
Sign inDemoInstall

bns

Package Overview
Dependencies
16
Maintainers
1
Versions
49
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.3 to 0.0.4

lib/crypto-browser.js

158

bin/dig.js

@@ -5,22 +5,124 @@ #!/usr/bin/env node

const pkg = require('../package.json');
const {StubResolver} = require('../lib/resolver');
const reverse = process.argv.indexOf('-x');
const util = require('../lib/util');
if (reverse !== -1)
process.argv.splice(reverse, 1);
let name = null;
let type = null;
let host = null;
let port = null;
let inet6 = false;
let reverse = false;
let json = false;
let rd = true;
let edns = false;
let dnssec = false;
let debug = false;
function log(obj) {
console.log(obj.toString());
for (let i = 2; i < process.argv.length; i++) {
const arg = process.argv[i];
if (arg.length === 0)
throw new Error(`Unexpected argument: ${arg}.`);
switch (arg) {
case '-4':
inet6 = false;
break;
case '-6':
inet6 = true;
break;
case '-x':
reverse = true;
break;
case '-p':
port = util.parseU16(process.argv[i + 1]);
i += 1;
break;
case '-j':
json = true;
break;
case '-q':
name = arg;
break;
case '-t':
type = arg;
break;
case '-h':
case '--help':
case '-?':
case '-v':
console.log(`bns ${pkg.version}`);
process.exit(0);
break;
case '+edns':
edns = true;
break;
case '+noedns':
edns = false;
break;
case '+dnssec':
edns = true;
dnssec = true;
break;
case '+nodnssec':
dnssec = false;
break;
case '+rd':
rd = true;
break;
case '+nord':
rd = false;
break;
case '+debug':
debug = true;
break;
case '+nodebug':
debug = false;
break;
default:
if (arg[0] === '@') {
host = arg.substring(1);
break;
}
if (!name) {
name = arg;
break;
}
if (!type) {
type = arg;
break;
}
throw new Error(`Unexpected argument: ${arg}.`);
}
}
async function resolve(name, type, host, port) {
const resolver = new StubResolver('udp4');
if (!name)
name = '.';
resolver.on('log', (...args) => {
console.error(...args);
});
if (!type)
type = 'A';
async function resolve(name, type, options) {
const {host, port} = options;
const resolver = new StubResolver(options.inet6 ? 'udp6' : 'udp4');
resolver.rd = options.rd == null ? true : options.rd;
resolver.edns = Boolean(options.edns);
resolver.dnssec = Boolean(options.dnssec);
resolver.conf.fromSystem();
if (options.debug) {
resolver.on('log', (...args) => {
console.error(...args);
});
}
await resolver.open();
if (reverse !== -1) {
if (options.reverse) {
try {

@@ -41,7 +143,29 @@ return await resolver.reverse(name, port, host);

(async () => {
const name = process.argv[2] || null;
const type = process.argv[3] || null;
const host = process.argv[4] || null;
const port = (process.argv[5] | 0) || null;
log(await resolve(name, type, host, port));
})();
const now = Date.now();
const res = await resolve(name, type, {
host,
port,
inet6,
reverse,
rd,
edns,
dnssec,
debug
});
const ms = Date.now() - now;
if (json) {
const text = JSON.stringify(res.toJSON(), null, 2);
process.stdout.write(text + '\n');
} else {
const argv = process.argv.slice(2).join(' ');
process.stdout.write('\n');
process.stdout.write(`; <<>> bns ${pkg.version} <<>> ${argv}\n`);
process.stdout.write(res.toString(ms) + '\n');
}
})().catch((err) => {
console.error(err.message);
process.exit(1);
});

@@ -5,22 +5,129 @@ #!/usr/bin/env node

const pkg = require('../package.json');
const {RecursiveResolver} = require('../lib/resolver');
const reverse = process.argv.indexOf('-x');
const util = require('../lib/util');
if (reverse !== -1)
process.argv.splice(reverse, 1);
let name = null;
let type = null;
let host = null;
let port = null;
let inet6 = false;
let reverse = false;
let json = false;
let rd = false;
let edns = false;
let dnssec = false;
let nsec3 = false;
let debug = false;
function log(obj) {
console.log(obj.toString());
for (let i = 2; i < process.argv.length; i++) {
const arg = process.argv[i];
if (arg.length === 0)
throw new Error(`Unexpected argument: ${arg}.`);
switch (arg) {
case '-4':
inet6 = false;
break;
case '-6':
inet6 = true;
break;
case '-x':
reverse = true;
break;
case '-p':
port = util.parseU16(process.argv[i + 1]);
i += 1;
break;
case '-j':
json = true;
break;
case '-q':
name = arg;
break;
case '-t':
type = arg;
break;
case '-h':
case '--help':
case '-?':
case '-v':
console.log(`bns ${pkg.version}`);
process.exit(0);
break;
case '+edns':
edns = true;
break;
case '+noedns':
edns = false;
break;
case '+dnssec':
edns = true;
dnssec = true;
break;
case '+nodnssec':
dnssec = false;
break;
case '+rd':
rd = true;
break;
case '+nord':
rd = false;
break;
case '+nsec3':
nsec3 = true;
break;
case '+nonsec3':
nsec3 = false;
break;
case '+debug':
debug = true;
break;
case '+nodebug':
debug = false;
break;
default:
if (arg[0] === '@') {
host = arg.substring(1);
break;
}
if (!name) {
name = arg;
break;
}
if (!type) {
type = arg;
break;
}
throw new Error(`Unexpected argument: ${arg}.`);
}
}
async function resolve(name, type, host, port) {
const resolver = new RecursiveResolver('udp4');
if (!name)
name = '.';
resolver.on('log', (...args) => {
console.error(...args);
});
if (!type)
type = 'A';
async function resolve(name, type, options) {
const resolver = new RecursiveResolver(options.inet6 ? 'udp6' : 'udp4');
resolver.rd = Boolean(options.rd);
resolver.edns = Boolean(options.edns);
resolver.dnssec = Boolean(options.dnssec);
resolver.nsec3 = Boolean(options.nsec3);
if (options.debug) {
resolver.on('log', (...args) => {
console.error(...args);
});
}
await resolver.open();
if (reverse !== -1) {
if (options.reverse) {
try {

@@ -41,7 +148,30 @@ return await resolver.reverse(name);

(async () => {
const name = process.argv[2] || null;
const type = process.argv[3] || null;
const host = process.argv[4] || null;
const port = (process.argv[5] | 0) || null;
log(await resolve(name, type, host, port));
})();
const now = Date.now();
const res = await resolve(name, type, {
host,
port,
inet6,
reverse,
rd,
edns,
dnssec,
nsec3,
debug
});
const ms = Date.now() - now;
if (json) {
const text = JSON.stringify(res.toJSON(), null, 2);
process.stdout.write(text + '\n');
} else {
const argv = process.argv.slice(2).join(' ');
process.stdout.write('\n');
process.stdout.write(`; <<>> bns ${pkg.version} <<>> ${argv}\n`);
process.stdout.write(res.toString(ms) + '\n');
}
})().catch((err) => {
console.error(err.message);
process.exit(1);
});

34

lib/bns.js

@@ -9,21 +9,25 @@ /*!

const constants = require('./constants');
const dnssec = require('./dnssec');
const encoding = require('./encoding');
const wire = require('./wire');
const util = require('./util');
const dnssec = require('./dnssec');
const hints = require('./hints');
const Hosts = require('./hosts');
const nsec3 = require('./nsec3');
const ResolvConf = require('./resolvconf');
const resolver = require('./resolver');
const server = require('./server');
const resolver = require('./resolver');
const hints = require('./hints');
const util = require('./util');
const wire = require('./wire');
exports.constants = constants;
exports.dnssec = dnssec;
exports.encoding = encoding;
exports.wire = wire;
exports.util = util;
exports.dnssec = dnssec;
exports.hints = hints;
exports.Hosts = Hosts;
exports.nsec3 = nsec3;
exports.DNSServer = server.DNSServer;
exports.StubServer = server.StubServer;
exports.RecursiveServer = server.RecursiveServer;
exports.ResolvConf = ResolvConf;
exports.DNSResolver = resolver.DNSResolver;
exports.StubResolver = resolver.StubResolver;
exports.OSResolver = resolver.OSResolver;
exports.RecursiveResolver = resolver.RecursiveResolver;

@@ -33,2 +37,8 @@ exports.Cache = resolver.Cache;

exports.Authority = resolver.Authority;
exports.hints = hints;
exports.DNSServer = server.DNSServer;
exports.StubServer = server.StubServer;
exports.RecursiveServer = server.RecursiveServer;
exports.util = util;
exports.wire = wire;

@@ -14,2 +14,4 @@ /*!

const assert = require('assert');
/**

@@ -492,3 +494,117 @@ * Message Opcodes

/**
* Max domain name length.
* @const {Number}
* @default
*/
const MAX_DOMAIN_LENGTH = 256;
/*
* Helpers
*/
function toSymbol(value, map, prefix, size) {
assert((value & size) === value);
const symbol = map[value];
if (typeof symbol === 'string')
return symbol;
return `${prefix}${value.toString(10)}`;
}
function fromSymbol(symbol, name, map, prefix, size) {
assert(typeof symbol === 'string');
if (symbol.length > 64)
throw new Error(`Unknown ${name}.`);
const value = map[symbol];
if (typeof value === 'number')
return value;
if (symbol.length <= prefix.length)
throw new Error(`Unknown ${name}: ${symbol}.`);
if (symbol.substring(0, prefix.length) !== prefix)
throw new Error(`Unknown ${name}: ${symbol}.`);
if (symbol.length > prefix.length + size)
throw new Error(`Unknown ${name}.`);
let word = 0;
for (let i = prefix.length; i < symbol.length; i++) {
const ch = symbol.charCodeAt(i) - 0x30;
if (ch < 0 || ch > 9)
throw new Error(`Unknown ${name}: ${symbol}.`);
word *= 10;
word += ch;
}
return word;
}
function opcodeToString(opcode) {
return toSymbol(opcode, opcodesByVal, 'OPCODE', 0x0f);
}
function stringToOpcode(symbol) {
return fromSymbol(symbol, 'opcode', opcodes, 'OPCODE', 2) & 0x0f;
}
function codeToString(code) {
return toSymbol(code, codesByVal, 'RCODE', 0x0f);
}
function stringToCode(symbol) {
return fromSymbol(symbol, 'code', codes, 'RCODE', 2) & 0x0f;
}
function typeToString(type) {
return toSymbol(type, typesByVal, 'TYPE', 0xffff);
}
function stringToType(symbol) {
return fromSymbol(symbol, 'type', types, 'TYPE', 5);
}
function classToString(class_) {
return toSymbol(class_, classesByVal, 'CLASS', 0xffff);
}
function stringToClass(symbol) {
return fromSymbol(symbol, 'class', classes, 'CLASS', 5);
}
function shortToString(class_) {
return toSymbol(class_, shortByVal, 'CLASS', 0xffff);
}
function stringToShort(symbol) {
return fromSymbol(symbol, 'short', short, 'CLASS', 5);
}
function ecodeToString(ecode) {
return toSymbol(ecode, ecodesByVal, 'RCODE', 0xff);
}
function stringToEcode(symbol) {
return fromSymbol(symbol, 'code', ecodes, 'RCODE', 3) & 0xff;
}
function optionToString(option) {
return toSymbol(option, optionsByVal, 'OPTION', 0xffff);
}
function stringToOption(symbol) {
return fromSymbol(symbol, 'option', options, 'OPTION', 5);
}
/*
* Expose

@@ -516,1 +632,17 @@ */

exports.YEAR68 = YEAR68;
exports.MAX_DOMAIN_LENGTH = MAX_DOMAIN_LENGTH;
exports.opcodeToString = opcodeToString;
exports.stringToOpcode = stringToOpcode;
exports.codeToString = codeToString;
exports.stringToCode = stringToCode;
exports.typeToString = typeToString;
exports.stringToType = stringToType;
exports.classToString = classToString;
exports.stringToClass = stringToClass;
exports.shortToString = shortToString;
exports.stringToShort = stringToShort;
exports.ecodeToString = ecodeToString;
exports.stringToEcode = stringToEcode;
exports.optionToString = optionToString;
exports.stringToOption = stringToOption;

@@ -495,7 +495,4 @@ /*!

dnssec.verifyRRSIG = function verifyRRSIG(msg, keyMap) {
const sections = [msg.answer];
const sections = [msg.answer, msg.authority];
if (msg.aa)
sections.push(msg.authority);
for (const section of sections) {

@@ -511,2 +508,5 @@ if (section.length === 0)

if (rr.type === types.NS)
continue;
set.add(rr.type);

@@ -513,0 +513,0 @@ }

@@ -219,4 +219,11 @@ /*!

if (socket && socket.pending === 0)
socket.close();
socket.destroy();
}
kill(port, host) {
const key = IP.toHost(host, port);
const socket = this.sockets.get(key);
if (socket)
socket.destroy();
}
}

@@ -293,2 +300,3 @@

this.connected = false;
this.destroyed = false;
this.parser = new Parser();

@@ -445,5 +453,6 @@ this.buffered = 0;

destroy() {
if (!this.connected)
if (this.destroyed)
return this;
this.destroyed = true;
this.cleanup();

@@ -450,0 +459,0 @@ this.socket.destroy();

@@ -7,3 +7,3 @@ /*!

* Parts of this software are based on miekg/dns and golang/go:
* https://github.com/miekg/dns/blob/master/dnssec.go
* https://github.com/miekg/dns/blob/master/nsecx.go
*

@@ -10,0 +10,0 @@ * Parts of this software are based on solvere:

@@ -14,3 +14,3 @@ /*!

const EventEmitter = require('events');
const IP = require('binet');
const Heap = require('bheep');
const encoding = require('./encoding');

@@ -22,4 +22,5 @@ const wire = require('./wire');

const {Client} = require('./net');
const Heap = require('bheep');
const rootZone = require('./hints');
const Hosts = require('./hosts');
const ResolvConf = require('./resolvconf');

@@ -33,2 +34,4 @@ const {

types,
MAX_DOMAIN_LENGTH,
typeToString,
codes

@@ -43,2 +46,3 @@ } = wire;

randomItem,
equal,
isSubdomain,

@@ -48,37 +52,2 @@ now

/*
* Constants
*/
const OPENDNS_IPV4 = [
'208.67.222.222', // resolver1.opendns.com
'208.67.220.220', // resolver2.opendns.com
'208.67.222.220', // resolver3.opendns.com
'208.67.220.222' // resolver4.opendns.com
];
const OPENDNS_IPV6 = [
'2620:0:ccc::2',
'2620:0:ccd::2'
];
const GOOGLE_IPV4 = [
'8.8.8.8',
'8.8.4.4'
];
const GOOGLE_IPV6 = [
'2001:4860:4860::8888',
'2001:4860:4860::8844'
];
const MAX_DOMAIN_LENGTH = 256;
const MAX_REFERRALS = 20;
const MAX_RETRIES = 5;
const MAX_CACHE_SIZE = 20 << 20;
// Make eslint happy.
OPENDNS_IPV4;
OPENDNS_IPV6;
/**

@@ -96,2 +65,4 @@ * DNSResolver

this.timer = null;
this.maxRetries = 5;
this.rd = false;
this.edns = true;

@@ -132,3 +103,3 @@ this.dnssec = true;

this.socket.setSendBufferSize(4096);
this.timer = setInterval(() => this.timeout(), 5000);
this.timer = setInterval(() => this.timeout(), 1000);
}

@@ -153,7 +124,12 @@

timeout() {
const time = now();
const now = Date.now();
for (const item of this.pending.values()) {
if (time > item.time + 10)
this.retry(item, item.rinfo);
const {id, time, rinfo} = item;
const {address} = rinfo;
if (now > time + 2000) {
this.log('Retrying (%s): %d...', address, id);
this.retry(item, false);
}
}

@@ -166,7 +142,18 @@ }

retry(item, rinfo, tcp) {
if (tcp == null)
tcp = rinfo.tcp;
verify(msg, host, port) {
return true;
}
if (item.retries >= MAX_RETRIES) {
append(msg, host, port) {
return msg;
}
retry(item, forceTCP) {
const {rinfo} = item;
const {port, address} = rinfo;
if (rinfo.tcp)
this.socket.kill(port, address);
if (item.retries >= this.maxRetries) {
this.pending.delete(item.id);

@@ -177,4 +164,7 @@ item.reject(new Error('Request timed out.'));

if (forceTCP)
rinfo.tcp = true;
const {tcp} = rinfo;
const msg = item.req.encode();
const {port, address} = item.rinfo;

@@ -185,3 +175,3 @@ // Retry over TCP or UDP.

// Update time.
item.time = now();
item.time = Date.now();
item.retries += 1;

@@ -198,3 +188,3 @@ }

if (msg.length < 2) {
this.error('Unsolicited msg.');
this.error(`Malformed message (${address}).`);
return;

@@ -207,3 +197,3 @@ }

if (!item) {
this.error(`Unsolicited msg: ${id}.`);
this.error(`Unsolicited message (${address}): ${id}.`);
return;

@@ -214,3 +204,3 @@ }

|| item.rinfo.port !== port) {
this.error(`Unsolicited msg: ${id}.`);
this.error(`Possible reflection attack (${address}): ${id}.`);
return;

@@ -249,5 +239,5 @@ }

// Retry over TCP.
this.log('Retrying over TCP.');
this.retry(item, rinfo, true);
// Retry over TCP if truncated.
this.log('Retrying over TCP (%s): %d.', address, id);
this.retry(item, true);

@@ -271,3 +261,4 @@ return;

item.req = req;
this.retry(item, rinfo);
this.log('Retrying without EDNS (%s): %d.', address, id);
this.retry(item, false);
return;

@@ -283,3 +274,4 @@ }

if (res.code === codes.SERVERFAILURE) {
this.retry(item, rinfo);
this.log('Retrying due to failure (%s): %d.', address, id);
this.retry(item, false);
return;

@@ -294,2 +286,8 @@ }

if (!this.verify(msg, address, port)) {
this.pending.delete(id);
item.reject(new Error('Could not verify response.'));
return;
}
this.pending.delete(id);

@@ -309,3 +307,3 @@

const msg = req.encode();
const msg = this.append(req.encode(), host, port);
const tcp = msg.length >= 4096;

@@ -325,3 +323,3 @@

},
time: now(),
time: Date.now(),
resolve,

@@ -333,11 +331,10 @@ reject

async query(qs, port, host, rd) {
async query(qs, port, host) {
assert(qs instanceof Question);
assert(typeof port === 'number');
assert(typeof host === 'string');
assert(typeof rd === 'boolean');
const req = new Message();
req.opcode = opcodes.QUERY;
req.rd = rd;
req.rd = this.rd;
req.question.push(qs);

@@ -351,10 +348,10 @@

async lookup(name, type, port, host, rd) {
async lookup(name, type, port, host) {
const qs = new Question(name, type);
return this.query(qs, port, host, rd);
return this.query(qs, port, host);
}
async reverse(addr, port, host, rd) {
async reverse(addr, port, host) {
const name = encoding.reverse(addr);
return this.lookup(name, types.PTR, port, host, rd);
return this.lookup(name, types.PTR, port, host);
}

@@ -371,18 +368,36 @@ }

super(options);
this.rd = true;
this.conf = new ResolvConf();
}
getServers() {
return this.conf.getServers();
}
setServers(servers) {
this.conf.setServers(servers);
return this;
}
randomServer() {
return this.conf.randomServer(this.inet6);
}
async resolve(qs, port, host) {
if (host == null) {
const addr = this.randomServer();
host = addr.host;
if (port == null)
port = addr.port;
}
if (port == null)
port = 53;
if (host == null) {
host = randomItem(this.inet6 ? GOOGLE_IPV6 : GOOGLE_IPV4);
host = IP.normalize(host);
port = 53;
}
assert(typeof port === 'number');
assert(typeof host === 'string');
return this.query(qs, port, host, true, null);
return this.query(qs, port, host);
}

@@ -395,3 +410,3 @@

async reverse(addr, port, host, rd) {
async reverse(addr, port, host) {
const name = encoding.reverse(addr);

@@ -403,2 +418,45 @@ return this.lookup(name, types.PTR, port, host);

/**
* OSResolver
* @extends StubResolver
*/
class OSResolver extends StubResolver {
constructor(options) {
super(options);
this.conf = ResolvConf.fromSystem();
this.hosts = Hosts.fromSystem();
}
async query(qs, port, host) {
assert(qs instanceof Question);
assert(typeof port === 'number');
assert(typeof host === 'string');
const {name, type} = qs;
const answer = this.hosts.query(name, type);
if (answer) {
const res = new Message();
res.id = (Math.random() * 0x10000) >>> 0;
res.opcode = opcodes.QUERY;
res.code = codes.NOERROR;
res.qr = true;
res.rd = true;
res.ra = true;
res.ad = true;
res.question = [qs];
res.answer = answer;
if (this.edns)
res.setEDNS(4096, this.dnssec);
return res;
}
return super.query(qs, port, host);
}
}
/**
* Hints

@@ -539,2 +597,3 @@ */

super(options);
this.rd = false;
this.cache = new Cache();

@@ -554,7 +613,7 @@ this.hints = Hints.fromZone(rootZone);

if (cache) {
this.log('Cache hit for %s/%d.', qs.name, qs.type);
this.log('Cache hit for %s/%s.', qs.name, typeToString(qs.type));
return [cache, true];
}
const res = await this.query(qs, port, host, false);
const res = await this.query(qs, port, host);

@@ -632,11 +691,17 @@ return [res, false];

if (ds.length === 0)
throw new Error('Invalid DNSKEY (DS absent).');
if (ds.length === 0) {
this.log('Invalid DNSKEY (DS absent).');
return null;
}
if (!hit) {
if (!dnssec.verifyDS(keyMap, ds))
throw new Error('Invalid DNSKEY (DS mismatch).');
if (!dnssec.verifyDS(keyMap, ds)) {
this.log('Invalid DNSKEY (DS mismatch).');
return null;
}
if (!dnssec.verifyRRSIG(res, keyMap))
throw new Error('Invalid RRSIG.');
if (!dnssec.verifyRRSIG(res, keyMap)) {
this.log('Invalid RRSIG (keys).');
return null;
}
}

@@ -659,8 +724,15 @@

if (keyMap.size === 0)
throw new Error('No DNSKEY found.');
if (!keyMap)
return false;
if (!dnssec.verifyRRSIG(msg, keyMap))
if (keyMap.size === 0) {
this.log('No DNSKEY found.');
return false;
}
if (!dnssec.verifyRRSIG(msg, keyMap)) {
this.log('Invalid RRSIG.');
return false;
}
this.log('Validated DNSSEC signatures.');

@@ -677,7 +749,7 @@

if (rr.type === types.NS)
nsmap.set(rr.data.ns, rr.name);
nsmap.set(rr.data.ns.toLowerCase(), rr.name.toLowerCase());
}
for (const rr of additional) {
const zone = nsmap.get(rr.name);
const zone = nsmap.get(rr.name.toLowerCase());

@@ -876,2 +948,8 @@ if (!zone)

if (this.nsec3 && rc.chain && rc.res.code === codes.NXDOMAIN) {
const nsec = extractSet(rc.res.authority, '', types.NSEC3);
if (!nsec3.verifyNameError(rc.qs, nsec))
throw new Error('NSEC missing coverage');
}
if (rc.res.answer.length > 0

@@ -890,8 +968,2 @@ && (rc.res.code === codes.NOERROR

if (this.nsec3 && rc.chain && rc.res.code === codes.NXDOMAIN) {
const nsec = extractSet(rc.res.authority, '', types.NSEC3);
if (!nsec3.verifyNameError(rc.qs, nsec))
throw new Error('NSEC missing coverage');
}
return false;

@@ -901,3 +973,3 @@ }

async iterate(rc) {
this.log('Querying %s/%d.', rc.qs.name, rc.qs.type);
this.log('Querying %s/%s.', rc.qs.name, typeToString(rc.qs.type));

@@ -909,6 +981,10 @@ for (;;) {

assert(rc.hops <= MAX_REFERRALS);
assert(rc.hops <= rc.maxReferrals);
this.log('Traversed zones: %s for %s/%d.',
rc.zones.join(', '), rc.question.name, rc.question.type);
this.log(
'Traversed zones: %s for %s/%s.',
rc.zones.join(', '),
rc.question.name,
typeToString(rc.question.type)
);

@@ -945,3 +1021,4 @@ if (rc.res.answer.length > 0) {

this.log('Finishing resolving %s/%d (hops=%d).', qs.name, qs.type, rc.hops);
this.log('Finishing resolving %s/%s (hops=%d).',
qs.name, typeToString(qs.type), rc.hops);

@@ -993,2 +1070,3 @@ return rc.toAnswer();

this.hit = false;
this.maxReferrals = 20;
this.switchZone(ns);

@@ -1015,3 +1093,3 @@ }

hop() {
if (this.hops >= MAX_REFERRALS)
if (this.hops >= this.maxReferrals)
throw new Error('Maximum referrals exceeded.');

@@ -1026,7 +1104,8 @@

res.id = this.res.id;
res.opcode = this.res.opcode;
res.code = this.res.code;
res.qr = true;
res.opcode = this.res.opcode;
res.ra = true;
res.ad = this.chain;
res.code = this.res.code;
res.question = [this.question];

@@ -1036,2 +1115,3 @@ res.answer = this.res.answer.slice();

res.additional = this.res.additional.slice();
res.edns = this.res.edns.clone();

@@ -1051,2 +1131,3 @@ return res;

this.size = 0;
this.maxSize = 5 << 20;
}

@@ -1072,3 +1153,3 @@

prune() {
while (this.size > MAX_CACHE_SIZE) {
while (this.size > this.maxSize) {
const [id, deadline] = this.queue.shift();

@@ -1195,11 +1276,23 @@ const entry = this.get(id);

function collapseChain(qname, records) {
function collapseChain(name, records) {
const chased = [];
const map = new Map();
const sigs = new Map();
for (const rr of records) {
if (rr.type === types.CNAME)
map.set(rr.name, rr);
const rd = rr.data;
if (rr.type === types.CNAME) {
map.set(rr.name.toLowerCase(), rr);
continue;
}
if (rr.type === types.RRSIG) {
if (rd.typeCovered === types.CNAME)
sigs.set(rr.name.toLowerCase(), rr);
continue;
}
}
let qname = name.toLowerCase();
let canonical = '';

@@ -1209,2 +1302,3 @@

const cname = map.get(qname);
const sig = sigs.get(qname);

@@ -1215,4 +1309,8 @@ if (!cname)

canonical = cname.data.target;
qname = canonical;
qname = canonical.toLowerCase();
chased.push(cname);
if (sig)
chased.push(sig);
}

@@ -1230,6 +1328,10 @@

if (rrs.length > 1) {
if (!hasAll(rrs, types.CNAME) || qs.type === types.CNAME)
if (!hasAll(rrs, types.CNAME)
|| qs.type === types.CNAME) {
return ['', null];
const [sname, chased] = collapseChain(qs.name, rrs);
return [sname, chased];
}
const [alias, chased] = collapseChain(qs.name, answer);
return [alias, chased];
}

@@ -1242,6 +1344,10 @@

case types.CNAME: {
if (qs.type === types.CNAME || qs.name !== rr.name)
if (qs.type === types.CNAME
|| !equal(qs.name, rr.name)) {
return ['', null];
return [rd.target, rrs];
}
return [rd.target, answer];
}
case types.DNAME: {

@@ -1255,8 +1361,8 @@ if (qs.type === types.DNAME)

const bottom = qs.name.slice(0, -rr.name.length);
const sname = bottom + rd.target;
const alias = bottom + rd.target;
if (sname.length > MAX_DOMAIN_LENGTH)
if (alias.length > MAX_DOMAIN_LENGTH)
throw new Error('DNAME too long.');
return [sname, rrs];
return [alias, answer];
}

@@ -1316,6 +1422,6 @@ }

if (util.equal(rr.name, name))
if (equal(rr.name, name))
continue;
if (util.isSubdomain(rr.name, name))
if (isSubdomain(rr.name, name))
continue;

@@ -1338,2 +1444,3 @@

exports.StubResolver = StubResolver;
exports.OSResolver = OSResolver;
exports.RecursiveResolver = RecursiveResolver;

@@ -19,4 +19,13 @@ /*!

const encoding = require('./encoding');
const {types, typesByVal, YEAR68, options} = require('./constants');
const constants = require('./constants');
const {
types,
YEAR68,
options,
typeToString,
stringToType,
typesByVal
} = constants;
/*

@@ -27,3 +36,3 @@ * Schemas

const UNKNOWNSchema = [
['data', 'hex']
['data', 'hex-end']
];

@@ -78,3 +87,3 @@

['protocol', 'u8'],
['bitmap', 'hex'] // ??
['bitmap', 'hex-end'] // ??
];

@@ -130,3 +139,3 @@

const NSAPSchema = [
['nsap', 'hex'] // ??
['nsap', 'hex-end'] // ??
];

@@ -145,3 +154,3 @@

['signerName', 'name'],
['signature', 'base64']
['signature', 'base64-end']
];

@@ -153,3 +162,3 @@

['algorithm', 'u8'],
['publicKey', 'base64']
['publicKey', 'base64-end']
];

@@ -185,11 +194,11 @@

['nextDomain', 'name'],
['typeBitmap', 'nsec3']
['typeBitmap', 'nsec']
];
const EIDSchema = [
['endpoint', 'hex']
['endpoint', 'hex-end']
];
const NIMLOCSchema = [
['locator', 'hex']
['locator', 'hex-end']
];

@@ -206,3 +215,3 @@

['format', 'u8'],
['address', 'hex'] // ??
['address', 'hex-end'] // ??
];

@@ -228,3 +237,3 @@

['algorithm', 'u8'],
['certificate', 'base64']
['certificate', 'base64-end']
];

@@ -245,3 +254,3 @@

['n', 'u8'],
['afd', 'hex'] // ??
['afd', 'hex-end'] // ??
];

@@ -253,3 +262,3 @@

['digestType', 'u8'],
['digest', 'hex']
['digest', 'hex-end']
];

@@ -260,3 +269,3 @@

['keyType', 'u8'],
['fingerprint', 'hex']
['fingerprint', 'hex-end']
];

@@ -269,3 +278,3 @@

['target', 'string'],
['publicKey', 'base64']
['publicKey', 'base64-end']
];

@@ -277,3 +286,3 @@

['nextDomain', 'name'],
['typeBitmap', 'nsec3']
['typeBitmap', 'nsec']
];

@@ -284,3 +293,3 @@

const DHCIDSchema = [
['digest', 'base64']
['digest', 'base64-end']
];

@@ -294,3 +303,3 @@

['nextDomain', 'base32'],
['typeBitmap', 'nsec3']
['typeBitmap', 'nsec']
];

@@ -309,3 +318,3 @@

['matchingType', 'u8'],
['certificate', 'hex']
['certificate', 'hex-end']
];

@@ -319,7 +328,7 @@

['publicKey', 'base64'],
['rendezvousServers', 'names']
['rendezvousServers', 'servers']
];
const NINFOSchema = [
['zsData', 'stxt']
['zsData', 'txt']
];

@@ -339,3 +348,3 @@

const OPENPGPKEYSchema = [
['publicKey', 'base64']
['publicKey', 'base64-end']
];

@@ -346,3 +355,3 @@

['flags', 'u16'],
['typeBitmap', 'nsec3']
['typeBitmap', 'nsec']
];

@@ -410,4 +419,4 @@

['algorithm', 'name'],
['inception', 'u32'], // time?
['expiration', 'u32'], // time?
['inception', 'u32'],
['expiration', 'u32'],
['mode', 'u16'],

@@ -421,4 +430,4 @@ ['error', 'u16'],

['algorithm', 'name'],
['timeSigned', 'u48'], // time?
['fudge', 'u16'], // time?
['timeSigned', 'u48'],
['fudge', 'u16'],
['mac', 'hex'],

@@ -436,3 +445,3 @@ ['origID', 'u16'],

['digestType', 'u8'],
['digest', 'hex']
['digest', 'hex-end']
];

@@ -455,7 +464,7 @@

const NSIDSchema = [
['nsid', 'hex']
['nsid', 'hex-end']
];
const DAUSchema = [
['algCode', 'hex']
['algCode', 'hex-end']
];

@@ -479,3 +488,3 @@

const COOKIESchema = [
['cookie', 'hex']
['cookie', 'hex-end']
];

@@ -489,7 +498,7 @@

const PADDINGSchema = [
['padding', 'hex']
['padding', 'hex-end']
];
const LOCALSchema = [
['data', 'hex']
['data', 'hex-end']
];

@@ -638,6 +647,8 @@

switch (type) {
case 'base64':
case 'names':
case 'nsec3':
case 'txt': {
case 'hex-end':
case 'base64-end':
case 'servers':
case 'nsec':
case 'txt':
case 'octet': {
const left = parts.slice(i).join(' ');

@@ -679,3 +690,3 @@ rd[name] = readType(type, left);

}
case 'names': {
case 'servers': {
const names = part.split(' ');

@@ -705,2 +716,8 @@ for (const name of names)

}
case 'hex-end': {
const hex = part.replace(/\s+/g, '');
const data = Buffer.from(hex, 'hex');
assert(data.length === (hex.length >>> 1));
return data;
}
case 'base32': {

@@ -710,3 +727,7 @@ return base32.decodeHex(part);

case 'base64': {
const b64 = part.replace(/ +/, '');
assert(/^[A-Za-z0-9+\/=]+$/.test(part));
return Buffer.from(part, 'base64');
}
case 'base64-end': {
const b64 = part.replace(/\s+/g, '');
assert(/^[A-Za-z0-9+\/=]+$/.test(b64));

@@ -749,11 +770,8 @@ return Buffer.from(b64, 'base64');

}
case 'nsec3': {
case 'nsec': {
const tns = part.split(' ');
const ts = [];
for (const tn of tns) {
const t = types[tn];
assert(t != null);
ts.push(t);
}
for (const tn of tns)
ts.push(stringToType(tn));

@@ -766,53 +784,18 @@ return encoding.toBitmap(ts);

case 'type': {
const type = types[part];
assert(type != null);
return type;
return stringToType(part);
}
case 'u8': {
const n = parseInt(part, 10);
assert((n & 0xff) === n);
return n;
return util.parseU8(part);
}
case 'u16': {
const n = parseInt(part, 10);
assert((n & 0xffff) === n);
return n;
return util.parseU16(part);
}
case 'u32': {
const n = parseInt(part, 10);
assert((n >>> 0) === n);
return n;
return util.parseU32(part);
}
case 'u48': {
const n = parseInt(part, 10);
assert(n >= 0 && n <= 0xffffffffffff);
return n;
return util.parseU48(part);
}
case 'u64': {
let hi = 0;
let lo = 0;
for (let i = 0; i < part.length; i++) {
let ch = part.charCodeAt(i);
if (ch < 0x30 || ch > 0x39)
throw new Error('Invalid string (parse error).');
ch -= 0x30;
lo *= 10;
lo += ch;
hi *= 10;
if (lo > 0xffffffff) {
ch = lo % 0x100000000;
hi += (lo - ch) / 0x100000000;
lo = ch;
}
if (hi > 0xffffffff)
throw new Error('Invalid string (overflow).');
}
const [hi, lo] = util.parseU64(part);
const out = Buffer.allocUnsafe(8);

@@ -823,18 +806,2 @@ out.writeUInt32BE(hi, true);

}
case 'bool': {
assert(part === '0' || part === '1');
return part === '1';
}
case 'nodes': {
const parts = part.split(':');
const nodes = [];
for (const part of parts) {
const data = Buffer.from(part, 'hex');
assert(data.length === (part.length >>> 1));
nodes.push(data);
}
return nodes;
}
default: {

@@ -852,3 +819,3 @@ throw new Error('Unknown type.');

}
case 'names': {
case 'servers': {
assert(Array.isArray(value));

@@ -867,10 +834,26 @@ return value.join(' ');

assert(Buffer.isBuffer(value));
return value.toString('hex');
return value.toString('hex').toUpperCase();
}
case 'hex-end': {
assert(Buffer.isBuffer(value));
const hex = value.toString('hex').toUpperCase();
const out = [];
for (let i = 0; i < hex.length; i += 56)
out.push(hex.substring(i, i + 56));
return out.join(' ');
}
case 'base32': {
assert(Buffer.isBuffer(value));
return base32.encodeHex(value);
return base32.encodeHex(value).toUpperCase();
}
case 'base64': {
assert(Buffer.isBuffer(value));
return value.toString('base64');
}
case 'base64-end': {
assert(Buffer.isBuffer(value));
const b64 = value.toString('base64');

@@ -894,8 +877,11 @@ const out = [];

assert(Array.isArray(value));
const out = [];
for (const str of value)
out.push(JSON.stringify(str));
return out.join(' ');
}
case 'nsec3': {
case 'nsec': {
assert(Buffer.isBuffer(value));

@@ -907,5 +893,4 @@

for (const t of ts) {
const tn = typesByVal[t];
if (tn != null)
tns.push(tn);
if (typesByVal[t])
tns.push(typeToString(t));
}

@@ -916,23 +901,22 @@

case 'time': {
assert(typeof value === 'number');
return timeToString(value);
}
case 'type': {
assert(typeof value === 'number');
return typesByVal[value] || 'UNKNOWN';
return typeToString(value);
}
case 'u8': {
assert(typeof value === 'number');
assert((value & 0xff) === value);
return value.toString(10);
}
case 'u16': {
assert(typeof value === 'number');
assert((value & 0xffff) === value);
return value.toString(10);
}
case 'u32': {
assert(typeof value === 'number');
assert((value >>> 0) === value);
return value.toString(10);
}
case 'u48': {
assert(typeof value === 'number');
assert(Number.isSafeInteger(value));
assert(value >= 0 && value <= 0xffffffffffff);
return value.toString(10);

@@ -942,36 +926,6 @@ }

assert(Buffer.isBuffer(value) && value.length === 8);
let hi = value.readUInt32BE(0, true);
let lo = value.readUInt32BE(4, true);
let str = '';
do {
const mhi = hi % 10;
hi -= mhi;
hi /= 10;
lo += mhi * 0x100000000;
const mlo = lo % 10;
lo -= mlo;
lo /= 10;
let ch = mlo;
ch += 0x30;
str = String.fromCharCode(ch) + str;
} while (lo > 0 || hi > 0);
return str;
const hi = value.readUInt32BE(0, true);
const lo = value.readUInt32BE(4, true);
return util.serializeU64(hi, lo);
}
case 'bool': {
assert(typeof value === 'boolean');
return value ? '1' : '0';
}
case 'nodes': {
const out = [];
for (const node of value)
out.push(node.toString('hex'));
return out.join(':');
}
default: {

@@ -1017,3 +971,3 @@ throw new Error('Unknown type.');

}
case 'names': {
case 'servers': {
assert(Array.isArray(value));

@@ -1041,3 +995,4 @@ const names = [];

}
case 'hex': {
case 'hex':
case 'hex-end': {
assert(typeof value === 'string');

@@ -1052,3 +1007,4 @@ const data = Buffer.from(value, 'hex');

}
case 'base64': {
case 'base64':
case 'base64-end': {
assert(typeof value === 'string');

@@ -1078,3 +1034,3 @@ assert(/^[A-Za-z0-9+\/=]+$/.test(value));

}
case 'nsec3': {
case 'nsec': {
return encoding.toBitmap(value);

@@ -1086,5 +1042,3 @@ }

case 'type': {
const type = types[value];
assert(type != null);
return type;
return stringToType(value);
}

@@ -1104,4 +1058,4 @@ case 'u8': {

case 'u48': {
assert(Number.isSafeInteger(value));
assert(value >= 0 && value <= 0xffffffffffff);
assert((value % 1) === 0);
return value;

@@ -1116,17 +1070,2 @@ }

}
case 'bool': {
assert(typeof value === 'boolean');
return value;
}
case 'nodes': {
assert(Array.isArray(value));
const nodes = [];
for (const item of value) {
assert(typeof item === 'string');
const data = Buffer.from(item, 'hex');
assert(data.length === (item.length >>> 1));
nodes.push(data);
}
return nodes;
}
default: {

@@ -1144,3 +1083,3 @@ throw new Error('Unknown type.');

}
case 'names': {
case 'servers': {
assert(Array.isArray(value));

@@ -1157,3 +1096,4 @@ return value;

}
case 'hex': {
case 'hex':
case 'hex-end': {
assert(Buffer.isBuffer(value));

@@ -1166,3 +1106,4 @@ return value.toString('hex');

}
case 'base64': {
case 'base64':
case 'base64-end': {
assert(Buffer.isBuffer(value));

@@ -1183,3 +1124,3 @@ return value.toString('base64');

}
case 'nsec3': {
case 'nsec': {
assert(Buffer.isBuffer(value));

@@ -1194,18 +1135,19 @@ return encoding.fromBitmap(value);

assert(typeof value === 'number');
return typesByVal[value] || 'UNKNOWN';
return typeToString(value);
}
case 'u8': {
assert(typeof value === 'number');
assert((value & 0xff) === value);
return value;
}
case 'u16': {
assert(typeof value === 'number');
assert((value & 0xffff) === value);
return value;
}
case 'u32': {
assert(typeof value === 'number');
assert((value >>> 0) === value);
return value;
}
case 'u48': {
assert(typeof value === 'number');
assert(Number.isSafeInteger(value));
assert(value >= 0 && value <= 0xffffffffffff);
return value;

@@ -1217,16 +1159,2 @@ }

}
case 'bool': {
assert(typeof value === 'boolean');
return value;
}
case 'nodes': {
assert(Array.isArray(value));
const json = [];
for (const node of value)
json.push(node.toString('hex'));
return json;
}
default: {

@@ -1250,9 +1178,8 @@ throw new Error('Unknown type.');

function unpad(str, start, end) {
const s = str.substring(start, end);
assert(/^\d+$/.test(s));
return parseInt(s, 10);
const num = str.substring(start, end);
return util.parseU16(num);
}
function timeToString(t) {
assert(typeof t === 'number' && isFinite(t) && t >= 0);
assert(Number.isSafeInteger(t) && t >= 0);

@@ -1259,0 +1186,0 @@ const div = (t - util.now()) / YEAR68;

@@ -27,3 +27,3 @@ /*!

const {port, address, tcp} = this.rinfo;
const msg = this.encode(!tcp);
const msg = this.server.sign(this.encode(!tcp), address, port);
return this.server.send(msg, 0, msg.length, port, address, tcp);

@@ -141,2 +141,6 @@ }

sign(msg, host, port) {
return msg;
}
async handle(msg, rinfo) {

@@ -163,3 +167,3 @@ const req = Message.decode(msg);

const {port, address, tcp} = rinfo;
const msg = res.encode(!tcp);
const msg = this.sign(res.encode(!tcp), address, port);
this.server.send(msg, 0, msg.length, port, address, tcp);

@@ -166,0 +170,0 @@ this.emit('query', req, res, rinfo);

@@ -7,3 +7,4 @@ /*!

* Parts of this software are based on miekg/dns and golang/go:
* https://github.com/miekg/dns/blob/master/dnssec.go
* https://github.com/miekg/dns/blob/master/labels.go
* https://github.com/miekg/dns/blob/master/dnsutil/util.go
*/

@@ -78,3 +79,3 @@

if (a !== b)
if (!util.equal(a, b))
return n;

@@ -91,3 +92,3 @@

if (a !== b)
if (!util.equal(a, b))
break;

@@ -207,3 +208,3 @@

let ai = a.charCodeAt(i);
let bi = a.charCodeAt(i);
let bi = b.charCodeAt(i);

@@ -461,3 +462,3 @@ if (ai >= 0x41 && ai <= 0x5a)

|| rr.class !== class_
|| rr.name !== name) {
|| !util.equal(rr.name, name)) {
return false;

@@ -473,7 +474,7 @@ }

const map = new Set(types);
const set = new Set(types);
const out = [];
for (const rr of records) {
if (!map.has(rr.type))
if (!set.has(rr.type))
out.push(rr);

@@ -489,8 +490,8 @@ }

const map = new Set(types);
const set = new Set(types);
const out = [];
for (const rr of records) {
if (map.has(rr.type)) {
if (name !== '' && name !== rr.name)
if (set.has(rr.type)) {
if (name !== '' && !util.equal(rr.name, name))
continue;

@@ -543,27 +544,113 @@ out.push(rr);

util.digDate = function digDate(time) {
const d = time != null ? new Date(time) : new Date();
const d = time != null ? new Date(time * 1000) : new Date();
const str = d.toString();
const parts = str.split(' ');
const [day, month, date, year, ts, , tz] = parts;
const z = tz.slice(1, -1);
return `${day} ${month} ${date} ${ts} ${z} ${year}`;
};
let [
day,
month,
date,
year,
ts,
,
tz
] = parts;
util.parseInteger = function parseInteger(str, max, size) {
assert(typeof str === 'string');
tz = tz.slice(1, -1);
let word = 0;
return `${day} ${month} ${date} ${ts} ${tz} ${year}`;
if (str.length > size)
throw new Error('Invalid integer.');
for (let i = 0; i < str.length; i++) {
const ch = str.charCodeAt(i) - 0x30;
if (ch < 0 || ch > 9)
throw new Error('Invalid integer.');
word *= 10;
word += ch;
if (word > max)
throw new Error('Invalid integer.');
}
return word;
};
util.dir = function dir(obj) {
util.parseU8 = function parseU8(str) {
return util.parseInteger(str, 0xff, 3);
};
util.parseU16 = function parseU16(str) {
return util.parseInteger(str, 0xffff, 5);
};
util.parseU32 = function parseU32(str) {
return util.parseInteger(str, 0xffffffff, 10);
};
util.parseU48 = function parseU48(str) {
return util.parseInteger(str, 0xffffffffffff, 15);
};
util.parseU64 = function parseU64(str) {
assert(typeof str === 'string');
if (str.length > 20)
throw new Error('Invalid integer.');
let hi = 0;
let lo = 0;
for (let i = 0; i < str.length; i++) {
const ch = str.charCodeAt(i) - 0x30;
if (ch < 0 || ch > 9)
throw new Error('Invalid integer.');
lo *= 10;
lo += ch;
hi *= 10;
if (lo > 0xffffffff) {
const m = lo % 0x100000000;
hi += (lo - m) / 0x100000000;
lo = m;
}
if (hi > 0xffffffff)
throw new Error('Invalid integer.');
}
return [hi, lo];
};
util.serializeU64 = function serializeU64(hi, lo) {
assert((hi >>> 0) === hi);
assert((lo >>> 0) === lo);
let str = '';
do {
const mhi = hi % 10;
hi -= mhi;
hi /= 10;
lo += mhi * 0x100000000;
const mlo = lo % 10;
lo -= mlo;
lo /= 10;
const ch = mlo + 0x30;
str = String.fromCharCode(ch) + str;
} while (lo > 0 || hi > 0);
return str;
};
util.dir = function dir(obj, inspect = true) {
console.dir(obj, {
depth: 20,
colors: true,
customInspect: true
customInspect: inspect
});
};
{
"name": "bns",
"version": "0.0.3",
"version": "0.0.4",
"description": "DNS bike-shed",

@@ -31,2 +31,3 @@ "keywords": [

"dependencies": {
"bfile": "~0.0.2",
"bheep": "~0.0.1",

@@ -56,3 +57,3 @@ "binet": "~0.1.0",

"browser": {
"./lib/crypto": "./lib/crypto.js"
"./lib/crypto": "./lib/crypto-browser.js"
},

@@ -59,0 +60,0 @@ "browserify": {

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc