diff --git a/cmd/cloudflared/tunnel/configuration.go b/cmd/cloudflared/tunnel/configuration.go index 9200a2e9..0a2bb24b 100644 --- a/cmd/cloudflared/tunnel/configuration.go +++ b/cmd/cloudflared/tunnel/configuration.go @@ -348,11 +348,24 @@ func prepareTunnelConfig( if err != nil { return nil, nil, err } - edgeBindAddr, err := parseConfigBindAddress(c.String("edge-bind-address")) if err != nil { return nil, nil, err } + if ok, err := isIPHostLocal(edgeBindAddr); !ok { + if err != nil { + // There could be unforeseen reasons that net.InterfaceAddrs() may fail + // Better not to be fatal here, or it could be annoying for users + log.Warn().Msgf("Cannot determine if edge-bind-address is available: %v", err) + } else { + return nil, nil, fmt.Errorf("edge-bind-address is not local to this host: %s", edgeBindAddr) + } + } + edgeIPVersion, err = adjustIPVersionByBindAddress(edgeIPVersion, edgeBindAddr) + if err != nil { + // This is not a fatal error, we just overrode edgeIPVersion + log.Warn().Msgf("Overriding edge-ip-version to %s: %v", edgeIPVersion, err) + } var pqKexIdx int if needPQ { @@ -481,6 +494,37 @@ func parseConfigBindAddress(ipstr string) (net.IP, error) { return ip, nil } +func isIPHostLocal(ip net.IP) (bool, error) { + addrs, err := net.InterfaceAddrs() + if err != nil { + return false, err + } + for _, addr := range addrs { + if ip.Equal(addr.(*net.IPNet).IP) { + return true, nil + } + } + return false, nil +} + +func adjustIPVersionByBindAddress(ipVersion allregions.ConfigIPVersion, ip net.IP) (allregions.ConfigIPVersion, error) { + if ip == nil { + return ipVersion, nil + } + // https://pkg.go.dev/net#IP.To4: "If ip is not an IPv4 address, To4 returns nil." + if ip.To4() != nil { + if ipVersion == allregions.IPv6Only { + return allregions.IPv4Only, fmt.Errorf("IPv4 bind address is specified, but edge-ip-version is IPv6") + } + return allregions.IPv4Only, nil + } else { + if ipVersion == allregions.IPv4Only { + return allregions.IPv6Only, fmt.Errorf("IPv6 bind address is specified, but edge-ip-version is IPv4") + } + return allregions.IPv6Only, nil + } +} + func newPacketConfig(c *cli.Context, logger *zerolog.Logger) (*ingress.GlobalRouterConfig, error) { ipv4Src, err := determineICMPv4Src(c.String("icmpv4-src"), logger) if err != nil { diff --git a/edgediscovery/allregions/discovery.go b/edgediscovery/allregions/discovery.go index dafaac13..e6c6105e 100644 --- a/edgediscovery/allregions/discovery.go +++ b/edgediscovery/allregions/discovery.go @@ -41,6 +41,19 @@ const ( IPv6Only ConfigIPVersion = 6 ) +func (c ConfigIPVersion) String() string { + switch c { + case Auto: + return "auto" + case IPv4Only: + return "4" + case IPv6Only: + return "6" + default: + return "" + } +} + // IPVersion is the IP version of an EdgeAddr type EdgeIPVersion int8