diff --git a/jobsupervisor/provider_windows.go b/jobsupervisor/provider_windows.go index 0e5cd07cd..ea02a2cfc 100644 --- a/jobsupervisor/provider_windows.go +++ b/jobsupervisor/provider_windows.go @@ -31,7 +31,7 @@ func NewProvider( fs := platform.GetFs() runner := platform.GetRunner() - network, err := platform.GetDefaultNetwork() + network, err := platform.GetDefaultNetwork(false) var machineIP string if err != nil { machineIP, _ = os.Hostname() //nolint:errcheck diff --git a/platform/dummy_platform.go b/platform/dummy_platform.go index 40fcc1c73..cd47a6fb0 100644 --- a/platform/dummy_platform.go +++ b/platform/dummy_platform.go @@ -498,7 +498,7 @@ func (p dummyPlatform) DeleteARPEntryWithIP(ip string) error { return nil } -func (p dummyPlatform) GetDefaultNetwork() (boshsettings.Network, error) { +func (p dummyPlatform) GetDefaultNetwork(is_ipv6 bool) (boshsettings.Network, error) { var network boshsettings.Network networkPath := filepath.Join(p.dirProvider.BoshDir(), "dummy-default-network-settings.json") diff --git a/platform/linux_platform.go b/platform/linux_platform.go index 5d0fed6d6..d32a79654 100644 --- a/platform/linux_platform.go +++ b/platform/linux_platform.go @@ -1530,8 +1530,8 @@ func (p linux) DeleteARPEntryWithIP(ip string) error { return nil } -func (p linux) GetDefaultNetwork() (boshsettings.Network, error) { - return p.defaultNetworkResolver.GetDefaultNetwork() +func (p linux) GetDefaultNetwork(is_ipv6 bool) (boshsettings.Network, error) { + return p.defaultNetworkResolver.GetDefaultNetwork(is_ipv6) } func (p linux) calculateEphemeralDiskPartitionSizes(diskSizeInBytes uint64, desiredSwapSizeInBytes *uint64) (uint64, uint64, error) { diff --git a/platform/net/arp/arping.go b/platform/net/arp/arping.go index 7674a798d..c68e27fcb 100644 --- a/platform/net/arp/arping.go +++ b/platform/net/arp/arping.go @@ -49,7 +49,7 @@ func (a arping) BroadcastMACAddresses(addresses []boship.InterfaceAddress) { var wg sync.WaitGroup for _, addr := range addresses { - ip, err := addr.GetIP() + ip, err := addr.GetIP(false) if err != nil { continue } @@ -90,7 +90,7 @@ func (a arping) blockUntilInterfaceExists(interfaceName string) { // broadcastMACAddress broadcasts an IP/MAC pair to the specified network and logs any failure func (a arping) broadcastMACAddress(address boship.InterfaceAddress) { - ip, err := address.GetIP() + ip, err := address.GetIP(false) if err != nil { a.logger.Info(arpingLogTag, "Ignoring GetIP failure: %s", err.Error()) return diff --git a/platform/net/default_network_resolver.go b/platform/net/default_network_resolver.go index 39d304153..4726bdedd 100644 --- a/platform/net/default_network_resolver.go +++ b/platform/net/default_network_resolver.go @@ -24,10 +24,11 @@ func NewDefaultNetworkResolver( } } -func (r defaultNetworkResolver) GetDefaultNetwork() (boshsettings.Network, error) { +func (r defaultNetworkResolver) GetDefaultNetwork(is_ipv6 bool) (boshsettings.Network, error) { network := boshsettings.Network{} - routes, err := r.routesSearcher.SearchRoutes() + routes, err := r.routesSearcher.SearchRoutes(is_ipv6) + if err != nil { return network, bosherr.WrapError(err, "Searching routes") } @@ -41,9 +42,15 @@ func (r defaultNetworkResolver) GetDefaultNetwork() (boshsettings.Network, error continue } - ip, err := r.ipResolver.GetPrimaryIPv4(route.InterfaceName) + ip, err := r.ipResolver.GetPrimaryIP(route.InterfaceName, is_ipv6) + if err != nil { - return network, bosherr.WrapErrorf(err, "Getting primary IPv4 for interface '%s'", route.InterfaceName) + ipVersion := 4 + + if is_ipv6 { + ipVersion = 6 + } + return network, bosherr.WrapErrorf(err, "Getting primary IPv%d for interface '%s'", ipVersion, route.InterfaceName) } return boshsettings.Network{ diff --git a/platform/net/fakes/fake_routes_searcher.go b/platform/net/fakes/fake_routes_searcher.go index 94499dec0..f7807898e 100644 --- a/platform/net/fakes/fake_routes_searcher.go +++ b/platform/net/fakes/fake_routes_searcher.go @@ -9,6 +9,6 @@ type FakeRoutesSearcher struct { SearchRoutesErr error } -func (s *FakeRoutesSearcher) SearchRoutes() ([]boshnet.Route, error) { +func (s *FakeRoutesSearcher) SearchRoutes(ipv6 bool) ([]boshnet.Route, error) { return s.SearchRoutesRoutes, s.SearchRoutesErr } diff --git a/platform/net/ip/fakes/fake_ip_resolver.go b/platform/net/ip/fakes/fake_ip_resolver.go index e0c1c3581..7e4d676c7 100644 --- a/platform/net/ip/fakes/fake_ip_resolver.go +++ b/platform/net/ip/fakes/fake_ip_resolver.go @@ -5,12 +5,12 @@ import ( ) type FakeResolver struct { - GetPrimaryIPv4InterfaceName string - GetPrimaryIPv4IPNet *gonet.IPNet - GetPrimaryIPv4Err error + GetPrimaryIPInterfaceName string + GetPrimaryIPIPNet *gonet.IPNet + GetPrimaryIPErr error } -func (r *FakeResolver) GetPrimaryIPv4(interfaceName string) (*gonet.IPNet, error) { - r.GetPrimaryIPv4InterfaceName = interfaceName - return r.GetPrimaryIPv4IPNet, r.GetPrimaryIPv4Err +func (r *FakeResolver) GetPrimaryIP(interfaceName string, is_ipv6 bool) (*gonet.IPNet, error) { + r.GetPrimaryIPInterfaceName = interfaceName + return r.GetPrimaryIPIPNet, r.GetPrimaryIPErr } diff --git a/platform/net/ip/interface_address.go b/platform/net/ip/interface_address.go index 436b16c75..5ecb8b5b6 100644 --- a/platform/net/ip/interface_address.go +++ b/platform/net/ip/interface_address.go @@ -10,7 +10,7 @@ import ( type InterfaceAddress interface { GetInterfaceName() string // GetIP gets the exposed internet protocol address of the above interface - GetIP() (string, error) + GetIP(is_ipv6 bool) (string, error) } type simpleInterfaceAddress struct { @@ -24,7 +24,7 @@ func NewSimpleInterfaceAddress(interfaceName string, ip string) InterfaceAddress func (s simpleInterfaceAddress) GetInterfaceName() string { return s.interfaceName } -func (s simpleInterfaceAddress) GetIP() (string, error) { +func (s simpleInterfaceAddress) GetIP(is_ipv6 bool) (string, error) { ip2 := net.ParseIP(s.ip) if ip2 == nil { return "", fmt.Errorf("Cannot parse IP '%s'", s.ip) //nolint:staticcheck @@ -51,14 +51,20 @@ func NewResolvingInterfaceAddress( func (s resolvingInterfaceAddress) GetInterfaceName() string { return s.interfaceName } -func (s *resolvingInterfaceAddress) GetIP() (string, error) { +func (s *resolvingInterfaceAddress) GetIP(is_ipv6 bool) (string, error) { if s.ip != "" { return s.ip, nil } - ip, err := s.ipResolver.GetPrimaryIPv4(s.interfaceName) + ip, err := s.ipResolver.GetPrimaryIP(s.interfaceName, is_ipv6) if err != nil { - return "", bosherr.WrapError(err, "Getting primary IPv4") + var ipVersion int + if is_ipv6 { + ipVersion = 6 + } else { + ipVersion = 4 + } + return "", bosherr.WrapErrorf(err, "Getting primary IPv%d ", ipVersion) } s.ip = fmtIP(ip.IP) diff --git a/platform/net/ip/interface_addresses_validator.go b/platform/net/ip/interface_addresses_validator.go index ae9e93a76..168300baa 100644 --- a/platform/net/ip/interface_addresses_validator.go +++ b/platform/net/ip/interface_addresses_validator.go @@ -33,9 +33,9 @@ func (i InterfaceAddressesValidator) Attempt() (bool, error) { } var actualIPs []string - desiredIP, _ := desiredInterfaceAddress.GetIP() //nolint:errcheck + desiredIP, _ := desiredInterfaceAddress.GetIP(false) //nolint:errcheck for _, iface := range ifaces { - actualIP, _ := iface.GetIP() //nolint:errcheck + actualIP, _ := iface.GetIP(false) //nolint:errcheck if desiredIP == actualIP { return false, nil diff --git a/platform/net/ip/ip_resolver.go b/platform/net/ip/ip_resolver.go index 45b863cf6..ca20288eb 100644 --- a/platform/net/ip/ip_resolver.go +++ b/platform/net/ip/ip_resolver.go @@ -18,8 +18,8 @@ func NetworkInterfaceToAddrsFunc(interfaceName string) ([]gonet.Addr, error) { } type Resolver interface { - // GetPrimaryIPv4 always returns error unless IPNet is found for given interface - GetPrimaryIPv4(interfaceName string) (*gonet.IPNet, error) + // GetPrimaryIP always returns error unless IPNet is found for given interface + GetPrimaryIP(interfaceName string, is_ipv6 bool) (*gonet.IPNet, error) } type ipResolver struct { @@ -30,7 +30,7 @@ func NewResolver(ifaceToAddrsFunc InterfaceToAddrsFunc) Resolver { return ipResolver{ifaceToAddrsFunc: ifaceToAddrsFunc} } -func (r ipResolver) GetPrimaryIPv4(interfaceName string) (*gonet.IPNet, error) { +func (r ipResolver) GetPrimaryIP(interfaceName string, is_ipv6 bool) (*gonet.IPNet, error) { addrs, err := r.ifaceToAddrsFunc(interfaceName) if err != nil { return nil, bosherr.WrapErrorf(err, "Looking up addresses for interface '%s'", interfaceName) @@ -46,11 +46,20 @@ func (r ipResolver) GetPrimaryIPv4(interfaceName string) (*gonet.IPNet, error) { continue } - // todo dual stack - if ip.IP.To4() != nil || ip.IP.IsGlobalUnicast() { - return ip, nil + if is_ipv6 { + if ip.IP.To16() != nil || ip.IP.IsGlobalUnicast() { + return ip, nil + } + } else { + if ip.IP.To4() != nil || ip.IP.IsGlobalUnicast() { + return ip, nil + } } } + ipVersion := 4 + if is_ipv6 { + ipVersion = 6 + } - return nil, bosherr.Errorf("Failed to find primary address for interface '%s'", interfaceName) + return nil, bosherr.Errorf("Failed to find primary address IPv%d for interface '%s'", ipVersion, interfaceName) } diff --git a/platform/net/routes_searcher_interface.go b/platform/net/routes_searcher_interface.go index 243257dee..53b33df5a 100644 --- a/platform/net/routes_searcher_interface.go +++ b/platform/net/routes_searcher_interface.go @@ -8,7 +8,7 @@ type Route struct { } type RoutesSearcher interface { - SearchRoutes() ([]Route, error) + SearchRoutes(ipv6 bool) ([]Route, error) } const DefaultAddress = `0.0.0.0` diff --git a/platform/net/routes_searcher_unix.go b/platform/net/routes_searcher_unix.go index 4794a56dc..ad427338b 100644 --- a/platform/net/routes_searcher_unix.go +++ b/platform/net/routes_searcher_unix.go @@ -54,10 +54,19 @@ func parseRoute(ipString string) (Route, error) { }, nil } -func (s cmdRoutesSearcher) SearchRoutes() ([]Route, error) { - stdout, _, _, err := s.runner.RunCommandQuietly("ip", "r") - if err != nil { - return []Route{}, bosherr.WrapError(err, "Running route") +func (s cmdRoutesSearcher) SearchRoutes(ipv6 bool) ([]Route, error) { + var stdout string + var err error + if ipv6 { + stdout, _, _, err = s.runner.RunCommandQuietly("ip", "-6", "r") + if err != nil { + return []Route{}, bosherr.WrapError(err, "Running IPv6 route") + } + } else { + stdout, _, _, err = s.runner.RunCommandQuietly("ip", "r") + if err != nil { + return []Route{}, bosherr.WrapError(err, "Running IPv4 route") + } } routeEntries := strings.Split(stdout, "\n") diff --git a/platform/net/routes_searcher_windows.go b/platform/net/routes_searcher_windows.go index 2bf46dd51..7545b8bd9 100644 --- a/platform/net/routes_searcher_windows.go +++ b/platform/net/routes_searcher_windows.go @@ -15,15 +15,22 @@ func NewRoutesSearcher(_ boshlog.Logger, cmdRunner boshsys.CmdRunner, interfaceM return windowsRoutesSearcher{interfaceManager, cmdRunner} } -func (s windowsRoutesSearcher) SearchRoutes() ([]Route, error) { +func (s windowsRoutesSearcher) SearchRoutes(ipv6 bool) ([]Route, error) { ifs, err := s.interfaceManager.GetInterfaces() if err != nil { return nil, bosherr.WrapError(err, "Running route") } - defaultGateway, _, _, err := s.cmdRunner.RunCommandQuietly("(Get-NetRoute -DestinationPrefix '0.0.0.0/0').NextHop") - if err != nil { - return nil, bosherr.WrapError(err, "Running route") + if ipv6 { + defaultGateway, _, _, err := s.cmdRunner.RunCommandQuietly("(Get-NetRoute -DestinationPrefix '::/0').NextHop") + if err != nil { + return nil, bosherr.WrapError(err, "Running IPv6 route") + } + } else { + defaultGateway, _, _, err := s.cmdRunner.RunCommandQuietly("(Get-NetRoute -DestinationPrefix '0.0.0.0/0').NextHop") + if err != nil { + return nil, bosherr.WrapError(err, "Running IPv4 route") + } } routes := make([]Route, 0, len(ifs)) @@ -33,7 +40,11 @@ func (s windowsRoutesSearcher) SearchRoutes() ([]Route, error) { Gateway: fs.Gateway, } if fs.Gateway == defaultGateway { - route.Destination = "0.0.0.0" + if ipv6 { + route.Destination = "::/0" // Default route for IPv6 + } else { + route.Destination = "0.0.0.0" // Default route for IPv4 + } } routes = append(routes, route) } diff --git a/platform/platform_interface.go b/platform/platform_interface.go index 1dcdd3a8d..a4f906837 100644 --- a/platform/platform_interface.go +++ b/platform/platform_interface.go @@ -92,7 +92,7 @@ type Platform interface { GetFilesContentsFromDisk(diskPath string, fileNames []string) (contents [][]byte, err error) // Network misc - GetDefaultNetwork() (boshsettings.Network, error) + GetDefaultNetwork(is_ipv6 bool) (boshsettings.Network, error) GetConfiguredNetworkInterfaces() ([]string, error) PrepareForNetworkingChange() error DeleteARPEntryWithIP(ip string) error diff --git a/platform/windows_platform.go b/platform/windows_platform.go index 731916ac6..debc06b9c 100644 --- a/platform/windows_platform.go +++ b/platform/windows_platform.go @@ -717,8 +717,8 @@ func (p WindowsPlatform) RemoveStaticLibraries(packageFileListPath string) error return nil } -func (p WindowsPlatform) GetDefaultNetwork() (boshsettings.Network, error) { - return p.defaultNetworkResolver.GetDefaultNetwork() +func (p WindowsPlatform) GetDefaultNetwork(is_ipv6 bool) (boshsettings.Network, error) { + return p.defaultNetworkResolver.GetDefaultNetwork(is_ipv6) } func (p WindowsPlatform) GetHostPublicKey() (string, error) { diff --git a/settings/service.go b/settings/service.go index a27ae52ce..0eb0ab795 100644 --- a/settings/service.go +++ b/settings/service.go @@ -45,7 +45,7 @@ type settingsService struct { type DefaultNetworkResolver interface { // Ideally we would find a network based on a MAC address // but current CPI implementations do not include it - GetDefaultNetwork() (Network, error) + GetDefaultNetwork(ipv6 bool) (Network, error) } //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . PlatformSettingsGetter @@ -255,12 +255,19 @@ func (s *settingsService) GetSettings() Settings { continue } - resolvedNetwork, err := s.resolveNetwork(network) - if err != nil { - break + s.logger.Debug(settingsServiceLogTag, "DEBUGGING NAME%s", networkName) + s.logger.Debug(settingsServiceLogTag, "DEBUGGING NETWORK%s", network) + s.logger.Debug(settingsServiceLogTag, "DEBUGGING PREFIX%s", network.Prefix) + + if network.Prefix == "32" || network.Prefix == "128" || network.Prefix == "" { + resolvedNetwork, err := s.resolveNetwork(network) + if err != nil { + break + } + settingsCopy.Networks[networkName] = resolvedNetwork + } else { + settingsCopy.Networks[networkName] = network } - - settingsCopy.Networks[networkName] = resolvedNetwork } return settingsCopy } @@ -278,7 +285,13 @@ func (s *settingsService) resolveNetwork(network Network) (Network, error) { // Ideally this would be GetNetworkByMACAddress(mac string) // Currently, we are relying that if the default network does not contain // the MAC adddress the InterfaceConfigurationCreator will fail. - resolvedNetwork, err := s.platform.GetDefaultNetwork() + ipv6 := false + + if network.Prefix == "128" { + s.logger.Debug(settingsServiceLogTag, "DEBUGGING IPv6") + ipv6 = true + } + resolvedNetwork, err := s.platform.GetDefaultNetwork(ipv6) if err != nil { s.logger.Error(settingsServiceLogTag, "Failed retrieving default network %s", err.Error()) return Network{}, bosherr.WrapError(err, "Failed retrieving default network") diff --git a/settings/settings.go b/settings/settings.go index 129d4dedd..af755e0ea 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -356,6 +356,7 @@ type Network struct { IP string `json:"ip"` Netmask string `json:"netmask"` Gateway string `json:"gateway"` + Prefix string `json:"prefix"` Resolved bool `json:"resolved"` // was resolved via DHCP UseDHCP bool `json:"use_dhcp"`