diff --git a/components/_http.js b/components/_http.js index 8190592..b2db4f9 100644 --- a/components/_http.js +++ b/components/_http.js @@ -18,7 +18,7 @@ function logger (...p) { console.log("[DEBUG.http]:", ...p); } -function fetchProxy (req, res, reverseTo) { +function fetchProxy (server, req, res, reverseTo) { const params = { method: req.method.toUpperCase(), headers: Object.assign({}, req.headers), redirect: "follow", follow: 20, compress: false }; delete params.headers.host; delete params.headers.referer; @@ -26,7 +26,10 @@ function fetchProxy (req, res, reverseTo) { params.body = req.body; const reqAddress = url.resolve(reverseTo, path.join("/", req.originalUrl)); - fetch(reqAddress, params) + server.get("http://expample", res => { + console.log("res:", res); + }); + /*fetch(reqAddress, params) // Deprecated .then(async result => { const content = await result.arrayBuffer(); //logger("result:", result); @@ -49,7 +52,7 @@ function fetchProxy (req, res, reverseTo) { .catch(err => { console.error(err); res.status(500).send(req.st500); - }); + });*/ } function authPage (self, req, res, next) { @@ -206,7 +209,7 @@ module.exports = class HTTPServer extends Component { throw new SyntaxError("You can't call revHTTP domain from unsupported type. Supported types: revHTTP, simpleHTTP, redirectHTTP"); switch (callCommand) { case "proxy": - return fetchProxy(req, res, this.syntax.target); + return fetchProxy(this.server, req, res, this.syntax.target); case "auth": const authContext = context.syntax.auth === undefined ? this : context; return authPage(authContext, req, res, next); diff --git a/components/http-reverse.js b/components/http-reverse.js index 0121f4d..2053bab 100644 --- a/components/http-reverse.js +++ b/components/http-reverse.js @@ -30,7 +30,7 @@ module.exports = class HTTPReverse extends HTTPServer { .callDomain(currentDomain, this.syntax.domains[currentDomain]) .argv(this.syntax.domains[currentDomain].Type.type(), req, res); } - return fetchProxy(req, res, reverseTo); + return fetchProxy(this.server, req, res, reverseTo); }); this.postinit((err) => { diff --git a/components/index.js b/components/index.js index 470847c..d60428a 100644 --- a/components/index.js +++ b/components/index.js @@ -2,4 +2,6 @@ module.exports = { "revHTTP": require("./http-reverse"), "simpleHTTP": require("./http-simple"), "redirectHTTP": require("./http-redirector"), + "TCP": require("./tcp"), + "UDP": require("./udp"), }; diff --git a/components/tcp.js b/components/tcp.js index 2563a11..cc794fe 100644 --- a/components/tcp.js +++ b/components/tcp.js @@ -1,3 +1,118 @@ const Component = require("./_component"); +const net = require('net'); +const fs = require('fs'); -class TCPServer extends Component {} +function logger (...p) { + return; + console.debug("[TCP reverse]:", ...p); +}; + +async function isFirewalled () { // TODO: Firewall + return false; +} + +module.exports = class TCPServer extends Component { + static type () { + return "tcp-proxy"; + } + + constructor (adr, syntaxTree) { + super(adr, syntaxTree); + if (syntaxTree.firewall) { + throw new Error("Firewall doesn't supports"); + } + } + + run () { + this.server = net.createServer(async (srvSocket) => { + const isFrw = await isFirewalled(srvSocket.remoteAddress); + if (isFrw) { + srvSocket.end(); + logger(`${srvSocket.remoteAddress} firewalled, reject`); + } + srvSocket.on("error", (err) => { + logger("Caught server socket error: "); + logger(err.stack); + }); + }); + const connections = {}; + + this.server.on('connection', async (socket) => { + socket.fullAddress = `${socket.remoteAddress}:${socket.remotePort}`; + + //const loggerPromise = loggingIp(`${this.adr.address}:${this.adr.port}`, socket.remoteAddress, new Date()); + const isFrw = await isFirewalled(socket.remoteAddress); + if (isFrw) { + socket.end(); + logger(`${socket.remoteAddress} firewalled, reject`); + //await loggerPromise; + return; + } + else { + //await loggerPromise; + const remote = { + ip: this.syntax.target.split(/:/)[0], + port: this.syntax.target.split(/:/)[1], + }; + connections[socket.fullAddress] = net.createConnection(remote.port, remote.ip); + logger(`${socket.remoteAddress} was been connected, connect to remote created`); + + socket.on('data', (data) => { + logger(`from ${socket.remoteAddress} sended: ${data.length} bytes`); + connections[socket.fullAddress].write(data, function(err) { + if (err) + logger(`error: ${socket.remoteAddress} throwed: ${err.name}`); + // connections[socket.fullAddress].end(); + }); + // connections[socket.fullAddress].end(); + }); + + connections[socket.fullAddress].on('data', (data) => { + logger(`to ${socket.remoteAddress} sended: ${data.length} bytes`); + socket.write(data, function(err) { + if (err) + logger(`error: ${socket.remoteAddress} (remote) throwed: ${err.name}`); + // socket.end(); + }); + // socket.end(); + }); + + connections[socket.fullAddress].on('end', (data) => { + logger(`remote of ${socket.remoteAddress} disconnected`); + socket.end(); + }); + + connections[socket.fullAddress].on('error', (err) => { + logger(`remote of ${socket.remoteAddress} error:`); + logger(err.stack); + socket.end(); + }); + + socket.on('end', () => { + logger(`${socket.remoteAddress} disconnected`); + connections[socket.fullAddress].end(); + connections[socket.fullAddress] = undefined; // Free memory! + }); + + socket.on("error", (err) => { + logger( + `socket.on(${socket.remoteAddress}) error:` + ); + logger(err.stack); + connections[socket.fullAddress].end(); + // socket.end(); + }); + } + }); + + this.server.on('error', (err) => { + logger("Error of server"); + logger(err.stack); + }); + + this.server.listen(this.adr.port, this.adr.address, (err) => { + if (err) throw err; + console.log("TCP reverse proxy connected!"); + }); + } +} diff --git a/components/udp.js b/components/udp.js new file mode 100644 index 0000000..15786f8 --- /dev/null +++ b/components/udp.js @@ -0,0 +1,92 @@ +const Component = require("./_component"); +const dgram = require('node:dgram'); +const fs = require('fs'); + +function logger (...p) { + return; + console.debug("[UDP reverse]:", ...p); +}; + +function isFirewalled () { // TODO: Firewall + return false; +} + +module.exports = class UDPServer extends Component { + static type () { + return "udp-proxy"; + } + + constructor (adr, syntaxTree) { + super(adr, syntaxTree); + if (syntaxTree.firewall) { + throw new Error("Firewall doesn't supports"); + } + } + + run () { + const server = dgram.createSocket('udp4', (srvSocket) => {}); + const connections = {}; + // const connectionsTimeout = {}; + + const remote = { + ip: this.syntax.target.split(/:/)[0], + port: this.syntax.target.split(/:/)[1], + }; + + server.on('error', (err) => { + logger("Caught UDP server socket error: "); + logger(err.stack); + }); + + server.on('connect', (peer) => { + logger("connect event:", peer); + if (!isFirewalled(peer.address)) { + logger(`${peer.address}:${peer.port} connected!`); + connections[`${peer.address}:${peer.port}`] = dgram.createSocket('udp4'); + connections[`${peer.address}:${peer.port}`].on('message', (data, rmt) => { + if (`${rmt.address}:${rmt.port}` === `${remote.ip}:${remote.port}`) { + logger(`to ${peer.address}:${peer.port} sended: ${data.length} bytes`); + server.send(data, peer.port, peer.address, (err) => { + if (err) + logger(`error: ${peer.address}:${peer.port} throwed: ${err.name}`); + }); + } + }); + } + else { + logger(`${peer.address} firewalled, reject`); + } + }); + + server.on('message', (data, peer) => { + logger(`from ${peer.address}:${peer.port} attempt send to ${remote.ip}:${remote.port} ${data.length} bytes`); + if (`${peer.address}:${peer.port}` !== `${remote.ip}:${remote.port}`) { + logger(`from ${peer.address}:${peer.port} sended: ${data.length} bytes to ${remote.ip}:${remote.port}`); + if (connections[`${peer.address}:${peer.port}`] === undefined) { + server.emit("connect", peer); + } + if (connections[`${peer.address}:${peer.port}`] !== undefined) { + connections[`${peer.address}:${peer.port}`].send(data, remote.port, remote.ip, (err) => { + if (err) + logger(`error: ${peer.address} (remote) throwed: ${err.name}`); + }); + } + } + }); + + server.on('listening', () => { + const address = server.address(); + console.log(`UDP reverse proxy server listening on ${address.address}:${address.port}`); + }); + + server.bind(this.adr.port, this.adr.address, (err) => { + if (err) throw err; + console.log("UDP reverse proxy connected!"); + }); + + server.on('error', (err) => { + logger("Error of server"); + logger(err.stack); + }); + } +} diff --git a/routemap-parser.js b/routemap-parser.js index 0d2680a..c5cfbdc 100644 --- a/routemap-parser.js +++ b/routemap-parser.js @@ -126,7 +126,7 @@ function readInstructions (instructions, fullCode, forDomains=false) { } function logger (...p) { - //return; + return; console.debug("[DEBUG.routemap]:", ...p); } diff --git a/routemap.txt b/routemap.txt index 21000f1..2125752 100644 --- a/routemap.txt +++ b/routemap.txt @@ -3,7 +3,7 @@ type revHTTP; target https://example.org; # RRR - querylimit 0; + querylimit 5; domain localhost { firewall whitelist GLOBAL; type revHTTP; @@ -35,3 +35,9 @@ target /; #showdir; } + +127.0.0.1:1111 { + type TCP; + # SSH-Proxy to my device + target 127.0.0.1:22; +}