-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement support for the PROXY protocol #108
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,9 @@ type SSHConfig struct { | |
// See https://tools.ietf.org/html/rfc4253#page-4 section 4.2. Protocol Version Exchange | ||
// The trailing CR and LF characters should NOT be added to this string. | ||
ServerVersion SSHServerVersion `json:"serverVersion" yaml:"serverVersion" default:"SSH-2.0-ContainerSSH"` | ||
// AllowedProxies is a list of IP addresses or CIDR ranges that are allowed to use the | ||
// PROXY protocol to override the connection originator IP address. | ||
AllowedProxies []string `json:"allowedProxies" yaml:"allowedProxies"` | ||
// Ciphers are the ciphers offered to the client. | ||
Ciphers SSHCipherList `json:"ciphers" yaml:"ciphers" default:"[\"[email protected]\",\"[email protected]\",\"[email protected]\",\"aes256-ctr\",\"aes192-ctr\",\"aes128-ctr\"]" comment:"SSHCipher suites to use"` | ||
// KexAlgorithms are the key exchange algorithms offered to the client. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ import ( | |
messageCodes "github.com/containerssh/libcontainerssh/message" | ||
"github.com/containerssh/libcontainerssh/service" | ||
"golang.org/x/crypto/ssh" | ||
"github.com/pires/go-proxyproto" | ||
) | ||
|
||
type serverImpl struct { | ||
|
@@ -54,11 +55,20 @@ func (s *serverImpl) RunWithLifecycle(lifecycle service.Lifecycle) error { | |
Control: s.socketControl, | ||
} | ||
|
||
useProxy := len(s.cfg.AllowedProxies) > 0 | ||
|
||
netListener, err := listenConfig.Listen(lifecycle.Context(), "tcp", s.cfg.Listen) | ||
if err != nil { | ||
s.lock.Unlock() | ||
return messageCodes.Wrap(err, messageCodes.ESSHStartFailed, "failed to start SSH server on %s", s.cfg.Listen) | ||
} | ||
if useProxy { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems to me that PROXY is a wrapper protocol like many others (e.g. websocket). We should consider creating a generic abstraction for wrapper protocols. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't foresee having any other wrapping protocols in-front of the ssh server since, we can consider that if it's necessary further down the line. |
||
policy := proxyproto.MustStrictWhiteListPolicy(s.cfg.AllowedProxies) | ||
netListener = &proxyproto.Listener{ | ||
Listener: netListener, | ||
Policy: policy, | ||
} | ||
} | ||
s.listenSocket = netListener | ||
s.lock.Unlock() | ||
if err := s.handler.OnReady(); err != nil { | ||
|
@@ -84,7 +94,13 @@ func (s *serverImpl) RunWithLifecycle(lifecycle service.Lifecycle) error { | |
break | ||
} | ||
s.wg.Add(1) | ||
go s.handleConnection(tcpConn) | ||
logger := s.logger | ||
if useProxy { | ||
proxyConn := tcpConn.(*proxyproto.Conn) | ||
proxyIp := proxyConn.Raw().RemoteAddr() | ||
logger = logger.WithLabel("fromProxy", proxyIp.(*net.TCPAddr).IP.String()) | ||
This conversation was marked as resolved.
Show resolved
Hide resolved
|
||
} | ||
go s.handleConnection(logger, tcpConn) | ||
} | ||
lifecycle.Stopping() | ||
s.shuttingDown = true | ||
|
@@ -501,10 +517,10 @@ func (s *serverImpl) createPasswordCallback( | |
return passwordCallback | ||
} | ||
|
||
func (s *serverImpl) handleConnection(conn net.Conn) { | ||
func (s *serverImpl) handleConnection(logger log.Logger, conn net.Conn) { | ||
addr := conn.RemoteAddr().(*net.TCPAddr) | ||
connectionID := GenerateConnectionID() | ||
logger := s.logger. | ||
logger = logger. | ||
WithLabel("remoteAddr", addr.IP.String()). | ||
WithLabel("connectionId", connectionID) | ||
handlerNetworkConnection, err := s.handler.OnNetworkConnection(*addr, connectionID) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a third party library and should be abstracted away with its own package, including tests so it can be replaced if need be.