add multidomain support

This commit is contained in:
FullGreaM 2025-01-10 17:20:20 +03:00
parent 30c155f831
commit 57e8cd39df
5 changed files with 121 additions and 75 deletions

View File

@ -1,3 +1,8 @@
module.exports = class Component { module.exports = class Component {
constructor () {} constructor (address, syntaxTree) {
this.adr = address;
this.syntax = syntaxTree;
}
run () {}
}; };

View File

@ -1,5 +1,78 @@
const Component = require("./_component"); const Component = require("./_component");
const express = require("express");
const bodyParser = require("body-parser");
const bodyHand = require('body');
const url = require('url');
const path = require('path');
const fetch = require('node-fetch');
function logger (...p) {
return;
console.log("[DEBUG.main]:", ...p);
}
module.exports = class HTTPReverse extends Component { module.exports = class HTTPReverse extends Component {
constructor () { super(); } constructor (adr, syntaxTree) {
super(adr, syntaxTree);
}
run () {
this.app = express();
const address = this.adr.address ?? "127.0.0.1";
const reverseTo = this.syntax.target ?? "https://example.org";
this.app.use('/*', async (req, res, next) => { // Myself body parser :)
bodyHand(req, res, {
limit: 9999999999,
cache: false,
encoding: 'base64'
}, (err, body) => {
if (!err) {
req.body = Buffer.from(body, 'base64');
} else {
req.body = undefined;
}
next();
});
});
this.app.use("*", async (req, res) => {
logger("REQ HEADERS:>", req.headers);
logger("originalUrl:>", req.originalUrl);
const currentDomain = req.hostname;
const params = { method: req.method.toUpperCase(), headers: Object.assign({}, req.headers), redirect: "follow", follow: 20 };
delete params.headers.host;
delete params.headers.referer;
if (!["GET", "HEAD"].includes(params.method))
params.body = req.body;
logger("hostname:", currentDomain);
const reverseToLoc = !this.syntax.domains[currentDomain] ? reverseTo : this.syntax.domains[currentDomain].target;
const reqAddress = url.resolve(reverseToLoc, path.join("/", req.originalUrl));
fetch(reqAddress, params)
.then(async result => {
const content = await result.text();
logger("result:", result);
logger("result.text():", content);
Object.entries(result?.headers ? result.headers : new Object()).forEach(([header, value]) => {
res.set(header, value);
});
res.status(result.status).send(content);
})
.catch(err => {
console.error(err);
res.status(500).send("<head><title>Error</title></head><body><h1>Error:</h1><hr/><p>Error catched. Check logs</p></body>");
});
});
this.app.listen(this.adr.port, address, (err) => {
if (err) {
throw err;
}
console.log(`Koboldcpp reverse proxy server listened at ${
address
}:${this.adr.port}`);
})
}
}; };

View File

@ -5,17 +5,23 @@ const components = require("./components");
// General regexps // General regexps
// const FIND_ADDRESS_INSTR_REGEX = /([0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]{1,5}\s{0,}\{[\s\n\r0-9a-z;:\/\."',]{0,}\}/gmi; // const FIND_ADDRESS_INSTR_REGEX = /([0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]{1,5}\s{0,}\{[\s\n\r0-9a-z;:\/\."',]{0,}\}/gmi;
const DOMAINER_REGEX = /domain\s{1,}[a-z0-9\.]{1,}\s{1,}\{[\s\n\r0-9a-z;:\/\."',]{0,}\}/gmi; const DOMAINER_REGEX = /domain\s{1,}[a-z0-9\.]{1,}\s{1,}\{[\s\n\r0-9a-z;:\/\."',]{0,}\}/gmi;
const DOMAINER_VALUE_FIND_REGEX = /domain\s{1,}[a-z0-9\.]{1,}\s{1,}\{/gmi;
const ADDRESS_WITH_PORT_REGEX = /([0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]{1,5}/gmi const ADDRESS_WITH_PORT_REGEX = /([0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]{1,5}/gmi
const FIND_ADDRESS_INSTR_REGEX = /([0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]{1,5}\s{0,}\{([\s\n\r0-9a-z;:\/\."',]|domain\s{1,}[a-z0-9\.]{1,}\s{1,}\{[\s\n\r0-9a-z;:\/\."',]{0,}\}){0,}\}/gmi; const FIND_ADDRESS_INSTR_REGEX = /([0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]{1,5}\s{0,}\{([\s\n\r0-9a-z;:\/\."',]|domain\s{1,}[a-z0-9\.]{1,}\s{1,}\{[\s\n\r0-9a-z;:\/\."',]{0,}\}){0,}\}/gmi;
const COMMENT_REGEX = /#.{0,}(\n|\r|$)/gmi; const COMMENT_REGEX = /#.{0,}(\n|\r|$)/gmi;
const CONTENT_INTO_CURLY_BRACES = /\{[\s\n\r0-9a-z;:\/\."',]{0,}\}{0,}\}/gmi;
// Instruction regexps // Instruction regexps
function readInstructions (instructions, fullCode) { function readInstructions (instructions, fullCode, forDomains=false) {
const syntaxTree = { domains: {}, firewall: false }; const syntaxTree = { firewall: false };
for (let instruction of instructions) { for (let instruction of instructions) {
if (!instruction) if (!instruction) {
break; if (instructions.indexOf(instruction) === instructions.length - 1) {
break;
}
throw new SyntaxError("Invalid syntax: `;;`");
}
const instructionParts = instruction.split(/\s{1,}/); const instructionParts = instruction.split(/\s{1,}/);
const mainOperator = instructionParts[0]; const mainOperator = instructionParts[0];
switch (mainOperator) { switch (mainOperator) {
@ -32,13 +38,29 @@ function readInstructions (instructions, fullCode) {
throw new SyntaxError("Invalid syntax of operator `target`: target <connection_target>"); throw new SyntaxError("Invalid syntax of operator `target`: target <connection_target>");
syntaxTree.target = instructionParts[1]; syntaxTree.target = instructionParts[1];
break; break;
case "cert":
break;
case "firewall":
break;
case "#instuction:domain": case "#instuction:domain":
if (forDomains)
throw new SyntaxError("Nested use of domains doesn't not supported");
break; break;
default: default:
throw new SyntaxError(`Unknown routemap's operator: ${mainOperator}`); throw new SyntaxError(`Unknown routemap's operator: ${mainOperator}`);
} }
} }
if (!forDomains) {
syntaxTree.domains = new Object();
const allDomains = Object.fromEntries((fullCode.match(DOMAINER_REGEX) ?? [])
.map(x => [x.match(DOMAINER_VALUE_FIND_REGEX)[0].split(/\s{1,}/gmi)[1], x.match(CONTENT_INTO_CURLY_BRACES)[0].slice(1, -1).split(/\s{0,};\s{0,}/g).map(x => x.trim())]));
for (let domain in allDomains) {
syntaxTree.domains[domain] = readInstructions(allDomains[domain], "", true);
}
}
return syntaxTree; return syntaxTree;
} }
@ -68,4 +90,5 @@ module.exports.parse = function () {
syntaxTree[itemAdrInst.match(ADDRESS_WITH_PORT_REGEX)[0]] = localSyntaxTree; syntaxTree[itemAdrInst.match(ADDRESS_WITH_PORT_REGEX)[0]] = localSyntaxTree;
} }
logger("Full syntax tree:", syntaxTree); logger("Full syntax tree:", syntaxTree);
return syntaxTree;
} }

View File

@ -1,11 +1,17 @@
127.0.0.1:9889 { 127.0.0.1:9889 {
type revHTTP; type revHTTP;
target https://example.org; # RRR target https://example.org; # RRR
domain localhost { domain localhost {
firewall whitelist GLOBAL; firewall whitelist GLOBAL;
type revHTTP; type revHTTP;
target https://github.org; target https://github.com;
}; };
} }
127.0.0.1:7889 {} 127.0.0.1:7889 {
type revHTTP;
target https://google.com;
cert public /path/to/cert.pub;
cert private /path/to/cert.priv;
}

View File

@ -1,72 +1,11 @@
'use strict'; 'use strict';
const express = require("express");
const bodyParser = require("body-parser");
const bodyHand = require('body');
const url = require('url');
const path = require('path');
const fetch = require('node-fetch');
global.config = require("./config.json");
const rtmap = require("./routemap-parser"); const rtmap = require("./routemap-parser");
const syntaxTree = rtmap.parse();
const app = express(); for (let faddress in syntaxTree) {
const [address, port] = faddress.split(/:/gmi);
const address = global.config.net.address ?? "127.0.0.1"; const localSyntaxTree = syntaxTree[faddress];
const reverseTo = global.config.target ?? "https://example.org"; const instance = new localSyntaxTree.Type({ address, port }, localSyntaxTree);
instance.run();
function logger (...p) {
return;
console.log("[DEBUG.main]:", ...p);
} }
app.use('/*', async (req, res, next) => { // Myself body parser :)
bodyHand(req, res, {
limit: 9999999999,
cache: false,
encoding: 'base64'
}, (err, body) => {
if (!err) {
req.body = Buffer.from(body, 'base64');
} else {
req.body = undefined;
}
next();
});
});
app.use("*", async (req, res) => {
logger("REQ HEADERS:>", req.headers);
logger("originalUrl:>", req.originalUrl);
const params = { method: req.method.toUpperCase(), headers: req.headers, redirect: "follow", follow: 20 };
delete params.headers.host;
delete params.headers.referer;
if (!["GET", "HEAD"].includes(params.method))
params.body = req.body;
const reqAddress = url.resolve(reverseTo, path.join("/", req.originalUrl));
fetch(reverseTo, params)
.then(async result => {
const content = await result.text();
logger("result:", result);
logger("result.text():", content);
Object.entries(result?.headers ? result.headers : new Object()).forEach(([header, value]) => {
res.set(header, value);
});
res.status(result.status).send(content);
})
.catch(err => {
console.error(err);
res.status(500).send("<head><title>Error</title></head><body><h1>Error:</h1><hr/><p>Error catched. Check logs</p></body>");
});
});
rtmap.parse();
app.listen(global.config.net.port, address, (err) => {
if (err) {
throw err;
}
console.log(`Koboldcpp reverse proxy server listened at ${
address
}:${global.config.net.port}`);
})