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
|
#!/usr/bin/env node
const fs=require("fs");
const net=require("net");
const https=require("https");
const WebSocket=require("uWebSockets.js");
let listenport=null;
let upstream=null;
function parseUpstream(arg){
const [host, port]=arg.split(":");
return {host, port};
}
let httpsConfig=null;
if(process.argv.length==6){
upstream=parseUpstream(process.argv[2]);
listenport=+process.argv[3];
console.log("Reading keys for https");
httpsConfig={
key_file_name: process.argv[4],
cert_file_name: process.argv[5],
};
} else if(process.argv.length==4){
upstream=parseUpstream(process.argv[2]);
listenport=+process.argv[3];
console.log("WARNING: Running without SSL!");
} else {
console.error("Usage: ./server.js <host:port> <port> # proxy without SSL");
console.error(" ./server.js <host:port> <port> <key.pem> <cert.pem> # proxy with SSL");
console.error("'<host:port>' indicates the plain-tcp tomsg server to proxy to.");
console.error("'<port>' indicates the port to listen for websocket connections on.");
process.exit(1);
}
if(process.getuid()==0){
console.log(`Old uid: ${process.getuid()}, old gid: ${process.getgid()}; setting to nobody...`);
process.setgid("nobody");
process.setuid("nobody");
console.log(`New uid: ${process.getuid()}, new gid: ${process.getgid()}`);
}
let wsServer;
if(httpsConfig){
wsServer=WebSocket.SSLApp(httpsConfig);
} else {
wsServer=WebSocket.App();
}
wsServer=wsServer.ws("/*",{
open: sock=>{
const stateobj={netconn: null, buffer: [], sock_closed: false};
sock["tomsgdata"]=stateobj;
let linebuf="";
stateobj.netconn=net.connect(upstream.port,upstream.host,()=>{
for(const item of stateobj.buffer){
stateobj.netconn.write(item);
stateobj.netconn.write("\n");
}
stateobj.buffer=[];
});
stateobj.netconn.on("close",()=>{
if(!stateobj.sock_closed)sock.close();
});
stateobj.netconn.on("data",(data)=>{
linebuf+=data;
let idx;
while((idx=linebuf.indexOf("\n"))!=-1){
sock.send(linebuf.slice(0,idx));
linebuf=linebuf.slice(idx+1);
}
});
stateobj.netconn.on("error",()=>{
if(!stateobj.sock_closed)sock.close();
});
},
message: (sock,data,isBinary)=>{
const stateobj=sock["tomsgdata"];
data=new Uint8Array(data);
if(stateobj.netconn.connecting){
stateobj.buffer.push(data);
} else {
stateobj.netconn.write(data);
stateobj.netconn.write("\n");
}
},
close: sock=>{
const stateobj=sock["tomsgdata"];
stateobj.sock_closed=true;
try {stateobj.netconn.end();}
catch (e) {}
}
});
wsServer=wsServer.listen(listenport,listenSocket=>{
if(listenSocket){
console.log(`Websocket server${httpsConfig?" (SSL)":""} bound on port ${listenport}`);
}
});
|