155 lines
6.6 KiB
JavaScript
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*8}`)
|
||
|
// 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.new', '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;
|
||
|
}
|
||
|
}
|