Merge pull request #7883 from manuelbuil/ip4ip6dualstack125

[Release 1.25] Check if we are on ipv4, ipv6 or dualStack when doing tailscale
pull/7894/head
Manuel Buil 2023-07-07 11:28:28 +02:00 committed by GitHub
commit a827ad28dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 21 deletions

View File

@ -390,15 +390,24 @@ func get(ctx context.Context, envInfo *cmds.Agent, proxy proxy.Proxy) (*config.N
if err != nil { if err != nil {
return nil, err 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 { if len(envInfo.NodeIP) != 0 {
logrus.Warn("VPN provider overrides configured node-ip parameter") logrus.Warn("VPN provider overrides configured node-ip parameter")
} }
if len(envInfo.NodeExternalIP) != 0 { if len(envInfo.NodeExternalIP) != 0 {
logrus.Warn("VPN provider overrides node-external-ip parameter") logrus.Warn("VPN provider overrides node-external-ip parameter")
} }
nodeIPs = vpnInfo.IPs nodeIPs = vpnIPs
flannelIface, err = net.InterfaceByName(vpnInfo.VPNInterface) flannelIface, err = net.InterfaceByName(vpnInfo.VPNInterface)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "unable to find vpn interface: %s", vpnInfo.VPNInterface) return nil, errors.Wrapf(err, "unable to find vpn interface: %s", vpnInfo.VPNInterface)

View File

@ -232,12 +232,27 @@ func run(app *cli.Context, cfg *cmds.Server, leaderControllers server.CustomCont
if err != nil { if err != nil {
return err return err
} }
if len(vpnInfo.IPs) != 0 { // If we are in ipv6-only mode, we should pass the ipv6 address. Otherwise, ipv4
logrus.Infof("Advertise-address changed to %v due to VPN", vpnInfo.IPs) 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 != "" { 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") 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.IPs[0].String() 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")
}
} }
logrus.Warn("Etcd IP (PrivateIP) remains the local IP. Running etcd traffic over VPN is not recommended due to performance issues") logrus.Warn("Etcd IP (PrivateIP) remains the local IP. Running etcd traffic over VPN is not recommended due to performance issues")
} else { } else {

View File

@ -10,6 +10,7 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
apinet "k8s.io/apimachinery/pkg/util/net" apinet "k8s.io/apimachinery/pkg/util/net"
netutils "k8s.io/utils/net"
) )
// JoinIPs stringifies and joins a list of IP addresses with commas. // JoinIPs stringifies and joins a list of IP addresses with commas.
@ -85,11 +86,10 @@ func JoinIP4Nets(elems []*net.IPNet) string {
// If no IPv6 addresses are found, an error is raised. // If no IPv6 addresses are found, an error is raised.
func GetFirst6(elems []net.IP) (net.IP, error) { func GetFirst6(elems []net.IP) (net.IP, error) {
for _, elem := range elems { for _, elem := range elems {
if elem == nil || elem.To16() == nil { if elem != nil && netutils.IsIPv6(elem) {
continue
}
return elem, nil return elem, nil
} }
}
return nil, errors.New("no IPv6 address found") return nil, errors.New("no IPv6 address found")
} }
@ -97,11 +97,10 @@ func GetFirst6(elems []net.IP) (net.IP, error) {
// If no IPv6 addresses are found, an error is raised. // If no IPv6 addresses are found, an error is raised.
func GetFirst6Net(elems []*net.IPNet) (*net.IPNet, error) { func GetFirst6Net(elems []*net.IPNet) (*net.IPNet, error) {
for _, elem := range elems { for _, elem := range elems {
if elem == nil || elem.IP.To16() == nil { if elem != nil && netutils.IsIPv6(elem.IP) {
continue
}
return elem, nil return elem, nil
} }
}
return nil, errors.New("no IPv6 CIDRs found") return nil, errors.New("no IPv6 CIDRs found")
} }
@ -125,7 +124,7 @@ func GetFirst6String(elems []string) (string, error) {
func JoinIP6Nets(elems []*net.IPNet) string { func JoinIP6Nets(elems []*net.IPNet) string {
var strs []string var strs []string
for _, elem := range elems { for _, elem := range elems {
if elem != nil && elem.IP.To4() == nil { if elem != nil && netutils.IsIPv6(elem.IP) {
strs = append(strs, elem.String()) strs = append(strs, elem.String())
} }
} }

View File

@ -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 // VPNInfo includes node information of the VPN. It is a general struct in case we want to add more vpn integrations
type VPNInfo struct { type VPNInfo struct {
IPs []net.IP IPv4Address net.IP
IPv6Address net.IP
NodeID string NodeID string
ProviderName string ProviderName string
VPNInterface string VPNInterface string
@ -112,15 +113,14 @@ func getTailscaleInfo() (VPNInfo, error) {
logrus.Debugf("Output from tailscale status --json: %v", output) logrus.Debugf("Output from tailscale status --json: %v", output)
var tailscaleOutput TailscaleOutput var tailscaleOutput TailscaleOutput
var internalIPs []net.IP
err = json.Unmarshal([]byte(output), &tailscaleOutput) err = json.Unmarshal([]byte(output), &tailscaleOutput)
if err != nil { if err != nil {
return VPNInfo{}, fmt.Errorf("failed to unmarshal tailscale output: %v", err) return VPNInfo{}, fmt.Errorf("failed to unmarshal tailscale output: %v", err)
} }
for _, address := range tailscaleOutput.TailscaleIPs { // Errors are ignored because the interface might not have ipv4 or ipv6 addresses (that's the only possible error)
internalIPs = append(internalIPs, net.ParseIP(address)) 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
} }