<commit_before>package device

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"math/rand"
	"net"
	"os"
	"strconv"
	"strings"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/mdlayher/netx/eui64"
	log "gopkg.in/inconshreveable/log15.v2"

	"github.com/lxc/lxd/lxd/db"
	deviceConfig "github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/lxd/dnsmasq"
	"github.com/lxc/lxd/lxd/dnsmasq/dhcpalloc"
	firewallDrivers "github.com/lxc/lxd/lxd/firewall/drivers"
	"github.com/lxc/lxd/lxd/instance"
	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/lxd/ip"
	"github.com/lxc/lxd/lxd/network"
	"github.com/lxc/lxd/lxd/network/openvswitch"
	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/lxd/resources"
	"github.com/lxc/lxd/lxd/revert"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/validate"
)

type bridgeNetwork interface {
	UsesDNSMasq() bool
}

type nicBridged struct {
	deviceCommon

	network network.Network // Populated in validateConfig().
}

// CanHotPlug returns whether the device can be managed whilst the instance is running. Returns true.
func (d *nicBridged) CanHotPlug() bool {
	return true
}

// CanMigrate returns whether the device can be migrated to any other cluster member.
func (d *nicBridged) CanMigrate() bool {
	return d.config["network"] != ""
}

// validateConfig checks the supplied config for correctness.
func (d *nicBridged) validateConfig(instConf instance.ConfigReader) error {
	if !instanceSupported(instConf.Type(), instancetype.Container, instancetype.VM) {
		return ErrUnsupportedDevType
	}

	var requiredFields []string
	optionalFields := []string{
		"name",
		"network",
		"parent",
		"mtu",
		"hwaddr",
		"host_name",
		"limits.ingress",
		"limits.egress",
		"limits.max",
		"ipv4.address",
		"ipv6.address",
		"ipv4.routes",
		"ipv6.routes",
		"ipv4.routes.external",
		"ipv6.routes.external",
		"security.mac_filtering",
		"security.ipv4_filtering",
		"security.ipv6_filtering",
		"security.port_isolation",
		"maas.subnet.ipv4",
		"maas.subnet.ipv6",
		"boot.priority",
		"vlan",
	}

	// checkWithManagedNetwork validates the device's settings against the managed network.
	checkWithManagedNetwork := func(n network.Network) error {
		if n.Status() != api.NetworkStatusCreated {
			return fmt.Errorf("Specified network is not fully created")
		}

		if n.Type() != "bridge" {
			return fmt.Errorf("Specified network must be of type bridge")
		}

		netConfig := n.Config()

		if d.config["ipv4.address"] != "" {
			dhcpv4Subnet := n.DHCPv4Subnet()

			// Check that DHCPv4 is enabled on parent network (needed to use static assigned IPs) when
			// IP filtering isn't enabled (if it is we allow the use of static IPs for this purpose).
			if dhcpv4Subnet == nil && shared.IsFalseOrEmpty(d.config["security.ipv4_filtering"]) {
				return fmt.Errorf(`Cannot specify "ipv4.address" when DHCP is disabled (unless using security.ipv4_filtering) on network %q`, n.Name())
			}

			// Check the static IP supplied is valid for the linked network. It should be part of the
			// network's subnet, but not necessarily part of the dynamic allocation ranges.
			if dhcpv4Subnet != nil && !dhcpalloc.DHCPValidIP(dhcpv4Subnet, nil, net.ParseIP(d.config["ipv4.address"])) {
				return fmt.Errorf("Device IP address %q not within network %q subnet", d.config["ipv4.address"], n.Name())
			}

			parentAddress := netConfig["ipv4.address"]
			if shared.StringInSlice(parentAddress, []string{"", "none"}) {
				return nil
			}

			ip, _, err := net.ParseCIDR(parentAddress)
			if err != nil {
				return fmt.Errorf("Invalid network ipv4.address: %w", err)
			}

			if d.config["ipv4.address"] == "none" && shared.IsFalseOrEmpty(d.config["security.ipv4_filtering"]) {
				return fmt.Errorf("Cannot have ipv4.address as none unless using security.ipv4_filtering")
			}

			// IP should not be the same as the parent managed network address.
			if ip.Equal(net.ParseIP(d.config["ipv4.address"])) {
				return fmt.Errorf("IP address %q is assigned to parent managed network device %q", d.config["ipv4.address"], d.config["parent"])
			}
		}

		if d.config["ipv6.address"] != "" {
			dhcpv6Subnet := n.DHCPv6Subnet()

			// Check that DHCPv6 is enabled on parent network (needed to use static assigned IPs) when
			// IP filtering isn't enabled (if it is we allow the use of static IPs for this purpose).
			if (dhcpv6Subnet == nil || shared.IsFalseOrEmpty(netConfig["ipv6.dhcp.stateful"])) && shared.IsFalseOrEmpty(d.config["security.ipv6_filtering"]) {
				return fmt.Errorf(`Cannot specify "ipv6.address" when DHCP or "ipv6.dhcp.stateful" are disabled (unless using security.ipv6_filtering) on network %q`, n.Name())
			}

			// Check the static IP supplied is valid for the linked network. It should be part of the
			// network's subnet, but not necessarily part of the dynamic allocation ranges.
			if dhcpv6Subnet != nil && !dhcpalloc.DHCPValidIP(dhcpv6Subnet, nil, net.ParseIP(d.config["ipv6.address"])) {
				return fmt.Errorf("Device IP address %q not within network %q subnet", d.config["ipv6.address"], n.Name())
			}

			parentAddress := netConfig["ipv6.address"]
			if shared.StringInSlice(parentAddress, []string{"", "none"}) {
				return nil
			}

			ip, _, err := net.ParseCIDR(parentAddress)
			if err != nil {
				return fmt.Errorf("Invalid network ipv6.address: %w", err)
			}

			if d.config["ipv6.address"] == "none" && shared.IsFalseOrEmpty(d.config["security.ipv6_filtering"]) {
				return fmt.Errorf("Cannot have ipv6.address as none unless using security.ipv6_filtering")
			}

			// IP should not be the same as the parent managed network address.
			if ip.Equal(net.ParseIP(d.config["ipv6.address"])) {
				return fmt.Errorf("IP address %q is assigned to parent managed network device %q", d.config["ipv6.address"], d.config["parent"])
			}
		}

		// When we know the parent network is managed, we can validate the NIC's VLAN settings based on
		// on the bridge driver type.
		if shared.StringInSlice(netConfig["bridge.driver"], []string{"", "native"}) {
			// Check VLAN 0 isn't set when using a native Linux managed bridge, as not supported.
			if d.config["vlan"] == "0" {
				return fmt.Errorf("VLAN ID 0 is not allowed for native Linux bridges")
			}
<commit_msg>lxd/device: Allow ipv{n}.address=none for managed networks.<commit_after>package device

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"math/rand"
	"net"
	"os"
	"strconv"
	"strings"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/mdlayher/netx/eui64"
	log "gopkg.in/inconshreveable/log15.v2"

	"github.com/lxc/lxd/lxd/db"
	deviceConfig "github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/lxd/dnsmasq"
	"github.com/lxc/lxd/lxd/dnsmasq/dhcpalloc"
	firewallDrivers "github.com/lxc/lxd/lxd/firewall/drivers"
	"github.com/lxc/lxd/lxd/instance"
	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/lxd/ip"
	"github.com/lxc/lxd/lxd/network"
	"github.com/lxc/lxd/lxd/network/openvswitch"
	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/lxd/resources"
	"github.com/lxc/lxd/lxd/revert"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/validate"
)

type bridgeNetwork interface {
	UsesDNSMasq() bool
}

type nicBridged struct {
	deviceCommon

	network network.Network // Populated in validateConfig().
}

// CanHotPlug returns whether the device can be managed whilst the instance is running. Returns true.
func (d *nicBridged) CanHotPlug() bool {
	return true
}

// CanMigrate returns whether the device can be migrated to any other cluster member.
func (d *nicBridged) CanMigrate() bool {
	return d.config["network"] != ""
}

// validateConfig checks the supplied config for correctness.
func (d *nicBridged) validateConfig(instConf instance.ConfigReader) error {
	if !instanceSupported(instConf.Type(), instancetype.Container, instancetype.VM) {
		return ErrUnsupportedDevType
	}

	var requiredFields []string
	optionalFields := []string{
		"name",
		"network",
		"parent",
		"mtu",
		"hwaddr",
		"host_name",
		"limits.ingress",
		"limits.egress",
		"limits.max",
		"ipv4.address",
		"ipv6.address",
		"ipv4.routes",
		"ipv6.routes",
		"ipv4.routes.external",
		"ipv6.routes.external",
		"security.mac_filtering",
		"security.ipv4_filtering",
		"security.ipv6_filtering",
		"security.port_isolation",
		"maas.subnet.ipv4",
		"maas.subnet.ipv6",
		"boot.priority",
		"vlan",
	}

	// checkWithManagedNetwork validates the device's settings against the managed network.
	checkWithManagedNetwork := func(n network.Network) error {
		if n.Status() != api.NetworkStatusCreated {
			return fmt.Errorf("Specified network is not fully created")
		}

		if n.Type() != "bridge" {
			return fmt.Errorf("Specified network must be of type bridge")
		}

		netConfig := n.Config()

		if d.config["ipv4.address"] != "" {
			dhcpv4Subnet := n.DHCPv4Subnet()

			// Check that DHCPv4 is enabled on parent network (needed to use static assigned IPs) when
			// IP filtering isn't enabled (if it is we allow the use of static IPs for this purpose).
			if dhcpv4Subnet == nil && shared.IsFalseOrEmpty(d.config["security.ipv4_filtering"]) {
				return fmt.Errorf(`Cannot specify "ipv4.address" when DHCP is disabled (unless using security.ipv4_filtering) on network %q`, n.Name())
			}

			// Check the static IP supplied is valid for the linked network. It should be part of the
			// network's subnet, but not necessarily part of the dynamic allocation ranges.
			if dhcpv4Subnet != nil && d.config["ipv4.address"] != "none" && !dhcpalloc.DHCPValidIP(dhcpv4Subnet, nil, net.ParseIP(d.config["ipv4.address"])) {
				return fmt.Errorf("Device IP address %q not within network %q subnet", d.config["ipv4.address"], n.Name())
			}

			parentAddress := netConfig["ipv4.address"]
			if shared.StringInSlice(parentAddress, []string{"", "none"}) {
				return nil
			}

			ip, _, err := net.ParseCIDR(parentAddress)
			if err != nil {
				return fmt.Errorf("Invalid network ipv4.address: %w", err)
			}

			if d.config["ipv4.address"] == "none" && shared.IsFalseOrEmpty(d.config["security.ipv4_filtering"]) {
				return fmt.Errorf("Cannot have ipv4.address as none unless using security.ipv4_filtering")
			}

			// IP should not be the same as the parent managed network address.
			if ip.Equal(net.ParseIP(d.config["ipv4.address"])) {
				return fmt.Errorf("IP address %q is assigned to parent managed network device %q", d.config["ipv4.address"], d.config["parent"])
			}
		}

		if d.config["ipv6.address"] != "" {
			dhcpv6Subnet := n.DHCPv6Subnet()

			// Check that DHCPv6 is enabled on parent network (needed to use static assigned IPs) when
			// IP filtering isn't enabled (if it is we allow the use of static IPs for this purpose).
			if (dhcpv6Subnet == nil || shared.IsFalseOrEmpty(netConfig["ipv6.dhcp.stateful"])) && shared.IsFalseOrEmpty(d.config["security.ipv6_filtering"]) {
				return fmt.Errorf(`Cannot specify "ipv6.address" when DHCP or "ipv6.dhcp.stateful" are disabled (unless using security.ipv6_filtering) on network %q`, n.Name())
			}

			// Check the static IP supplied is valid for the linked network. It should be part of the
			// network's subnet, but not necessarily part of the dynamic allocation ranges.
			if dhcpv6Subnet != nil && d.config["ipv6.address"] != "none" && !dhcpalloc.DHCPValidIP(dhcpv6Subnet, nil, net.ParseIP(d.config["ipv6.address"])) {
				return fmt.Errorf("Device IP address %q not within network %q subnet", d.config["ipv6.address"], n.Name())
			}

			parentAddress := netConfig["ipv6.address"]
			if shared.StringInSlice(parentAddress, []string{"", "none"}) {
				return nil
			}

			ip, _, err := net.ParseCIDR(parentAddress)
			if err != nil {
				return fmt.Errorf("Invalid network ipv6.address: %w", err)
			}

			if d.config["ipv6.address"] == "none" && shared.IsFalseOrEmpty(d.config["security.ipv6_filtering"]) {
				return fmt.Errorf("Cannot have ipv6.address as none unless using security.ipv6_filtering")
			}

			// IP should not be the same as the parent managed network address.
			if ip.Equal(net.ParseIP(d.config["ipv6.address"])) {
				return fmt.Errorf("IP address %q is assigned to parent managed network device %q", d.config["ipv6.address"], d.config["parent"])
			}
		}

		// When we know the parent network is managed, we can validate the NIC's VLAN settings based on
		// on the bridge driver type.
		if shared.StringInSlice(netConfig["bridge.driver"], []string{"", "native"}) {
			// Check VLAN 0 isn't set when using a native Linux managed bridge, as not supported.
			if d.config["vlan"] == "0" {
				return fmt.Errorf("VLAN ID 0 is not allowed for native Linux bridges")
			}

{'fraction_non_alphanumeric': 0.13804583462372252, 'fraction_numerical': 0.009445648807680396, 'mean_word_length': 4.01631067961165, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4088900', 'n_tokens_mistral': 4881, 'n_tokens_neox': 4504, 'n_words': 1127}