Giter Club home page Giter Club logo

proxywrap's Introduction

Proxywrap Build Status

History

This module is a fork of original proxywrap by Josh Dague. Unfortunately, the project doesn't have recent changes. As so, we decided to contribute to it by forking it and make it better.

What's the purpose of this module?

This module wraps node's various Server interfaces so that they are compatible with the PROXY protocol. It automatically parses the PROXY headers and resets socket.remoteAddress and socket.remotePort so that they have the correct values.

This module is especially useful if you need to get the client IP address when you're behind an AWS ELB in TCP mode.

In HTTP or HTTPS mode (aka SSL termination at ELB), the ELB inserts X-Forwarded-For headers for you. However, in TCP mode, the ELB can't understand the underlying protocol, so you lose the client's IP address. With the PROXY protocol and this module, you're able to retain the client IP address with any protocol.

In order for this module to work with ELB, you must enable the PROXY protocol on your ELB (or whatever proxy your app is behind).

Compability

This module is only compatible with LTS and latest stable versions of node.

Installing

npm install --save findhit-proxywrap

Usage

proxywrap is a drop-in replacement. Here's a simple Express app:

var http = require( 'http' )
var proxiedHttp = require( 'findhit-proxywrap' ).proxy( http )
var express = require( 'express' )
var app = express()

// instead of http.createServer(app)
var srv = proxiedHttp.createServer( app ).listen( 80 )

app.get( '/', ( req, res ) => {
    res.send( 'IP = ' + req.connection.remoteAddress + ':' + req.connection.remotePort )
})

The magic happens in the proxywrap.proxy() call. It wraps the module's Server constructor and handles a bunch of messy details for you.

You can do the same with net (raw TCP streams), https, and spdy. It will probably work with other modules that follow the same pattern, but none have been tested.

Note: If you're wrapping node-spdy, its exports are a little strange:

var proxiedSpdy = require('proxywrap').proxy(require('spdy').server);

This also adds to all your sockets the properties:

  • socket.clientAddress - The IP Address that connected to your PROXY.
  • socket.clientPort - The Port used by who connected to your PROXY.
  • socket.proxyAddress - The IP Address exposed on Client <-> Proxy side.
  • socket.proxyPort - The Port exposed on Client <-> Proxy side. Usefull for detecting SSL on AWS ELB.
  • socket.remoteAddress [optional] - Same as socket.clientAddress, used for compability proposes.
  • socket.remotePort [optional] - Same as socket.clientPort, used for compability proposes.

Warning: By default, all traffic to your proxied server MUST use the PROXY protocol. If the first five bytes received aren't PROXY, the connection will be dropped. Obviously, the node server accepting PROXY connections should not be exposed directly to the internet; only the proxy (whether ELB, HAProxy, or something else) should be able to connect to node.

API

proxy(Server[, options])

Wraps something that inherits from the net module, exposing a Server and createServer. Returns the same module patched to support the PROXY protocol.

Options:

  • strict (default true): Incoming connections MUST use the PROXY protocol. If the first five bytes received aren't PROXY, the connection will be dropped. Disabling this option will allow connections that don't use the PROXY protocol (so long as the first bytes sent aren't PROXY). Disabling this option poses a security risk; it should be enabled in production.

  • ignoreStrictExceptions (default false): strict shutdowns your process with an error attached, meaning that if it isn't being caught on socket's error event, node will terminate process with an uncaughtException. This option tells strict methods to destroy sockets without providing the exception, so node ignores it. See #11 for more info.

  • overrideRemote (default true): findhit-proxywrap overrides socket.remoteAddress and socket.remotePort for compability proposes. If you set this as false, your socket.remoteAddress and socket.remotePort will have the Address and Port of your load-balancer or whatever you are using behind your app. You can also access client's Address and Port by using socket.clientAddress and socket.clientPort.

Contribute

Do you have any idea to improve this module? Feel free to open an Issue or a Pull Request.

People who have contributed so far

Thanks

Thanks to all contibuters and special thanks to Josh Dague for creating original proxywrap.

proxywrap's People

Contributors

cusspvz avatar daguej avatar danilobuiatti avatar kylegetson avatar revington avatar sandfox avatar tjlhope avatar xaka avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

proxywrap's Issues

Not working at all on node 0.12.2

Hello,

We are using node 0.12.2 and this lib doesn't work at all on this version of node :
Internally the "socket.remoteAddress" is correctly set with the overridden IP from the PROXY line sniffed (we have added some console.log to view the results...) but from the caller, the property "req.connection.remoteAddress" or "req.socket.remoteAddress" just give us the unmodified private ip from the ELB...

The same test was done on node 0.10.28... and works fine !

Please can you help with that issue ?

Thanks.

Catching the PROXY protocol error

We have a Node.js application behind ELB that uses proxywrap in strict mode. The application crashes intermittently with the following error:

events.js:87
      throw Error('Uncaught, unspecified "error" event.');
            ^
Error: Uncaught, unspecified "error" event.
    at Error (native)
    at Socket.emit (events.js:87:13)
    at net.js:459:14
    at process._tickCallback (node.js:355:11)

We have a strong suspicion that this is caused by non-PROXY requests somehow hitting the server because we get the same error if we run proxywrap in strict mode locally and then hit it with a non-PROXY request.

Now, how can we catch that error event, apparently emitted by the socket object here, and prevent it from crashing the whole application?

BSD license with dependency on GPL-3.0 findhit-util

Hi, I found this project as we're looking to use farhadi/node-smpp (which depends on it) in a commercial project.

node-smpp is MIT and this project (from the package.json) is BSD (though I did see #3 ), but proxywrap has a dependency on findhit-util which is GPL-3.0, meaning any derivative work (i.e. project using it) needs to be GPL as well.

Would you be willing to accept a PR removing the findhit-util GPL dep? (AFAICT it's only used for Util.extend and Util.is.object, which could be trivially replaced with equivalent methods from lodash)

TCP port are from 1 to 65535 and not from 1 to 65335

Hi,
In your regexp, you test if the port is contained in [1..65335].
But TCP ports are going until 65535.

Issue in on file "proxy-protocol.regexp.js".

Before :
Port = '([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-2][0-9]{2}|653[0-2][0-9]|6533[0-5])'; // 1..65335

After correction of your regexp :
Port = '([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-3][0-9]|6553[0-5])'; // 1..65535

Error when starting

Error:
(node:14) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_ARG_TYPE]: The "superCtor" argument must be of type function. Received undefined
Code:
const proxyMake = proxy.proxy(require('net').createServer(onClientConnection))
onClientConnection is a function

Rewrite of ProxyServer class

This Issue will host all contributors ideas to implement ProxyServer in a new way.

Rewrite should happen at rewrite branch.

Thank you

Just wanted to reach out and send my thanks for this. I also opened #30 to see if you had tested it with HTTP/2 yet?

Sockets are leaking

@jaslo commented at daguej#9

Sockets are leaking when I set up servers using proxywrap -- eventually my server fails with messages of "Error: accept EMFILE".
And I could see the growth of the open sockets in /proc/id/fd
node 10.29
ubuntu 13.10

When I remove the proxywrap and just use an http server, the leaks go away!

Under stress, some connections keep open

Under stress some connections will stay on CLOSE_WAIT state.

To reproduce the issue:

$ node close-wait.js close-wait.js below
$ wrk --latency -t4 -c400 -d30s "http://localhost:8000"

$ ss -e | grep 8000 | grep CLOSE
tcp    CLOSE-WAIT 0      0            127.0.0.1:8000          127.0.0.1:40084    uid:1000 ino:2562644 sk:ffff8803a9e2db00 -->

Everytime I run the stress test a new connection (the first one) remains in CLOSE_WAIT state

close-wait.js

'use strict';
var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;
var proxiedHttp = require('findhit-proxywrap').proxy(http, {
    strict: false
});
var i;

if (cluster.isMaster) {
    // Fork workers.
    for (i = 0; i < numCPUs; i++) {
        cluster.fork();
    }

} else {

    // Workers can share any TCP connection
    // In this case it is an HTTP server
    proxiedHttp.createServer(function handler(req, res) {
        return res.end('ok');
    }).listen(8000);
}

Add a license

We need to keep the notice of node-proxywrap/proxywrap.js and add a license to cover newer code.

proxy protcol v1 or v2

This project support both versions or one of them. Please add more detail information about compatible version of proxy protocol. Thank you guys

Proxy protocol version 2

Hi there, I'm currently using your module to test PRX, I'd like to know if the PROXY protocol version 2 is on the roadmap since it represents around 20% of PRX's code. I don't want to implement it myself as I want PRX's PROXY protocol implementation to be validated by a 3rd party.

Unable to mix proxied and unproxied services?

After the library patches http, is it possible to have an API that is not served with proxy protocol?

Amazon's ELBs can be configured to forward TCP traffic, which works wonderfully but one loses the source IP. The ELB can be modified to use Proxy Protocol to forward on the original connection's information. You knew that, obviously. The ELB can be configured with a health check. I am unable to configure an HTTP health check because the ELB sends requests (missing the Proxy Protocol header) to the HTTP health check endpoint. I must resort to TCP health checks, which means the port should be open when life is good and I should close it if I don't want traffic at this moment.

Is there a way to not patch http and have a new object get created that retains the properties from http and has a patched Server?

TypeScript support

I'm using the following module declaration to use this package in TypeScript. Thanks again for this package. ๐Ÿ™‡

declare module "findhit-proxywrap" {
  interface Options {
    strict?: boolean;
    ignoreStrictExceptions?: boolean;
    overrideRemote?: boolean;
  }

  import http from "http";
  function proxy(object: typeof http, options?: Options): typeof http;

  import https from "https";
  function proxy(object: typeof https, options?: Options): typeof https;
}

Why not add them to https://github.com/DefinitelyTyped/DefinitelyTyped?

I think types should live alongside the actual code to make sure they are up-to-date. I've created this issue for other people using TypeScript.

Coding policy suggestions

I'll think that the following would enrich this project.

  • Integration with travis testing LTS and stable versions of node
  • a code convention definition
  • a .eslintrc, .jshintrc or something similar
  • Better code readability I.E by replacing magic numbers with constants. parseInt(header[4], 10); โ†’ parseInt(header[REMOTE_PORT_HEADER], 10);
  • Refactoring functionality instead of inlining in order to enforce readablity

I can help with that if you agreed

Socket.Io running HTTPS behind AWS ELB

Hi,

I am trying to deploy for Socket.io running HTTPS behind AWS ELB.
This is how I implemented.

var https= require("https");
var proxiedHttp= require("findhit-proxywrap").proxy(https, { strict: false, overrideRemote: true });
var server= proxiedHttp.createServer(options);
server.listen(3000, function() { console.log("SERVER STARTED"); });
var io= require("socket.io").listen(server);

At https://github.com/findhit/proxywrap/blob/master/lib/proxywrap.js#L134, I added a console.log(header), and it appears that header was a string of gibberish nonsense. As though it's still in unencrypted HTTPS.

Like to ask if I have deployed your script wrongly?
Appreciate any advise!

Is proxywrap working properly with https module?

Hello,

I'm testing proxywrap module, which worked well with node's http module. When I moved to https module, it doesn't get the correct remote address from proxy-protocol.

See this code snippet (which runs behind an HA proxy with proxy-protocol enabled):

const https = require('https')
const proxiedHttp = require('findhit-proxywrap').proxy(https)

const options = {
  key: <some key file>
  cert: <some cert file>
}

proxiedHttp.createServer(options, (req, res) => {
  console.log(req.connection.remoteAddress) // prints the HA proxy IP address
  res.end()
}).listen(8443)

Note: I'm using node 6.5.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.