UNPKG

ws-to-socket-proxy

Version:

A proxy server which can be used to proxy an web socket connection to tcp or udp

273 lines 13.4 kB
#!/usr/bin/env node "use strict"; var dgram = require("dgram"); var websocket = require("websocket"); var http = require("http"); var chalk = require("chalk"); var net = require("net"); var WebSocketServer = websocket.server; // chalk instance used for coloring var font = new chalk.constructor({ enabled: true }); // this is the port used by the client to connect to this proxy var wsListeningPort = 8778; var verbose = process.argv.indexOf("-v") != -1; // TCP SERVER START var server = net.createServer().listen(5000, "0.0.0.0", undefined, function () { console.log('server listening to %j', server.address()); log(font.blue("TCP Server") + " > Server listneing on " + JSON.stringify(server.address())); }); server.on('connection', handleConnection); function stringToABuffer(str) { var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char var bufView = new Uint16Array(buf); for (var i = 0, strLen = str.length; i < strLen; i++) { bufView[i] = str.charCodeAt(i); } return bufView; } function aBufferToString(buf) { return String.fromCharCode.apply(null, new Uint16Array(buf)); } function handleConnection(conn) { var remoteAddress = conn.remoteAddress + ':' + conn.remotePort; log(font.blue("TCP Server") + " > New client connection from " + remoteAddress); // conn.write(Buffer.from([ 0x62, 0x75, 0x66, 0x66, 0x65, 0x72 ])); if (!serverConnection) { serverConnection = createServerConnectionTCP('192.168.5.205', 5001, { send: conn.write.bind(conn), remoteAddress: conn.remoteAddress, port: conn.remotePort }); } conn.on('data', onConnData); conn.once('close', onConnClose); conn.on('error', onConnError); function onConnData(data) { log(font.blue("TCP Server") + " > Received data from the client sending to server."); if (serverConnection) { serverConnection.sendBinary(data); } } function onConnClose() { log(font.blue("TCP Server") + " > Client " + remoteAddress + " socket closed."); } function onConnError(err) { log(font.red("TCP Server") + " > Client " + remoteAddress + " error: " + err.message + "}."); } } // TCP SERVER END // WS SERVER START // set up http server which is needed by the ws var httpServer = http.createServer(function (request, response) { log(font.blue("WS httpServer") + " > Received request for " + font.green(request.url)); response.writeHead(404); response.end(); }); httpServer.on('clientError', function (err, socket) { console.log("HTTP server error " + err + " on " + JSON.stringify(socket)); }); httpServer.on('error', function (err) { console.log("HTTP server error " + err); }); httpServer.listen(wsListeningPort, function () { log(font.blue("WS httpServer") + " > Listening on port " + font.green(wsListeningPort.toString())); }); // this is the web socket server instance used to listen for incoming client connections var proxyServer = new WebSocketServer({ httpServer: httpServer, autoAcceptConnections: false }); var serverConnection; // when there is incoming connection this method will be executed proxyServer.on('request', function (request) { var clientConnection = request.accept('echo-protocol', request.origin); log(font.blue("WS") + " > Connection accepted from " + font.green(request.socket.remoteAddress) + ":" + font.green(request.socket.remotePort.toString())); clientConnection.on('message', function (message) { if (message.type === 'utf8') { var config; //if a config file has been sent we configure/reconfigure the new connection config = tryParseConfigFile(message.utf8Data); if (config) { if (serverConnection) { serverConnection.close(); } // depending on the type property of the config we are either going to open tcp or udp connection to the requested remote server if (config && config.type == "udp") { // opening an UDP connection serverConnection = createServerConnectionUDP(config.ip, config.port, { send: clientConnection.send.bind(clientConnection), remoteAddress: clientConnection.socket.remoteAddress, port: clientConnection.socket.remotePort }); } else if (config && config.type == "tcp") { // opening an TCP connection serverConnection = createServerConnectionTCP(config.ip, config.port, { send: clientConnection.send.bind(clientConnection), remoteAddress: clientConnection.socket.remoteAddress, port: clientConnection.socket.remotePort }); } else { log(font.blue("WS") + " > no server connection type " + font.red(config && config.type)); } } else { //if a config file has not been sent if (!serverConnection || !serverConnection.isOpened()) { log(font.blue("WS") + " > " + font.red("There is no server connection that has been configured.") + " > Please send a string message with config data with type " + font.yellow("{type: \"udp\" | \"tcp\", ip: string, port: number}") + "\")}"); } else { serverConnection.sendUTF(message.utf8Data); } } } else if (message.type === 'binary') { // binary messages are redirected to the remote server. // log(`${font.blue("WS")} > Received Binary data from ${font.green(request.socket.remoteAddress)}:${font.green(request.socket.remotePort.toString())} size: ${font.green(message.binaryData.length.toString())}`); if (!serverConnection || !serverConnection.isOpened()) { log(font.blue("WS") + " > " + font.red("There is no server connection that has been configured.") + " > Please send a string message with config data with type " + font.yellow("{type: \"udp\" | \"tcp\", ip: string, port: number}") + "\")}"); } else { serverConnection.sendBinary(message.binaryData); } } }); clientConnection.on('close', function (reasonCode, description) { log(font.blue("WS") + " > Peer " + font.green(request.socket.remoteAddress) + ":" + font.green(request.socket.remotePort.toString()) + " disconnected"); }); }); function tryParseConfigFile(msg) { var config = JSON.parse(msg); return config.ip && config.port && config.type ? config : null; } // WS SERVER END /** * Creates and udp connection and returns and wrapper object for sending data to this connection. * * @param ip the ip of the remote server * @param port the port f the remote * @param wsConnection the WS socket of the connected client. will be used to automatically redirect messages from the udp server to the client. * @returns a wrapper object for sending data to this connection */ function createServerConnectionUDP(ip, port, clientConnection) { log(font.blue("Server Connection UDP") + " > create " + font.green(ip) + ":" + font.green(port.toString())); var bindAddress = '0.0.0.0'; var udpSocket = dgram.createSocket('udp4'); var socketOpened = false; try { udpSocket.bind(port, bindAddress, start); } catch (err) { log(font.blue("Server Connection UDP") + " > Socket bind error " + font.red(err.toString())); } // this callback will be called when the binding is done function start() { log(font.blue("Server Connection UDP") + " > bind on " + font.green(bindAddress) + " " + font.green(port.toString()) + " done"); var broadcast = true; udpSocket.setBroadcast(broadcast); log(font.blue("Server Connection UDP") + " > broadcast " + font.green(broadcast.toString())); } // error handler udpSocket.on('error', function (err) { log(font.blue("Server Connection UDP") + " > Error " + font.red(err.toString())); udpSocket.close(); }); // handles incomming messages form the udp server and redirects them to the websocket client. udpSocket.on('message', function (msg, rinfo) { // log(`${font.blue("Server Connection UDP")} > Message "${font.green(msg.toString())}" from ${font.green(rinfo.address)} ${font.green(rinfo.port.toString())}`); // log(`${font.blue("Server Connection UDP")} > resending to ${font.green(clientConnection.remoteAddress)}:${font.green(clientConnection.port.toString())}`); clientConnection && clientConnection.send(msg); }); udpSocket.on('listening', function () { log(font.blue("Server Connection UDP") + " > Listening"); socketOpened = true; }); udpSocket.on("close", function () { socketOpened = false; log(font.blue("Server Connection UDP") + " > Close"); }); // callback called when a message us send to the udp server. function sendCallback(err) { if (err) { log(font.blue("Server Connection UDP") + " > Send error " + err); console.log(err); } } return { isOpened: function () { return socketOpened; }, sendBinary: function (data) { log(font.blue("Server Connection UDP") + " > Send data to " + font.green(ip) + ":" + font.green(port.toString()) + " , data length " + font.green(data.length.toString())); udpSocket.send(data, port, ip, sendCallback); }, sendUTF: function (data) { log(font.blue("Server Connection UDP") + " > Sending string data to " + font.green(ip) + ":" + font.green(port.toString()) + "}"); udpSocket.send(data, port, ip, sendCallback); }, close: function () { udpSocket.close(); } }; } /** * Creates and TCP connection and returns and wrapper object for sending data to this connection. * * @param ip the ip of the remote server * @param port the port f the remote * @param wsConnection the WS socket of the connected client. will be used to automatically redirect messages from the udp server to the client. * @returns a wrapper object for sending data to this connection */ function createServerConnectionTCP(ip, port, clientConnection) { log(font.blue("Server Connection TCP") + " > " + font.green(ip) + ":" + font.green(port.toString()) + " > create"); var tcpSocket = new net.Socket(); tcpSocket.connect(port, ip, start); // callback executed on successful connect function start() { log(font.blue("Server Connection TCP") + " > " + font.green(ip) + ":" + font.green(port.toString()) + " > connected"); } // error handler tcpSocket.on('error', function (err) { log(font.blue("Server Connection TCP") + " > " + font.green(ip) + ":" + font.green(port.toString()) + " > error " + font.red(err.toString())); }); // handler for incoming server data. It will be redirected to the ws client tcpSocket.on('data', function (data) { // log(`${font.blue("Server Connection TCP")} > ${font.green(ip)}:${font.green(port.toString())} > data received, length ${font.green(data.length.toString())} ${data}`); // log(`${font.blue("Server Connection TCP")} > ${font.green(ip)}:${font.green(port.toString())} > resending to ${font.green(clientConnection.remoteAddress)}:${font.green(clientConnection.port.toString())}`); clientConnection && clientConnection.send(data); }); // connection close handler tcpSocket.on("close", function (hadError) { var color = hadError ? font.red : font.green; log(font.blue("Server Connection TCP") + " > " + font.green(ip) + ":" + font.green(port.toString()) + " > closed, because of an error: " + color(hadError.toString())); }); return { isOpened: function () { return tcpSocket.writable; }, sendBinary: function (data) { // log(`${font.blue("Server Connection TCP")} > ${font.green(ip)}:${font.green(port.toString())} > Send data, data length ${font.green(data.length.toString())}`); tcpSocket.write(data); }, sendUTF: function (data) { log(font.blue("Server Connection TCP") + " > " + font.green(ip) + ":" + font.green(port.toString()) + " > Sending string data }"); tcpSocket.write(data, 'UTF8'); }, close: function () { tcpSocket.end(); } }; } /** * Utility function for logging messages in the console. * Will write each message with a timestamp in front will have this format [HH:MM:SS] : msg * * @param msg the message to be displayed */ function log(msg) { if (verbose) { console.log("[" + font.gray(new Date().toTimeString().substr(0, 8)) + "] : " + msg); } } //# sourceMappingURL=wsproxy.js.map