mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-27 16:49:57 +00:00
TUN-9469: Centralize UDP origin proxy dialing as ingress service
Introduces a new `UDPOriginProxy` interface and `UDPOriginService` to standardize how UDP connections are dialed to origins. Allows for future overrides of the ingress service for specific dial destinations. Simplifies dependency injection for UDP dialing throughout both datagram v2 and v3 by using the same ingress service. Previous invocations called into a DialUDP function in the ingress package that was a light wrapper over `net.DialUDP`. Now a reference is passed into both datagram controllers that allows more control over the DialUDP method. Closes TUN-9469
This commit is contained in:
@@ -2,37 +2,57 @@ package ingress
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
type UDPProxy interface {
|
||||
io.ReadWriteCloser
|
||||
LocalAddr() net.Addr
|
||||
// UDPOriginService provides a proxy UDP dialer to origin services while allowing reserved
|
||||
// services to be provided. These reserved services are assigned to specific [netip.AddrPort]s
|
||||
// and provide their own [UDPOriginProxy]s to handle UDP origin dialing.
|
||||
type UDPOriginService struct {
|
||||
// Reserved services for reserved AddrPort values
|
||||
reservedServices map[netip.AddrPort]UDPOriginProxy
|
||||
// The default UDP Dialer used if no reserved services are found for an origin request.
|
||||
defaultDialer UDPOriginProxy
|
||||
|
||||
logger *zerolog.Logger
|
||||
}
|
||||
|
||||
type udpProxy struct {
|
||||
*net.UDPConn
|
||||
// UDPOriginProxy provides a UDP dial operation to a requested addr.
|
||||
type UDPOriginProxy interface {
|
||||
DialUDP(addr netip.AddrPort) (*net.UDPConn, error)
|
||||
}
|
||||
|
||||
func DialUDP(dstIP net.IP, dstPort uint16) (UDPProxy, error) {
|
||||
dstAddr := &net.UDPAddr{
|
||||
IP: dstIP,
|
||||
Port: int(dstPort),
|
||||
func NewUDPOriginService(reserved map[netip.AddrPort]UDPOriginProxy, logger *zerolog.Logger) *UDPOriginService {
|
||||
return &UDPOriginService{
|
||||
reservedServices: reserved,
|
||||
defaultDialer: DefaultUDPDialer,
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
// We use nil as local addr to force runtime to find the best suitable local address IP given the destination
|
||||
// address as context.
|
||||
udpConn, err := net.DialUDP("udp", nil, dstAddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create UDP proxy to origin (%v:%v): %w", dstIP, dstPort, err)
|
||||
}
|
||||
|
||||
return &udpProxy{udpConn}, nil
|
||||
}
|
||||
|
||||
func DialUDPAddrPort(dest netip.AddrPort) (*net.UDPConn, error) {
|
||||
// SetUDPDialer updates the default UDP Dialer used.
|
||||
// Typically used in unit testing.
|
||||
func (s *UDPOriginService) SetDefaultDialer(dialer UDPOriginProxy) {
|
||||
s.defaultDialer = dialer
|
||||
}
|
||||
|
||||
// DialUDP will perform a dial UDP to the requested addr.
|
||||
func (s *UDPOriginService) DialUDP(addr netip.AddrPort) (*net.UDPConn, error) {
|
||||
// Check to see if any reserved services are available for this addr and call their dialer instead.
|
||||
if dialer, ok := s.reservedServices[addr]; ok {
|
||||
return dialer.DialUDP(addr)
|
||||
}
|
||||
return s.defaultDialer.DialUDP(addr)
|
||||
}
|
||||
|
||||
type defaultUDPDialer struct{}
|
||||
|
||||
var DefaultUDPDialer UDPOriginProxy = &defaultUDPDialer{}
|
||||
|
||||
func (d *defaultUDPDialer) DialUDP(dest netip.AddrPort) (*net.UDPConn, error) {
|
||||
addr := net.UDPAddrFromAddrPort(dest)
|
||||
|
||||
// We use nil as local addr to force runtime to find the best suitable local address IP given the destination
|
||||
|
Reference in New Issue
Block a user