-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4b167ff
commit ddddfd4
Showing
3 changed files
with
190 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package proxyproto | ||
|
||
import ( | ||
"net" | ||
|
||
"github.com/pires/go-proxyproto" | ||
) | ||
|
||
// WrapProxy is a function that wraps a net.Conn around the PROXY tcp protocol. It is used for correctly reporting the originator IP address when a service is running behind a load balancer | ||
// In case proxy use is allowed the wrapped network connection is returned along with the IP address of the proxy that it is used. The wrapped network connection will return the IP address | ||
// of the client when RemoteAddr() is called | ||
// | ||
// conn is the network connection to wrap | ||
// proxyList is a list of addresses that are allowed to send proxy information | ||
// | ||
func WrapProxy(conn net.Conn, proxyList []string) (net.Conn, *net.TCPAddr, error) { | ||
if len(proxyList) == 0 { | ||
return conn, nil, nil | ||
} | ||
policyFunc := proxyproto.MustStrictWhiteListPolicy(proxyList) | ||
policy, err := policyFunc(conn.RemoteAddr()) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
if policy == proxyproto.REJECT || policy == proxyproto.IGNORE { | ||
// If it's not an approved proxy we should fail loudly, not silently | ||
return conn, nil, nil | ||
} | ||
tcpAddr := conn.RemoteAddr().(*net.TCPAddr) | ||
return proxyproto.NewConn( | ||
conn, | ||
proxyproto.WithPolicy(policy), | ||
), tcpAddr, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
package proxyproto_test | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"net" | ||
"testing" | ||
"time" | ||
|
||
"github.com/containerssh/libcontainerssh/internal/proxyproto" | ||
goproxyproto "github.com/pires/go-proxyproto" | ||
) | ||
|
||
type fakeConn struct { | ||
remoteAddr string | ||
localAddr string | ||
pipeReader io.ReadCloser | ||
pipeWriter io.WriteCloser | ||
} | ||
|
||
func NewFakeConn(clientAddr string, serverAddr string) (fakeConn, fakeConn) { | ||
clientPipeReader, clientPipeWriter := io.Pipe() | ||
serverPipeReader, serverPipeWriter := io.Pipe() | ||
return fakeConn{ | ||
remoteAddr: clientAddr, | ||
localAddr: serverAddr, | ||
pipeReader: serverPipeReader, | ||
pipeWriter: clientPipeWriter, | ||
}, fakeConn{ | ||
remoteAddr: serverAddr, | ||
localAddr: clientAddr, | ||
pipeReader: clientPipeReader, | ||
pipeWriter: serverPipeWriter, | ||
} | ||
} | ||
|
||
func (f fakeConn) Read(b []byte) (n int, err error) { | ||
return f.pipeReader.Read(b) | ||
} | ||
|
||
func (f fakeConn) Write(b []byte) (n int, err error) { | ||
return f.pipeWriter.Write(b) | ||
} | ||
|
||
func (f fakeConn) Close() error { | ||
f.pipeWriter.Close() | ||
f.pipeReader.Close() | ||
return nil | ||
} | ||
|
||
func (f fakeConn) LocalAddr() net.Addr { | ||
return &net.TCPAddr{ | ||
IP: net.ParseIP(f.localAddr), | ||
} | ||
} | ||
|
||
func (f fakeConn) RemoteAddr() net.Addr { | ||
return &net.TCPAddr{ | ||
IP: net.ParseIP(f.remoteAddr), | ||
} | ||
} | ||
func (f fakeConn) SetDeadline(t time.Time) error { | ||
return fmt.Errorf("Unimplemented") | ||
} | ||
func (f fakeConn) SetReadDeadline(t time.Time) error { | ||
return fmt.Errorf("Unimplemented") | ||
} | ||
func (f fakeConn) SetWriteDeadline(t time.Time) error { | ||
return fmt.Errorf("Unimplemented") | ||
} | ||
|
||
func TestProxyWithHeader(t *testing.T) { | ||
clientIP := "127.0.0.1" | ||
proxyIP := "127.0.0.2" | ||
serverIP := "127.0.0.3" | ||
|
||
server, proxy := NewFakeConn(proxyIP, serverIP) | ||
wrappedConn, proxyAddr, err := proxyproto.WrapProxy(server, []string{proxyIP}) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
header := &goproxyproto.Header{ | ||
Version: 1, | ||
Command: goproxyproto.PROXY, | ||
TransportProtocol: goproxyproto.TCPv4, | ||
SourceAddr: &net.TCPAddr{ | ||
IP: net.ParseIP(clientIP), | ||
Port: 1000, | ||
}, | ||
DestinationAddr: &net.TCPAddr{ | ||
IP: net.ParseIP(proxyIP), | ||
Port: 2000, | ||
}, | ||
} | ||
go func() { | ||
_, err := header.WriteTo(proxy) | ||
if err != nil { | ||
return | ||
} | ||
}() | ||
|
||
if proxyAddr == nil { | ||
t.Fatalf("Proxy info was rejected") | ||
} | ||
if proxyAddr.String() != proxyIP+":0" { | ||
t.Fatalf("Unexpected proxy address %s, expected %s", proxyAddr, proxyIP) | ||
} | ||
if wrappedConn.RemoteAddr().String() != clientIP+":1000" { | ||
t.Fatalf("Header not accepted when it should be %s != %s", wrappedConn.RemoteAddr().String(), clientIP+":1000") | ||
} | ||
} | ||
|
||
func TestProxyUnauthorizedHeader(t *testing.T) { | ||
clientIP := "127.0.0.1" | ||
proxyIP := "127.0.0.2" | ||
serverIP := "127.0.0.3" | ||
|
||
server, proxy := NewFakeConn(proxyIP, serverIP) | ||
_, proxyAddr, err := proxyproto.WrapProxy(server, []string{"128.0.0.2"}) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
header := &goproxyproto.Header{ | ||
Version: 1, | ||
Command: goproxyproto.PROXY, | ||
TransportProtocol: goproxyproto.TCPv4, | ||
SourceAddr: &net.TCPAddr{ | ||
IP: net.ParseIP(clientIP), | ||
Port: 1000, | ||
}, | ||
DestinationAddr: &net.TCPAddr{ | ||
IP: net.ParseIP(proxyIP), | ||
Port: 2000, | ||
}, | ||
} | ||
go func() { | ||
_, err := header.WriteTo(proxy) | ||
if err != nil { | ||
return | ||
} | ||
}() | ||
|
||
if proxyAddr != nil { | ||
t.Fatalf("Proxy info was accepted when unauthorized") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters