Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 45 additions & 7 deletions lib/multiplexer/multiplexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -563,15 +563,9 @@ func (m *Mux) detect(conn net.Conn) (*Conn, error) {
proxyLine = newPROXYLine
// repeat the cycle to detect the protocol
case ProtoTLS, ProtoSSH, ProtoHTTP, ProtoPostgres:
// Proxy and other services might call itself directly, avoiding
// load balancer, so we shouldn't fail connections without PROXY headers for such cases.
selfConnection, err := m.isSelfConnection(conn)
if err != nil {
if err := m.checkPROXYProtocolRequirement(conn, unsignedPROXYLineReceived); err != nil {
return nil, trace.Wrap(err)
}
if !selfConnection && m.PROXYProtocolMode == PROXYProtocolOn && !unsignedPROXYLineReceived {
return nil, trace.BadParameter(missingProxyLineError, conn.RemoteAddr().String(), conn.LocalAddr().String())
}

return &Conn{
protocol: proto,
Expand All @@ -585,6 +579,50 @@ func (m *Mux) detect(conn net.Conn) (*Conn, error) {
return nil, trace.BadParameter(unknownProtocolError)
}

// checkPROXYProtocolRequirement checks that if multiplexer is required to receive unsigned PROXY line
// that requirement is fulfilled, or exceptions apply - self connections and connections that are passed
// from upstream multiplexed listener (as it happens for alpn proxy).
func (m *Mux) checkPROXYProtocolRequirement(conn net.Conn, unsignedPROXYLineReceived bool) error {
if m.PROXYProtocolMode != PROXYProtocolOn {
return nil
}

// Proxy and other services might call itself directly, avoiding
// load balancer, so we shouldn't fail connections without PROXY headers for such cases.
selfConnection, err := m.isSelfConnection(conn)
if err != nil {
return trace.Wrap(err)
}

// We try to get inner multiplexer connection, if we succeed and there is on, it means conn was passed
// to us from another multiplexer listener and unsigned PROXY protocol requirement was handled there.
innerConn := unwrapMuxConn(conn)

if !selfConnection && innerConn == nil && !unsignedPROXYLineReceived {
return trace.BadParameter(missingProxyLineError, conn.RemoteAddr().String(), conn.LocalAddr().String())
}

return nil
}

func unwrapMuxConn(conn net.Conn) *Conn {
type netConn interface {
NetConn() net.Conn
}

for {
if muxConn, ok := conn.(*Conn); ok {
return muxConn
}

connGetter, ok := conn.(netConn)
if !ok {
return nil
}
conn = connGetter.NetConn()
}
}

func (m *Mux) isSelfConnection(conn net.Conn) (bool, error) {
if m.IgnoreSelfConnections {
return false, nil
Expand Down
12 changes: 1 addition & 11 deletions lib/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4410,16 +4410,6 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error {
return trace.Wrap(err)
}

proxyProtocol := cfg.Proxy.PROXYProtocolMode
if clusterNetworkConfig.GetProxyListenerMode() == types.ProxyListenerMode_Multiplex {
// If ProxyListenerMode is MULTIPLEX it means that the ALPN listener handles the PROXY line
// and sends the connection to the Proxy Kube listener. When it does, it uses the same net.Conn
// and doesn't dial so the PROXY Protocol cannot be present. Under those circumstances,
// ProxyProtocol for Proxy Kube listener must be off.

proxyProtocol = multiplexer.PROXYProtocolOff
}

kubeServer, err = kubeproxy.NewTLSServer(kubeproxy.TLSServerConfig{
ForwarderConfig: kubeproxy.ForwarderConfig{
Namespace: apidefaults.Namespace,
Expand Down Expand Up @@ -4455,7 +4445,7 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error {
Log: log,
IngressReporter: ingressReporter,
KubernetesServersWatcher: kubeServerWatcher,
PROXYProtocolMode: proxyProtocol,
PROXYProtocolMode: cfg.Proxy.PROXYProtocolMode,
})
if err != nil {
return trace.Wrap(err)
Expand Down