websockify.js

82 阅读1分钟
#!/usr/bin/env node// A WebSocket to TCP socket proxy// Copyright 2012 Joel Martin// Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)// Known to work with node 0.8.9// Requires node modules: ws and optimist//     npm install ws optimistfunction getIPAdress() {  var interfaces = require('os').networkInterfaces();  for (var devName in interfaces) {    var iface = interfaces[devName];    for (var i = 0; i < iface.length; i++) {      var alias = iface[i];      console.log('🚀:', 'alias', JSON.stringify(alias));      // if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {      //   return alias.address;      // }    }  }}const http = require('http');const https = require('https');const url = require('url');const net = require('net');const path = require('path');const fs = require('fs');const mime = require('mime-types');var argv = require('optimist').argv,  Buffer = require('buffer').Buffer,  WebSocketServer = require('ws').Server,  webServer,  wsServer,  source_host, source_port, target_host, target_port,  web_path = null;const ArgvWeb = path.resolve(__dirname, "noVNC");// Handle new WebSocket clientfunction handleSocket(client, req) {  var clientAddr = client._socket.remoteAddress, log;  var start_time = new Date().getTime();  console.log(req ? req.url : client.upgradeReq.url);  log = function (msg) {    console.log(' ' + clientAddr + ': ' + msg);  };  log('WebSocket connection');  log('Version ' + client.protocolVersion + ', subprotocol: ' + client.protocol);  if (argv.record) {    var rs = fs.createWriteStream(argv.record + '/' + new Date().toISOString().replace(/:/g, "_"));    rs.write('var VNC_frame_data = [\n');  } else {    var rs = null;  }  var target = net.createConnection(target_port, target_host, function () {    log('connected to target');  });  target.on('data', function (data) {    //log("sending message: " + data);    if (rs) {      var tdelta = Math.floor(new Date().getTime()) - start_time;      var rsdata = '\'{' + tdelta + '{' + decodeBuffer(data) + '\',\n';      rs.write(rsdata);    }    try {      client.send(data);    } catch (e) {      log("Client closed, cleaning up target");      target.end();    }  });  target.on('end', function () {    log('target disconnected');    client.close();    if (rs) {      rs.end('\'EOF\'];\n');    }  });  target.on('error', function () {    log('target connection error');    target.end();    client.close();    if (rs) {      rs.end('\'EOF\'];\n');    }  });  client.on('message', function (msg) {    //log('got message: ' + msg);    if (rs) {      var rdelta = Math.floor(new Date().getTime()) - start_time;      var rsdata = ('\'}' + rdelta + '}' + decodeBuffer(msg) + '\',\n');      rs.write(rsdata);    }    target.write(msg);  });  client.on('close', function (code, reason) {    log('WebSocket client disconnected: ' + code + ' [' + reason + ']');    target.end();  });  client.on('error', function (a) {    log('WebSocket client error: ' + a);    target.end();  });};function decodeBuffer(buf) {  var returnString = '';  for (var i = 0; i < buf.length; i++) {    if (buf[i] >= 48 && buf[i] <= 90) {      returnString += String.fromCharCode(buf[i]);    } else if (buf[i] === 95) {      returnString += String.fromCharCode(buf[i]);    } else if (buf[i] >= 97 && buf[i] <= 122) {      returnString += String.fromCharCode(buf[i]);    } else {      var charToConvert = buf[i].toString(16);      if (charToConvert.length === 0) {        returnString += '\\x00';      } else if (charToConvert.length === 1) {        returnString += '\\x0' + charToConvert;      } else {        returnString += '\\x' + charToConvert;      }    }  }  return returnString;}// Send an HTTP error responsehttp_error = function (response, code, msg) {  response.writeHead(code, { "Content-Type": "text/plain" });  response.write(msg + "\n");  response.end();  return;};// Process an HTTP static file requesthttp_request = function (request, response) {  //    console.log("pathname: " + url.parse(req.url).pathname);  //    res.writeHead(200, {'Content-Type': 'text/plain'});  //    res.end('okay');  if (!ArgvWeb) {    return http_error(response, 403, "403 Permission Denied");  }  var uri = url.parse(request.url).pathname    , filename = path.join(ArgvWeb, uri);  fs.exists(filename, function (exists) {    if (!exists) {      return http_error(response, 404, "404 Not Found");    }    if (fs.statSync(filename).isDirectory()) {      filename += '/index.html';    }    fs.readFile(filename, "binary", function (err, file) {      if (err) {        return http_error(response, 500, err);      }      var headers = {};      var contentType = mime.contentType(path.extname(filename));      if (contentType !== false) {        headers['Content-Type'] = contentType;      }      response.writeHead(200, headers);      response.write(file, "binary");      response.end();    });  });};// parse source and target arguments into partstry {  source_arg = "3003";  target_arg = "192.168.137.1:5900";  // target_arg = "10.143.133.222:3389";  try {    source_arg = argv._[0].toString();    target_arg = argv._[1].toString();  } catch (error) {  }  var idx;  idx = source_arg.indexOf(":");  if (idx >= 0) {    source_host = source_arg.slice(0, idx);    source_port = parseInt(source_arg.slice(idx + 1), 10);  } else {    source_host = "";    source_port = parseInt(source_arg, 10);  }  idx = target_arg.indexOf(":");  if (idx < 0) {    throw ("target must be host:port");  }  target_host = target_arg.slice(0, idx);  target_port = parseInt(target_arg.slice(idx + 1), 10);  if (isNaN(source_port) || isNaN(target_port)) {    throw ("illegal port");  }} catch (e) {  console.error("websockify.js [--web web_dir] [--cert cert.pem [--key key.pem]] [--record dir] [source_addr:]source_port target_addr:target_port");  process.exit(2);}console.log("WebSocket settings: ");console.log("    - proxying from " + source_host + ":" + source_port + " to " + target_host + ":" + target_port);console.log(`${getIPAdress()}`);if (ArgvWeb) {  console.log("    - Web server active. Serving: " + ArgvWeb);}function proxyRequest(cReq, cRes) {  console.log("cReq.url", cReq.url);  var u = url.parse(cReq.url);  var options = {    hostname: u.hostname,    port: u.port || 80,    path: u.path,    method: cReq.method,    headers: cReq.headers  };  var pReq = http.request(options, function (pRes) {    cRes.writeHead(pRes.statusCode, pRes.headers);    pRes.pipe(cRes);  }).on('error', function (e) {    cRes.end();  });  cReq.pipe(pReq);}if (argv.cert) {  argv.key = argv.key || argv.cert;  var cert = fs.readFileSync(argv.cert),    key = fs.readFileSync(argv.key);  console.log("    - Running in encrypted HTTPS (wss://) mode using: " + argv.cert + ", " + argv.key);  webServer = https.createServer({ cert: cert, key: key }, http_request);} else {  console.log("    - Running in unencrypted HTTP (ws://) mode");  webServer = http.createServer(http_request);}webServer.listen(source_port, () => {  wsServer = new WebSocketServer({ server: webServer });  wsServer.on('connection', handleSocket);});