diff --git a/lib/pipe-ws.js b/lib/pipe-ws.js index 9efe374..36b959f 100644 --- a/lib/pipe-ws.js +++ b/lib/pipe-ws.js @@ -16,7 +16,13 @@ module.exports = function pipeWs(servername, service, srv, conn, serviceport) { function sendWs(data, serviceOverride) { if (srv.ws && (!conn.tunnelClosing || serviceOverride)) { try { - srv.ws.send(Packer.pack(browserAddr, data, serviceOverride), { binary: true }); + if (data && !Buffer.isBuffer(data)) { + data = Buffer.from(JSON.stringify(data)); + } + srv.ws.send(Packer.packHeader(browserAddr, data, serviceOverride), { binary: true }); + if (data) { + srv.ws.send(data, { binary: true }); + } // If we can't send data over the websocket as fast as this connection can send it to us // (or there are a lot of connections trying to send over the same websocket) then we // need to pause the connection for a little. We pause all connections if any are paused @@ -39,6 +45,10 @@ module.exports = function pipeWs(servername, service, srv, conn, serviceport) { conn.serviceport = serviceport; conn.service = service; + // send peek at data too? + srv.ws.send(Packer.packHeader(browserAddr, null, 'connection'), { binary: true }); + + // TODO convert to read stream? conn.on('data', function (chunk) { //if (state.debug) { console.log('[pipeWs] client', cid, ' => srv', rid, chunk.byteLength, 'bytes'); } sendWs(chunk); diff --git a/lib/relay.js b/lib/relay.js index fdaeb59..6bd9d91 100644 --- a/lib/relay.js +++ b/lib/relay.js @@ -98,6 +98,13 @@ var Server = { return srv._commandHandlers[cmd[1]].apply(null, cmd.slice(2)).then(onSuccess, onError); } + , onconnection: function (tun) { + // I don't think this event can happen since this relay + // is acting the part of the client, but just in case... + // (in fact it should probably be explicitly disallowed) + console.error("[SANITY FAIL] reverse connection start"); + } + , onmessage: function (tun) { var cid = Packer.addrToId(tun); if (state.debug) { console.log("remote '" + Server.logName(state, srv) + "' has data for '" + cid + "'", tun.data.byteLength); } @@ -236,7 +243,11 @@ var Server = { Server.sendTunnelMsg(srv, null, [1, 'hello', [srv.unpacker._version], Object.keys(srv._commandHandlers)], 'control'); } , sendTunnelMsg: function sendTunnelMsg(srv, addr, data, service) { - srv.ws.send(Packer.pack(addr, data, service), {binary: true}); + if (data && !Buffer.isBuffer()) { + data = Buffer.from(JSON.stringify(data)); + } + srv.ws.send(Packer.packHeader(addr, data, service), {binary: true}); + srv.ws.send(data, {binary: true}); } , logName: function logName(state, srv) { var result = Object.keys(srv.grants).map(function (jwtoken) { @@ -399,7 +410,16 @@ var Server = { return; } - conn.once('data', function (firstChunk) { + // When using raw TCP we're already paired to the client by port + // and we can begin connecting right away, but we'll wait just a sec + // to reject known bad connections + var sendConnection = setTimeout(function () { + conn.removeListener('data', peekFirstPacket) + console.log("[debug tcp conn] Connecting possible telnet client to device..."); + pipeWs(null, 'tcp', nextDevice, conn, serviceport); + }, 350); + function peekFirstPacket(firstChunk) { + clearTimeout(sendConnection); if (state.debug) { console.log("[DynTcp]", serviceport, "examining firstChunk from", Packer.socketToId(conn)); } conn.pause(); //conn.unshift(firstChunk); @@ -434,7 +454,8 @@ var Server = { pipeWs(null, 'tcp', nextDevice, conn, serviceport); process.nextTick(function () { conn.resume(); }); - }); + } + conn.once('data', peekFirstPacket); } , addToken: function addToken(state, srv, rawAuth) { console.log("[addToken]", rawAuth); diff --git a/package.json b/package.json index 93db3f0..9e4cca1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "telebit-relay", - "version": "0.13.1", + "version": "0.20.0", "description": "Friends don't let friends localhost. Expose your bits with a secure connection even from behind NAT, Firewalls, in a box, with a fox, on a train or in a plane... or a Raspberry Pi in your closet. An attempt to create a better localtunnel.me server, a more open ngrok. Uses Automated HTTPS (Free SSL) via ServerName Indication (SNI). Can also tunnel tls and plain tcp.", "main": "lib/relay.js", "bin": { @@ -51,7 +51,7 @@ "jwk-to-pem": "^2.0.0", "mkdirp": "^0.5.1", "nowww": "^1.2.1", - "proxy-packer": "^1.4.3", + "proxy-packer": "^2.0.0", "recase": "^1.0.4", "redirect-https": "^1.1.5", "request": "^2.87.0",