hyperMC-Web-Relay/worker-server.js

155 lines
6.6 KiB
JavaScript

const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
console.log(`Total Workers ${numCPUs}`)
// Fork workers
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
});
} else {
const fs = require('fs');
const http = require('http');
const httpProxy = require('http-proxy');
const HyperDHTServer = require('hyperdht');
const b32 = require("hi-base32");
const net = require("net");
let invalid = false;
const tunnels = {};
const agent = new http.Agent({ maxSockets: Number.MAX_VALUE });
const content = fs.readFileSync('404.txt', 'utf8');
const DEBUG = 0; // Set DEBUG to 1 to enable debug mode
const CONINFO = 0; // Set CONINFO to 1 for a smaller breakdown of connections.
const dhtServer = new HyperDHTServer();
const startServer = async () => {
console.log(`Worker ${process.pid} started`);
await dhtServer.ready();
const proxy = httpProxy.createProxyServer({
ws: true,
agent: agent,
timeout: 360000
});
const server = http.createServer(async function (req, res) {
try {
if (DEBUG === 1 || CONINFO === 1) console.log("Incoming HTTP request...");
const split = req.headers.host.split('.');
if (DEBUG === 1) console.log("Request Headers Host Split: ", split);
const publicKey = Buffer.from(b32.decode.asBytes(split[0].toUpperCase()));
if (DEBUG === 1) {
console.log("Public Key Buffer: ", publicKey);
console.log("Length: " + publicKey.length);
}
if (!(publicKey.length >= 32)) {
console.log("Invalid Connection!")
res.writeHead(418, { 'Content-Type': 'text/html' });
res.end(content);
invalid = true
} else {
invalid = false
}
if (invalid == true) return
if (!tunnels[publicKey]) {
if (DEBUG === 1 || CONINFO === 1) console.log("No tunnel found for public key, creating new tunnel...");
const port = await getAvailablePort(); // Get an available port
const server = net.createServer(function (servsock) {
if (DEBUG === 1 || CONINFO === 1) console.log('Incoming Connection, Connecting to:', publicKey.toString('hex'));
if (DEBUG === 1) console.log("Public Key Length: ", publicKey.toString('hex').length);
const socket = dhtServer.connect(publicKey);
const local = servsock;
let open = { local: true, remote: true };
local.on('data', (d) => {
if (DEBUG === 1) console.log("Local Data: ", d);
socket.write(d);
});
socket.on('data', (d) => {
if (DEBUG === 1) console.log("Socket Data: ", d);
local.write(d);
});
const remoteend = (type) => {
if (DEBUG === 1) console.log('Local Connection Ended, Ending Remote Connection');
if (open.remote) socket.end();
open.remote = false;
};
const localend = (type) => {
if (DEBUG === 1) console.log('Remote Connection Ended, Ending Local Connection');
if (open.local) local.end();
open.local = false;
};
local.on('error', remoteend);
local.on('finish', remoteend);
local.on('end', remoteend);
socket.on('finish', localend);
socket.on('error', localend);
socket.on('end', localend);
});
// Check if the port is available
server.listen(port, "127.0.0.1", () => {
if (DEBUG === 1 | CONINFO === 1) console.log(`Tunnel server listening on port ${port}`);
tunnels[publicKey] = port;
if (DEBUG === 1 || CONINFO === 1) console.log("New tunnel created. Public Key:", publicKey, "Port:", port);
proxy.web(req, res, {
target: 'http://127.0.0.1:' + port
}, function (e) {
console.log("Proxy Web Error: ", e);
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end(content);
});
});
return;
} else {
if (DEBUG === 1) console.log('Tunnel exists for public key:', publicKey);
proxy.web(req, res, {
target: 'http://127.0.0.1:' + tunnels[publicKey]
}, function (e) {
console.log("Proxy Web Error: ", e);
res.writeHead(418, { 'Content-Type': 'text/html' });
res.end(content);
});
}
} catch (e) {
console.error("Error Occurred: ", e);
}
});
server.on('upgrade', function (req, socket, head) {
if (DEBUG === 1) console.log('Upgrade Request');
const split = req.headers.host.split('.');
const publicKey = Buffer.from(b32.decode.asBytes(split[0].toUpperCase()));
proxy.ws(req, socket, {
target: 'http://127.0.0.1:' + tunnels[publicKey]
}, function (e) {
console.error("Proxy WS Error: ", e);
socket.end();
});
});
server.listen(8081, () => {
console.log(`Worker ${process.pid} listening on port 8081`);
});
};
startServer().catch(console.error);
async function getAvailablePort() {
let port;
do {
port = 1337 + Math.floor(Math.random() * 1000); // Generate a random port between 1337 and 2336
} while (Object.values(tunnels).includes(port)); // Check if the port is already used
return port;
}
}