add multidomain support
This commit is contained in:
parent
30c155f831
commit
57e8cd39df
@ -1,3 +1,8 @@
|
|||||||
module.exports = class Component {
|
module.exports = class Component {
|
||||||
constructor () {}
|
constructor (address, syntaxTree) {
|
||||||
|
this.adr = address;
|
||||||
|
this.syntax = syntaxTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
run () {}
|
||||||
};
|
};
|
||||||
|
@ -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}`);
|
||||||
|
})
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
10
routemap.txt
10
routemap.txt
@ -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;
|
||||||
|
}
|
||||||
|
73
server.js
73
server.js
@ -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}`);
|
|
||||||
})
|
|
||||||
|
Loading…
Reference in New Issue
Block a user