telebit.js/lib/sorting-hat.js

106 lines
3.2 KiB
JavaScript

module.exports.assign = function (state, tun, cb) {
var net = state.net || require('net');
var service = tun.service.toLowerCase();
var portList = state.services[service];
var port;
if (!tun.name && !tun.serviceport) {
console.log('tun:\n',tun);
//console.warn(tun.data.toString());
cb(new Error("missing routing information for ':tun_id'"));
return;
}
port = portList[tun.name];
if (!port) {
// Check for any wildcard domains, sorted longest to shortest so the one with the
// biggest natural match will be found first.
Object.keys(portList).filter(function (pattern) {
return pattern[0] === '*' && pattern.length > 1;
}).sort(function (a, b) {
return b.length - a.length;
}).some(function (pattern) {
var subPiece = pattern.slice(1);
if (subPiece === tun.name.slice(-subPiece.length)) {
port = portList[pattern];
return true;
}
});
}
if (!port) {
port = portList['*'];
}
var createOpts = {
port: port
, host: '127.0.0.1'
, servername: tun.name
, name: tun.name
, serviceport: tun.serviceport
, data: tun.data
, remoteFamily: tun.family
, remoteAddress: tun.address
, remotePort: tun.port
};
var conn;
function handleNow(socket) {
var httpServer;
var tlsServer;
if ('https' === service) {
if (!state.greenlock) {
state.greenlock = require('greenlock').create(state.greenlockConfig);
}
httpServer = require('http').createServer(function (req, res) {
console.log('[hit http/s server]');
res.end('Hello, Encrypted Tunnel World!');
});
tlsServer = require('tls').createServer(state.greenlock.tlsOptions, function (tlsSocket) {
console.log('[hit tls server]');
httpServer.emit('connection', tlsSocket);
});
tlsServer.emit('connection', socket);
} else {
httpServer = require('http').createServer(state.greenlock.middleware(function (req, res) {
console.log('[hit pure http server]');
res.end('Hello, Encrypted Tunnel World!');
}));
// http://aj.telebit.cloud/.well-known/acme-challenge/blah
httpServer.emit('connection', socket);
}
}
if ('aj.telebit.cloud' === tun.name) {
console.log('NEW CONNECTION to AJ\'s telebit could');
// For performance it may be better to use socket-pair, needs testing
var socketPair = require('socket-pair');
conn = socketPair.create(function (err, other) {
if (err) { console.error('[Error] ' + err.message); }
handleNow(other);
if (createOpts.data) {
conn.write(createOpts.data);
}
});
/*
var streamPair = require('stream-pair');
var pair = streamPair.create();
conn = pair.other;
process.nextTick(function () {
if (createOpts.data) {
conn.write(createOpts.data);
}
});
*/
} else {
conn = net.createConnection(createOpts, function () {
// this will happen before 'data' or 'readable' is triggered
// We use the data from the createOpts object so that the createConnection function has
// the oppurtunity of removing/changing it if it wants/needs to handle it differently.
if (createOpts.data) {
conn.write(createOpts.data);
}
});
}
cb(null, conn);
};