Skip to content

Instantly share code, notes, and snippets.

@CyprienRicque
Last active August 12, 2024 13:33
Show Gist options
  • Save CyprienRicque/3f7398e5063520c0cb728401167e1ef6 to your computer and use it in GitHub Desktop.
Save CyprienRicque/3f7398e5063520c0cb728401167e1ef6 to your computer and use it in GitHub Desktop.
Forwards http requests from server to local proxy

Setup

Local

mkdir proxy
cd proxy
# Copy the proxy.js file

npm install http net http-proxy readline-sync ucipass-logger --save
node proxy.js

-> Proxy is running on port 3128

Forward connection to on server 8080 to the local proxy using ssh

ssh -R 8080:localhost:3128 username@host -N -f

Server

export https_proxy=http://127.0.0.1:8080
export http_proxy=http://127.0.0.1:8080
// Tip of the hat to: https://stackoverflow.com/questions/8165570/https-proxy-server-in-node-js/49864522#49864522
const http = require("http");
const net = require('net');
const httpProxy = require("http-proxy");
const readlineSync = require('readline-sync');
const log = require("ucipass-logger")("proxy")
log.transports.console.level = process.env.LOG_LEVEL ? process.env.LOG_LEVEL :'info'
const PROXY_PORT = 3128
class Proxy{
constructor(PROXY_PORT){
this.port = PROXY_PORT ? PROXY_PORT : process.env.PROXY_PORT ? process.env.PROXY_PORT : 3128
this.server = null
this.proxy = null
this.sockets = {}
this.nextSocketId = 0
}
async start(){
log.debug(`Proxy server starting on port ${this.port}`)
this.server = http.createServer( (req, res)=> {
let urlObj = new URL(req.url)
// var target = urlObj.protocol + "//" + urlObj.host;
log.info("HTTP request for:", urlObj.hostname);
// log.info("HTTP request for:", urlObj);
this.proxy = httpProxy.createProxyServer({ws: true});
this.proxy.on("error", (err, req, res)=> {
log.info("proxy error", err);
res.end();
});
this.proxy.web(req, res, {target: urlObj.origin});
})
this.server.on('connection', (socket)=> {
// Add a newly connected socket
var socketId = this.nextSocketId++;
this.sockets[socketId] = socket;
log.debug('socket', socketId, 'opened');
// Remove the socket when it closes
socket.on('close', ()=> {
log.debug('socket', socketId, 'closed');
delete this.sockets[socketId];
});
});
var regex_hostport = /^([^:]+)(:([0-9]+))?$/;
var getHostPortFromString = (hostString, defaultPort)=> {
var host = hostString;
var port = defaultPort;
var result = regex_hostport.exec(hostString);
if (result != null) {
host = result[1];
if (result[2] != null) {
port = result[3];
}
}
return ( [host, port] );
};
this.server.addListener('connect', (req, socket, bodyhead)=> {
var socketId = this.nextSocketId++;
var hostPort = getHostPortFromString(req.url, 443);
var hostDomain = hostPort[0];
var port = parseInt(hostPort[1]);
log.info("HTTPS request for:", hostDomain, port);
var proxySocket = new net.Socket();
log.debug("psocket",socketId)
this.sockets[socketId] = proxySocket;
proxySocket.connect(port, hostDomain, function () {
proxySocket.write(bodyhead);
socket.write("HTTP/" + req.httpVersion + " 200 Connection established\r\n\r\n");
}
);
proxySocket.on('data', function (chunk) {
socket.write(chunk);
});
proxySocket.on('close', ()=> {
delete this.sockets[socketId];
});
proxySocket.on('end', function () {
socket.end();
});
proxySocket.on('error', function () {
socket.write("HTTP/" + req.httpVersion + " 500 Connection error\r\n\r\n");
socket.end();
});
socket.on('data', function (chunk) {
proxySocket.write(chunk);
});
socket.on('end', function () {
proxySocket.end();
});
socket.on('error', function () {
proxySocket.end();
});
});
return new Promise((resolve, reject) => {
this.server.once('error', function (error) {
reject(error)
});
this.server.listen(this.port,(error)=>{
resolve(this)
});
});
}
async stop(){
// Destroy all open sockets
for (var socketId in this.sockets) {
// log.debug('socket', socketId, 'destroyed!!!!!!');
this.sockets[socketId].destroy();
}
return new Promise((resolve, reject) => {
this.server.close( ()=> {
log.debug("proxy closed!")
resolve(true)
});
});
}
}
const proxy = (proxyPort)=>{ return (new Proxy(proxyPort)).start()}
module.exports = proxy
if (require.main === module) {
let PROXY_PORT = process.env.PROXY_PORT ? process.env.PROXY_PORT : readlineSync.question(`Enter PROXY_PORT [3128]: `);
proxy(PROXY_PORT)
.then ( server => log.info (`Proxy server started on port ${PROXY_PORT}`))
.catch( error => log.error(`Proxy start failure: ${error.message}`))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment