2018-06-06 06:59:03 +00:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
var Packer = require('proxy-packer');
|
|
|
|
var Devices = require('./device-tracker');
|
2018-08-21 02:58:04 +00:00
|
|
|
var Server = require('./server.js');
|
2018-06-07 01:39:16 +00:00
|
|
|
|
2018-06-19 23:43:28 +00:00
|
|
|
module.exports.store = { Devices: Devices };
|
|
|
|
module.exports.create = function (state) {
|
2018-08-20 19:45:13 +00:00
|
|
|
state.deviceLists = { _domains: {}, _devices: {} };
|
2018-06-19 23:43:28 +00:00
|
|
|
state.deviceCallbacks = {};
|
|
|
|
state.srvs = {};
|
2018-06-06 06:59:03 +00:00
|
|
|
|
2018-06-19 23:43:28 +00:00
|
|
|
if (!parseInt(state.activityTimeout, 10)) {
|
|
|
|
state.activityTimeout = 2 * 60 * 1000;
|
|
|
|
}
|
|
|
|
if (!parseInt(state.pongTimeout, 10)) {
|
|
|
|
state.pongTimeout = 10 * 1000;
|
|
|
|
}
|
|
|
|
state.Devices = Devices;
|
2018-06-06 06:59:03 +00:00
|
|
|
|
2018-06-19 23:43:28 +00:00
|
|
|
// TODO Use a Single TCP Handler
|
|
|
|
// Issues:
|
|
|
|
// * dynamic ports are dedicated to a device or cluster
|
|
|
|
// * servernames could come in on ports that belong to a different device
|
|
|
|
// * servernames could come in that belong to no device
|
|
|
|
// * this could lead to an attack / security vulnerability with ACME certificates
|
|
|
|
// Solutions
|
|
|
|
// * Restrict dynamic ports to a particular device
|
|
|
|
// * Restrict the use of servernames
|
2018-06-06 06:59:03 +00:00
|
|
|
|
2018-06-19 23:43:28 +00:00
|
|
|
function onWsConnection(_ws, _upgradeReq) {
|
|
|
|
var srv = {};
|
|
|
|
var initToken;
|
|
|
|
srv.ws = _ws;
|
|
|
|
srv.upgradeReq = _upgradeReq;
|
2018-08-20 19:45:13 +00:00
|
|
|
// TODO use device's ECDSA thumbprint as device id
|
|
|
|
srv.id = null;
|
2018-06-19 23:43:28 +00:00
|
|
|
srv.socketId = Packer.socketToId(srv.upgradeReq.socket);
|
|
|
|
srv.grants = {};
|
|
|
|
srv.clients = {};
|
|
|
|
srv.domainsMap = {};
|
|
|
|
srv.portsMap = {};
|
|
|
|
srv.pausedConns = [];
|
2018-08-21 02:58:04 +00:00
|
|
|
srv.domains = [];
|
|
|
|
srv.ports = [];
|
2018-06-19 23:43:28 +00:00
|
|
|
|
|
|
|
if (state.debug) { console.log('[ws] connection', srv.socketId); }
|
|
|
|
|
|
|
|
initToken = Server.parseAuth(state, srv);
|
|
|
|
|
|
|
|
srv.ws._socket.on('drain', function () {
|
|
|
|
// the websocket library has it's own buffer apart from node's socket buffer, but that one
|
|
|
|
// is much more difficult to watch, so we watch for the lower level buffer to drain and
|
|
|
|
// then check to see if the upper level buffer is still too full to write to. Note that
|
|
|
|
// the websocket library buffer has something to do with compression, so I'm not requiring
|
|
|
|
// that to be 0 before we start up again.
|
|
|
|
if (srv.ws.bufferedAmount > 128*1024) {
|
|
|
|
return;
|
2018-06-06 06:59:03 +00:00
|
|
|
}
|
|
|
|
|
2018-06-19 23:43:28 +00:00
|
|
|
srv.pausedConns.forEach(function (conn) {
|
|
|
|
if (!conn.manualPause) {
|
|
|
|
// console.log('resuming', conn.tunnelCid, 'now that the web socket has caught up');
|
|
|
|
conn.resume();
|
2018-06-06 06:59:03 +00:00
|
|
|
}
|
2018-06-19 23:43:28 +00:00
|
|
|
});
|
|
|
|
srv.pausedConns.length = 0;
|
|
|
|
});
|
2018-06-06 06:59:03 +00:00
|
|
|
|
2018-06-19 23:43:28 +00:00
|
|
|
if (initToken) {
|
2018-06-29 11:02:44 +00:00
|
|
|
console.log('[wss.onConnection] token provided in http headers');
|
2018-06-19 23:43:28 +00:00
|
|
|
return Server.addToken(state, srv, initToken).then(function () {
|
|
|
|
Server.init(state, srv);
|
|
|
|
}).catch(function (err) {
|
|
|
|
Server.sendTunnelMsg(srv, null, [0, err], 'control');
|
|
|
|
srv.ws.close();
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
return Server.init(state, srv);
|
2018-06-06 06:59:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
2018-06-19 23:43:28 +00:00
|
|
|
tcp: require('./unwrap-tls').createTcpConnectionHandler(state)
|
2018-06-06 06:59:03 +00:00
|
|
|
, ws: onWsConnection
|
|
|
|
, isClientDomain: Devices.exist.bind(null, state.deviceLists)
|
|
|
|
};
|
|
|
|
};
|