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
136
|
#!/usr/bin/env node
// Note: this is unfinished and not currently used. Stashed in case we resurrect this idea.
var UDP_PORT_START = 9994;
var UDP_PORT_COUNT = 16384;
var HTTP_PORT = 8080;
var LONG_POLLING_TIMEOUT = 25000;
var http = require('http');
var dgram = require('dgram');
// clients[token] = [ most recent HTTP activity, assigned UDP socket ]
var clients = {};
// GETs[token] = [ [ request, timestamp ], ... ]
var GETs = {};
// mappings[localPort+'/'+remoteIp+'/'+remotePort] = { ZT source: [ token ] }
var mappings = {};
// Array of available UDP sockets to assign randomly to clients
var udpSocketPool = [];
function onIncomingUdp(socket,message,remoteIp,remotePort)
{
if (message.length > 16) {
var mappingKey = socket.localPort + '/' + remoteIp + '/' + remotePort;
var mapping = mappings[mappingKey];
if (mapping) {
var ztDestination = message.readUIntBE(8,5);
if (ztDestination in mapping) {
}
}
}
}
function onOutgoingUdp(token,socket,message,remoteIp,remotePort)
{
if (message.length > 16) {
var ztDestination = message.readUIntBE(8,5);
var ztSource = (message.length >= 28) ? message.readUIntBE(13,5) ? 0;
if ((ztSource & 0xff00000000) == 0xff00000000) // fragment
ztSource = 0;
if ((ztDestination !== 0)&&((ztDestination & 0xff00000000) !== 0xff00000000)) {
socket.send(message,0,message.length,remotePort,remoteIp);
}
}
}
function doHousekeeping()
{
}
for(var udpPort=UDP_PORT_START;udpPort<(UDP_PORT_START+UDP_PORT_COUNT)++udpPort) {
var socket = dgram.createSocket('udp4',function(message,rinfo) { onIncomingUdp(socket,message,rinfo.address,rinfo.port); });
socket.on('listening',function() {
console.log('Listening on '+socket.localPort);
udpSocketPool.push(socket);
}
socket.on('error',function() {
console.log('Error listening on '+socket.localPort);
socket.close();
})
socket.bind(udpPort);
}
server = http.createServer(function(request,response) {
console.log(request.socket.remoteAddress+" "+request.method+" "+request.url);
try {
// /<proxy token>/<ignored>/...
var urlSp = request.url.split('/');
if ((urlSp.length >= 3)&&(udpSocketPool.length > 0)) {
var token = urlSp[1]; // urlSp[0] == '' since URLs start with /
if (token.length >= 8) {
var client = clients[token];
if (!Array.isArray(client)) {
client = [ Date.now(),udpSocketPool[Math.floor(Math.random() * udpSocketPool.length)] ];
clients[token] = client;
} else client[0] = Date.now();
if (request.method === "GET") {
// /<proxy token>/<ignored> ... waits via old skool long polling
} else if (request.method === "POST") {
// /<proxy token>/<ignored>/<dest ip>/<dest port>
if (urlSp.length === 5) {
var ipSp = urlSp[3].split('.');
var port = parseInt(urlSp[4],10);
// Note: do not allow the use of this proxy to talk to privileged ports
if ((ipSp.length === 4)&&(port >= 1024)&&(port <= 0xffff)) {
var ip = [ parseInt(ipSp[0]),parseInt(ipSp[1]),parseInt(ipSp[2]),parseInt(ipSp[3]) ];
if ( (ip[0] > 0)
&&(ip[0] < 240)
&&(ip[0] !== 127)
&&(ip[1] >= 0)
&&(ip[1] <= 255)
&&(ip[2] >= 0)
&&(ip[2] <= 255)
&&(ip[3] > 0)
&&(ip[3] < 255) ) {
var postData = null;
request.on('data',function(chunk) {
postData = ((postData === null) ? chunk : Buffer.concat([ postData,chunk ]));
});
request.on('end',function() {
if (postData !== null)
onOutgoingUdp(token,client[1],postData,urlSp[3],port);
response.writeHead(200,{'Content-Length':0,'Pragma':'no-cache','Cache-Control':'no-cache'});
response.end();
});
return; // no 400 -- read from stream
} // else 400
} // else 400
} // else 400
} // else 400
} // else 400
} // else 400
} catch (e) {} // 400
response.writeHead(400,{'Content-Length':0,'Pragma':'no-cache','Cache-Control':'no-cache'});
response.end();
return;
});
setInterval(doHousekeeping,5000);
server.setTimeout(120000);
server.listen(HTTP_PORT);
|