demo works
This commit is contained in:
parent
f3d962cb2a
commit
d999107ea8
|
@ -21,7 +21,9 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/Daplie/node-tunnel-server#readme",
|
"homepage": "https://github.com/Daplie/node-tunnel-server#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"cluster-store": "^2.0.4",
|
||||||
"jsonwebtoken": "^7.1.9",
|
"jsonwebtoken": "^7.1.9",
|
||||||
"sni": "^1.0.0"
|
"sni": "^1.0.0",
|
||||||
|
"tunnel-packer": "^1.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
191
serve.js
191
serve.js
|
@ -1,81 +1,113 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var crypto = require('crypto');
|
|
||||||
var net = require('net');
|
var net = require('net');
|
||||||
var sni = require('sni');
|
var sni = require('sni');
|
||||||
var jwt = require('jsonwebtoken');
|
var jwt = require('jsonwebtoken');
|
||||||
|
var packer = require('tunnel-packer');
|
||||||
|
|
||||||
var Transform = require('stream').Transform;
|
var Transform = require('stream').Transform;
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
|
|
||||||
function pad(str, len, ch) {
|
|
||||||
var x = '';
|
|
||||||
|
|
||||||
while (str.length < len) {
|
|
||||||
x += (ch || ' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
function MyTransform(options) {
|
function MyTransform(options) {
|
||||||
if (!(this instanceof MyTransform)) {
|
if (!(this instanceof MyTransform)) {
|
||||||
return new MyTransform(options);
|
return new MyTransform(options);
|
||||||
}
|
}
|
||||||
this.__my_id = options.id;
|
|
||||||
this.__my_addr = options.address;
|
this.__my_addr = options.address;
|
||||||
Transform.call(this, options);
|
Transform.call(this, options);
|
||||||
}
|
}
|
||||||
util.inherits(MyTransform, Transform);
|
util.inherits(MyTransform, Transform);
|
||||||
MyTransform.prototype._transform = function (data, encoding, callback) {
|
function transform(me, data, encoding, callback) {
|
||||||
var id = this.__my_id;
|
var address = me.__my_addr;
|
||||||
var address = this.__my_addr;
|
|
||||||
|
|
||||||
this.push('<');
|
|
||||||
this.push(id);
|
|
||||||
if ('IPv4' === address.family) {
|
|
||||||
this.push('IPv4:' + pad(address.address, 11, ' ') + ':' + pad(address.port, 5)); // 11 ch
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.push('IPv6:' + pad(address.address, 39, ' ') + ':' + pad(address.port, 5)); // ipv6 39-ch
|
|
||||||
}
|
|
||||||
//client.socket.write('IPv5:2001:0db8:85a3:0000:0000:ffff:80fe:fefe:00:00'); // ipv4 in ipv6 45-ch
|
|
||||||
this.push(data);
|
|
||||||
this.push(id);
|
|
||||||
this.push('>');
|
|
||||||
|
|
||||||
|
me.push(packer.pack(address, data));
|
||||||
callback();
|
callback();
|
||||||
|
}
|
||||||
|
MyTransform.prototype._transform = function (data, encoding, callback) {
|
||||||
|
return transform(this, data, encoding, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
require('cluster-store').create().then(function (store) {
|
function socketToAddr(socket) {
|
||||||
|
return { family: socket.remoteFamily, address: socket.remoteAddress, port: socket.remotePort };
|
||||||
|
}
|
||||||
|
|
||||||
|
function addrToId(address) {
|
||||||
|
return address.family + ',' + address.address + ',' + address.port;
|
||||||
|
}
|
||||||
|
|
||||||
|
function socketToId(socket) {
|
||||||
|
return addrToId(socketToAddr(socket));
|
||||||
|
}
|
||||||
|
|
||||||
|
//require('cluster-store').create().then(function (/*store*/) {
|
||||||
// initialization is now complete
|
// initialization is now complete
|
||||||
//store.set('foo', 'bar');
|
//store.set('foo', 'bar');
|
||||||
|
|
||||||
var remotes = {};
|
var remotes = {};
|
||||||
var server443 = net.createServer(function (socket) {
|
|
||||||
socket.once(function (hello) {
|
setInterval(function () {
|
||||||
|
Object.keys(remotes).forEach(function (id) {
|
||||||
|
var remote = remotes[id];
|
||||||
|
|
||||||
|
console.log('Remote ', id, 'has', Object.keys(remote.clients).length, 'clients', remote.socket.bytesRead, remote.socket.bytesWritten);
|
||||||
|
/*
|
||||||
|
forEach(function (cid) {
|
||||||
|
var client = remote.clients[cid];
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
});
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
var server443 = net.createServer(function (browser) {
|
||||||
|
browser.once('data', function (hello) {
|
||||||
|
//require('fs').writeFileSync('/tmp/sni.hello.bin', hello);
|
||||||
var servername = sni(hello);
|
var servername = sni(hello);
|
||||||
var client = remotes[servername];
|
var remote = remotes[servername];
|
||||||
if (!client) {
|
if (!remote) {
|
||||||
socket.end();
|
console.log("no remote for '" + servername + "'");
|
||||||
|
browser.end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//var id = crypto.randomBytes(16).toString('hex');
|
var address = socketToAddr(browser);
|
||||||
var id = client.id;
|
var id = addrToId(address);
|
||||||
var address = client.socket.address();
|
var wrapForRemote = new MyTransform({ id: id, remoteId: remote.id, address: address, servername: servername });
|
||||||
var transform = new MyTransform({ id: id, address: address });
|
|
||||||
|
|
||||||
client.socket.unshift(hello);
|
//socket.unshift(hello);
|
||||||
|
|
||||||
socket.pipe(transform).pipe(client.socket, { end: true });
|
//remote.socket/*.pipe(transform)*/.pipe(socket, { end: false });
|
||||||
|
var bstream = browser.pipe(wrapForRemote);
|
||||||
client.clients[id] = socket;
|
/*
|
||||||
socket.on('error', function () {
|
function write() {
|
||||||
transform.write('|_ERROR_|');
|
console.log("client '" + address.address + "' writing to '" + servername + "'");
|
||||||
delete client.clients[id];
|
var bytes = browser.read();
|
||||||
|
if (bytes) {
|
||||||
|
console.log("wrote ", bytes.byteLength);
|
||||||
|
remote.socket.write(bytes, write);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log("nothing to write right now");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bstream.on('readable', write);
|
||||||
|
*/
|
||||||
|
bstream.on('data', function (chunk) {
|
||||||
|
console.log("client '" + address.address + "' writing to '" + servername + "'", chunk.byteLength);
|
||||||
|
remote.socket.write(chunk);
|
||||||
});
|
});
|
||||||
socket.on('end', function () {
|
|
||||||
delete client.clients[id];
|
var data = packer.pack(address, hello);
|
||||||
|
console.log("client '" + address.address + "' greeting '" + servername + "'", hello.byteLength, data.byteLength);
|
||||||
|
remote.socket.write(data);
|
||||||
|
|
||||||
|
remote.clients[id] = browser;
|
||||||
|
bstream.on('error', function () {
|
||||||
|
console.error("browser has erred");
|
||||||
|
//wrapForRemote.write('|_ERROR_|');
|
||||||
|
delete remote.clients[id];
|
||||||
|
});
|
||||||
|
bstream.on('end', function () {
|
||||||
|
console.log("browser has closed the socket");
|
||||||
|
//wrapForRemote.write('|_END_|');
|
||||||
|
delete remote.clients[id];
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -84,28 +116,75 @@ require('cluster-store').create().then(function (store) {
|
||||||
console.log('listening on 443');
|
console.log('listening on 443');
|
||||||
});
|
});
|
||||||
|
|
||||||
var server5443 = net.createServer(function (socket) {
|
var server5443 = net.createServer(function (rserver) {
|
||||||
socket.once(function (hello) {
|
rserver.once('data', function (hello) {
|
||||||
var token;
|
var token;
|
||||||
try {
|
try {
|
||||||
token = jwt.decode(hello.toString('utf8'));
|
token = jwt.decode(hello.toString('utf8'));
|
||||||
console.log(token);
|
console.log(token);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
socket.end();
|
rserver.end();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
var id = crypto.randomBytes(16).toString('hex');
|
|
||||||
|
|
||||||
socket.write(id, function () {
|
if (!token.name) {
|
||||||
remotes[token.name] = {
|
console.log("no 'name' in token");
|
||||||
socket: socket
|
rserver.end();
|
||||||
, id: id
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var remote = {
|
||||||
|
socket: rserver
|
||||||
|
, id: socketToId(rserver)
|
||||||
, clients: {}
|
, clients: {}
|
||||||
};
|
};
|
||||||
|
var unpacker = packer.create({ onMessage: function (opts) {
|
||||||
|
// opts.data
|
||||||
|
var id = addrToId(opts);
|
||||||
|
|
||||||
|
console.log("remote '" + remote.id + "' has data for '" + id + "'", opts.data.byteLength);
|
||||||
|
|
||||||
|
if (!remote.clients[id]) {
|
||||||
|
console.log('no client for', id, opts.data.toString('utf8').substr(0, 100));
|
||||||
|
//remote.socket.write(packer.pack(opts, Buffer.from('|__END__|')));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
remote.clients[id].write(opts.data);
|
||||||
|
} });
|
||||||
|
|
||||||
|
console.log('new remote:', token.name);
|
||||||
|
/*
|
||||||
|
var data = packer.pack({ family: 'IPv4', address: '254.254.254.1', port: 443 }, Buffer.from(remote.id));
|
||||||
|
|
||||||
|
rserver.write(data, function () {
|
||||||
|
remotes[token.name] = remote;
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
rserver.on('data', function (chunk) {
|
||||||
|
unpacker.fns.addChunk(chunk);
|
||||||
|
});
|
||||||
|
|
||||||
|
function closeEm() {
|
||||||
|
delete remotes[token.name];
|
||||||
|
|
||||||
|
Object.keys(remote.clients).forEach(function (cid) {
|
||||||
|
remote.clients[cid].end();
|
||||||
|
delete remote.clients[cid];
|
||||||
|
});
|
||||||
|
|
||||||
|
//remote = null;
|
||||||
|
//rserver = null;
|
||||||
|
//unpacker = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
rserver.on('end', closeEm);
|
||||||
|
rserver.on('error', closeEm);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
server5443.listen(5443, function () {
|
server5443.listen(5443, function () {
|
||||||
console.log('listening on 5443');
|
console.log('listening on 5443');
|
||||||
});
|
});
|
||||||
});
|
//});
|
||||||
|
|
Loading…
Reference in New Issue