TUN-6339: Add config for IPv6 support

This commit is contained in:
Devin Carr 2022-06-02 10:57:37 -07:00
parent d714a62bd3
commit ee80e55833
10 changed files with 94 additions and 14 deletions

View File

@ -514,6 +514,12 @@ func tunnelFlags(shouldHide bool) []cli.Flag {
Usage: "Cloudflare Edge region to connect to. Omit or set to empty to connect to the global region.", Usage: "Cloudflare Edge region to connect to. Omit or set to empty to connect to the global region.",
EnvVars: []string{"TUNNEL_REGION"}, EnvVars: []string{"TUNNEL_REGION"},
}), }),
altsrc.NewStringFlag(&cli.StringFlag{
Name: "edge-ip-version",
Usage: "Cloudflare Edge ip address version to connect with. {4, 6, auto}",
EnvVars: []string{"TUNNEL_EDGE_IP_VERSION"},
Hidden: true,
}),
altsrc.NewStringFlag(&cli.StringFlag{ altsrc.NewStringFlag(&cli.StringFlag{
Name: tlsconfig.CaCertFlag, Name: tlsconfig.CaCertFlag,
Usage: "Certificate Authority authenticating connections with Cloudflare's edge network.", Usage: "Certificate Authority authenticating connections with Cloudflare's edge network.",

View File

@ -18,6 +18,7 @@ import (
"golang.org/x/crypto/ssh/terminal" "golang.org/x/crypto/ssh/terminal"
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil" "github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
"github.com/cloudflare/cloudflared/edgediscovery/allregions"
"github.com/cloudflare/cloudflared/config" "github.com/cloudflare/cloudflared/config"
"github.com/cloudflare/cloudflared/connection" "github.com/cloudflare/cloudflared/connection"
@ -324,6 +325,10 @@ func prepareTunnelConfig(
CompressionSetting: h2mux.CompressionSetting(uint64(c.Int("compression-quality"))), CompressionSetting: h2mux.CompressionSetting(uint64(c.Int("compression-quality"))),
MetricsUpdateFreq: c.Duration("metrics-update-freq"), MetricsUpdateFreq: c.Duration("metrics-update-freq"),
} }
edgeIPVersion, err := parseConfigIPVersion(c.String("edge-ip-version"))
if err != nil {
return nil, nil, err
}
tunnelConfig := &supervisor.TunnelConfig{ tunnelConfig := &supervisor.TunnelConfig{
GracePeriod: gracePeriod, GracePeriod: gracePeriod,
@ -332,6 +337,7 @@ func prepareTunnelConfig(
ClientID: clientID, ClientID: clientID,
EdgeAddrs: c.StringSlice("edge"), EdgeAddrs: c.StringSlice("edge"),
Region: c.String("region"), Region: c.String("region"),
EdgeIPVersion: edgeIPVersion,
HAConnections: c.Int("ha-connections"), HAConnections: c.Int("ha-connections"),
IncidentLookup: supervisor.NewIncidentLookup(), IncidentLookup: supervisor.NewIncidentLookup(),
IsAutoupdated: c.Bool("is-autoupdated"), IsAutoupdated: c.Bool("is-autoupdated"),
@ -404,3 +410,18 @@ func dedup(slice []string) []string {
} }
return keys return keys
} }
// ParseConfigIPVersion returns the IP version from possible expected values from config
func parseConfigIPVersion(version string) (v allregions.ConfigIPVersion, err error) {
switch version {
case "4":
v = allregions.IPv4Only
case "6":
v = allregions.IPv6Only
case "auto":
v = allregions.Auto
default: // unspecified or invalid
err = fmt.Errorf("invalid value for edge-ip-version: %s", version)
}
return
}

View File

@ -18,6 +18,15 @@ func (e DupConnRegisterTunnelError) Error() string {
return "already connected to this server, trying another address" return "already connected to this server, trying another address"
} }
// Dial to edge server with quic failed
type EdgeQuicDialError struct {
Cause error
}
func (e EdgeQuicDialError) Error() string {
return "failed to dial to edge with quic: " + e.Cause.Error()
}
// RegisterTunnel error from server // RegisterTunnel error from server
type ServerRegisterTunnelError struct { type ServerRegisterTunnelError struct {
Cause error Cause error

View File

@ -1,6 +1,7 @@
package connection package connection
import ( import (
"net"
"strings" "strings"
"github.com/rs/zerolog" "github.com/rs/zerolog"
@ -8,6 +9,7 @@ import (
const ( const (
LogFieldLocation = "location" LogFieldLocation = "location"
LogFieldIPAddress = "ip"
observerChannelBufferSize = 16 observerChannelBufferSize = 16
) )
@ -41,11 +43,12 @@ func (o *Observer) RegisterSink(sink EventSink) {
o.addSinkChan <- sink o.addSinkChan <- sink
} }
func (o *Observer) logServerInfo(connIndex uint8, location, msg string) { func (o *Observer) logServerInfo(connIndex uint8, location string, address net.IP, msg string) {
o.sendEvent(Event{Index: connIndex, EventType: Connected, Location: location}) o.sendEvent(Event{Index: connIndex, EventType: Connected, Location: location})
o.log.Info(). o.log.Info().
Uint8(LogFieldConnIndex, connIndex). Uint8(LogFieldConnIndex, connIndex).
Str(LogFieldLocation, location). Str(LogFieldLocation, location).
IPAddr(LogFieldIPAddress, address).
Msg(msg) Msg(msg)
o.metrics.registerServerLocation(uint8ToString(connIndex), location) o.metrics.registerServerLocation(uint8ToString(connIndex), location)
} }

View File

@ -55,7 +55,7 @@ func NewQUICConnection(
) (*QUICConnection, error) { ) (*QUICConnection, error) {
session, err := quic.DialAddr(edgeAddr.String(), tlsConfig, quicConfig) session, err := quic.DialAddr(edgeAddr.String(), tlsConfig, quicConfig)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to dial to edge: %w", err) return nil, EdgeQuicDialError{Cause: err}
} }
datagramMuxer, err := quicpogs.NewDatagramMuxer(session, logger) datagramMuxer, err := quicpogs.NewDatagramMuxer(session, logger)

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"net"
"time" "time"
"github.com/rs/zerolog" "github.com/rs/zerolog"
@ -114,7 +115,7 @@ func (rsc *registrationServerClient) RegisterConnection(
observer.metrics.regSuccess.WithLabelValues("registerConnection").Inc() observer.metrics.regSuccess.WithLabelValues("registerConnection").Inc()
observer.logServerInfo(connIndex, conn.Location, fmt.Sprintf("Connection %s registered", conn.UUID)) observer.logServerInfo(connIndex, conn.Location, options.OriginLocalIP, fmt.Sprintf("Connection %s registered", conn.UUID))
observer.sendConnectedEvent(connIndex, conn.Location) observer.sendConnectedEvent(connIndex, conn.Location)
return conn, nil return conn, nil
@ -274,7 +275,7 @@ func (h *h2muxConnection) logServerInfo(ctx context.Context, rpcClient *tunnelSe
h.observer.log.Err(err).Msg("Failed to retrieve server information") h.observer.log.Err(err).Msg("Failed to retrieve server information")
return err return err
} }
h.observer.logServerInfo(h.connIndex, serverInfo.LocationName, "Connection established") h.observer.logServerInfo(h.connIndex, serverInfo.LocationName, net.IP{}, "Connection established")
return nil return nil
} }

View File

@ -32,10 +32,40 @@ var (
netLookupIP = net.LookupIP netLookupIP = net.LookupIP
) )
// ConfigIPVersion is the selection of IP versions from config
type ConfigIPVersion int8
const (
Auto ConfigIPVersion = 2
IPv4Only ConfigIPVersion = 4
IPv6Only ConfigIPVersion = 6
)
// IPVersion is the IP version of an EdgeAddr
type EdgeIPVersion int8
const (
V4 EdgeIPVersion = 4
V6 EdgeIPVersion = 6
)
// String returns the enum's constant name.
func (c EdgeIPVersion) String() string {
switch c {
case V4:
return "4"
case V6:
return "6"
default:
return ""
}
}
// EdgeAddr is a representation of possible ways to refer an edge location. // EdgeAddr is a representation of possible ways to refer an edge location.
type EdgeAddr struct { type EdgeAddr struct {
TCP *net.TCPAddr TCP *net.TCPAddr
UDP *net.UDPAddr UDP *net.UDPAddr
IPVersion EdgeIPVersion
} }
// If the call to net.LookupSRV fails, try to fall back to DoT from Cloudflare directly. // If the call to net.LookupSRV fails, try to fall back to DoT from Cloudflare directly.
@ -120,9 +150,14 @@ func resolveSRV(srv *net.SRV) ([]*EdgeAddr, error) {
} }
addrs := make([]*EdgeAddr, len(ips)) addrs := make([]*EdgeAddr, len(ips))
for i, ip := range ips { for i, ip := range ips {
version := V6
if ip.To4() != nil {
version = V4
}
addrs[i] = &EdgeAddr{ addrs[i] = &EdgeAddr{
TCP: &net.TCPAddr{IP: ip, Port: int(srv.Port)}, TCP: &net.TCPAddr{IP: ip, Port: int(srv.Port)},
UDP: &net.UDPAddr{IP: ip, Port: int(srv.Port)}, UDP: &net.UDPAddr{IP: ip, Port: int(srv.Port)},
IPVersion: version,
} }
} }
return addrs, nil return addrs, nil
@ -143,9 +178,14 @@ func ResolveAddrs(addrs []string, log *zerolog.Logger) (resolved []*EdgeAddr) {
log.Error().Str(logFieldAddress, addr).Err(err).Msg("failed to resolve to UDP address") log.Error().Str(logFieldAddress, addr).Err(err).Msg("failed to resolve to UDP address")
continue continue
} }
version := V6
if udpAddr.IP.To4() != nil {
version = V4
}
resolved = append(resolved, &EdgeAddr{ resolved = append(resolved, &EdgeAddr{
TCP: tcpAddr, TCP: tcpAddr,
UDP: udpAddr, UDP: udpAddr,
IPVersion: version,
}) })
} }

View File

@ -36,7 +36,7 @@ func newMockAddrs(port uint16, numRegions uint8, numAddrsPerRegion uint8) mockAd
IP: net.ParseIP(fmt.Sprintf("10.0.%v.%v", r, a)), IP: net.ParseIP(fmt.Sprintf("10.0.%v.%v", r, a)),
Port: int(port), Port: int(port),
} }
addrs = append(addrs, &EdgeAddr{tcpAddr, udpAddr}) addrs = append(addrs, &EdgeAddr{tcpAddr, udpAddr, V4})
} }
addrMap[srv] = addrs addrMap[srv] = addrs
numAddrs += len(addrs) numAddrs += len(addrs)

View File

@ -63,7 +63,6 @@ var errEarlyShutdown = errors.New("shutdown started")
type tunnelError struct { type tunnelError struct {
index int index int
addr *allregions.EdgeAddr
err error err error
} }
@ -235,7 +234,7 @@ func (s *Supervisor) startFirstTunnel(
) )
const firstConnIndex = 0 const firstConnIndex = 0
defer func() { defer func() {
s.tunnelErrors <- tunnelError{index: firstConnIndex, addr: addr, err: err} s.tunnelErrors <- tunnelError{index: firstConnIndex, err: err}
}() }()
addr, err = s.edgeIPs.GetAddr(firstConnIndex) addr, err = s.edgeIPs.GetAddr(firstConnIndex)
@ -306,7 +305,7 @@ func (s *Supervisor) startTunnel(
err error err error
) )
defer func() { defer func() {
s.tunnelErrors <- tunnelError{index: index, addr: addr, err: err} s.tunnelErrors <- tunnelError{index: index, err: err}
}() }()
addr, err = s.edgeIPs.GetDifferentAddr(index) addr, err = s.edgeIPs.GetDifferentAddr(index)

View File

@ -43,6 +43,7 @@ type TunnelConfig struct {
CloseConnOnce *sync.Once // Used to close connectedSignal no more than once CloseConnOnce *sync.Once // Used to close connectedSignal no more than once
EdgeAddrs []string EdgeAddrs []string
Region string Region string
EdgeIPVersion allregions.ConfigIPVersion
HAConnections int HAConnections int
IncidentLookup IncidentLookup IncidentLookup IncidentLookup
IsAutoupdated bool IsAutoupdated bool