Add PROXY protocol line support
- HAProxy or stud are commonly used to do edge load balancing or TLS termination.
- When you are behind an ELB that is terminating TLS or doing a TCP load balancer, you will use the PROXY protocol to keep the client IP address.
For these reasons Vulcan should support the PROXY protocol line.
Library for doing this is here: https://github.com/racker/go-proxy-protocol
cc @songgao
I was looking into this the other day. It seems that it's non-trivial to make Vulcan to accept PROXY line, because the http package in Go doesn't support serving a given connection, or io.ReadWriter etc. What it supports is either serving a existing listener, or "ListenAndServe". It needs to accept connections itself. Also, there's no easy way to hijack incoming connections either. You can, however, hijack in a handler, where http package already parsed the request and hijacking would cause http not writing into the connection anymore.
I think there are only two ways to implement PROXY protocol with http package:
- Fork the
httppackage, to either 1) allow hijacking incoming connections; or 2) allow serving connections (rather than only listeners) - Create a relay. For each incoming connection that consists HTTP request, the relay 1) accepts the TCP connection; 2) then consumes the PROXY line if it exists; 3) initiate a new TCP connection to the actual HTTP server that's maintained by
httppackage; 4) and thenio.Copyfrom the old connection to the new connection.
Method 1 requires more work and introduces maintenance work if it's not merged into golang project. Method 2 seems simple and will not require much maintenance work in the future, but is less efficient. The question is how much overhead it introduces in context of everything else that Vulcan does?
Similar to how for ListenAndServeTLS to work with Server Name Indication, I think it might be possible to make our own ListenAndServe?
See this example Code:
https://groups.google.com/d/msg/golang-nuts/rUm2iYTdrU4/PaEBya4dzvoJ
@pquerna Please correct me if I'm wrong: did you mean we make a listener (like tls.NewListener, line 1747 in http://golang.org/src/pkg/net/http/server.go) that http serves on, and the listener would take the PROXY line? But how could we pass the infomation in PROXY line through http all the way to vulcan?
I was thinking about making a drop-in replacement for http in go-proxy-protocol that takes PROXY line during accepting a connection, and amends something in http.Request. Does that sound good?
Here's a drop-in alternative to net/http that supports ProxyProtocol: https://github.com/songgao/go.http/pull/1