0

HTTP proxy to SOCKS5 parent

Free lines JavaScript 1 revisions 102 a year ago a year ago
#!/usr/bin/env node
"use strict";

const http = require('http');
const net = require('net');
const socks = require('socks');
const url = require('url');

const BYPASS_HEADERS = ["connection", "proxy-connection", "transfer-encoding"];

function prepare_headers(headers) {
    for (let key of BYPASS_HEADERS) {
        delete headers[key];
    }
    return headers;
}

function doProxy(sReq, sRes) {
    console.log('Proxied', sReq.url);

    let sUrl = url.parse(sReq.url);
    let cOptions = {
        method   : sReq.method,
        hostname : sUrl.hostname,
        port     : sUrl.port || 80,
        path     : sUrl.path,
        headers  : prepare_headers(sReq.headers),
        agent    : new socks.Agent({
            proxy: {
                ipaddress: process.env.SOCKS_HOST,
                port: process.env.SOCKS_PORT,
	            authentication: {
	            	username: process.env.SOCKS_USER,
	            	password: process.env.SOCKS_PASS,
	            },
                type: 5,
            }}),
    };

    let cReq = http.request(cOptions);
    cReq.on('response', (cRes) => {
        sRes.writeHead(cRes.statusCode, cRes.statusMessage,
                       prepare_headers(cRes.headers));
        cRes.pipe(sRes);
    });
    cReq.on('error', (err) => {
        console.error(err);
        sRes.end();
    });

    sReq.pipe(cReq);
}

function doTunnel(sReq, sSock) {
    console.log('Tunnel', sReq.url);

    let sUrl = url.parse(`http://${sReq.url}/`);
    let dOpts = {
        proxy: {
            ipaddress: process.env.SOCKS_HOST,
            port: process.env.SOCKS_PORT,
            authentication: {
            	username: process.env.SOCKS_USER,
            	password: process.env.SOCKS_PASS,
            },
            type: 5,
        },
        target: {
            host: sUrl.hostname,
            port: sUrl.port || 80,
        },
    };

    socks.createConnection(dOpts, (err, dSock, info) => {
        if (err) {
            console.error(err);
            return sSock.end();
        }

        sSock.write('HTTP/1.1 200 Connection Established\r\n\r\n');
        dSock.pipe(sSock);
        sSock.pipe(dSock);

        sSock.on('close', () => dSock.end());
        dSock.on('close', () => sSock.end());

        dSock.resume();
    });
}

let httpd = http.createServer();
httpd.on('request', doProxy);
httpd.on('connect', doTunnel);
httpd.listen(process.env.PORT);

console.log("Listening on port", process.env.PORT);

An HTTP proxy and relays to a SOCKS5 parent with authentication.

Simply run with node with these Environment Variables:

PORT       // HTTP proxy port
SOCKS_HOST // Parent SOCKS5 host
SOCKS_PORT // Parent SOCKS5 port
SOCKS_USER // Parent SOCKS5 username for auth
SOCKS_PASS // Parent SOCKS5 password for auth

Something like:

PORT=9050 SOCKS_HOST=example.com SOCKS_PORT=1080 node index.js