diff --git a/pkg/agent/config/config.go b/pkg/agent/config/config.go index a35410014a..26d4069f0d 100644 --- a/pkg/agent/config/config.go +++ b/pkg/agent/config/config.go @@ -390,15 +390,24 @@ func get(ctx context.Context, envInfo *cmds.Agent, proxy proxy.Proxy) (*config.N if err != nil { return nil, err } - if len(vpnInfo.IPs) != 0 { - logrus.Infof("Node-ip changed to %v due to VPN", vpnInfo.IPs) + + var vpnIPs []net.IP + if vpnInfo.IPv4Address != nil { + vpnIPs = append(vpnIPs, vpnInfo.IPv4Address) + } + if vpnInfo.IPv6Address != nil { + vpnIPs = append(vpnIPs, vpnInfo.IPv6Address) + } + + if len(vpnIPs) != 0 { + logrus.Infof("Node-ip changed to %v due to VPN", vpnIPs) if len(envInfo.NodeIP) != 0 { logrus.Warn("VPN provider overrides configured node-ip parameter") } if len(envInfo.NodeExternalIP) != 0 { logrus.Warn("VPN provider overrides node-external-ip parameter") } - nodeIPs = vpnInfo.IPs + nodeIPs = vpnIPs flannelIface, err = net.InterfaceByName(vpnInfo.VPNInterface) if err != nil { return nil, errors.Wrapf(err, "unable to find vpn interface: %s", vpnInfo.VPNInterface) diff --git a/pkg/cli/server/server.go b/pkg/cli/server/server.go index caf86c254f..f41fe1aeda 100644 --- a/pkg/cli/server/server.go +++ b/pkg/cli/server/server.go @@ -228,12 +228,27 @@ func run(app *cli.Context, cfg *cmds.Server, leaderControllers server.CustomCont if err != nil { return err } - if len(vpnInfo.IPs) != 0 { - logrus.Infof("Advertise-address changed to %v due to VPN", vpnInfo.IPs) - if serverConfig.ControlConfig.AdvertiseIP != "" { - logrus.Warn("Conflict in the config detected. VPN integration overwrites advertise-address but the config is setting the advertise-address parameter") + // If we are in ipv6-only mode, we should pass the ipv6 address. Otherwise, ipv4 + if utilsnet.IsIPv6CIDRString(util.JoinIPNets(serverConfig.ControlConfig.ClusterIPRanges)) { + if vpnInfo.IPv6Address != nil { + logrus.Infof("Advertise-address changed to %v due to VPN", vpnInfo.IPv6Address) + if serverConfig.ControlConfig.AdvertiseIP != "" { + logrus.Warn("Conflict in the config detected. VPN integration overwrites advertise-address but the config is setting the advertise-address parameter") + } + serverConfig.ControlConfig.AdvertiseIP = vpnInfo.IPv6Address.String() + } else { + return errors.New("tailscale does not provide an ipv6 address") + } + } else { + if vpnInfo.IPv4Address != nil { + logrus.Infof("Advertise-address changed to %v due to VPN", vpnInfo.IPv4Address) + if serverConfig.ControlConfig.AdvertiseIP != "" { + logrus.Warn("Conflict in the config detected. VPN integration overwrites advertise-address but the config is setting the advertise-address parameter") + } + serverConfig.ControlConfig.AdvertiseIP = vpnInfo.IPv4Address.String() + } else { + return errors.New("tailscale does not provide an ipv4 address") } - serverConfig.ControlConfig.AdvertiseIP = vpnInfo.IPs[0].String() } logrus.Warn("Etcd IP (PrivateIP) remains the local IP. Running etcd traffic over VPN is not recommended due to performance issues") } else { diff --git a/pkg/util/net.go b/pkg/util/net.go index 5a949a20a9..913d90736d 100644 --- a/pkg/util/net.go +++ b/pkg/util/net.go @@ -10,6 +10,7 @@ import ( "github.com/sirupsen/logrus" "github.com/urfave/cli" apinet "k8s.io/apimachinery/pkg/util/net" + netutils "k8s.io/utils/net" ) // JoinIPs stringifies and joins a list of IP addresses with commas. @@ -85,10 +86,9 @@ func JoinIP4Nets(elems []*net.IPNet) string { // If no IPv6 addresses are found, an error is raised. func GetFirst6(elems []net.IP) (net.IP, error) { for _, elem := range elems { - if elem == nil || elem.To16() == nil { - continue + if elem != nil && netutils.IsIPv6(elem) { + return elem, nil } - return elem, nil } return nil, errors.New("no IPv6 address found") } @@ -97,10 +97,9 @@ func GetFirst6(elems []net.IP) (net.IP, error) { // If no IPv6 addresses are found, an error is raised. func GetFirst6Net(elems []*net.IPNet) (*net.IPNet, error) { for _, elem := range elems { - if elem == nil || elem.IP.To16() == nil { - continue + if elem != nil && netutils.IsIPv6(elem.IP) { + return elem, nil } - return elem, nil } return nil, errors.New("no IPv6 CIDRs found") } @@ -125,7 +124,7 @@ func GetFirst6String(elems []string) (string, error) { func JoinIP6Nets(elems []*net.IPNet) string { var strs []string for _, elem := range elems { - if elem != nil && elem.IP.To4() == nil { + if elem != nil && netutils.IsIPv6(elem.IP) { strs = append(strs, elem.String()) } } diff --git a/pkg/vpn/vpn.go b/pkg/vpn/vpn.go index 77a628d28c..466b145590 100644 --- a/pkg/vpn/vpn.go +++ b/pkg/vpn/vpn.go @@ -22,7 +22,8 @@ type TailscaleOutput struct { // VPNInfo includes node information of the VPN. It is a general struct in case we want to add more vpn integrations type VPNInfo struct { - IPs []net.IP + IPv4Address net.IP + IPv6Address net.IP NodeID string ProviderName string VPNInterface string @@ -112,15 +113,14 @@ func getTailscaleInfo() (VPNInfo, error) { logrus.Debugf("Output from tailscale status --json: %v", output) var tailscaleOutput TailscaleOutput - var internalIPs []net.IP err = json.Unmarshal([]byte(output), &tailscaleOutput) if err != nil { return VPNInfo{}, fmt.Errorf("failed to unmarshal tailscale output: %v", err) } - for _, address := range tailscaleOutput.TailscaleIPs { - internalIPs = append(internalIPs, net.ParseIP(address)) - } + // Errors are ignored because the interface might not have ipv4 or ipv6 addresses (that's the only possible error) + ipv4Address, _ := util.GetFirst4String(tailscaleOutput.TailscaleIPs) + ipv6Address, _ := util.GetFirst6String(tailscaleOutput.TailscaleIPs) - return VPNInfo{IPs: internalIPs, NodeID: "", ProviderName: "tailscale", VPNInterface: tailscaleIf}, nil + return VPNInfo{IPv4Address: net.ParseIP(ipv4Address), IPv6Address: net.ParseIP(ipv6Address), NodeID: "", ProviderName: "tailscale", VPNInterface: tailscaleIf}, nil }