Handle HTTP connections to TLS socket in a more graceful way (#2886)

This commit is contained in:
Gus Luxton
2019-08-13 14:03:22 -03:00
committed by GitHub
parent 55bf093fa6
commit 4b022fcacb
6 changed files with 47 additions and 33 deletions
+2 -2
View File
@@ -466,10 +466,10 @@ func SSHServerListenAddr() *utils.NetAddr {
return makeAddr(BindIP, SSHServerListenPort)
}
// ReverseTunnellListenAddr returns the default listening address for the SSH Proxy service used
// ReverseTunnelListenAddr returns the default listening address for the SSH Proxy service used
// by the SSH nodes to establish proxy<->ssh_node connection from behind a firewall which
// blocks inbound connecions to ssh_nodes
func ReverseTunnellListenAddr() *utils.NetAddr {
func ReverseTunnelListenAddr() *utils.NetAddr {
return makeAddr(BindIP, SSHProxyTunnelListenPort)
}
+3 -2
View File
@@ -16,8 +16,9 @@ limitations under the License.
package defaults
import (
"github.com/gravitational/teleport/lib/utils"
"testing"
"github.com/gravitational/teleport/lib/utils"
)
func TestMakeAddr(t *testing.T) {
@@ -37,7 +38,7 @@ func TestDefaultAddresses(t *testing.T) {
"tcp://0.0.0.0:3023": ProxyListenAddr(),
"tcp://0.0.0.0:3080": ProxyWebListenAddr(),
"tcp://0.0.0.0:3022": SSHServerListenAddr(),
"tcp://0.0.0.0:3024": ReverseTunnellListenAddr(),
"tcp://0.0.0.0:3024": ReverseTunnelListenAddr(),
}
for expected, actual := range table {
if actual == nil {
+32 -2
View File
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// package multiplexer implements SSH and TLS multiplexing
// Package multiplexer implements SSH and TLS multiplexing
// on the same listener
//
// mux, _ := multiplexer.New(Config{Listener: listener})
@@ -235,6 +235,9 @@ func (m *Mux) detectAndForward(conn net.Conn) {
connWrapper.Close()
return
}
case ProtoHTTP:
m.Debug("Detected an HTTP request. If this is for a health check, use an HTTPS request instead.")
conn.Close()
default:
// should not get here, handle this just in case
connWrapper.Close()
@@ -275,7 +278,7 @@ func detect(conn net.Conn, enableProxyProtocol bool) (*Conn, error) {
return nil, trace.Wrap(err)
}
// repeat the cycle to detect the protocol
case ProtoTLS, ProtoSSH:
case ProtoTLS, ProtoSSH, ProtoHTTP:
return &Conn{
protocol: proto,
Conn: conn,
@@ -297,6 +300,8 @@ const (
ProtoSSH
// ProtoProxy is a HAProxy proxy line protocol
ProtoProxy
// ProtoHTTP is HTTP protocol
ProtoHTTP
)
var (
@@ -305,6 +310,29 @@ var (
tlsPrefix = []byte{0x16}
)
// isHTTP returns true if the first 3 bytes of the prefix indicate
// the use of an HTTP method.
func isHTTP(in []byte) bool {
methods := [...][]byte{
[]byte("GET"),
[]byte("POST"),
[]byte("PUT"),
[]byte("DELETE"),
[]byte("HEAD"),
[]byte("CONNECT"),
[]byte("OPTIONS"),
[]byte("TRACE"),
[]byte("PATCH"),
}
for _, verb := range methods {
// we only get 3 bytes, so can only compare the first 3 bytes of each verb
if bytes.HasPrefix(verb, in[:3]) {
return true
}
}
return false
}
func detectProto(in []byte) (int, error) {
switch {
// reader peeks only 3 bytes, slice the longer proxy prefix
@@ -314,6 +342,8 @@ func detectProto(in []byte) (int, error) {
return ProtoSSH, nil
case bytes.HasPrefix(in, tlsPrefix):
return ProtoTLS, nil
case isHTTP(in):
return ProtoHTTP, nil
default:
return ProtoUnknown, trace.BadParameter("failed to detect protocol by prefix: %v", in)
}
+7 -24
View File
@@ -58,10 +58,7 @@ func (s *MuxSuite) SetUpSuite(c *check.C) {
// TestMultiplexing tests basic use case of multiplexing TLS
// and SSH on the same listener socket
func (s *MuxSuite) TestMultiplexing(c *check.C) {
ports, err := utils.GetFreeTCPPorts(1)
c.Assert(err, check.IsNil)
listener, err := net.Listen("tcp", net.JoinHostPort("127.0.0.1", ports[0]))
listener, err := net.Listen("tcp", "127.0.0.1:0")
c.Assert(err, check.IsNil)
mux, err := New(Config{
@@ -130,10 +127,7 @@ func (s *MuxSuite) TestMultiplexing(c *check.C) {
// TestProxy tests Proxy line support protocol
func (s *MuxSuite) TestProxy(c *check.C) {
ports, err := utils.GetFreeTCPPorts(1)
c.Assert(err, check.IsNil)
listener, err := net.Listen("tcp", net.JoinHostPort("127.0.0.1", ports[0]))
listener, err := net.Listen("tcp", "127.0.0.1:0")
c.Assert(err, check.IsNil)
mux, err := New(Config{
@@ -185,10 +179,7 @@ func (s *MuxSuite) TestProxy(c *check.C) {
// TestDisabledProxy makes sure the connection gets dropped
// when Proxy line support protocol is turned off
func (s *MuxSuite) TestDisabledProxy(c *check.C) {
ports, err := utils.GetFreeTCPPorts(1)
c.Assert(err, check.IsNil)
listener, err := net.Listen("tcp", net.JoinHostPort("127.0.0.1", ports[0]))
listener, err := net.Listen("tcp", "127.0.0.1:0")
c.Assert(err, check.IsNil)
mux, err := New(Config{
@@ -238,10 +229,7 @@ func (s *MuxSuite) TestDisabledProxy(c *check.C) {
// TestTimeout tests client timeout - client dials, but writes nothing
// make sure server hangs up
func (s *MuxSuite) TestTimeout(c *check.C) {
ports, err := utils.GetFreeTCPPorts(1)
c.Assert(err, check.IsNil)
listener, err := net.Listen("tcp", net.JoinHostPort("127.0.0.1", ports[0]))
listener, err := net.Listen("tcp", "127.0.0.1:0")
c.Assert(err, check.IsNil)
config := Config{
@@ -313,10 +301,7 @@ func (s *MuxSuite) TestUnknownProtocol(c *check.C) {
// TestDisableSSH disables SSH
func (s *MuxSuite) TestDisableSSH(c *check.C) {
ports, err := utils.GetFreeTCPPorts(1)
c.Assert(err, check.IsNil)
listener, err := net.Listen("tcp", net.JoinHostPort("127.0.0.1", ports[0]))
listener, err := net.Listen("tcp", "127.0.0.1:0")
c.Assert(err, check.IsNil)
mux, err := New(Config{
@@ -365,10 +350,7 @@ func (s *MuxSuite) TestDisableSSH(c *check.C) {
// TestDisableTLS tests scenario with disabled TLS
func (s *MuxSuite) TestDisableTLS(c *check.C) {
ports, err := utils.GetFreeTCPPorts(1)
c.Assert(err, check.IsNil)
listener, err := net.Listen("tcp", net.JoinHostPort("127.0.0.1", ports[0]))
listener, err := net.Listen("tcp", "127.0.0.1:0")
c.Assert(err, check.IsNil)
mux, err := New(Config{
@@ -444,6 +426,7 @@ func clientConfig(srv *httptest.Server) *tls.Config {
}
}
// testClient is a test HTTP client set up for TLS
func testClient(srv *httptest.Server) *http.Client {
return &http.Client{
Transport: &http.Transport{
+1 -1
View File
@@ -470,7 +470,7 @@ func ApplyDefaults(cfg *Config) {
cfg.Proxy.Enabled = true
cfg.Proxy.SSHAddr = *defaults.ProxyListenAddr()
cfg.Proxy.WebAddr = *defaults.ProxyWebListenAddr()
cfg.Proxy.ReverseTunnelListenAddr = *defaults.ReverseTunnellListenAddr()
cfg.Proxy.ReverseTunnelListenAddr = *defaults.ReverseTunnelListenAddr()
defaults.ConfigureLimiter(&cfg.Proxy.Limiter)
// defaults for the Kubernetes proxy service
+2 -2
View File
@@ -1897,7 +1897,7 @@ func (process *TeleportProcess) setupProxyListeners() (*proxyListeners, error) {
go listeners.mux.Serve()
return &listeners, nil
default:
process.Debugf("Proxy reverse tunnel are listening on the separate ports.")
process.Debugf("Proxy and reverse tunnel are listening on separate ports.")
if !cfg.Proxy.DisableReverseTunnel {
listeners.reverseTunnel, err = process.importOrCreateListener(teleport.Component(teleport.ComponentProxy, "tunnel"), cfg.Proxy.ReverseTunnelListenAddr.Addr)
if err != nil {
@@ -1985,7 +1985,7 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error {
if err != nil {
return trace.Wrap(err)
}
process.RegisterCriticalFunc("proxy.reveresetunnel.server", func() error {
process.RegisterCriticalFunc("proxy.reversetunnel.server", func() error {
utils.Consolef(cfg.Console, teleport.ComponentProxy, "Reverse tunnel service is starting on %v.", cfg.Proxy.ReverseTunnelListenAddr.Addr)
log.Infof("Starting on %v using %v", cfg.Proxy.ReverseTunnelListenAddr.Addr, process.Config.CachePolicy)
if err := tsrv.Start(); err != nil {