├── .gitignore ├── Dockerfile ├── LICENSE ├── bin └── wstun.js ├── docs └── docker.md ├── etc ├── init.d │ └── wstun └── systemd │ └── system │ └── wstun.service ├── index.js ├── lib ├── bindSockets.js ├── bindSockets_reverse.js ├── client.js ├── client_reverse.js ├── https_override.js ├── server.js ├── server_reverse.js └── wrapper.js ├── package.json ├── readme.md └── scripts └── postinst /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | ssl/ 3 | .directory 4 | .idea 5 | *.tgz -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:carbon-alpine 2 | 3 | RUN npm install -g --unsafe @mdslab/wstun \ 4 | && npm cache --force clean 5 | 6 | ENV NODE_PATH=/usr/local/lib/node_modules 7 | 8 | WORKDIR /usr/bin/ 9 | 10 | EXPOSE 8080 11 | 12 | ENTRYPOINT ["wstun", "-r", "-s", "8080", "--ssl=false"] 13 | #ENTRYPOINT ["wstun", "-r", "-s", "8080", "--ssl=true", "--key=", "--cert="] 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /bin/wstun.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | //############################################################################### 4 | //## 5 | //# Copyright (C) 2014-2015 Andrea Rocco Lotronto, 2017 Nicola Peditto 6 | //## 7 | //# Licensed under the Apache License, Version 2.0 (the "License"); 8 | //# you may not use this file except in compliance with the License. 9 | //# You may obtain a copy of the License at 10 | //## 11 | //# http://www.apache.org/licenses/LICENSE-2.0 12 | //## 13 | //# Unless required by applicable law or agreed to in writing, software 14 | //# distributed under the License is distributed on an "AS IS" BASIS, 15 | //# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | //# See the License for the specific language governing permissions and 17 | //# limitations under the License. 18 | //## 19 | //############################################################################### 20 | 21 | 22 | log4js = require('log4js'); 23 | 24 | try{ 25 | log4js.loadAppender('file'); 26 | logfile = '/var/log/wstun/wstun.log'; 27 | loglevel = 'debug'; 28 | log4js.addAppender(log4js.appenders.file(logfile)); 29 | } 30 | catch (err) { 31 | console.log("error log folder creation") 32 | } 33 | 34 | var logger = log4js.getLogger('main'); 35 | logger.setLevel(loglevel); 36 | 37 | var portTunnel , argv, client, host, localport, optimist, port, server, wsHost, wst, _, _ref, _ref1; 38 | 39 | var _ = require("under_score"); 40 | 41 | optimist = require('optimist').usage("Tunnels and reverse tunnels over WebSocket.\n" + 42 | "\nUsage: https://github.com/MDSLab/wstun/blob/master/readme.md") 43 | .string("s").alias('s', "server").describe('s', 'run as server, specify listening port') 44 | .string("t").alias('t', "tunnel").describe('t', 'run as tunnel client, specify localport:host:port') 45 | .boolean("r").alias('r', "reverse").describe('r', 'run in reverse tunneling mode') 46 | .string("a").alias('a', "allow").describe('a', '[only with --server="true" and --reverse="true"] accept only the requests coming from authorized clients, specify the path to the file containing authorized clients') 47 | .string("u").alias('u', "uuid").describe('u', '[only with --tunnel="true" and --reverse="true"] specify the uuid of the client') 48 | .string("ssl").describe('ssl', '\"true\" | \"false\" to enable|disable HTTPS communication.') 49 | .string("key").describe('key', '[only with --ssl="true"] path to private key certificate.') 50 | .string("cert").describe('cert', '[only with --ssl="true"] path to public key certificate.'); 51 | 52 | argv = optimist.argv; 53 | 54 | wst = require("../lib/wrapper"); 55 | 56 | if (argv.s && !argv.r) { 57 | 58 | // WS tunnel server side 59 | if (argv.t) { 60 | _ref = argv.t.split(":"), host = _ref[0], port = _ref[1]; 61 | server_opts = {dstHost:dstHost, dstPort:dstPort, ssl:https_flag, key:key, cert:cert}; 62 | } 63 | else { 64 | server_opts = {ssl:argv.ssl, key:argv.key, cert:argv.cert}; 65 | } 66 | 67 | server = new wst.server(server_opts); 68 | server.start(argv.s); 69 | 70 | }else if (argv.t) { 71 | 72 | // WS tunnel client side 73 | 74 | client = new wst.client; 75 | 76 | wsHost = _.last(argv._); 77 | _ref1 = argv.t.split(":"), localport = _ref1[0], host = _ref1[1], port = _ref1[2]; 78 | 79 | if (host && port) { 80 | client.start(localport, wsHost, "" + host + ":" + port); 81 | } else { 82 | client.start(localport, wsHost); 83 | } 84 | 85 | 86 | }else if (argv.r) { 87 | 88 | // WS reverse tunnel 89 | 90 | if (argv.s){ 91 | 92 | // Server side 93 | server_opts = {ssl:argv.ssl, key:argv.key, cert:argv.cert, allow:argv.a}; 94 | server = new wst.server_reverse(server_opts); 95 | server.start(argv.s); 96 | } 97 | else{ 98 | 99 | // Client side 100 | client = new wst.client_reverse; 101 | wsHost = _.last(argv._); 102 | _ref1 = argv.r.split(":"), portTunnel = _ref1[0], host = _ref1[1], port =_ref1[2]; 103 | uuid = argv.u; 104 | client.start(portTunnel, wsHost, "" + host + ":" + port, uuid); 105 | 106 | } 107 | 108 | } else { 109 | 110 | // Wrong options 111 | return console.log(optimist.help()); 112 | 113 | } 114 | -------------------------------------------------------------------------------- /docs/docker.md: -------------------------------------------------------------------------------- 1 | # Installation on Docker 2 | 3 | WSTUN repositoriy: 4 | * [x86_64](https://hub.docker.com/r/mdslab/wstun/) 5 | 6 | MDSLAB Docker Hub [webpage](https://hub.docker.com/r/mdslab/) 7 | 8 | ## Requirements 9 | 10 | * Docker! Follow the official [guides](https://docs.docker.com/install/) 11 | 12 | ## Get container 13 | 14 | Create container editing the following command substituting < PARAMETERS > with those ones specified in ["Usage (from command line)"](https://github.com/MDSLab/wstun#usage-from-command-line) doc section. 15 | ``` 16 | docker run -d --name=wstun -p 8080:8080 mdslab/wstun 17 | ``` -------------------------------------------------------------------------------- /etc/init.d/wstun: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | NAME=wstun 4 | FOLDER=$NODE_PATH/@mdslab/wstun 5 | DAEMON=$NODE_PATH/@mdslab/wstun/bin/wstun.js 6 | DAEMON_OPTS='-r -s 8080' 7 | NAME=wstun 8 | LOGFILE="/var/log/iotronic/wstun.log" 9 | PIDFILE="/var/run/wstun.pid" 10 | 11 | 12 | test -x $DAEMON || exit 0 13 | set -e 14 | 15 | . /lib/lsb/init-functions 16 | 17 | MYPID2=`ps www | grep $NODE_PATH/@mdslab/wstun/bin/wstun.js | grep -v grep | awk {'print $1'}` 18 | 19 | 20 | case "$1" in 21 | start) 22 | 23 | # WSTUN 24 | echo -e "Starting $NAME ..." 25 | 26 | # IF empty... 27 | if [[ -z $MYPID2 ]]; 28 | then 29 | start-stop-daemon --start -d $FOLDER --quiet --make-pidfile --pidfile $PIDFILE --exec $DAEMON -- $DAEMON_OPTS >> /dev/null & # ${LOGFILE} & 30 | elif [[ -s $PIDFILE && `cat $PIDFILE` == $MYPID2 ]]; 31 | then 32 | echo -e "Already started!" 33 | else 34 | echo $MYPID2 > $PIDFILE 35 | echo -e "Already started!" 36 | fi 37 | 38 | ;; 39 | 40 | 41 | stop) 42 | 43 | # WSTUN 44 | echo -e "Stopping $NAME ..." 45 | if [[ -s $PIDFILE && `cat $PIDFILE` == $MYPID2 ]]; 46 | then 47 | kill -9 `cat $PIDFILE` 48 | rm $PIDFILE 49 | else 50 | echo -e "inactive!" 51 | fi 52 | ;; 53 | 54 | 55 | restart) 56 | 57 | # WSTUN 58 | echo -e "Restarting $NAME ..." 59 | if [[ -s $PIDFILE && `cat $PIDFILE` == $MYPID2 ]]; 60 | then 61 | kill -9 `ps aux | grep wstun | grep -v grep | awk {'print $2'}` 62 | rm $PIDFILE 63 | fi 64 | sleep 1 65 | start-stop-daemon --start -d $FOLDER --quiet --make-pidfile --pidfile $PIDFILE --exec $DAEMON -- $DAEMON_OPTS >> /dev/null & # ${LOGFILE} & 66 | 67 | ;; 68 | 69 | 70 | status) 71 | 72 | # WSTUN 73 | echo -e "$NAME status..." 74 | if [[ -z $MYPID2 ]]; 75 | then 76 | echo -e "inactive!" 77 | else 78 | echo -e "PID: "`cat $PIDFILE` 79 | fi 80 | 81 | ;; 82 | 83 | *) 84 | N=/etc/init.d/$NAME 85 | echo "Usage: $N {start|stop|restart|status}" >&2 86 | exit 1 87 | ;; 88 | 89 | esac 90 | 91 | exit 0 92 | -------------------------------------------------------------------------------- /etc/systemd/system/wstun.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=wstun 3 | After=network.target 4 | 5 | [Service] 6 | Type=simple 7 | User=root 8 | Group=root 9 | StandardInput=null 10 | StandardOutput=journal 11 | StandardError=journal 12 | Environment="NODE_PATH=/usr/lib/node_modules" 13 | ExecStart=/usr/bin/wstun -r -s 8080 --ssl=false 14 | #ExecStart=/usr/bin/wstun -r -s 8080 --ssl=true --key="" --cert="" 15 | Restart=always 16 | 17 | [Install] 18 | WantedBy=multi-user.target 19 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | //############################################################################### 2 | //## 3 | //# Copyright (C) 2014-2015 Andrea Rocco Lotronto 4 | //## 5 | //# Licensed under the Apache License, Version 2.0 (the "License"); 6 | //# you may not use this file except in compliance with the License. 7 | //# You may obtain a copy of the License at 8 | //## 9 | //# http://www.apache.org/licenses/LICENSE-2.0 10 | //## 11 | //# Unless required by applicable law or agreed to in writing, software 12 | //# distributed under the License is distributed on an "AS IS" BASIS, 13 | //# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | //# See the License for the specific language governing permissions and 15 | //# limitations under the License. 16 | //## 17 | //############################################################################### 18 | 19 | module.exports = require('./lib/wrapper'); -------------------------------------------------------------------------------- /lib/bindSockets.js: -------------------------------------------------------------------------------- 1 | //############################################################################### 2 | //## 3 | //# Copyright (C) 2014-2015 Andrea Rocco Lotronto, 2017 Nicola Peditto 4 | //## 5 | //# Licensed under the Apache License, Version 2.0 (the "License"); 6 | //# you may not use this file except in compliance with the License. 7 | //# You may obtain a copy of the License at 8 | //## 9 | //# http://www.apache.org/licenses/LICENSE-2.0 10 | //## 11 | //# Unless required by applicable law or agreed to in writing, software 12 | //# distributed under the License is distributed on an "AS IS" BASIS, 13 | //# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | //# See the License for the specific language governing permissions and 15 | //# limitations under the License. 16 | //## 17 | //############################################################################### 18 | 19 | var logger = log4js.getLogger('wstun'); 20 | 21 | (function() { 22 | var bindSockets; 23 | 24 | module.exports = bindSockets = function(wsconn, tcpconn) { 25 | 26 | wsconn.__paused = false; 27 | 28 | wsconn.on('message', function(message) { 29 | if (message.type === 'utf8') { 30 | return logger.info('Error, Not supposed to received message '); 31 | } else if (message.type === 'binary') { 32 | if (false === tcpconn.write(message.binaryData)) { 33 | wsconn.socket.pause(); 34 | wsconn.__paused = true; 35 | return ""; 36 | } else { 37 | if (true === wsconn.__paused) { 38 | wsconn.socket.resume(); 39 | return wsconn.__paused = false; 40 | } 41 | } 42 | } 43 | }); 44 | 45 | wsconn.on("overflow", function() { 46 | return tcpconn.pause(); 47 | }); 48 | 49 | wsconn.socket.on("drain", function() { 50 | return tcpconn.resume(); 51 | }); 52 | 53 | wsconn.on("error", function(err) { 54 | return logger.info('ws Error ' + err); 55 | }); 56 | 57 | wsconn.on('close', function(reasonCode, description) { 58 | logger.info("[SYSTEM] --> WS Peer " + wsconn.remoteAddress + ' disconnected - Reason: '+description); 59 | return tcpconn.destroy(); 60 | }); 61 | 62 | 63 | tcpconn.on("drain", function() { 64 | wsconn.socket.resume(); 65 | return wsconn.__paused = false; 66 | }); 67 | 68 | tcpconn.on("data", function(buffer) { 69 | //logger.info('[SYSTEM] --> TCP data received:\n\n\n' + buffer + "\n\n"); //logger.info(JSON.stringify(buffer)); 70 | return wsconn.sendBytes(buffer); 71 | }); 72 | 73 | tcpconn.on("error", function(err) { 74 | return logger.info('tcp Error ' + err); 75 | }); 76 | 77 | 78 | return tcpconn.on("close", function() { 79 | logger.info("[SYSTEM] --> TCP connection close."); 80 | return wsconn.close(); 81 | }); 82 | 83 | }; 84 | 85 | }).call(this); 86 | -------------------------------------------------------------------------------- /lib/bindSockets_reverse.js: -------------------------------------------------------------------------------- 1 | //############################################################################### 2 | //## 3 | //# Copyright (C) 2014-2015 Andrea Rocco Lotronto, 2017 Nicola Peditto 4 | //## 5 | //# Licensed under the Apache License, Version 2.0 (the "License"); 6 | //# you may not use this file except in compliance with the License. 7 | //# You may obtain a copy of the License at 8 | //## 9 | //# http://www.apache.org/licenses/LICENSE-2.0 10 | //## 11 | //# Unless required by applicable law or agreed to in writing, software 12 | //# distributed under the License is distributed on an "AS IS" BASIS, 13 | //# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | //# See the License for the specific language governing permissions and 15 | //# limitations under the License. 16 | //## 17 | //############################################################################### 18 | 19 | var logger = log4js.getLogger('wstun'); 20 | 21 | bindSockets = function(wsconn, tcpconn) { 22 | 23 | wsconn.__paused = false; 24 | 25 | wsconn.on('message', function(message) { 26 | 27 | //logger.debug('[SYSTEM] --> WS MESSAGE:'); logger.debug(JSON.stringify(message)); 28 | 29 | if (message.type === 'utf8') { 30 | return logger.info('Error, Not supposed to received message '); 31 | } 32 | else if (message.type === 'binary') { 33 | if (false === tcpconn.write(message.binaryData)) { 34 | wsconn.socket.pause(); 35 | wsconn.__paused = true; 36 | //DEBUG logger.info('WS message pause true'); 37 | return ""; 38 | } 39 | else { 40 | if (true === wsconn.__paused) { 41 | wsconn.socket.resume(); 42 | //DEBUG logger.info('WS message pause false'); 43 | return wsconn.__paused = false; 44 | } 45 | } 46 | } 47 | }); 48 | 49 | wsconn.on("overflow", function() { 50 | //DEBUG logger.info('TCP pause'); 51 | return tcpconn.pause(); 52 | }); 53 | 54 | wsconn.socket.on("drain", function() { 55 | //DEBUG logger.info('WS message pause false'); 56 | return tcpconn.resume(); 57 | }); 58 | 59 | wsconn.on("error", function(err) { 60 | return logger.info('[SYSTEM] --> WS Error: ' + err); 61 | }); 62 | 63 | wsconn.on('close', function(reasonCode, description) { 64 | logger.info("[SYSTEM] --> WS Peer " + wsconn.remoteAddress + " disconnected - Reason: ["+reasonCode+"] " + description); 65 | return tcpconn.destroy(); 66 | }); 67 | 68 | 69 | tcpconn.on("drain", function() { 70 | wsconn.socket.resume(); 71 | //DEBUG logger.info('WS resume'); 72 | return wsconn.__paused = false; 73 | }); 74 | 75 | tcpconn.on("data", function(buffer) { 76 | //DEBUG 77 | //logger.info('[SYSTEM] --> TCP data received:\n\n\n' + buffer + "\n\n"); //logger.info(JSON.stringify(buffer)); 78 | return wsconn.sendBytes(buffer); 79 | }); 80 | 81 | tcpconn.on("error", function(err) { 82 | logger.info("[SYSTEM] --> TCP Error " + err); 83 | return tcpconn.destroy(); 84 | }); 85 | 86 | tcpconn.on("close", function() { 87 | //DEBUG 88 | logger.info("[SYSTEM] --> TCP connection close."); 89 | //return tcpconn.destroy(); 90 | return wsconn.close(); 91 | }); 92 | 93 | }; 94 | 95 | module.exports = bindSockets; -------------------------------------------------------------------------------- /lib/client.js: -------------------------------------------------------------------------------- 1 | //############################################################################### 2 | //## 3 | //# Copyright (C) 2014-2015 Andrea Rocco Lotronto, 2017 Nicola Peditto 4 | //## 5 | //# Licensed under the Apache License, Version 2.0 (the "License"); 6 | //# you may not use this file except in compliance with the License. 7 | //# You may obtain a copy of the License at 8 | //## 9 | //# http://www.apache.org/licenses/LICENSE-2.0 10 | //## 11 | //# Unless required by applicable law or agreed to in writing, software 12 | //# distributed under the License is distributed on an "AS IS" BASIS, 13 | //# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | //# See the License for the specific language governing permissions and 15 | //# limitations under the License. 16 | //## 17 | //############################################################################### 18 | 19 | var logger = log4js.getLogger('wstun'); 20 | 21 | (function() { 22 | 23 | var WebSocketClient, bindSockets, net, wst_client; 24 | 25 | WebSocketClient = require('websocket').client; 26 | net = require("net"); 27 | bindSockets = require("./bindSockets"); 28 | 29 | module.exports = wst_client = (function() { 30 | 31 | function wst_client() { 32 | logger.info("[SYSTEM] - WS Tunnel Client starting..."); 33 | this.tcpServer = net.createServer(); 34 | } 35 | 36 | wst_client.prototype.start = function(localPort, wsHostUrl, remoteAddr) { 37 | 38 | logger.info("[SYSTEM] --> client started."); 39 | 40 | var proto = wsHostUrl.split(":")[0]; 41 | if(proto == "wss") 42 | require("../lib/https_override"); 43 | 44 | this.tcpServer.listen(localPort); 45 | 46 | logger.info("[SYSTEM] --> WS tunnel established. Waiting for incoming connections..."); 47 | 48 | return this.tcpServer.on("connection", (function(_this) { 49 | 50 | return function(tcpConn) { 51 | 52 | var url, wsClient; 53 | logger.info("[SYSTEM] - New connection..."); 54 | 55 | wsClient = new WebSocketClient(); 56 | 57 | wsClient.on('connectFailed', function(error) { 58 | logger.info("[SYSTEM] --> WS connect error: " + error.toString()); 59 | return tcpConn.destroy(); 60 | }); 61 | 62 | wsClient.on('connect', function(wsConn) { 63 | logger.info("[SYSTEM] --> WS connected."); 64 | return bindSockets(wsConn, tcpConn); 65 | }); 66 | 67 | if (remoteAddr) { 68 | url = "" + wsHostUrl + "/?dst=" + remoteAddr; 69 | } else { 70 | url = "" + wsHostUrl; 71 | } 72 | 73 | return wsClient.connect(url, 'tunnel-protocol'); 74 | 75 | }; 76 | 77 | })(this)); 78 | 79 | }; 80 | 81 | return wst_client; 82 | 83 | })(); 84 | 85 | }).call(this); -------------------------------------------------------------------------------- /lib/client_reverse.js: -------------------------------------------------------------------------------- 1 | //############################################################################### 2 | //## 3 | //# Copyright (C) 2014-2015 Andrea Rocco Lotronto, 2017 Nicola Peditto 4 | //## 5 | //# Licensed under the Apache License, Version 2.0 (the "License"); 6 | //# you may not use this file except in compliance with the License. 7 | //# You may obtain a copy of the License at 8 | //## 9 | //# http://www.apache.org/licenses/LICENSE-2.0 10 | //## 11 | //# Unless required by applicable law or agreed to in writing, software 12 | //# distributed under the License is distributed on an "AS IS" BASIS, 13 | //# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | //# See the License for the specific language governing permissions and 15 | //# limitations under the License. 16 | //## 17 | //############################################################################### 18 | 19 | var logger = log4js.getLogger('wstun'); 20 | 21 | var WebSocketClient = require('websocket').client; 22 | var net = require("net"); 23 | 24 | var bindSockets = require("./bindSockets_reverse"); 25 | 26 | wst_client_reverse = function() { 27 | this.wsClientForControll = new WebSocketClient(); 28 | }; 29 | 30 | wst_client_reverse.prototype.start = function(portTunnel, wsHostUrl, remoteAddr, uuid) { 31 | 32 | //Getting paramiters 33 | var url = require("url"); 34 | var urlWsHostObj = url.parse(wsHostUrl); 35 | var _ref1 = remoteAddr.split(":"), remoteHost = _ref1[0], remotePort = _ref1[1]; 36 | 37 | var proto = wsHostUrl.split(":")[0]; 38 | if(proto == "wss") 39 | require("../lib/https_override"); 40 | 41 | if(uuid != undefined){ 42 | url = "" + wsHostUrl + "/?dst=" + urlWsHostObj.hostname+":"+portTunnel + "&uuid=" +uuid; 43 | } 44 | else{ 45 | url = "" + wsHostUrl + "/?dst=" + urlWsHostObj.hostname+":"+portTunnel; 46 | } 47 | 48 | logger.info("[SYSTEM] -------------------- Connecting to", wsHostUrl); 49 | logger.info("[SYSTEM] --------------------> exposing", remoteAddr, "on port", portTunnel); 50 | if(uuid != undefined) 51 | logger.info("[SYSTEM] --> My UUID is ", uuid); 52 | 53 | //Connection to Controll WS Server 54 | this.wsClientForControll.connect(url, 'tunnel-protocol'); 55 | 56 | this.wsClientForControll.on('connect', (function(_this){ 57 | 58 | return function(wsConnectionForControll) { 59 | 60 | logger.info("[SYSTEM] --> TCP connection established!"); 61 | 62 | wsConnectionForControll.on('message', function(message) { 63 | 64 | //Only utf8 message used in Controll WS Socket 65 | var parsing = message.utf8Data.split(":"); 66 | 67 | //Managing new TCP connection on WS Server 68 | if (parsing[0] === 'NC'){ 69 | 70 | //Identification of ID connection 71 | var idConnection = parsing[1]; 72 | 73 | this.wsClientData = new WebSocketClient(); 74 | this.wsClientData.connect(wsHostUrl+"/?id="+idConnection, 'tunnel-protocol'); 75 | 76 | //Management of new WS Client for every TCP connection on WS Server 77 | this.wsClientData.on('connect', (function(_this){ 78 | 79 | return function(wsConnectionForData){ 80 | 81 | //Waiting of WS Socket with WS Server 82 | wsConnectionForData.socket.pause(); 83 | 84 | //DEBUG logger.info("Connected wsClientData to WS-Server for id "+parsing[1]+" on localport::"+wsConnectionForData.socket.localPort); 85 | logger.info("[SYSTEM] --> Start TCP connection on client to "+remoteHost+":"+remotePort); 86 | 87 | tcpConnection(wsConnectionForData, remoteHost, remotePort); 88 | 89 | } 90 | })(this)); 91 | 92 | } 93 | }); 94 | 95 | } 96 | 97 | })(this)); 98 | 99 | 100 | //Management of WS Connection failed 101 | this.wsClientForControll.on('connectFailed', function(error) { 102 | logger.info("[SYSTEM] --> WS connect error: " + error.toString()); 103 | }); 104 | 105 | 106 | }; 107 | 108 | function tcpConnection(wsConn, host, port){ 109 | 110 | var tcpConn = net.connect( {port: port, host: host}, function(){}); 111 | bindSockets(wsConn, tcpConn); 112 | 113 | tcpConn.on("connect",function(){ 114 | //Resume of the WS Socket after the connection to WS Server 115 | wsConn.socket.resume(); 116 | }); 117 | 118 | tcpConn.on('error',(function(_this){ 119 | return function(request){ 120 | logger.info("[SYSTEM] --> "+request); 121 | } 122 | })(this)); 123 | 124 | //wst_client_reverse 125 | 126 | } 127 | 128 | module.exports = wst_client_reverse; 129 | -------------------------------------------------------------------------------- /lib/https_override.js: -------------------------------------------------------------------------------- 1 | //############################################################################### 2 | //## 3 | //# Copyright (C) 2014-2015 Andrea Rocco Lotronto 4 | //## 5 | //# Licensed under the Apache License, Version 2.0 (the "License"); 6 | //# you may not use this file except in compliance with the License. 7 | //# You may obtain a copy of the License at 8 | //## 9 | //# http://www.apache.org/licenses/LICENSE-2.0 10 | //## 11 | //# Unless required by applicable law or agreed to in writing, software 12 | //# distributed under the License is distributed on an "AS IS" BASIS, 13 | //# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | //# See the License for the specific language governing permissions and 15 | //# limitations under the License. 16 | //## 17 | //############################################################################### 18 | 19 | var logger = log4js.getLogger('wstun'); 20 | 21 | (function() { 22 | var https, old_https_request; 23 | 24 | https = require("https"); 25 | 26 | old_https_request = https.request; 27 | 28 | https.request = function() { 29 | var options; 30 | options = arguments[0]; 31 | options.rejectUnauthorized = false; 32 | return old_https_request.apply(void 0, Array.apply(null, arguments)); 33 | }; 34 | 35 | }).call(this); 36 | -------------------------------------------------------------------------------- /lib/server.js: -------------------------------------------------------------------------------- 1 | //############################################################################### 2 | //## 3 | //# Copyright (C) 2014-2015 Andrea Rocco Lotronto, 2017 Nicola Peditto 4 | //## 5 | //# Licensed under the Apache License, Version 2.0 (the "License"); 6 | //# you may not use this file except in compliance with the License. 7 | //# You may obtain a copy of the License at 8 | //## 9 | //# http://www.apache.org/licenses/LICENSE-2.0 10 | //## 11 | //# Unless required by applicable law or agreed to in writing, software 12 | //# distributed under the License is distributed on an "AS IS" BASIS, 13 | //# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | //# See the License for the specific language governing permissions and 15 | //# limitations under the License. 16 | //## 17 | //############################################################################### 18 | 19 | var logger = log4js.getLogger('wstun'); 20 | 21 | (function() { 22 | 23 | var WebSocketServer, bindSockets, http, net, url, wst_server; 24 | 25 | WebSocketServer = require('websocket').server; 26 | 27 | http = require('http'); 28 | url = require("url"); 29 | net = require("net"); 30 | bindSockets = require("./bindSockets"); 31 | 32 | https_flag = null; 33 | 34 | module.exports = wst_server = (function() { 35 | 36 | function wst_server(options) { 37 | 38 | if(options != undefined) { 39 | 40 | logger.info("[SYSTEM] - WS Tunnel Server starting with these paramters:\n" + JSON.stringify(options, null, "\t")); 41 | this.dstHost = options.dstHost; 42 | this.dstPort = options.dstPort; 43 | 44 | https_flag = options.ssl; 45 | 46 | } 47 | else 48 | logger.info("[SYSTEM] - WS Tunnel Server starting..."); 49 | 50 | if(https_flag == "true"){ 51 | 52 | //HTTPS 53 | logger.info("[SYSTEM] - WS over HTTPS"); 54 | 55 | var https = require('https'); 56 | var fs = require('fs'); 57 | 58 | require("../lib/https_override"); 59 | 60 | try{ 61 | // certificates loading from file 62 | this.s4t_key = fs.readFileSync(options.key, 'utf8'); 63 | this.s4t_cert = fs.readFileSync(options.cert, 'utf8'); 64 | 65 | }catch (err) { 66 | // handle the error safely 67 | logger.info("[SYSTEM] --> ERROR: " + err); 68 | process.exit(1); 69 | } 70 | 71 | var credentials = { 72 | key: this.s4t_key, 73 | cert: this.s4t_cert 74 | }; 75 | 76 | this.httpServer = https.createServer(credentials, function(request, response) { 77 | logger.info(request, response); 78 | }); 79 | 80 | this.wsServer = new WebSocketServer({ 81 | httpServer: this.httpServer, 82 | autoAcceptConnections: false 83 | }); 84 | 85 | 86 | }else{ 87 | 88 | //HTTP 89 | logger.info("[SYSTEM] - WS over HTTP"); 90 | 91 | this.httpServer = http.createServer(function(request, response) { 92 | logger.info(request, response); 93 | }); 94 | 95 | this.wsServer = new WebSocketServer({ 96 | httpServer: this.httpServer, 97 | autoAcceptConnections: false 98 | }); 99 | 100 | } 101 | 102 | 103 | 104 | } 105 | 106 | wst_server.prototype.start = function(port) { 107 | 108 | if (https_flag == "true") 109 | logger.info("[SYSTEM] - WS Tunnel Server starting on: wss://localhost:" + port + " - CERT: \n" + this.s4t_cert); 110 | else 111 | logger.info("[SYSTEM] - WS Tunnel Server starting on: ws://localhost:" + port); 112 | 113 | this.httpServer.listen(port, function() { 114 | return logger.info("[SYSTEM] - Server is listening on port " + port + "..."); 115 | }); 116 | 117 | return this.wsServer.on('request', (function(_this) { 118 | return function(request) { 119 | 120 | var host, remoteAddr, tcpconn, uri, _ref, _ref1; 121 | 122 | if (!_this.originIsAllowed(request.origin)) { 123 | return _this._reject(request, "Illegal origin " + origin); 124 | } 125 | 126 | uri = url.parse(request.httpRequest.url, true); 127 | _ref = [_this.dstHost, _this.dstPort], host = _ref[0], port = _ref[1]; 128 | 129 | if (host && port) { 130 | 131 | remoteAddr = "" + host + ":" + port; 132 | 133 | } else { 134 | 135 | if (!uri.query.dst) { 136 | return _this._reject(request, "No tunnel target specified"); 137 | } 138 | 139 | remoteAddr = uri.query.dst; 140 | _ref1 = remoteAddr.split(":"), host = _ref1[0], port = _ref1[1]; 141 | 142 | } 143 | 144 | tcpconn = net.connect( { port: port, host: host }, function() { 145 | var wsconn; 146 | logger.info("[SYSTEM] - Establishing tunnel to " + remoteAddr); 147 | wsconn = request.accept('tunnel-protocol', request.origin); 148 | return bindSockets(wsconn, tcpconn); 149 | }); 150 | 151 | return tcpconn.on("error", function(err) { 152 | return _this._reject(request, "Tunnel connect error to " + remoteAddr + ": " + err); 153 | }); 154 | 155 | }; 156 | 157 | })(this)); 158 | 159 | }; 160 | 161 | wst_server.prototype.originIsAllowed = function(origin) { 162 | return true; 163 | }; 164 | 165 | wst_server.prototype._reject = function(request, msg) { 166 | request.reject(); 167 | return logger.info("[SYSTEM] - Connection from " + request.remoteAddress + " rejected: " + msg); 168 | }; 169 | 170 | return wst_server; 171 | 172 | })(); 173 | 174 | }).call(this); 175 | -------------------------------------------------------------------------------- /lib/server_reverse.js: -------------------------------------------------------------------------------- 1 | //############################################################################### 2 | //## 3 | //# Copyright (C) 2014-2015 Andrea Rocco Lotronto, 2017 Nicola Peditto 4 | //## 5 | //# Licensed under the Apache License, Version 2.0 (the "License"); 6 | //# you may not use this file except in compliance with the License. 7 | //# You may obtain a copy of the License at 8 | //## 9 | //# http://www.apache.org/licenses/LICENSE-2.0 10 | //## 11 | //# Unless required by applicable law or agreed to in writing, software 12 | //# distributed under the License is distributed on an "AS IS" BASIS, 13 | //# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | //# See the License for the specific language governing permissions and 15 | //# limitations under the License. 16 | //## 17 | //############################################################################### 18 | 19 | var logger = log4js.getLogger('wstun'); 20 | 21 | var WebSocketServer, bindSockets, http, net, url, wst_server_reverse; 22 | 23 | WebSocketServer = require('websocket').server; 24 | http = require('http'); 25 | url = require("url"); 26 | net = require("net"); 27 | bindSockets = require("./bindSockets_reverse"); 28 | 29 | uuid = require('node-uuid'); 30 | 31 | logger.info("WSTUN STARTED!"); 32 | 33 | https_flag = null; 34 | 35 | var allow_list; 36 | 37 | var eventEmitter = require('events').EventEmitter; 38 | eventEmitter.prototype._maxListeners = 1000; 39 | 40 | var newWSTCP_DATA = new eventEmitter(); 41 | 42 | wst_server_reverse = function(options) { 43 | 44 | if(options != undefined) { 45 | 46 | logger.info("[SYSTEM] - WS Reverse Tunnel Server starting with these paramters:\n" + JSON.stringify(options, null, "\t")); 47 | this.dstHost = options.dstHost; 48 | this.dstPort = options.dstPort; 49 | 50 | https_flag = options.ssl; 51 | allow_list_file = options.allow; 52 | 53 | //logger.info("allow_list_file: " + allow_list_file); 54 | 55 | } 56 | else 57 | logger.info("[SYSTEM] - WS Reverse Tunnel Server starting..."); 58 | 59 | 60 | if(https_flag == "true"){ 61 | 62 | //HTTPS 63 | logger.info("[SYSTEM] - WS Reverse Tunnel Server over HTTPS."); 64 | var https = require('https'); 65 | var fs = require('fs'); 66 | 67 | require("../lib/https_override"); //add parameters overriding each https request 68 | 69 | https_flag = options.ssl; 70 | 71 | try{ 72 | // certificates loading from file 73 | this.s4t_key = fs.readFileSync(options.key, 'utf8'); 74 | this.s4t_cert = fs.readFileSync(options.cert, 'utf8'); 75 | 76 | }catch (err) { 77 | // handle the error safely 78 | logger.info("[SYSTEM] --> ERROR: " + err); 79 | process.exit(1); 80 | 81 | } 82 | 83 | var credentials = { 84 | key: this.s4t_key, 85 | cert: this.s4t_cert 86 | }; 87 | 88 | this.httpServer = https.createServer(credentials, function(request, response) { 89 | //logger.info(request, response); 90 | //response.writeHead(404); 91 | //return response.end(); 92 | response.writeHead(200, {"Content-Type": "text/html"}); 93 | response.write(""); 94 | response.write(""); 95 | response.write(""); 96 | response.write("WSTUN"); 97 | response.write(""); 98 | response.write(""); 99 | response.write("iotronic-wstun is running!"); 100 | response.write(""); 101 | response.write(""); 102 | response.end(); 103 | }); 104 | 105 | 106 | }else{ 107 | 108 | //HTTP 109 | logger.info("[SYSTEM] - WS Reverse Tunnel Server over HTTP."); 110 | this.httpServer = http.createServer(function(request, response) { 111 | //logger.info(request, response); 112 | //response.writeHead(404); 113 | //return response.end(); 114 | response.writeHead(200, {"Content-Type": "text/html"}); 115 | response.write(""); 116 | response.write(""); 117 | response.write(""); 118 | response.write("WSTUN"); 119 | response.write(""); 120 | response.write(""); 121 | response.write("iotronic-wstun is running!"); 122 | response.write(""); 123 | response.write(""); 124 | response.end(); 125 | 126 | }); 127 | 128 | } 129 | 130 | //create websocket 131 | this.wsServerForControll = new WebSocketServer({ 132 | httpServer: this.httpServer, 133 | autoAcceptConnections: false 134 | }); 135 | 136 | }; 137 | 138 | wst_server_reverse.prototype.start = function(port) { 139 | 140 | if (https_flag == "true") 141 | logger.info("[SYSTEM] - WS Reverse Tunnel Server starting on: wss://localhost:" + port + " - CERT: \n" + this.s4t_cert); 142 | else 143 | logger.info("[SYSTEM] - WS Reverse Tunnel Server starting on: ws://localhost:" + port); 144 | 145 | //Activate HTTP/S server 146 | this.httpServer.listen(port, function() { 147 | logger.info("[SYSTEM] - WS Reverse Tunnel Server is listening..."); 148 | }); 149 | 150 | 151 | this.wsServerForControll.on('request', (function(_this){ 152 | return function(request){ 153 | 154 | //Create one TCP server for each client WebSocketRequest 155 | request.tcpServer = new net.createServer(); 156 | 157 | var uri = url.parse(request.httpRequest.url, true); 158 | 159 | var src_address = request.httpRequest.client._peername.address.split(":")[3]; 160 | 161 | if (uri.query.dst != undefined){ 162 | 163 | var remoteAddr = uri.query.dst; 164 | var client_uuid = uri.query.uuid; 165 | ref1 = remoteAddr.split(":"); 166 | var portTcp = ref1[1]; 167 | 168 | if(client_uuid != undefined){ 169 | logger.info("[SYSTEM] WebSocket creation towards " + src_address + " on port " + portTcp + " from client " + client_uuid); 170 | } 171 | else{ 172 | logger.info("[SYSTEM] WebSocket creation towards " + src_address + " on port " + portTcp ); 173 | } 174 | 175 | if(allow_list_file != undefined ){ 176 | if(client_uuid != undefined){ 177 | 178 | var fs = require('fs'); 179 | 180 | try{ 181 | // allowlist loading from file 182 | allow_list = JSON.parse(fs.readFileSync(allow_list_file)); 183 | //logger.info(allow_list); 184 | }catch (err) { 185 | // handle the error safely 186 | logger.info("[SYSTEM] --> ERROR: " + err); 187 | process.exit(1); 188 | } 189 | 190 | var c = allow_list.filter(it => it.client === client_uuid); 191 | if (c.length > 0){ 192 | logger.info("[SYSTEM] --> Client " + client_uuid + " found in the allowlist as " + JSON.stringify(c)); 193 | var p = c.filter(it => it.port === portTcp); 194 | } 195 | else 196 | logger.info("[SYSTEM] --> Client " + client_uuid + " not found in the allowlist"); 197 | 198 | if(p != undefined && p.length > 0 && p[0].port == portTcp){ 199 | logger.info("[SYSTEM] --> Port is allowed: " + portTcp); 200 | request.tcpServer.listen(portTcp); 201 | logger.info("[SYSTEM] --> TCP server is listening on port " + portTcp); 202 | 203 | request.wsConnectionForControll = request.accept('tunnel-protocol', request.origin); 204 | logger.info("[SYSTEM] --> WS connection created"); 205 | 206 | request.wsConnectionForControll.on('close', function(reasonCode, description) { 207 | logger.info("[SYSTEM] - WebSocket Controll Peer " + request.wsConnectionForControll.remoteAddress + " disconnected - Reason: ["+reasonCode+"] " + description); 208 | logger.info("[SYSTEM] --> Close websocket server on port " + portTcp); 209 | request.tcpServer.close(); 210 | }); 211 | 212 | } 213 | else{ 214 | logger.info("Port is not allowed: " + portTcp + " so the connection is not authorized"); 215 | //reject the request 216 | request.reject(401, "Request unauthorized!"); 217 | logger.info("[SYSTEM] --> WS connection closed"); 218 | } 219 | } 220 | else{ 221 | logger.info("Client is not specified so the connection is not authorized."); 222 | //reject the request 223 | request.reject(401, "Request unauthorized!"); 224 | logger.info("[SYSTEM] --> WS connection closed"); 225 | 226 | } 227 | } 228 | else{ 229 | request.tcpServer.listen(portTcp); 230 | logger.info("[SYSTEM] --> TCP server is listening on port " + portTcp); 231 | 232 | request.wsConnectionForControll = request.accept('tunnel-protocol', request.origin); 233 | logger.info("[SYSTEM] --> WS connection created"); 234 | 235 | request.wsConnectionForControll.on('close', function(reasonCode, description) { 236 | logger.info("[SYSTEM] - WebSocket Controll Peer " + request.wsConnectionForControll.remoteAddress + " disconnected - Reason: ["+reasonCode+"] " + description); 237 | logger.info("[SYSTEM] --> Close websocket server on port " + portTcp); 238 | request.tcpServer.close(); 239 | }); 240 | } 241 | } 242 | else{ 243 | //REQUEST FOR WS USED FOR DATA 244 | logger.info("[SYSTEM] --> WebSocket Request for Data"); 245 | newWSTCP_DATA.emit('created', request); 246 | } 247 | 248 | //Manage TCP error events 249 | request.tcpServer.on('error', function(message) { 250 | if(message.code == "EADDRINUSE"){ 251 | logger.info("[SYSTEM] - Error - Port " + message.port + " already used: connection aborted."); 252 | request.wsConnectionForControll.close(); 253 | }else 254 | logger.info("[SYSTEM] - Error establishing TCP connection: " + message); 255 | 256 | }); 257 | 258 | //Manage TCP Connection event 259 | request.tcpServer.on('connection', (function(_this){ 260 | 261 | return function(tcpConn){ 262 | 263 | tcpConn.wsConnection; 264 | 265 | //Putting in pause the tcp connection waiting the new socket WS Socket for data 266 | tcpConn.pause(); 267 | var idConnection = uuid.v4(); 268 | var msgForNewConnection = "NC:"+idConnection; 269 | 270 | request.wsConnectionForControll.sendUTF(msgForNewConnection); 271 | 272 | var EventManager = (function(_this){ 273 | 274 | return function(request){ 275 | 276 | try{ 277 | 278 | var uri = url.parse(request.httpRequest.url, true); 279 | 280 | if(idConnection == uri.query.id){ 281 | 282 | //tcpConn.wsConnection = wsTCP; 283 | tcpConn.wsConnection = request.accept('tunnel-protocol', request.origin); 284 | bindSockets(tcpConn.wsConnection, tcpConn); 285 | //DEBUG logger.info("Bind ws tcp"); 286 | 287 | //Resuming of the tcp connection after WS Socket is just created 288 | tcpConn.resume(); 289 | //DEBUG logger.info("TCP RESUME"); 290 | newWSTCP_DATA.removeListener('created', EventManager); 291 | } 292 | 293 | }catch (err) { 294 | // handle the error 295 | logger.info("[SYSTEM] --> ERROR: " + err); 296 | request.tcpServer.close(); 297 | newWSTCP_DATA.removeListener('created', EventManager); 298 | } 299 | 300 | } 301 | 302 | })(this) 303 | 304 | newWSTCP_DATA.on('created', EventManager); 305 | 306 | } 307 | 308 | })(_this)); 309 | 310 | } 311 | })(this)); 312 | }; 313 | 314 | 315 | module.exports = wst_server_reverse; 316 | -------------------------------------------------------------------------------- /lib/wrapper.js: -------------------------------------------------------------------------------- 1 | //############################################################################### 2 | //## 3 | //# Copyright (C) 2014-2015 Andrea Rocco Lotronto, 2017 Nicola Peditto 4 | //## 5 | //# Licensed under the Apache License, Version 2.0 (the "License"); 6 | //# you may not use this file except in compliance with the License. 7 | //# You may obtain a copy of the License at 8 | //## 9 | //# http://www.apache.org/licenses/LICENSE-2.0 10 | //## 11 | //# Unless required by applicable law or agreed to in writing, software 12 | //# distributed under the License is distributed on an "AS IS" BASIS, 13 | //# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | //# See the License for the specific language governing permissions and 15 | //# limitations under the License. 16 | //## 17 | //############################################################################### 18 | 19 | var logger = log4js.getLogger('wstun'); 20 | 21 | (function() { 22 | module.exports = { 23 | server: require("./server"), 24 | client: require("./client"), 25 | server_reverse : require("./server_reverse"), 26 | client_reverse : require("./client_reverse") 27 | }; 28 | 29 | }).call(this); 30 | 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mdslab/wstun", 3 | "version": "1.1.0", 4 | "description": "A set of tools to establish TCP tunnels (or TCP reverse tunnels) over WebSocket connections for circumventing the problem of directly connect to hosts behind a strict firewall or without public IP. It also supports WebSocket Secure (wss) connections.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "postinstall": "./scripts/postinst" 9 | }, 10 | "dependencies": { 11 | "websocket": "<=1.0.28", 12 | "optimist": "<=0.6.1", 13 | "node-uuid":"<=1.4.7", 14 | "under_score": "<=0.1.0", 15 | "log4js":"<=1.1.1" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/MDSLab/wstun.git" 20 | }, 21 | "keywords": [ 22 | "tunnel", 23 | "reverse", 24 | "WebSocket" 25 | ], 26 | "author": "Nicola Peditto ", 27 | "contributors": [ 28 | "Dario Bruneo ", 29 | "Francesco Longo ", 30 | "Giovanni Merlino ", 31 | "Andrea Rocco Lotronto " 32 | ], 33 | "license": "Apache-2.0", 34 | "bugs": { 35 | "url": "https://github.com/MDSLab/wstun/issues" 36 | }, 37 | "homepage": "https://github.com/MDSLab/wstun", 38 | "bin": { 39 | "wstun": "./bin/wstun.js" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # WSTUN - Tunnels and Reverse Tunnels over WebSocket for Node.js 2 | 3 | [![npm version](https://badge.fury.io/js/%40mdslab%2Fwstun.svg)](https://badge.fury.io/js/%40mdslab%2Fwstun) 4 | 5 | ## Overview 6 | 7 | A set of Node.js tools to establish TCP tunnels (or TCP reverse tunnels) over WebSocket connections for circumventing the problem of directly connect to hosts behind a strict firewall or without public IP. It also supports WebSocket Secure (wss) connections. 8 | 9 | ## Installation 10 | ``` 11 | npm install @mdslab/wstun 12 | ``` 13 | 14 | ## Usage (from a Node.js application) 15 | 16 | ### Instantiation of a tunnel server 17 | ```JavaScript 18 | var wstun = require("@mdslab/wstun"); 19 | 20 | // without security 21 | server = new wstun.server(); 22 | 23 | // or with security ( and are the paths of the private and public keys in .pem formats) 24 | server = new wstun.server({ssl:true, key:"", cert:""}); 25 | 26 | //start the server ( is the listening port) 27 | server.start() 28 | ``` 29 | 30 | ### Implementation of a tunnel client 31 | ```JavaScript 32 | var wstun = require("@mdslab/wstun"); 33 | 34 | client = new wstun.client(); 35 | 36 | // without security 37 | wstunHost = 'ws://wstunServerIP:wstunPort'; 38 | 39 | // or with security 40 | wstunHost = 'wss://wstunServerIP:wstunPort'; 41 | 42 | // is the port on the localhost on which the tunneled service will be reachable 43 | // : is the endpoint of the service to be tunneled 44 | client.start(, wstunHost, ':'); 45 | ``` 46 | 47 | ### Instantiation of a reverse tunnel server 48 | ```JavaScript 49 | var wstun = require("@mdslab/wstun"); 50 | 51 | // without security 52 | reverse_server = new wstun.server_reverse(); 53 | 54 | // or with security ( and are the paths of the private and public keys in .pem formats) 55 | reverse_server = new wstun.server_reverse({ssl:true, key:"", cert:""}); 56 | 57 | //start the server ( is the listening port) 58 | reverse_server.start(); 59 | 60 | ``` 61 | ### Implementation of a reverse tunnel client 62 | ```JavaScript 63 | var wstun = require("reverse-wstunnel"); 64 | 65 | reverse_client = new wstun.client_reverse(); 66 | 67 | // without security 68 | wstunHost = 'ws://wstunServerIP:wstunPort'; 69 | 70 | // or with security 71 | wstunHost = 'wss://wstunServerIP:wstunPort'; 72 | 73 | // is the port on the reverse tunnel server on which the tunneled service will be reachable 74 | // : is the endpoint of the service to be reverse tunneled 75 | reverse_client.start(, wstunHost, ':'); 76 | ``` 77 | 78 | ## Usage (from command line) 79 | A command line tool (wstun.js) is also available in the bin directory. 80 | 81 | Examples about how to run a tunnel server: 82 | ``` 83 | //without security 84 | ./wstun.js -s 8080 85 | 86 | //with security 87 | ./wstun.js -s 8080 --ssl=true --key="" --cert="" 88 | ``` 89 | Examples about how to run a tunnel client: 90 | ``` 91 | //without security 92 | ./wstun.js -t 33:2.2.2.2:33 ws://wstunServerIP:8080 93 | 94 | //with security 95 | ./wstun.js -t 33:2.2.2.2:33 wss://wstunServerIP:8080 96 | ``` 97 | In both examples, connections to localhost:33 on the client will be tunneled to 2.2.2.2:33 through the Websocket connection with the server. Note that the decision about the final destination of the tunnel is up to the client. Alternatively, it is possible to lock the final destination of the tunnel on the server side. 98 | 99 | Examples about how to run a tunnel server locking the final tunnel destination: 100 | ``` 101 | //without security 102 | ./wstun.js -s 8080 -t 2.2.2.2:33 103 | 104 | //with security 105 | ./wstun.js -s 8080 -t 2.2.2.2:33 --ssl=true --key="" --cert="" 106 | ``` 107 | Examples about how to run a tunnel client when the final tunnel destination has been locked by the server: 108 | ``` 109 | //without security 110 | ./wstun.js -t 33 ws://wstunServerIP:8080 111 | 112 | //with security 113 | ./wstun.js -t 33 wss://wstunServerIP:8080 114 | ``` 115 | 116 | Examples about how to run a reverse tunnel server: 117 | ``` 118 | //without security 119 | ./wstun.js -r -s 8080 120 | 121 | //with security 122 | ./wstun.js -r -s 8080 --ssl=true --key="" --cert="" 123 | ``` 124 | Examples about how to run a reverse tunnel client: 125 | ``` 126 | //without security 127 | ./wstun.js -r6666:2.2.2.2:33 ws://server:8080 128 | 129 | //with security 130 | ./wstun.js -r6666:2.2.2.2:33 wss://server:8080 131 | ``` 132 | In the above examples, the client asks the server to open a TCP server on port 6666 and all connections on this port are tunneled to the client that is directely connected to 2.2.2.2:33. 133 | 134 | 135 | ## Logging system 136 | WSTUN uses Log4js library to manage its logs in /var/log/wstun/ 137 | -------------------------------------------------------------------------------- /scripts/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mkdir -p /var/log/wstun 4 | touch /var/log/wstun/wstun.log 5 | echo "WSTUN logging set." --------------------------------------------------------------------------------