first commit
This commit is contained in:
commit
c51c98aacd
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
node_modules
|
221
404.txt
Normal file
221
404.txt
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" >
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>My-MC.LINK - Peer Not Found! </title>
|
||||||
|
<link rel="canonical" href="https://codepen.io/ricardpriet/pen/zPqyvY">
|
||||||
|
<style>
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Montserrat:400,600,700');
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Catamaran:400,800');
|
||||||
|
.error-container {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 180px;
|
||||||
|
font-family: 'Catamaran', sans-serif;
|
||||||
|
font-weight: 800;
|
||||||
|
margin: 20px 15px;
|
||||||
|
}
|
||||||
|
.error-container > span {
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 0.7;
|
||||||
|
position: relative;
|
||||||
|
color: #FFB485;
|
||||||
|
}
|
||||||
|
.error-container > span {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.error-container > span:nth-of-type(1) {
|
||||||
|
color: #D1F2A5;
|
||||||
|
animation: colordancing 4s infinite;
|
||||||
|
}
|
||||||
|
.error-container > span:nth-of-type(3) {
|
||||||
|
color: #F56991;
|
||||||
|
animation: colordancing2 4s infinite;
|
||||||
|
}
|
||||||
|
.error-container > span:nth-of-type(2) {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
.error-container > span:nth-of-type(2):before,
|
||||||
|
.error-container > span:nth-of-type(2):after {
|
||||||
|
border-radius: 0%;
|
||||||
|
content:"";
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 0;
|
||||||
|
width: inherit; height: inherit;
|
||||||
|
border-radius: 999px;
|
||||||
|
box-shadow: inset 30px 0 0 rgba(209, 242, 165, 0.4),
|
||||||
|
inset 0 30px 0 rgba(239, 250, 180, 0.4),
|
||||||
|
inset -30px 0 0 rgba(255, 196, 140, 0.4),
|
||||||
|
inset 0 -30px 0 rgba(245, 105, 145, 0.4);
|
||||||
|
animation: shadowsdancing 4s infinite;
|
||||||
|
}
|
||||||
|
.error-container > span:nth-of-type(2):before {
|
||||||
|
-webkit-transform: rotate(45deg);
|
||||||
|
-moz-transform: rotate(45deg);
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen-reader-text {
|
||||||
|
position: absolute;
|
||||||
|
top: -9999em;
|
||||||
|
left: -9999em;
|
||||||
|
}
|
||||||
|
@keyframes shadowsdancing {
|
||||||
|
0% {
|
||||||
|
box-shadow: inset 30px 0 0 rgba(209, 242, 165, 0.4),
|
||||||
|
inset 0 30px 0 rgba(239, 250, 180, 0.4),
|
||||||
|
inset -30px 0 0 rgba(255, 196, 140, 0.4),
|
||||||
|
inset 0 -30px 0 rgba(245, 105, 145, 0.4);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
box-shadow: inset 30px 0 0 rgba(245, 105, 145, 0.4),
|
||||||
|
inset 0 30px 0 rgba(209, 242, 165, 0.4),
|
||||||
|
inset -30px 0 0 rgba(239, 250, 180, 0.4),
|
||||||
|
inset 0 -30px 0 rgba(255, 196, 140, 0.4);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
box-shadow: inset 30px 0 0 rgba(255, 196, 140, 0.4),
|
||||||
|
inset 0 30px 0 rgba(245, 105, 145, 0.4),
|
||||||
|
inset -30px 0 0 rgba(209, 242, 165, 0.4),
|
||||||
|
inset 0 -30px 0 rgba(239, 250, 180, 0.4);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
box-shadow: inset 30px 0 0 rgba(239, 250, 180, 0.4),
|
||||||
|
inset 0 30px 0 rgba(255, 196, 140, 0.4),
|
||||||
|
inset -30px 0 0 rgba(245, 105, 145, 0.4),
|
||||||
|
inset 0 -30px 0 rgba(209, 242, 165, 0.4);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
box-shadow: inset 30px 0 0 rgba(209, 242, 165, 0.4),
|
||||||
|
inset 0 30px 0 rgba(239, 250, 180, 0.4),
|
||||||
|
inset -30px 0 0 rgba(255, 196, 140, 0.4),
|
||||||
|
inset 0 -30px 0 rgba(245, 105, 145, 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes colordancing {
|
||||||
|
0% {
|
||||||
|
color: #D1F2A5;
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
color: #F56991;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
color: #FFC48C;
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
color: #EFFAB4;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
color: #D1F2A5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes colordancing2 {
|
||||||
|
0% {
|
||||||
|
color: #FFC48C;
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
color: #EFFAB4;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
color: #D1F2A5;
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
color: #F56991;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
color: #FFC48C;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* demo stuff */
|
||||||
|
* {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: #416475;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
html, button, input, select, textarea {
|
||||||
|
font-family: 'Montserrat', Helvetica, sans-serif;
|
||||||
|
color: #92a4ad;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
margin: 30px 15px;
|
||||||
|
}
|
||||||
|
.zoom-area {
|
||||||
|
max-width: 550px;
|
||||||
|
margin: 30px auto 30px;
|
||||||
|
font-size: 19px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.link-container {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
a.more-link {
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 13px;
|
||||||
|
background-color: #92a4ad;
|
||||||
|
padding: 10px 15px;
|
||||||
|
border-radius: 0;
|
||||||
|
color: #416475;
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
line-height: 1.5;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-top: 50px;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
window.console = window.console || function(t) {};
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const errorMessages = [
|
||||||
|
"Whoopsie daisy! Our code took a coffee break.",
|
||||||
|
"Houston, we have a problem...with our code.",
|
||||||
|
"Error 404: Sense of Direction Not Found.",
|
||||||
|
"Looks like our code is doing the electric slide...backward.",
|
||||||
|
"Oops! Did someone trip over the server cable again?",
|
||||||
|
"404 Error: Wit Not Found. Please try again later.",
|
||||||
|
"This wasn't in the developer manual!",
|
||||||
|
"Well, that's a funny way to say 'Hello, World!'",
|
||||||
|
"Looks like our code decided to go on a spontaneous vacation.",
|
||||||
|
"Hold on tight, we're experiencing technical turbulence.",
|
||||||
|
"Error 101: Gremlins in the System.",
|
||||||
|
"If at first you don't succeed, call IT support.",
|
||||||
|
"Congratulations! You've found the hidden feature...of bugs.",
|
||||||
|
"Looks like our code got lost in translation.",
|
||||||
|
"Abandon hope, all ye who debug here.",
|
||||||
|
"Error 418: I'm a teapot. But seriously, something's wrong.",
|
||||||
|
"Well, this is awkward...even for code.",
|
||||||
|
"Have you tried turning it off and on again? No, seriously.",
|
||||||
|
"Error 505: Brain.exe has stopped responding.",
|
||||||
|
"Looks like our code took a wrong turn at Albuquerque."];
|
||||||
|
let currentMessageIndex = 0;
|
||||||
|
const errorMessageElement = document.getElementById('error-message');
|
||||||
|
setInterval(() => {
|
||||||
|
currentMessageIndex = (currentMessageIndex + 1) % errorMessages.length;
|
||||||
|
errorMessageElement.textContent = errorMessages[currentMessageIndex];
|
||||||
|
}, 3000); // Change message every 5 seconds
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body translate="no">
|
||||||
|
<h1 id="error-message">Look's like we did not get that quite right... </h1>
|
||||||
|
<p class="zoom-area"><b>Routing Error: Invalid hash or connection timeout.</b><BR>Please reset your link and try again. </p>
|
||||||
|
<section class="error-container">
|
||||||
|
<span>4</span>
|
||||||
|
<span><span class="screen-reader-text">0</span></span>
|
||||||
|
<span>4</span>
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</html>
|
132
README.md
Normal file
132
README.md
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
|
||||||
|
# hyperMC-Web-Relay
|
||||||
|
|
||||||
|
This relays Hyper Relay connection hashes over wildcard DNS and wildcard virtualhost reverse proxy to allow for automatic URLs via connection topics.
|
||||||
|
|
||||||
|
Set up instructions:
|
||||||
|
|
||||||
|
This will require a server listening to a connection topic using our version of hyper-relay:
|
||||||
|
|
||||||
|
|
||||||
|
https://git.ssh.surf/hypermc/hyper-relay
|
||||||
|
|
||||||
|
`git clone git@git.ssh.surf:hypermc/hyper-relay.git`
|
||||||
|
|
||||||
|
`cd hyper-relay`
|
||||||
|
|
||||||
|
`npm i`
|
||||||
|
|
||||||
|
Now listen to a TCP port over the Hyper Network:
|
||||||
|
```
|
||||||
|
root@server:/hyper-relay# node server.js 80 hellothere
|
||||||
|
w7zpwusw6ljrgbffxtklak23rkhaxwhs2kskozteme6ofefevlia
|
||||||
|
```
|
||||||
|
|
||||||
|
The result above shows the connection hash for your hyper port.
|
||||||
|
|
||||||
|
This will be the hash used as your subdomain later in this process.
|
||||||
|
|
||||||
|
NOTE: The "hellothere" above is the connection "topic" this is used to generate the hash and it can be any string or key phrase you wish.
|
||||||
|
|
||||||
|
|
||||||
|
# The Reverse proxy
|
||||||
|
|
||||||
|
We will proxy all of the traffic to their specific peers using a reverse proxy method, in this example, we will utilize httpd/apache below you will find the standard configuration that will work for our purposes.
|
||||||
|
|
||||||
|
```
|
||||||
|
<VirtualHost *:443>
|
||||||
|
SSLProxyEngine On
|
||||||
|
ServerAlias *.your-tld.here
|
||||||
|
ServerAdmin webmaster@your-tld.here
|
||||||
|
DocumentRoot /var/www/html
|
||||||
|
|
||||||
|
ErrorLog /var/log/error.log
|
||||||
|
CustomLog /var/log/access.log combined
|
||||||
|
|
||||||
|
SSLCertificateFile /path/to/fullchain.pem
|
||||||
|
SSLCertificateKeyFile /path/to/privkey.pem
|
||||||
|
|
||||||
|
# Reverse Proxy for subdomains
|
||||||
|
<Proxy *>
|
||||||
|
Require all granted
|
||||||
|
</Proxy>
|
||||||
|
|
||||||
|
ProxyPreserveHost On
|
||||||
|
RequestHeader set X-Forwarded-Proto https
|
||||||
|
ProxyPass "/" "http://localhost:8081/"
|
||||||
|
ProxyPassReverse "/" "http://localhost:8081/"
|
||||||
|
</VirtualHost>
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTE 1: This requires `mod_proxy` and `mod_ssl` to work properly.
|
||||||
|
|
||||||
|
NOTE 2: This requires the full use of the wildcard *.your-told.here you will not be able to use any subdomain within this scope unless it runs via a hyper-relay.
|
||||||
|
|
||||||
|
We highly reccomend using SSL only for this reverse connection, however, you may configure your proxy pass as desired.
|
||||||
|
|
||||||
|
# Wildcard DNS Entry
|
||||||
|
|
||||||
|
In order to serve your subdomain hashes without the need to generate an A record create a wildcard subdomain record.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
`*.example.com. IN A 192.0.2.1`
|
||||||
|
|
||||||
|
This system does work well with cloudflare proxy, feel free to proxy your traffic!
|
||||||
|
|
||||||
|
# Running the Web Relay ServerAdmin
|
||||||
|
|
||||||
|
`git clone git@git.ssh.surf:hypermc/hyperMC-Web-Relay.git`
|
||||||
|
|
||||||
|
`cd hyperMC-Web-Relay`
|
||||||
|
|
||||||
|
`npm i`
|
||||||
|
|
||||||
|
There are two servers provided within this repo.
|
||||||
|
|
||||||
|
One will work without the use of workers, and it can work well for static content sites.
|
||||||
|
|
||||||
|
To deploy this server, run `node non-worker-server.js`
|
||||||
|
|
||||||
|
The relay will begin listening on port 8081, this port may be changed in the script.
|
||||||
|
```
|
||||||
|
[root@server hyperMC-Web-Relay]# node fullyworking_proxy.js
|
||||||
|
Creating HyperDHT server...
|
||||||
|
HyperDHT server created and ready.
|
||||||
|
HTTP server listening on port 8081
|
||||||
|
```
|
||||||
|
|
||||||
|
To deploy a multi worker server, run `node worker-server.js`
|
||||||
|
|
||||||
|
The server will start workers based off your CPU count and then start those workers listening for connections:
|
||||||
|
|
||||||
|
```
|
||||||
|
[root@server hyper-web-relay]# node worker-server.js
|
||||||
|
Master 703855 is running
|
||||||
|
Total Workers 4
|
||||||
|
Worker 703885 started
|
||||||
|
Worker 703878 started
|
||||||
|
Worker 703904 started
|
||||||
|
Worker 703929 started
|
||||||
|
Worker 703878 listening on port 8081
|
||||||
|
Worker 703965 listening on port 8081
|
||||||
|
Worker 704044 listening on port 8081
|
||||||
|
Worker 703885 listening on port 8081
|
||||||
|
```
|
||||||
|
|
||||||
|
You now can make a request from a hyper-relay connection hash:
|
||||||
|
|
||||||
|
```
|
||||||
|
~ ❯ curl -IL https://w7zpwusw6ljrgbffxtklak23rkhaxwhs2kskozteme6ofefevlia.your-tld.here/
|
||||||
|
HTTP/2 200
|
||||||
|
date: Fri, 29 Mar 2024 06:39:38 GMT
|
||||||
|
content-type: text/html; charset=UTF-8
|
||||||
|
last-modified: Tue, 19 Mar 2024 05:07:41 GMT
|
||||||
|
vary: Accept-Encoding
|
||||||
|
cf-cache-status: DYNAMIC
|
||||||
|
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=mGhuDrFp%2B2lMm9iQ45CshdOmN7Sbf%2Fs1dgWKD3PtcISbcBi6uB4YZIG2qTTmfRpL1C1f3vqF01IFERjjpDspEuQ98dRfgQpelyODFjd99aeUY5uGQcPxQoAusjb%2BBxwRWkI6ZQE0EPKy4m%2BeGbY0%2FGLVndHc%2F52vEvvAIIhzR%2FqMIweFqgyAwGAaELc7sUIDayE%3D"}],"group":"cf-nel","max_age":604800}
|
||||||
|
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
|
||||||
|
server: cloudflare
|
||||||
|
cf-ray: 86bddd2349cf8bbb-ATL
|
||||||
|
alt-svc: h3=":443"; ma=86400
|
||||||
|
```
|
141
non-worker-server.js
Normal file
141
non-worker-server.js
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const http = require('http');
|
||||||
|
const httpProxy = require('http-proxy');
|
||||||
|
const HyperDHTServer = require('hyperdht');
|
||||||
|
const libNet = require('hyper-cmd-lib-net');
|
||||||
|
const goodbye = require('graceful-goodbye');
|
||||||
|
const libKeys = require('hyper-cmd-lib-keys');
|
||||||
|
const b32 = require("hi-base32");
|
||||||
|
const net = require("net");
|
||||||
|
const pump = require("pump");
|
||||||
|
let invalid = false;
|
||||||
|
|
||||||
|
let mod = 0;
|
||||||
|
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
|
||||||
|
// Enabling DEBUG mode will slow down the code, please only enable this if you need
|
||||||
|
// Information about connections coming in because you need to validate connection hashes.
|
||||||
|
|
||||||
|
const startServer = async () => {
|
||||||
|
console.log("Creating HyperDHT server...");
|
||||||
|
const dhtServer = new HyperDHTServer();
|
||||||
|
await dhtServer.ready();
|
||||||
|
console.log("HyperDHT server created and ready.");
|
||||||
|
|
||||||
|
const proxy = httpProxy.createProxyServer({
|
||||||
|
ws: true,
|
||||||
|
agent: agent,
|
||||||
|
timeout: 360000
|
||||||
|
});
|
||||||
|
|
||||||
|
const server = http.createServer(async function (req, res) {
|
||||||
|
try {
|
||||||
|
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(404, { 'Content-Type': 'text/html' });
|
||||||
|
res.end(content);
|
||||||
|
invalid = true
|
||||||
|
} else {
|
||||||
|
invalid = false
|
||||||
|
}
|
||||||
|
if (invalid == true) return
|
||||||
|
if (!tunnels[publicKey]) {
|
||||||
|
console.log("No tunnel found for public key, creating new tunnel...");
|
||||||
|
const port = 1337 + ((mod++) % 1000);
|
||||||
|
const server = net.createServer(function (servsock) {
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(port, "127.0.0.1");
|
||||||
|
tunnels[publicKey] = port;
|
||||||
|
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 {
|
||||||
|
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(404, { 'Content-Type': 'text/html' });
|
||||||
|
res.end(content);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error Occurred: ", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on('upgrade', function (req, socket, head) {
|
||||||
|
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("HTTP server listening on port 8081");
|
||||||
|
|
||||||
|
process.on('SIGINT', function () {
|
||||||
|
console.log("Shutting down...");
|
||||||
|
server.close();
|
||||||
|
dhtServer.destroy();
|
||||||
|
console.log("Shutdown complete.");
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
startServer().catch(console.error);
|
24
package.json
Normal file
24
package.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "raven",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "proxy.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@hyperswarm/dht": "^6.5.1",
|
||||||
|
"bun": "^1.0.35",
|
||||||
|
"graceful-goodbye": "^1.3.0",
|
||||||
|
"hi-base32": "^0.5.1",
|
||||||
|
"http": "^0.0.1-security",
|
||||||
|
"http-proxy": "^1.18.1",
|
||||||
|
"http2-proxy": "^5.0.53",
|
||||||
|
"hyper-cmd-lib-keys": "^0.1.0",
|
||||||
|
"hyper-cmd-lib-net": "^0.1.0",
|
||||||
|
"hyperdht": "^6.13.1",
|
||||||
|
"pump": "^3.0.0"
|
||||||
|
}
|
||||||
|
}
|
35
relay.js
Normal file
35
relay.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
const DHT = require("@hyperswarm/dht");
|
||||||
|
const net = require("net");
|
||||||
|
const pump = require("pump");
|
||||||
|
const node = new DHT({});
|
||||||
|
module.exports = () => {
|
||||||
|
return {
|
||||||
|
serve: (keyPair, host, port) => {
|
||||||
|
const server = node.createServer();
|
||||||
|
server.on("connection", function (servsock) {
|
||||||
|
const socket = net.connect(port, host);
|
||||||
|
socket.on('serve error', console.error);
|
||||||
|
let open = { servsock: true, remote: true };
|
||||||
|
servsock.on('data', (d) => { socket.write(d) });
|
||||||
|
socket.on('data', (d) => { servsock.write(d) });
|
||||||
|
|
||||||
|
const remoteend = () => {
|
||||||
|
if (open.remote) socket.end();
|
||||||
|
open.remote = false;
|
||||||
|
}
|
||||||
|
const servsockend = () => {
|
||||||
|
if (open.servsock) servsock.end();
|
||||||
|
open.servsock = false;
|
||||||
|
}
|
||||||
|
servsock.on('error', remoteend)
|
||||||
|
servsock.on('finish', remoteend)
|
||||||
|
servsock.on('end', remoteend)
|
||||||
|
socket.on('finish', servsockend)
|
||||||
|
socket.on('error', servsockend)
|
||||||
|
socket.on('end', servsockend)
|
||||||
|
});
|
||||||
|
server.listen(keyPair);
|
||||||
|
return keyPair.publicKey;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
34
server.js
Normal file
34
server.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
const net = require('net');
|
||||||
|
const b32 = require("hi-base32");
|
||||||
|
const DHT = require("@hyperswarm/dht");
|
||||||
|
const node = new DHT({});
|
||||||
|
const pump = require("pump");
|
||||||
|
const { pipeline } = require('stream');
|
||||||
|
const server = net.createServer(clientSocket => {
|
||||||
|
clientSocket.on('end', () => {
|
||||||
|
console.log('Client disconnected');
|
||||||
|
});
|
||||||
|
|
||||||
|
clientSocket.on('error', err => {
|
||||||
|
console.error('Client socket error:', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
clientSocket.once("data",(firstData) => {
|
||||||
|
const firstLine = firstData.toString()
|
||||||
|
if (firstLine !== '') {
|
||||||
|
console.log(firstLine)
|
||||||
|
const [hostname] = firstLine.split("\n").filter(a=>a.toLowerCase().startsWith('host:'));
|
||||||
|
const split = hostname.split(":")[1].trim().split('.');
|
||||||
|
console.log(split);
|
||||||
|
const publicKey = Buffer.from(b32.decode.asBytes(split[0].toUpperCase()), 'hex');
|
||||||
|
console.log(publicKey.toString('hex'))
|
||||||
|
const socket = node.connect(publicKey);
|
||||||
|
socket.on('client error', console.error);
|
||||||
|
pump(socket,clientSocket,socket)
|
||||||
|
socket.write(firstLine);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
server.listen(8081, () => {
|
||||||
|
console.log('Proxy server listening');
|
||||||
|
});
|
154
worker-server.js
Normal file
154
worker-server.js
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user