/
ws-tcp-bridge
executable file
·135 lines (110 loc) · 2.8 KB
/
ws-tcp-bridge
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env node
var ws_module = require('ws');
var net = require('net');
var argv = require('optimist')
.usage('Forward tcp connections to websocket servers, or websocket connections to tcp servers.')
.demand('lport')
.describe('lport','port to listen for connections on.')
.demand('rhost')
.describe('rhost','address to forward the connection to.')
.demand('method')
.describe('method','either tcp2ws or ws2tcp').argv;
var wsMask = (argv.method == 'tcp2ws');
function initSocketCallbacks(state,ws,s) {
function flushSocketBuffer() {
if(state.sBuffer.length > 0) {
s.write(Buffer.concat(state.sBuffer));
}
state.sBuffer = null;
};
function flushWebsocketBuffer() {
if(state.wsBuffer.length > 0) {
ws.send(Buffer.concat(state.wsBuffer),{binary: true,mask: wsMask});
}
state.wsBuffer = null;
};
s.on('close', function(had_error) {
ws.removeAllListeners('close');
ws.close();
});
ws.on('close', function() {
s.removeAllListeners('close');
s.end();
});
ws.on('error', function (e) {
console.log('websocket error');
console.log(e);
ws.removeAllListeners('close');
s.removeAllListeners('close');
ws.close();
s.end();
});
s.on('error', function (e) {
console.log('socket error');
console.log(e);
ws.removeAllListeners('close');
s.removeAllListeners('close');
ws.close();
s.end();
});
s.on('connect', function() {
state.sReady = true;
flushSocketBuffer();
});
ws.on('open', function () {
state.wsReady = true;
flushWebsocketBuffer();
});
s.on('data', function(data) {
if(! state.wsReady) {
state.wsBuffer.push(data);
} else {
ws.send(data,{binary: true,mask: wsMask});
}
});
ws.on('message', function(m,flags) {
if(!state.sReady) {
state.sBuffer.push(m);
} else {
s.write(m);
}
});
}
function tcp2ws() {
console.log('proxy mode tcp -> ws');
console.log('forwarding port ' + argv.lport + ' to ' + argv.rhost);
var server = net.createServer(function(s) {
var ws = new ws_module(argv.rhost);
var state = {
sReady : true,
wsReady : false,
wsBuffer: [],
sBuffer : []
};
initSocketCallbacks(state,ws,s);
});
server.listen(argv.lport);
}
function ws2tcp() {
console.log('proxy mode ws -> tcp');
console.log('forwarding port ' + argv.lport + ' to ' + argv.rhost);
wss = new ws_module.Server({port: argv.lport});
wss.on('connection', function(ws) {
var addr_port = argv.rhost.split(':');
var s = net.connect(addr_port[1],addr_port[0]);
var state = {
sReady : false,
wsReady : true, // there is no callback so i assume its already connected
wsBuffer: [],
sBuffer : []
};
initSocketCallbacks(state,ws,s);
});
}
if(argv.method == 'tcp2ws') {
tcp2ws();
} else if (argv.method == 'ws2tcp') {
ws2tcp();
} else {
console.error("Method must be either tcp2ws or ws2tcp!");
}