func()

in google_guest_agent/addresses.go [276:437]


func (a *addressMgr) Set(ctx context.Context) error {
	config := cfg.Get()

	if runtime.GOOS == "windows" {
		a.applyWSFCFilter(config)
	}

	// Guest Agent does not manage interfaces on Windows.
	if runtime.GOOS != "windows" {
		// Setup network interfaces.
		err := network.SetupInterfaces(ctx, config, newMetadata)
		if err != nil {
			return fmt.Errorf("failed to setup network interfaces: %v", err)
		}
	}

	if !config.NetworkInterfaces.IPForwarding {
		return nil
	}

	logger.Debugf("Add routes for aliases, forwarded IP and target-instance IPs")
	// Add routes for IP aliases, forwarded and target-instance IPs.
	for _, ni := range newMetadata.Instance.NetworkInterfaces {
		iface, err := network.GetInterfaceByMAC(ni.Mac)
		if err != nil {
			if !slices.Contains(badMAC, ni.Mac) {
				logger.Errorf("Error getting interface: %s", err)
				badMAC = append(badMAC, ni.Mac)
			}
			continue
		}
		wantIPs := ni.ForwardedIps
		wantIPs = append(wantIPs, ni.ForwardedIpv6s...)
		if config.IPForwarding.TargetInstanceIPs {
			wantIPs = append(wantIPs, ni.TargetInstanceIps...)
		}
		// IP Aliases are not supported on windows.
		if runtime.GOOS != "windows" && config.IPForwarding.IPAliases {
			wantIPs = append(wantIPs, ni.IPAliases...)
		}

		var forwardedIPs []string
		var configuredIPs []string
		if runtime.GOOS == "windows" {
			addrs, err := iface.Addrs()
			if err != nil {
				logger.Errorf("Error getting addresses for interface %s: %s", iface.Name, err)
			}
			for _, addr := range addrs {
				configuredIPs = append(configuredIPs, strings.TrimSuffix(addr.String(), "/32"))
			}
			regFwdIPs, err := getForwardsFromRegistry(ni.Mac)
			if err != nil {
				logger.Errorf("Error getting forwards from registry: %s", err)
				continue
			}
			for _, ip := range configuredIPs {
				// Only add to `forwardedIPs` if it is recorded in the registry.
				if slices.Contains(regFwdIPs, ip) {
					forwardedIPs = append(forwardedIPs, ip)
				}
			}
		} else {
			forwardedIPs, err = getLocalRoutes(ctx, config, iface.Name)
			if err != nil {
				logger.Errorf("Error getting routes: %v", err)
				continue
			}
		}

		// Trims any '/32' suffix for consistency.
		trimSuffix := func(entries []string) []string {
			var res []string
			for _, entry := range entries {
				res = append(res, strings.TrimSuffix(entry, "/32"))
			}
			return res
		}
		forwardedIPs = trimSuffix(forwardedIPs)
		wantIPs = trimSuffix(wantIPs)

		toAdd, toRm := compareRoutes(forwardedIPs, wantIPs)

		if len(toAdd) != 0 || len(toRm) != 0 {
			var msg string
			msg = fmt.Sprintf("Changing forwarded IPs for %s from %q to %q by", ni.Mac, forwardedIPs, wantIPs)
			if len(toAdd) != 0 {
				msg += fmt.Sprintf(" adding %q", toAdd)
			}
			if len(toRm) != 0 {
				if len(toAdd) != 0 {
					msg += " and"
				}
				msg += fmt.Sprintf(" removing %q", toRm)
			}
			logger.Infof(msg)
		}

		var registryEntries []string
		for _, ip := range wantIPs {
			// If the IP is not in toAdd, add to registry list and continue.
			if !slices.Contains(toAdd, ip) {
				registryEntries = append(registryEntries, ip)
				continue
			}
			var err error
			if runtime.GOOS == "windows" {
				// Don't addAddress if this is already configured.
				if !slices.Contains(configuredIPs, ip) {
					// In case of forwardedIpv6 we get IPV6 CIDR and Parse IP will return nil.
					netip := net.ParseIP(ip)
					if netip != nil && !isIPv6(netip) {
						// Retains existing behavior for ipv4 addresses.
						err = addAddress(netip, net.IPv4Mask(255, 255, 255, 255), uint32(iface.Index))
					} else {
						err = addIpv6Address(ip, uint32(iface.Index))
					}
				}
			} else {
				err = addLocalRoute(ctx, config, ip, iface.Name)
			}
			if err == nil {
				registryEntries = append(registryEntries, ip)
			} else {
				logger.Errorf("error adding route: %v", err)
			}
		}

		for _, ip := range toRm {
			var err error
			if runtime.GOOS == "windows" {
				if !slices.Contains(configuredIPs, ip) {
					continue
				}
				netip := net.ParseIP(ip)
				// In case of forwardedIpv6 we get IPV6 CIDR and Parse IP will return nil.
				if netip != nil && !isIPv6(netip) {
					// Retains existing behavior for ipv4 addresses.
					err = removeAddress(netip, net.IPv4Mask(255, 255, 255, 255), uint32(iface.Index))
				} else {
					err = removeIpv6Address(ip, uint32(iface.Index))
				}
			} else {
				err = removeLocalRoute(ctx, config, ip, iface.Name)
			}
			if err != nil {
				logger.Errorf("error removing route: %v", err)
				// Add IPs we fail to remove to registry to maintain accurate record.
				registryEntries = append(registryEntries, ip)
			}
		}

		if runtime.GOOS == "windows" {
			if err := writeRegMultiString(addressKey, ni.Mac, registryEntries); err != nil {
				logger.Errorf("error writing registry: %s", err)
			}
		}
	}
	logger.Infof("Completed adding/removing routes for aliases, forwarded IP and target-instance IPs")

	return nil
}