Last active
April 3, 2025 07:00
-
-
Save moeiscool/6204d56cb4ea09241a8b2028db3b64f1 to your computer and use it in GitHub Desktop.
Revisions
-
moeiscool revised this gist
Apr 3, 2025 . 1 changed file with 40 additions and 14 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -8,7 +8,7 @@ const [HOST, PORT] = WS_HOST.split(':'); const START_PORT = 9022; // Client tracking const clients = new Map(); // identifier -> { ws, port, server, socket, lastActive } const portAllocation = new Map(); // port -> identifier const PORT_TIMEOUT = 24 * 60 * 60 * 1000; // 24 hours @@ -56,39 +56,65 @@ wss.on('connection', (ws) => { for (const [identifier, client] of clients.entries()) { if (client.ws === ws) { console.log(`Client ${identifier} disconnected`); // Don't close the server, just mark WS as disconnected and close socket client.ws = null; if (client.socket) { client.socket.end(); client.socket = null; } } } }); }); function registerClient(ws, identifier) { // Check if this identifier already has a port assigned const existingClient = clients.get(identifier); if (existingClient) { // Reuse the existing port existingClient.ws = ws; existingClient.lastActive = Date.now(); console.log(`[${identifier}] Reconnected, using existing port ${existingClient.port}`); ws.send(JSON.stringify({ type: 'registered', port: existingClient.port })); return; } // Find available port for new client let port = START_PORT; while (portAllocation.has(port)) port++; const server = net.createServer((socket) => { const client = clients.get(identifier); if (client) { client.socket = socket; console.log(`[${identifier}] New connection on port ${port}`); } socket.on('data', (data) => { const client = clients.get(identifier); if (client && client.ws) { client.ws.send(JSON.stringify({ type: 'data', identifier, data: data.toString('base64') })); } }); socket.on('close', () => { const client = clients.get(identifier); if (client) { client.socket = null; } }); }); server.listen(port, '0.0.0.0', () => { clients.set(identifier, { ws, port, server, socket: null, lastActive: Date.now() }); portAllocation.set(port, identifier); console.log(`[${identifier}] Assigned port ${port}`); ws.send(JSON.stringify({ type: 'registered', port })); }); } -
moeiscool created this gist
Apr 3, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,28 @@ ## Simple Remote SSH over Websocket Protocol with Node.js (Alpha) ### by Shinobi Systems #### Based on the Simple TCP Proxy by kfox at https://gist.github.com/kfox/2313683 With this you spawn a websocket server on a server to allow SSH to a remote machine. When a client is connected it will be available on 9022 of the server. Every new client connected will be on port proceeding 9022. So if a server is already on 9022 the next one will be on 9023 and the next on 9024 and so on. Ports are released 24 hours after disconnection to be used again later. Server machine run : ``` node server.js BIND_ADDRESS ``` Example : ``` node server.js 0.0.0.0:8090 ``` Client machine run : ``` node client.js HOST IDENTIFIER ``` Example : ``` node client.js 127.0.0.1:8090 someserverid ``` This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,111 @@ const WebSocket = require('ws'); const net = require('net'); const process = require('process'); // Configuration if (process.argv.length < 4) { console.log('Usage: node client.js <host:port> <identifier>'); process.exit(1); } const WS_SERVER = process.argv[2]; const IDENTIFIER = process.argv[3]; const SSH_PORT = 22; const RECONNECT_INTERVAL = 10000; let ws = null; let sshSocket = null; let assignedPort = null; let reconnectTimer = null; function connectWebSocket() { if (ws) { ws.removeAllListeners(); if (ws.readyState === ws.OPEN) ws.close(); } console.log(`Connecting to ${WS_SERVER} as ${IDENTIFIER}...`); ws = new WebSocket(`ws://${WS_SERVER}`); ws.on('open', () => { console.log('Connected, registering...'); ws.send(JSON.stringify({ type: 'register', identifier: IDENTIFIER })); }); ws.on('message', (message) => { const msg = JSON.parse(message); if (msg.type === 'registered') { assignedPort = msg.port; console.log(`Registered! Forwarding port ${assignedPort} to SSH`); } else if (msg.type === 'data') { if (!sshSocket) connectSSH(); sshSocket.write(Buffer.from(msg.data, 'base64')); } }); ws.on('close', () => { console.log('Disconnected from server'); if (sshSocket) sshSocket.end(); scheduleReconnect(); }); ws.on('error', (err) => { console.error('WebSocket error:', err); scheduleReconnect(); }); } function connectSSH() { if (sshSocket) sshSocket.end(); sshSocket = new net.Socket(); sshSocket.connect(SSH_PORT, '127.0.0.1', () => { console.log('Connected to SSH server'); }); sshSocket.on('data', (data) => { if (ws && ws.readyState === ws.OPEN) { ws.send(JSON.stringify({ type: 'data', identifier: IDENTIFIER, data: data.toString('base64') })); } }); sshSocket.on('error', (err) => { console.error('SSH error:', err); sshSocket = null; }); sshSocket.on('close', () => { sshSocket = null; }); } function scheduleReconnect() { if (!reconnectTimer) { console.log(`Reconnecting in ${RECONNECT_INTERVAL/1000} seconds...`); reconnectTimer = setTimeout(() => { reconnectTimer = null; connectWebSocket(); }, RECONNECT_INTERVAL); } } // Cleanup function cleanup() { if (reconnectTimer) clearTimeout(reconnectTimer); if (ws) ws.close(); if (sshSocket) sshSocket.end(); } process.on('SIGINT', cleanup); process.on('SIGTERM', cleanup); // Start connection connectWebSocket(); This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,94 @@ const WebSocket = require('ws'); const net = require('net'); const process = require('process'); // Configuration const WS_HOST = process.argv[2] || '127.0.0.1:8090'; const [HOST, PORT] = WS_HOST.split(':'); const START_PORT = 9022; // Client tracking const clients = new Map(); // identifier -> { ws, port, lastActive } const portAllocation = new Map(); // port -> identifier const PORT_TIMEOUT = 24 * 60 * 60 * 1000; // 24 hours const wss = new WebSocket.Server({ host: HOST, port: PORT }); console.log(`WebSocket server running on ws://${HOST}:${PORT}`); // Cleanup old ports setInterval(() => { const now = Date.now(); for (const [identifier, client] of clients.entries()) { if (now - client.lastActive > PORT_TIMEOUT) { console.log(`Releasing port ${client.port} from ${identifier} (inactive 24h)`); client.server.close(); portAllocation.delete(client.port); clients.delete(identifier); } } }, 60 * 60 * 1000); // Check hourly wss.on('connection', (ws) => { ws.on('message', (message) => { try { const msg = JSON.parse(message); // Handle registration if (msg.type === 'register' && msg.identifier) { registerClient(ws, msg.identifier); return; } // Handle data forwarding const client = clients.get(msg.identifier); if (client && client.ws === ws) { client.lastActive = Date.now(); if (msg.type === 'data' && client.socket) { client.socket.write(Buffer.from(msg.data, 'base64')); } } } catch (err) { console.error('Message processing error:', err); } }); ws.on('close', () => { for (const [identifier, client] of clients.entries()) { if (client.ws === ws) { console.log(`Client ${identifier} disconnected`); if (client.socket) client.socket.end(); // Keep port reserved until timeout } } }); }); function registerClient(ws, identifier) { // Find available port let port = START_PORT; while (portAllocation.has(port)) port++; const server = net.createServer((socket) => { clients.get(identifier).socket = socket; console.log(`[${identifier}] New connection on port ${port}`); socket.on('data', (data) => { ws.send(JSON.stringify({ type: 'data', identifier, data: data.toString('base64') })); }); socket.on('close', () => { clients.get(identifier).socket = null; }); }); server.listen(port, '0.0.0.0', () => { clients.set(identifier, { ws, port, server, lastActive: Date.now() }); portAllocation.set(port, identifier); console.log(`[${identifier}] Assigned port ${port}`); ws.send(JSON.stringify({ type: 'registered', port })); }); }