TUN-6938: Force h2mux protocol to http2 for named tunnels

Going forward, the only protocols supported will be QUIC and HTTP2,
defaulting to QUIC for "auto". Selecting h2mux protocol will be forcibly
upgraded to http2 internally.
This commit is contained in:
Devin Carr
2023-02-06 11:06:02 -08:00
parent ae46af9236
commit 0f95f8bae5
9 changed files with 139 additions and 419 deletions

View File

@@ -19,8 +19,6 @@ import (
)
const (
// SRV and TXT record resolution TTL
ResolveTTL = time.Hour
// Waiting time before retrying a failed tunnel connection
tunnelRetryDuration = time.Second * 10
// Interval between registering new tunnels

View File

@@ -1,74 +0,0 @@
package supervisor
import (
"context"
"testing"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/cloudflare/cloudflared/connection"
"github.com/cloudflare/cloudflared/edgediscovery"
"github.com/cloudflare/cloudflared/edgediscovery/allregions"
"github.com/cloudflare/cloudflared/signal"
)
type mockProtocolSelector struct {
protocols []connection.Protocol
index int
}
func (m *mockProtocolSelector) Current() connection.Protocol {
return m.protocols[m.index]
}
func (m *mockProtocolSelector) Fallback() (connection.Protocol, bool) {
m.index++
if m.index == len(m.protocols) {
return m.protocols[len(m.protocols)-1], false
}
return m.protocols[m.index], true
}
type mockEdgeTunnelServer struct {
config *TunnelConfig
}
func (m *mockEdgeTunnelServer) Serve(ctx context.Context, connIndex uint8, protocolFallback *protocolFallback, connectedSignal *signal.Signal) error {
// This is to mock the first connection falling back because of connectivity issues.
protocolFallback.protocol, _ = m.config.ProtocolSelector.Fallback()
connectedSignal.Notify()
return nil
}
// Test to check if initialize sets all the different connections to the same protocol should the first
// tunnel fall back.
func Test_Initialize_Same_Protocol(t *testing.T) {
edgeIPs, err := edgediscovery.ResolveEdge(&zerolog.Logger{}, "us", allregions.Auto)
assert.Nil(t, err)
s := Supervisor{
edgeIPs: edgeIPs,
config: &TunnelConfig{
ProtocolSelector: &mockProtocolSelector{protocols: []connection.Protocol{connection.QUIC, connection.HTTP2, connection.H2mux}},
},
tunnelsProtocolFallback: make(map[int]*protocolFallback),
edgeTunnelServer: &mockEdgeTunnelServer{
config: &TunnelConfig{
ProtocolSelector: &mockProtocolSelector{protocols: []connection.Protocol{connection.QUIC, connection.HTTP2, connection.H2mux}},
},
},
}
ctx := context.Background()
connectedSignal := signal.New(make(chan struct{}))
s.initialize(ctx, connectedSignal)
// Make sure we fell back to http2 as the mock Serve is wont to do.
assert.Equal(t, s.tunnelsProtocolFallback[0].protocol, connection.HTTP2)
// Ensure all the protocols we set to try are the same as what the first tunnel has fallen back to.
for _, protocolFallback := range s.tunnelsProtocolFallback {
assert.Equal(t, protocolFallback.protocol, s.tunnelsProtocolFallback[0].protocol)
}
}

View File

@@ -487,7 +487,7 @@ func (e *EdgeTunnelServer) serveConnection(
)
switch protocol {
case connection.QUIC, connection.QUICWarp:
case connection.QUIC:
connOptions := e.config.connectionOptions(addr.UDP.String(), uint8(backoff.Retries()))
return e.serveQUIC(ctx,
addr.UDP,
@@ -496,7 +496,7 @@ func (e *EdgeTunnelServer) serveConnection(
controlStream,
connIndex)
case connection.HTTP2, connection.HTTP2Warp:
case connection.HTTP2:
edgeConn, err := edgediscovery.DialEdge(ctx, dialTimeout, e.config.EdgeTLSConfigs[protocol], addr.TCP)
if err != nil {
connLog.ConnAwareLogger().Err(err).Msg("Unable to establish connection with Cloudflare edge")

View File

@@ -18,7 +18,7 @@ type dynamicMockFetcher struct {
err error
}
func (dmf *dynamicMockFetcher) fetch() connection.PercentageFetcher {
func (dmf *dynamicMockFetcher) fetch() edgediscovery.PercentageFetcher {
return func() (edgediscovery.ProtocolPercents, error) {
return dmf.protocolPercents, dmf.err
}
@@ -32,24 +32,22 @@ func TestWaitForBackoffFallback(t *testing.T) {
}
log := zerolog.Nop()
resolveTTL := time.Duration(0)
namedTunnel := &connection.NamedTunnelProperties{}
mockFetcher := dynamicMockFetcher{
protocolPercents: edgediscovery.ProtocolPercents{edgediscovery.ProtocolPercent{Protocol: "http2", Percentage: 100}},
protocolPercents: edgediscovery.ProtocolPercents{edgediscovery.ProtocolPercent{Protocol: "quic", Percentage: 100}},
}
warpRoutingEnabled := false
protocolSelector, err := connection.NewProtocolSelector(
"auto",
warpRoutingEnabled,
namedTunnel,
"",
false,
false,
mockFetcher.fetch(),
resolveTTL,
&log,
false,
)
assert.NoError(t, err)
initProtocol := protocolSelector.Current()
assert.Equal(t, connection.HTTP2, initProtocol)
assert.Equal(t, connection.QUIC, initProtocol)
protoFallback := &protocolFallback{
backoff,
@@ -100,12 +98,12 @@ func TestWaitForBackoffFallback(t *testing.T) {
// The reason why there's no fallback available is because we pick a specific protocol instead of letting it be auto.
protocolSelector, err = connection.NewProtocolSelector(
"quic",
warpRoutingEnabled,
namedTunnel,
"",
false,
false,
mockFetcher.fetch(),
resolveTTL,
&log,
false,
)
assert.NoError(t, err)
protoFallback = &protocolFallback{backoff, protocolSelector.Current(), false}