Merge branch 'layers' of git.daplie.com:Daplie/Goldilocks.js into layers

This commit is contained in:
AJ ONeal 2017-05-04 23:43:46 -06:00
commit 3c5bc9103e
5 changed files with 195 additions and 25 deletions

View File

@ -61,6 +61,9 @@ function readConfigAndRun(args) {
); );
} }
} }
if (!config.dns) {
config.dns = { proxy: { port: 3053 } };
}
if (!config.tcp) { if (!config.tcp) {
config.tcp = {}; config.tcp = {};
} }
@ -116,24 +119,63 @@ function readConfigAndRun(args) {
config.addresses = addresses; config.addresses = addresses;
config.device = { hostname: 'daplien-pod' }; config.device = { hostname: 'daplien-pod' };
var PromiseA = require('bluebird');
var tcpProm, dnsProm;
if (config.tcp.ports) { if (config.tcp.ports) {
run(config); tcpProm = PromiseA.resolve();
return; } else {
tcpProm = new PromiseA(function (resolve, reject) {
require('../lib/check-ports').checkTcpPorts(function (failed, bound) {
config.tcp.ports = Object.keys(bound);
if (config.tcp.ports.length) {
resolve();
} else {
reject(failed);
}
});
});
} }
require('../lib/check-ports.js').checkPorts(config, function (failed, bound) { if (config.dns.bind) {
config.tcp.ports = Object.keys(bound); dnsProm = PromiseA.resolve();
} else {
dnsProm = new PromiseA(function (resolve) {
require('../lib/check-ports').checkUdpPorts(function (failed, bound) {
var ports = Object.keys(bound);
if (!config.tcp.ports.length) { if (ports.length === 0) {
// I don't think we want to prevent the rest of the app from running in
// this case like we do for TCP, do don't call reject.
console.warn('could not bind to the desired ports for DNS');
Object.keys(failed).forEach(function (key) {
console.log('[error bind]', key, failed[key].code);
});
}
else if (ports.length === 1) {
config.dns.bind = parseInt(ports[0], 10);
}
else {
config.dns.bind = ports.map(function (numStr) {
return parseInt(numStr, 10);
});
}
resolve();
});
});
}
PromiseA.all([tcpProm, dnsProm])
.then(function () {
run(config);
})
.catch(function (failed) {
console.warn("could not bind to the desired ports"); console.warn("could not bind to the desired ports");
Object.keys(failed).forEach(function (key) { Object.keys(failed).forEach(function (key) {
console.log('[error bind]', key, failed[key].code); console.log('[error bind]', key, failed[key].code);
}); });
return; });
}
run(config);
});
} }
function readEnv(args) { function readEnv(args) {
@ -166,7 +208,7 @@ else if (process.argv.length > 2) {
var program = require('commander'); var program = require('commander');
program program
.version(require('package.json').version) .version(require('../package.json').version)
.option('--agree-tos [url1,url2]', "agree to all Terms of Service for Daplie, Let's Encrypt, etc (or specific URLs only)") .option('--agree-tos [url1,url2]', "agree to all Terms of Service for Daplie, Let's Encrypt, etc (or specific URLs only)")
.option('--config', 'Path to config file (Goldilocks.json or Goldilocks.yml) example: --config /etc/goldilocks/Goldilocks.json') .option('--config', 'Path to config file (Goldilocks.json or Goldilocks.yml) example: --config /etc/goldilocks/Goldilocks.json')
.option('--tunnel [token]', 'Turn tunnel on. This will enter interactive mode for login if no token is specified.') .option('--tunnel [token]', 'Turn tunnel on. This will enter interactive mode for login if no token is specified.')

View File

@ -11,7 +11,18 @@ function bindTcpAndRelease(port, cb) {
}); });
} }
function checkPorts(config, cb) { function bindUdpAndRelease(port, cb) {
var socket = require('dgram').createSocket('udp4');
socket.on('error', function (e) {
cb(e);
});
socket.bind(port, function () {
socket.close();
cb();
});
}
function checkTcpPorts(cb) {
var bound = {}; var bound = {};
var failed = {}; var failed = {};
@ -32,7 +43,6 @@ function checkPorts(config, cb) {
} }
if (bound['80'] && bound['443']) { if (bound['80'] && bound['443']) {
//config.tcp.ports = [ 80, 443 ];
cb(null, bound); cb(null, bound);
return; return;
} }
@ -52,4 +62,34 @@ function checkPorts(config, cb) {
}); });
} }
module.exports.checkPorts = checkPorts; function checkUdpPorts(cb) {
var bound = {};
var failed = {};
bindUdpAndRelease(53, function (e) {
if (e) {
failed[53] = e;
} else {
bound[53] = true;
}
if (bound[53]) {
cb(null, bound);
return;
}
console.warn("default DNS port 53 not available, trying 8053");
bindUdpAndRelease(8053, function (e) {
if (e) {
failed[8053] = e;
} else {
bound[8053] = true;
}
cb(null, bound);
});
});
}
module.exports.checkTcpPorts = checkTcpPorts;
module.exports.checkUdpPorts = checkUdpPorts;

View File

@ -236,6 +236,12 @@ module.exports.create = function (deps, config) {
}); });
} }
function dnsListener(msg) {
var dgram = require('dgram');
var socket = dgram.createSocket('udp4');
socket.send(msg, config.dns.proxy.port, config.dns.proxy.address || '127.0.0.1');
}
function approveDomains(opts, certs, cb) { function approveDomains(opts, certs, cb) {
// This is where you check your database and associated // This is where you check your database and associated
// email addresses with domains and agreements and such // email addresses with domains and agreements and such
@ -448,7 +454,19 @@ module.exports.create = function (deps, config) {
}); });
}); });
PromiseA.all(config.tcp.ports.map(function (port) { var listenPromises = config.tcp.ports.map(function (port) {
return listeners.tcp.add(port, netHandler); return listeners.tcp.add(port, netHandler);
})); });
if (config.dns.bind) {
if (Array.isArray(config.dns.bind)) {
listenPromises = listenPromises.concat(config.dns.bind.map(function (port) {
return listeners.udp.add(port, dnsListener);
}));
} else {
listenPromises.push(listeners.udp.add(config.dns.bind, dnsListener));
}
}
return PromiseA.all(listenPromises);
}; };

View File

@ -1,12 +1,12 @@
'use strict'; 'use strict';
var serversMap = module.exports._serversMap = {}; var serversMap = module.exports._serversMap = {};
var dgramMap = module.exports._dgramMap = {};
var PromiseA = require('bluebird');
module.exports.addTcpListener = function (port, handler) { module.exports.addTcpListener = function (port, handler) {
var PromiseA = require('bluebird');
return new PromiseA(function (resolve, reject) { return new PromiseA(function (resolve, reject) {
var stat = serversMap[port] || serversMap[port]; var stat = serversMap[port];
if (stat) { if (stat) {
if (stat._closing) { if (stat._closing) {
@ -34,9 +34,13 @@ module.exports.addTcpListener = function (port, handler) {
stat = serversMap[port] = { stat = serversMap[port] = {
server: server server: server
, handler: handler , handler: handler
, _closing: false , _closing: null
}; };
// Add .destroy so we can close all open connections. Better if added before listen
// to eliminate any possibility of it missing an early connection in it's records.
enableDestroy(server);
server.on('connection', function (conn) { server.on('connection', function (conn) {
conn.__port = port; conn.__port = port;
conn.__proto = 'tcp'; conn.__proto = 'tcp';
@ -62,16 +66,13 @@ module.exports.addTcpListener = function (port, handler) {
resolved = true; resolved = true;
resolve(); resolve();
}); });
enableDestroy(server); // adds .destroy
}); });
}; };
module.exports.closeTcpListener = function (port) { module.exports.closeTcpListener = function (port) {
var PromiseA = require('bluebird');
return new PromiseA(function (resolve) { return new PromiseA(function (resolve) {
var stat = serversMap[port]; var stat = serversMap[port];
if (!stat) { if (!stat) {
resolve();
return; return;
} }
stat.server.on('close', function () { stat.server.on('close', function () {
@ -98,10 +99,79 @@ module.exports.destroyTcpListener = function (port) {
stat = null; stat = null;
}; };
module.exports.addUdpListener = function (port, handler) {
return new PromiseA(function (resolve, reject) {
var stat = dgramMap[port];
if (stat) {
// we'll replace the current listener
stat.handler = handler;
resolve();
return;
}
var dgram = require('dgram');
var server = dgram.createSocket('udp4');
var resolved = false;
stat = dgramMap[port] = {
server: server
, handler: handler
};
server.on('message', function (msg, rinfo) {
msg._size = rinfo.size;
msg._remoteFamily = rinfo.family;
msg._remoteAddress = rinfo.address;
msg._remotePort = rinfo.port;
msg._port = port;
stat.handler(msg);
});
server.on('error', function (err) {
if (!resolved) {
delete dgramMap[port];
reject(err);
}
else if (stat.handler.onError) {
stat.handler.onError(err);
}
else {
throw err;
}
});
server.on('close', function () {
delete dgramMap[port];
});
server.bind(port, function () {
resolved = true;
resolve();
});
});
};
module.exports.closeUdpListener = function (port) {
var stat = dgramMap[port];
if (!stat) {
return PromiseA.resolve();
}
return new PromiseA(function (resolve) {
stat.server.once('close', resolve);
stat.server.close();
});
};
module.exports.listeners = { module.exports.listeners = {
tcp: { tcp: {
add: module.exports.addTcpListener add: module.exports.addTcpListener
, close: module.exports.closeTcpListener , close: module.exports.closeTcpListener
, destroy: module.exports.destroyTcpListener , destroy: module.exports.destroyTcpListener
} }
, udp: {
add: module.exports.addUdpListener
, close: module.exports.closeUdpListener
}
}; };

View File

@ -18,5 +18,5 @@ popd
mkdir -p well-known mkdir -p well-known
pushd well-known pushd well-known
ln -sf ../org.oauth3/well-known/oauth3 ./oauth3 ln -snf ../org.oauth3/well-known/oauth3 ./oauth3
popd popd