Add support for the PROXY protocol
This commit is contained in:
parent
f64eb89cee
commit
e3ac31414f
|
@ -4,6 +4,7 @@ A TLS reverse proxy.
|
||||||
|
|
||||||
- Automatic TLS with Let's Encrypt
|
- Automatic TLS with Let's Encrypt
|
||||||
- Route incoming connections to backends using Server Name Indication
|
- Route incoming connections to backends using Server Name Indication
|
||||||
|
- Support for the [PROXY protocol]
|
||||||
|
|
||||||
Example configuration:
|
Example configuration:
|
||||||
|
|
||||||
|
@ -14,3 +15,5 @@ Example configuration:
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|
||||||
|
[PROXY protocol]: https://www.haproxy.org/download/2.3/doc/proxy-protocol.txt
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -5,4 +5,5 @@ go 1.15
|
||||||
require (
|
require (
|
||||||
github.com/caddyserver/certmagic v0.11.2
|
github.com/caddyserver/certmagic v0.11.2
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||||
|
github.com/pires/go-proxyproto v0.1.3
|
||||||
)
|
)
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -195,6 +195,8 @@ github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJ
|
||||||
github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
||||||
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
|
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
|
github.com/pires/go-proxyproto v0.1.3 h1:2XEuhsQluSNA5QIQkiUv8PfgZ51sNYIQkq/yFquiSQM=
|
||||||
|
github.com/pires/go-proxyproto v0.1.3/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
|
5
main.go
5
main.go
|
@ -98,7 +98,10 @@ func parseBackend(backend *Backend, d *Directive) error {
|
||||||
return fmt.Errorf("failed to parse backend URI %q: %v", backendURI, err)
|
return fmt.Errorf("failed to parse backend URI %q: %v", backendURI, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: +proxy to use the PROXY protocol
|
if strings.HasSuffix(u.Scheme, "+proxy") {
|
||||||
|
u.Scheme = strings.TrimSuffix(u.Scheme, "+proxy")
|
||||||
|
backend.Proxy = true
|
||||||
|
}
|
||||||
|
|
||||||
switch u.Scheme {
|
switch u.Scheme {
|
||||||
case "", "tcp":
|
case "", "tcp":
|
||||||
|
|
37
server.go
37
server.go
|
@ -9,6 +9,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/caddyserver/certmagic"
|
"github.com/caddyserver/certmagic"
|
||||||
|
"github.com/pires/go-proxyproto"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
|
@ -152,12 +153,20 @@ func (fe *Frontend) handle(downstream net.Conn) error {
|
||||||
}
|
}
|
||||||
defer upstream.Close()
|
defer upstream.Close()
|
||||||
|
|
||||||
|
if be.Proxy {
|
||||||
|
h := proxyHeader(downstream.RemoteAddr(), downstream.LocalAddr())
|
||||||
|
if _, err := h.WriteTo(upstream); err != nil {
|
||||||
|
return fmt.Errorf("failed to write PROXY protocol header: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return duplexCopy(upstream, downstream)
|
return duplexCopy(upstream, downstream)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Backend struct {
|
type Backend struct {
|
||||||
Network string
|
Network string
|
||||||
Address string
|
Address string
|
||||||
|
Proxy bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func duplexCopy(a, b io.ReadWriter) error {
|
func duplexCopy(a, b io.ReadWriter) error {
|
||||||
|
@ -172,3 +181,31 @@ func duplexCopy(a, b io.ReadWriter) error {
|
||||||
}()
|
}()
|
||||||
return <-done
|
return <-done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func proxyHeader(sourceAddr, destAddr net.Addr) *proxyproto.Header {
|
||||||
|
h := proxyproto.Header{
|
||||||
|
Version: 2,
|
||||||
|
Command: proxyproto.PROXY,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch sourceAddr := sourceAddr.(type) {
|
||||||
|
case *net.TCPAddr:
|
||||||
|
destAddr, ok := destAddr.(*net.TCPAddr)
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if localIP4 := sourceAddr.IP.To4(); len(localIP4) == net.IPv4len {
|
||||||
|
h.TransportProtocol = proxyproto.TCPv4
|
||||||
|
} else if len(sourceAddr.IP) == net.IPv6len {
|
||||||
|
h.TransportProtocol = proxyproto.TCPv6
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
h.SourceAddress = sourceAddr.IP
|
||||||
|
h.DestinationAddress = destAddr.IP
|
||||||
|
h.SourcePort = uint16(sourceAddr.Port)
|
||||||
|
h.DestinationPort = uint16(destAddr.Port)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &h
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue