sjitech / proxy-login-automator

A single node.js script to automatically inject user/password to http proxy server via a local forwarder

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ECONNRESET

ModeMan12345 opened this issue · comments

Hello, I'm trying to use this with firefox.
I started it with proxy but i keep getting this error:

[LocalProxy(:44626)][Incoming connection] Error: read ECONNRESET

image

This is preventing some https pages to not load. am i doing anything wrong?

npm version 5.7.1
node version 8.8.1

when i added

-ignore_https_cert true

i get ended by remote peer.. i'm not sure but is this the same issue as #9 ?

i'm still looking if there's a solution. thanks!

commented

thanks for you feedback! Can you show me ???? in the log:

OK: forward http://.... to ?????

I just want to know ???? is http or https.

commented

ignore_https_cert is just used when your real proxy server itself is using https to talk to proxy client, otherwise, it should be no effect.

This is completely not concerned with your https communication from browser to outside web server.

I am thinking if following code has an unexpected result:

    var realCon = (is_remote_https ? tls : net).connect({
      port: remote_port, host: remote_host, allowHalfOpen: true,
      rejectUnauthorized: !ignore_https_cert /*not used when is_remote_https false*/
    });

Your is_remote_https is false, so the rejectUnauthorized should have no effect, but somehow, it affect your real https! Weird.

thanks for the fast response, it's http. screenshot:

image

PS: i tried using the proxy in the browser and it's working, but i need to use it in your script.

Thanks!

commented

can you replace proxy-login-automator.js with following contents and test?

#!/usr/bin/env node
'use strict';
var net = require('net'), tls = require('tls');
var HTTPParser = process.binding('http_parser').HTTPParser;
var http = require('http'), https = require('https');
var url = require('url');

function main() {
  //convert `-key value` to cfg[key]=value
  var cfg = process.argv.slice(2/*skip ["node", "xxx.js"]*/).reduce(function (cfg, arg, i, argv) {
    return (i % 2 === 0 && (arg.slice(0, 1) === '-' && (cfg[arg.slice(1)] = argv[i + 1])), cfg);
  }, {local_host: '', local_port: 0, remote_host: '', remote_port: 0, usr: '', pwd: '', as_pac_server: 0});
  cfg.local_host = cfg.local_host || 'localhost';
  cfg.local_port = (cfg.local_port & 0xffff) || 8080;
  cfg.remote_port = (cfg.remote_port & 0xffff) || 8080;
  cfg.as_pac_server = cfg.as_pac_server === 'true';
  cfg.is_remote_https = cfg.is_remote_https === 'true';
  cfg.ignore_https_cert = cfg.ignore_https_cert === 'true';
  cfg.are_remotes_in_pac_https = cfg.are_remotes_in_pac_https === 'true';

  if (!cfg.local_host || !cfg.local_port || !cfg.remote_host || !cfg.remote_port || !cfg.usr || !cfg.pwd)
    return console.error('Usage of parameters:\n'
      + '-local_host host\t' + 'Listening address. Default: localhost. (* means all interfaces)\n'
      + '-local_port port\t' + 'Listening port. Default: 8080\n'
      + '-remote_host host\t' + 'Real proxy/PAC server address\n'
      + '-remote_port port\t' + 'Real proxy/PAC server port. Default: 8080\n'
      + '-usr user\t\t' + 'Real proxy/PAC server user id\n'
      + '-pwd password\t\t' + 'Real proxy/PAC user password\n'
      + '-as_pac_server true/false\t' + 'Treat real proxy/PAC server as a PAC server. Default: false\n'
      + '\n'
      + '-is_remote_https true/false\t' + 'Talk to real proxy/PAC server with HTTPS. Default: false\n'
      + '-ignore_https_cert true/false\t' + 'ignore error when verify real proxy/PAC server. Default: false\n'
      + '-are_remotes_in_pac_https true/false\t' + 'Talk to proxy servers defined in PAC with HTTPS. Default: false\n'
    );
  if (cfg.as_pac_server && (cfg.local_host === '*' || cfg.local_host === '0.0.0.0' || cfg.local_host === '::')) {
    return console.error('when use as a PAC server, the local_host parameter must be a definite address');
  }
  console.log('Using parameters: ' + JSON.stringify(cfg, null, '  '));
  cfg.buf_proxy_basic_auth = new Buffer('Proxy-Authorization: Basic ' + new Buffer(cfg.usr + ':' + cfg.pwd).toString('base64'));

  if (cfg.as_pac_server) {
    createPacServer(cfg.local_host, cfg.local_port, cfg.remote_host, cfg.remote_port, cfg.buf_proxy_basic_auth, cfg.is_remote_https, cfg.ignore_https_cert, cfg.are_remotes_in_pac_https);
  } else {
    createPortForwarder(cfg.local_host, cfg.local_port, cfg.remote_host, cfg.remote_port, cfg.buf_proxy_basic_auth, cfg.is_remote_https, cfg.ignore_https_cert);
  }
}

var CR = 0xd, LF = 0xa, BUF_CR = new Buffer([0xd]), BUF_CR_LF_CR_LF = new Buffer([0xd, 0xa, 0xd, 0xa]), BUF_LF_LF = new Buffer([0xa, 0xa]);
var STATE_NONE = 0, STATE_FOUND_LF = 1, STATE_FOUND_LF_CR = 2;

function createPortForwarder(local_host, local_port, remote_host, remote_port, buf_proxy_basic_auth, is_remote_https, ignore_https_cert) {
  net.createServer({allowHalfOpen: true}, function (socket) {
    var realCon = is_remote_https ? tls.connect({
      port: remote_port, host: remote_host, allowHalfOpen: true,
      rejectUnauthorized: !ignore_https_cert
    }) : net.connect({
      port: remote_port, host: remote_host, allowHalfOpen: true
    });
    realCon.on('data', function (buf) {
      //console.log('<<<<' + (Date.t=new Date()) + '.' + Date.t.getMilliseconds() + '\n' + buf.toString('ascii'));
      socket.write(buf);
      realCon.__haveGotData = true;
    }).on('end', function () {
      socket.end();
      if (!realCon.__haveGotData && !realCon.__haveShownError) {
        console.error('[LocalProxy(:' + local_port + ')][Connection to ' + remote_host + ':' + remote_port + '] Error: ended by remote peer');
        realCon.__haveShownError = true;
      }
    }).on('close', function () {
      socket.end();
      if (!realCon.__haveGotData && !realCon.__haveShownError) {
        console.error('[LocalProxy(:' + local_port + ')][Connection to ' + remote_host + ':' + remote_port + '] Error: reset by remote peer');
        realCon.__haveShownError = true;
      }
    }).on('error', function (err) {
      console.error('[LocalProxy(:' + local_port + ')][Connection to ' + remote_host + ':' + remote_port + '] ' + err);
      realCon.__haveShownError = true;
    });

    var parser = new HTTPParser(HTTPParser.REQUEST);
    parser[HTTPParser.kOnHeadersComplete] = function () {
      //console.log('---- kOnHeadersComplete----');
      //console.log(arguments);
      parser.__is_headers_complete = true;
    };
    //parser[HTTPParser.kOnMessageComplete] = function () {
    //    console.log('---- kOnMessageComplete----');
    //    console.log(arguments);
    //};

    var state = STATE_NONE;

    socket.on('data', function (buf) {
      //console.log('[' + remote_host + ':' + remote_port + ']>>>>' + (Date.t = new Date()) + '.' + Date.t.getMilliseconds() + '\n' + buf.toString('ascii'));
      //var ret = parser.execute(buf);
      //console.log('\n\n----parser result: ' + ret + ' buf len:' + buf.length);
      //realCon.write(buf);
      //return;

      var buf_ary = [], unsavedStart = 0, buf_len = buf.length;

      //process orphan CR
      if (state === STATE_FOUND_LF_CR && buf[0] !== LF) {
        parser.execute(BUF_CR);
        buf_ary.push(BUF_CR);
      }

      for (var i = 0; i < buf_len; i++) {
        //find first LF
        if (state === STATE_NONE) {
          if (buf[i] === LF) {
            state = STATE_FOUND_LF;
          }
          continue;
        }

        //find second CR LF or LF
        if (buf[i] === LF) {
          parser.__is_headers_complete = false;
          parser.execute(buf.slice(unsavedStart, i + 1));

          if (parser.__is_headers_complete) {
            buf_ary.push(buf.slice(unsavedStart, buf[i - 1] === CR ? i - 1 : i));
            //console.log('insert auth header');
            buf_ary.push(buf_proxy_basic_auth);
            buf_ary.push(state === STATE_FOUND_LF_CR ? BUF_CR_LF_CR_LF : BUF_LF_LF);

            unsavedStart = i + 1;
            state = STATE_NONE;
          }
          else {
            state = STATE_FOUND_LF;
          }
        }
        else if (buf[i] === CR && state === STATE_FOUND_LF) {
          state = STATE_FOUND_LF_CR;
        } else {
          state = STATE_NONE;
        }
      }

      if (unsavedStart < buf_len) {
        //strip last CR if found LF_CR
        buf = buf.slice(unsavedStart, state === STATE_FOUND_LF_CR ? buf_len - 1 : buf_len);
        if (buf.length) {
          parser.execute(buf);
          buf_ary.push(buf);
        }
      }

      buf = Buffer.concat(buf_ary);
      realCon.write(buf);

    }).on('end', cleanup).on('close', cleanup).on('error', function (err) {
      console.error('[LocalProxy(:' + local_port + ')][Incoming connection] ' + err);
    });

    function cleanup() {
      if (parser) {
        parser.close();
        parser = null;
      }
      realCon.end();
    }
  }).on('error', function (err) {
    console.error('[LocalProxy(:' + local_port + ')] ' + err);
    process.exit(1);
  }).listen(local_port, local_host === '*' ? undefined : local_host, function () {
    console.log('[LocalProxy(:' + local_port + ')] OK: forward http://' + local_host + ':' + local_port + ' to ' + ' to http' + (is_remote_https ? 's' : '') + '://' + remote_host + ':' + remote_port);
  });
}

var proxyAddrMap = {};

function createPacServer(local_host, local_port, remote_host, remote_port, buf_proxy_basic_auth, is_remote_https, ignore_https_cert, are_remotes_in_pac_https) {
  http.createServer(function (req, res) {

    var internal_req = url.parse(req.url);

    internal_req.host = remote_host;
    internal_req.port = remote_port;
    req.headers['host'] = remote_host + ':' + remote_port;
    if (!req.headers['authorization']) {
      req.headers['authorization'] = buf_proxy_basic_auth.slice('Proxy-Authorization: '.length).toString();
    }
    internal_req.headers = req.headers;
    internal_req.rejectUnauthorized = !ignore_https_cert; //only used for SSL

    (is_remote_https ? https : http).get(internal_req, function (internal_res) {

      delete internal_res.headers['content-length'];
      delete internal_res.headers['transfer-encoding'];

      res.writeHead(internal_res.statusCode, internal_res.headers);
      res.__haveWrittenData = true;

      var buf_ary = [];
      internal_res.on('data', function (buf) {
        // console.log('<<<<' + (Date.t=new Date()) + '.' + Date.t.getMilliseconds() + '\n' + buf.toString('ascii'));
        buf_ary.push(buf);
      }).on('end', function () {
        var s = Buffer.concat(buf_ary).toString();
        buf_ary = [];
        s = s.replace(/\bPROXY\s+([^'":;\s]+):(\d+)/g, function (_, host, port) {
          var remoteAddr = host + ':' + port;
          var _local_port = proxyAddrMap[remoteAddr];
          if (!_local_port) {
            _local_port = local_port + Object.keys(proxyAddrMap).length + 1;
            proxyAddrMap[remoteAddr] = _local_port;
            createPortForwarder(local_host, _local_port, host, Number(port), buf_proxy_basic_auth, are_remotes_in_pac_https, ignore_https_cert);
          }
          return 'PROXY ' + local_host + ':' + _local_port;
        });
        //console.log('return patched pac');
        res.end(s);
      }).on('error', function (err) {
        res.end();
        console.error('[LocalPAC][Reading response from ' + remote_host + ':' + remote_port + '] ' + err);
      });
    }).on('error', function (err) {
      if (!res.__haveWrittenData) {
        res.statusCode = 500;
        res.end();
      }
      console.error('[LocalPAC][Connection to ' + remote_host + ':' + remote_port + '] ' + err);
    });
    res.on('error', function (err) {
      console.error('[LocalPAC][Writing response] ' + err);
    });
  }).on('error', function (err) {
    console.error('[LocalPAC] ' + err);
    process.exit(1);
  }).listen(local_port, local_host === '*' ? undefined : local_host, function () {
    console.log('[LocalPAC] OK: forward http://' + local_host + ':' + local_port + ' to http' + (is_remote_https ? 's' : '') + '://' + remote_host + ':' + remote_port);
  });
}

main();

same
image

commented

As my test for both version, the ECONNRESET does not matter, the http/https from browser works fine.

commented

Do not worry. Just a log, means browser has abandoned the connection to this proxy automator.

iam facing the same problem, when the connection gets dropped the page reverts to my local ip

@syrakozz exactly, same here.. i'm mainly facing this problem when testing automating payment pages. keeps reverting me back to the same page and won't progress to the next page

commented

thank you all, let me check it again.

commented

This issue is probably caused by wrongly intercept and inject HTTPS packets as HTTP.

I'd better refactor it with other implementation.

There is another tool named anyproxy, you may have a look.

commented

@ModeMan12345 @syrakozz hi guys, I have modified source to mitigate the ECONNRESET error.