【问题标题】:ENOENT error on "connect"“连接”上的 ENOENT 错误
【发布时间】:2014-06-01 13:47:55
【问题描述】:

我正在尝试使用 Node.js 创建一个 HTTP/S MitM 转发代理。

我处理这个项目的方式是重复使用@runk 在Node HTTP Proxy project 问题跟踪器上提出问题后创建的NPM Proxy Cache project 文件中的./lib/proxy.js 文件中的解决方案。

我的Proxy() 类如下所示:

var request = require('request')
  , https = require('https')
  , http = require('http')
  , net = require('net')
  , url = require('url')
  , os = require('os')
  , fs = require('fs');

var SOCKET_PATH = os.tmpdir() + 'mitm.sock';
console.log('[SOCKET PATH] ' + SOCKET_PATH);

function Proxy (config) {
    config = config || {};

    if(fs.existsSync(SOCKET_PATH)) {
        fs.unlinkSync(SOCKET_PATH);
    }

    var options = {
        key: fs.readFileSync('./certs/dummy.key', 'utf8'),
        cert: fs.readFileSync('./certs/dummy.crt', 'utf8')
    };

    // HTTPS Server
    https.createServer(options, this.handler).listen(config.port + 1, this.hostname, function (e) {
        if(e) {
            console.log('[HTTPS] Server listen() error !');
            throw e;
        }
    });

    // HTTP Server
    var server = http.createServer(this.handler);
    server.listen(config.port, this.hostname, function (e) {
        if(e) {
            console.log('[HTTP] Server listen() error !');
            throw e;
        }
    });

    // Intercept CONNECT requests for HTTPS handshake
    server.addListener('connect', this.httpsHandler);
}

Proxy.prototype.handler = function (req, res) {
    var schema = !!req.client.pair ? 'https' : 'http'
      , path = url.parse(req.url).path;

    var dest = schema + '://' + req.headers['host'] + path;

    console.log('(1) - [' + schema.toUpperCase() + '] ' + req.method + ' ' + req.url);

    var params = {
        rejectUnauthorized: false,
        url: dest
    };

    if(req.method.toUpperCase() !== 'GET') {
        return console.log('[HTTP] Request is not HTTP GET.');
    }

    var onResponse = function (e, response) {
        if(e == null && response.statusCode === 200) {
            return r.pipe(res);
        }

        var body = 'Status ' + response.statusCode + ' returned';
        if(e) {
            body = e.toString();
        }

        res.end(body);
    };

    var r = request(params);
    r.on('response', onResponse.bind(null, null));
    r.on('error', onResponse.bind(null));
};

Proxy.prototype.httpsHandler = function (request, socketRequest, bodyHead) {
    var httpVersion = request['httpVersion']
      , url = request['url'];

    console.log('(2) - [HTTPS] ' + request['method'] + ' ' + request['url']);

    var proxySocket = new net.Socket();

    // ProxySocket event handlers
    proxySocket.connect(SOCKET_PATH, function () {
        proxySocket.write(bodyHead);
        proxySocket.write('HTTP/' + httpVersion + ' 200 Connection established\r\n\r\n');
    });

    proxySocket.on('data', function (chunk) {
        console.log('ProxySocket - "data"');
        socketRequest.write(chunk);
    });

    proxySocket.on('end', function () {
        console.log('ProxySocket - "end"');
        socketRequest.end();
    });

    proxySocket.on('error', function (e) {
        console.log('ProxySocket - "error"');
        console.log(e);
        console.log(e.stack);
        socketRequest.write('HTTP/' + httpVersion + ' 500 Connection error\r\n\r\n');
        socketRequest.end();
    });

    // SocketRequest event handlers
    socketRequest.on('data', function (chunk) {
        console.log('SocketRequest - "data"');
        proxySocket.write(chunk);
    });

    socketRequest.on('end', function () {
        console.log('SocketRequest - "end"');
        proxySocket.end();
    });

    socketRequest.on('error', function (e) {
        console.log('socketRequest - "error"');
        console.log(e);
        console.log(e.stack);
        proxySocket.end();
    });

};

module.exports = Proxy;

启动我的程序的Index.js 文件如下所示:

var Proxy = require('./lib/proxy');

var proxy = new Proxy({
    hostname: '127.0.0.1',
    port: 8000
});

这是我的目录/文件结构:

/my_project
    /certs
        dummy.crt // Copied from the NPM Proxy Cache project
        dummy.csr // Copied from the NPM Proxy Cache project
        dummy.key // Copied from the NPM Proxy Cache project
    /lib
        proxy.js
    index.js

我正在通过将 HTTP 和 HTTPS 代理设置(在 Mac OSX Maverick 中)作为 IP 地址 127.0.0.1 和端口 8000 来测试我的程序。

浏览仅 HTTP 的网站时一切正常,但如果我浏览 HTTPS 网站,则会收到以下错误:

{[Error: connect ENOENT] code: 'ENOENT', errno: 'ENOENT', syscall: 'connect'}
Error: connect ENOENT
    at errnoException (net.js:904:11)
    at Object.afterConnect [as oncomplete] (net.js:895:19)
  • 有什么想法可能来自此问题以及如何解决此问题?

非常感谢您!

(如果你想测试我的代码,NPM 模块request 是运行代码所需的唯一依赖项。)

编辑:可以从这里下载证书:https://github.com/runk/npm-proxy-cache/tree/master/cert

【问题讨论】:

  • 这就是你所有的堆栈跟踪吗?您是否尝试过在 *nix 环境中使用 VirtualBox?
  • 另外,我想在 Windows 上测试它,但我如何获得证书?
  • @Vinz243,你可以从这里下载证书:github.com/runk/npm-proxy-cache/tree/master/cert。我的测试是在 Mac OSX 上进行的,所以从技术上讲,它是一个 *nix 环境,但我会在 VirtualBox 上尝试。

标签: node.js http https proxy mitmproxy


【解决方案1】:

我是npm-proxy-cache 的作者。事实上,我已经创建了另一个名为 thin https://www.npmjs.org/package/thin 的项目,我希望将来 npm 代理缓存能够利用它。尽管它仍然非常粗糙,但它仍然可以使用并且可以满足您的需求。

例如

代理代码

var Thin = require('thin')

var proxy = new Thin;

// `req` and `res` params are `http.ClientRequest` and `http.ServerResponse` accordingly
// be sure to check http://nodejs.org/api/http.html for more details
proxy.use(function(req, res, next) {
  console.log('Proxying:', req.url);
  next();
});

// you can add different layers of "middleware" similar to "connect", 
// but with few exclusions
proxy.use(function(req, res, next) {
  if (req.url === '/foobar')
    return res.end('intercepted');
  next();
});

proxy.listen(8081, 'localhost', function(err) {
  // .. error handling code ..
});

服务器代码

var express = require('express'); // v3.4
var app = express();

app.use(express.urlencoded({limit: '10mb'}));

app.get('/test', function(req, res){
  console.log(req.protocol, 'get req.query', req.query);
  res.end('get: hello world');
});

app.post('/test', function(req, res) {
  console.log(req.protocol, 'post req.query', req.query);
  console.log(req.protocol, 'post req.body', req.body);
  res.end('post: hello world');
});

app.listen(3000);


var fs = require('fs');
var https = require('https');

https.createServer({
  key: fs.readFileSync('./cert/dummy.key'), // your mitm server keys
  cert: fs.readFileSync('./cert/dummy.crt')
}, app).listen(3001);

你需要在两个终端会话中启动代理和服务器,然后

curl -d "foo=baz" -k -x https://localhost:8081 https://localhost:3001/test?foo=bar
curl -d "foo=baz" -x http://localhost:8081 http://localhost:3000/test?foo=bar

之后您应该能够看到服务器的以下输出

https post req.query { foo: 'bar' }
https post req.body { foo: 'baz' }
http post req.query { foo: 'bar' }
http post req.body { foo: 'baz' }

拦截器小例子

curl -d "foo=baz" -k -x https://localhost:8081 https://localhost:3001/foobar

它应该返回intercepted

希望有帮助:)

【讨论】:

    猜你喜欢
    • 2018-10-30
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 2022-01-27
    • 1970-01-01
    • 2021-07-22
    • 1970-01-01
    相关资源
    最近更新 更多