TUN-9470: Add OriginDialerService to include TCP

Adds an OriginDialerService that takes over the roles of both DialUDP and DialTCP 
towards the origin. This provides the possibility to leverage dialer "middleware"
to inject virtual origins, such as the DNS resolver service.

DNS Resolver service also gains access to the DialTCP operation to service TCP
DNS requests.

Minor refactoring includes changes to remove the needs previously provided by
the warp-routing configuration. This configuration cannot be disabled by cloudflared
so many of the references have been adjusted or removed.

Closes TUN-9470
This commit is contained in:
Devin Carr
2025-06-30 13:24:16 -07:00
parent 9ca8b41cf7
commit 70ed7ffc5f
19 changed files with 503 additions and 254 deletions

View File

@@ -40,13 +40,13 @@ type SessionManager interface {
type sessionManager struct {
sessions map[RequestID]Session
mutex sync.RWMutex
originDialer ingress.UDPOriginProxy
originDialer ingress.OriginUDPDialer
limiter cfdflow.Limiter
metrics Metrics
log *zerolog.Logger
}
func NewSessionManager(metrics Metrics, log *zerolog.Logger, originDialer ingress.UDPOriginProxy, limiter cfdflow.Limiter) SessionManager {
func NewSessionManager(metrics Metrics, log *zerolog.Logger, originDialer ingress.OriginUDPDialer, limiter cfdflow.Limiter) SessionManager {
return &sessionManager{
sessions: make(map[RequestID]Session),
originDialer: originDialer,

View File

@@ -11,6 +11,7 @@ import (
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"github.com/cloudflare/cloudflared/config"
"github.com/cloudflare/cloudflared/mocks"
cfdflow "github.com/cloudflare/cloudflared/flow"
@@ -18,9 +19,21 @@ import (
v3 "github.com/cloudflare/cloudflared/quic/v3"
)
var (
testDefaultDialer = ingress.NewDialer(ingress.WarpRoutingConfig{
ConnectTimeout: config.CustomDuration{Duration: 1 * time.Second},
TCPKeepAlive: config.CustomDuration{Duration: 15 * time.Second},
MaxActiveFlows: 0,
})
)
func TestRegisterSession(t *testing.T) {
log := zerolog.Nop()
manager := v3.NewSessionManager(&noopMetrics{}, &log, ingress.DefaultUDPDialer, cfdflow.NewLimiter(0))
originDialerService := ingress.NewOriginDialer(ingress.OriginConfig{
DefaultDialer: testDefaultDialer,
TCPWriteTimeout: 0,
}, &log)
manager := v3.NewSessionManager(&noopMetrics{}, &log, originDialerService, cfdflow.NewLimiter(0))
request := v3.UDPSessionRegistrationDatagram{
RequestID: testRequestID,
@@ -76,7 +89,11 @@ func TestRegisterSession(t *testing.T) {
func TestGetSession_Empty(t *testing.T) {
log := zerolog.Nop()
manager := v3.NewSessionManager(&noopMetrics{}, &log, ingress.DefaultUDPDialer, cfdflow.NewLimiter(0))
originDialerService := ingress.NewOriginDialer(ingress.OriginConfig{
DefaultDialer: testDefaultDialer,
TCPWriteTimeout: 0,
}, &log)
manager := v3.NewSessionManager(&noopMetrics{}, &log, originDialerService, cfdflow.NewLimiter(0))
_, err := manager.GetSession(testRequestID)
if !errors.Is(err, v3.ErrSessionNotFound) {
@@ -86,6 +103,10 @@ func TestGetSession_Empty(t *testing.T) {
func TestRegisterSessionRateLimit(t *testing.T) {
log := zerolog.Nop()
originDialerService := ingress.NewOriginDialer(ingress.OriginConfig{
DefaultDialer: testDefaultDialer,
TCPWriteTimeout: 0,
}, &log)
ctrl := gomock.NewController(t)
flowLimiterMock := mocks.NewMockLimiter(ctrl)
@@ -93,7 +114,7 @@ func TestRegisterSessionRateLimit(t *testing.T) {
flowLimiterMock.EXPECT().Acquire("udp").Return(cfdflow.ErrTooManyActiveFlows)
flowLimiterMock.EXPECT().Release().Times(0)
manager := v3.NewSessionManager(&noopMetrics{}, &log, ingress.DefaultUDPDialer, flowLimiterMock)
manager := v3.NewSessionManager(&noopMetrics{}, &log, originDialerService, flowLimiterMock)
request := v3.UDPSessionRegistrationDatagram{
RequestID: testRequestID,

View File

@@ -88,7 +88,11 @@ func (m *mockEyeball) SendICMPTTLExceed(icmp *packet.ICMP, rawPacket packet.RawP
func TestDatagramConn_New(t *testing.T) {
log := zerolog.Nop()
conn := v3.NewDatagramConn(newMockQuicConn(), v3.NewSessionManager(&noopMetrics{}, &log, ingress.DefaultUDPDialer, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log)
originDialerService := ingress.NewOriginDialer(ingress.OriginConfig{
DefaultDialer: testDefaultDialer,
TCPWriteTimeout: 0,
}, &log)
conn := v3.NewDatagramConn(newMockQuicConn(), v3.NewSessionManager(&noopMetrics{}, &log, originDialerService, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log)
if conn == nil {
t.Fatal("expected valid connection")
}
@@ -96,8 +100,12 @@ func TestDatagramConn_New(t *testing.T) {
func TestDatagramConn_SendUDPSessionDatagram(t *testing.T) {
log := zerolog.Nop()
originDialerService := ingress.NewOriginDialer(ingress.OriginConfig{
DefaultDialer: testDefaultDialer,
TCPWriteTimeout: 0,
}, &log)
quic := newMockQuicConn()
conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, ingress.DefaultUDPDialer, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log)
conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, originDialerService, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log)
payload := []byte{0xef, 0xef}
err := conn.SendUDPSessionDatagram(payload)
@@ -111,8 +119,12 @@ func TestDatagramConn_SendUDPSessionDatagram(t *testing.T) {
func TestDatagramConn_SendUDPSessionResponse(t *testing.T) {
log := zerolog.Nop()
originDialerService := ingress.NewOriginDialer(ingress.OriginConfig{
DefaultDialer: testDefaultDialer,
TCPWriteTimeout: 0,
}, &log)
quic := newMockQuicConn()
conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, ingress.DefaultUDPDialer, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log)
conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, originDialerService, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log)
err := conn.SendUDPSessionResponse(testRequestID, v3.ResponseDestinationUnreachable)
require.NoError(t, err)
@@ -133,8 +145,12 @@ func TestDatagramConn_SendUDPSessionResponse(t *testing.T) {
func TestDatagramConnServe_ApplicationClosed(t *testing.T) {
log := zerolog.Nop()
originDialerService := ingress.NewOriginDialer(ingress.OriginConfig{
DefaultDialer: testDefaultDialer,
TCPWriteTimeout: 0,
}, &log)
quic := newMockQuicConn()
conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, ingress.DefaultUDPDialer, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log)
conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, originDialerService, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log)
ctx, cancel := context.WithTimeout(t.Context(), 1*time.Second)
defer cancel()
@@ -146,11 +162,15 @@ func TestDatagramConnServe_ApplicationClosed(t *testing.T) {
func TestDatagramConnServe_ConnectionClosed(t *testing.T) {
log := zerolog.Nop()
originDialerService := ingress.NewOriginDialer(ingress.OriginConfig{
DefaultDialer: testDefaultDialer,
TCPWriteTimeout: 0,
}, &log)
quic := newMockQuicConn()
ctx, cancel := context.WithTimeout(t.Context(), 1*time.Second)
defer cancel()
quic.ctx = ctx
conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, ingress.DefaultUDPDialer, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log)
conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, originDialerService, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log)
err := conn.Serve(t.Context())
if !errors.Is(err, context.DeadlineExceeded) {
@@ -160,8 +180,12 @@ func TestDatagramConnServe_ConnectionClosed(t *testing.T) {
func TestDatagramConnServe_ReceiveDatagramError(t *testing.T) {
log := zerolog.Nop()
originDialerService := ingress.NewOriginDialer(ingress.OriginConfig{
DefaultDialer: testDefaultDialer,
TCPWriteTimeout: 0,
}, &log)
quic := &mockQuicConnReadError{err: net.ErrClosed}
conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, ingress.DefaultUDPDialer, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log)
conn := v3.NewDatagramConn(quic, v3.NewSessionManager(&noopMetrics{}, &log, originDialerService, cfdflow.NewLimiter(0)), &noopICMPRouter{}, 0, &noopMetrics{}, &log)
err := conn.Serve(t.Context())
if !errors.Is(err, net.ErrClosed) {