The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6358
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === Fixes https://discuss.linuxcontainers.org/t/lxd-3-18-security-mac-filtering-on-bridged-nic-fails/6022/9
From d993f4a7a2399caeeab727415bcb8429f1ed67e7 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 28 Oct 2019 11:20:35 +0000 Subject: [PATCH 1/2] lxd/device/nic/bridged: Allow MAC filtering on unmanaged bridges Allows to use the security.mac_filtering nic option when parent is an unmanaged bridge. Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- lxd/device/nic_bridged.go | 42 +++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/lxd/device/nic_bridged.go b/lxd/device/nic_bridged.go index 8b2776ea58..b4a26ff265 100644 --- a/lxd/device/nic_bridged.go +++ b/lxd/device/nic_bridged.go @@ -19,6 +19,7 @@ import ( "github.com/google/gopacket/layers" "github.com/mdlayher/eui64" + "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/instance/instancetype" @@ -265,7 +266,10 @@ func (d *nicBridged) postStop() error { } networkRemoveVethRoutes(d.config) - d.removeFilters(d.config) + err := d.removeFilters(d.config) + if err != nil { + logger.Errorf("Failed to remove nic filters: %v", err) + } return nil } @@ -385,9 +389,12 @@ func (d *nicBridged) removeFilters(m deviceConfig.Device) error { } // Read current static IP allocation configured from dnsmasq host config (if exists). - IPv4, IPv6, err := d.getDHCPStaticIPs(m["parent"], d.instance.Name()) - if err != nil { - return fmt.Errorf("Failed to remove network filters for %s: %v", m["name"], err) + var IPv4, IPv6 dhcpAllocation + if shared.PathExists(shared.VarPath("networks", m["parent"], "dnsmasq.hosts") + "/" + d.instance.Name()) { + IPv4, IPv6, err = d.getDHCPStaticIPs(m["parent"], d.instance.Name()) + if err != nil { + return fmt.Errorf("Failed to retrieve static IPs for filter removal from %s: %v", m["name"], err) + } } // Get a current list of rules active on the host. @@ -564,12 +571,22 @@ func (d *nicBridged) setFilters() (err error) { } } - // Retrieve existing IPs, or allocate new ones if needed. - IPv4, IPv6, err := d.allocateFilterIPs() - if err != nil { + // Check if the parent is managed and load config. If parent is unmanaged continue anyway. + var IPv4, IPv6 net.IP + _, netInfo, err := d.state.Cluster.NetworkGet(d.config["parent"]) + if err != nil && err != db.ErrNoSuchObject { return err } + // If network is unmanaged we cannot allocate static IPs. + if netInfo != nil { + // Retrieve existing IPs, or allocate new ones if needed. + IPv4, IPv6, err = d.allocateFilterIPs(netInfo.Config) + if err != nil { + return err + } + } + // If anything goes wrong, clean up so we don't leave orphaned rules. defer func() { if err != nil { @@ -601,7 +618,9 @@ func (d *nicBridged) setFilters() (err error) { } // networkAllocateVethFilterIPs retrieves previously allocated IPs, or allocate new ones if needed. -func (d *nicBridged) allocateFilterIPs() (net.IP, net.IP, error) { +// This function only works with LXD managed networks, and as such, requires the managed network's +// config to be supplied. +func (d *nicBridged) allocateFilterIPs(netConfig map[string]string) (net.IP, net.IP, error) { var IPv4, IPv6 net.IP // Check if there is a valid static IPv4 address defined. @@ -620,13 +639,6 @@ func (d *nicBridged) allocateFilterIPs() (net.IP, net.IP, error) { } } - _, dbInfo, err := d.state.Cluster.NetworkGet(d.config["parent"]) - if err != nil { - return nil, nil, err - } - - netConfig := dbInfo.Config - // Check the conditions required to dynamically allocated IPs. canIPv4Allocate := netConfig["ipv4.address"] != "" && netConfig["ipv4.address"] != "none" && (netConfig["ipv4.dhcp"] == "" || shared.IsTrue(netConfig["ipv4.dhcp"])) canIPv6Allocate := netConfig["ipv6.address"] != "" && netConfig["ipv6.address"] != "none" && (netConfig["ipv6.dhcp"] == "" || shared.IsTrue(netConfig["ipv6.dhcp"])) From ab0236efb708366d412bdb87e614301ae5d1c49d Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@canonical.com> Date: Mon, 28 Oct 2019 11:21:15 +0000 Subject: [PATCH 2/2] test: Adds test for using security.mac_filtering with unmanaged parent Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com> --- ...container_devices_nic_bridged_filtering.sh | 50 +++++++++++++++---- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/test/suites/container_devices_nic_bridged_filtering.sh b/test/suites/container_devices_nic_bridged_filtering.sh index a7a3eeb76f..9376b2aaa8 100644 --- a/test/suites/container_devices_nic_bridged_filtering.sh +++ b/test/suites/container_devices_nic_bridged_filtering.sh @@ -311,13 +311,6 @@ test_container_devices_nic_bridged_filtering() { lxc stop -f "${ctPrefix}A" lxc stop -f "${ctPrefix}B" - # Check we haven't left any NICS lying around. - endNicCount=$(find /sys/class/net | wc -l) - if [ "$startNicCount" != "$endNicCount" ]; then - echo "leftover NICS detected" - false - fi - lxc delete -f "${ctPrefix}A" lxc delete -f "${ctPrefix}B" @@ -345,7 +338,7 @@ test_container_devices_nic_bridged_filtering() { ctAHost=$(lxc config get "${ctPrefix}A" volatile.eth0.host_name) ctAMAC=$(lxc config get "${ctPrefix}A" volatile.eth0.hwaddr) if ! ebtables --concurrent -L --Lmac2 --Lx | grep -e "-s ! ${ctAMAC} -i ${ctAHost} -j DROP" ; then - echo "MAC ebtables filter not applied as part of ipv6_filtering in ebtables" + echo "MAC ebtables filter not applied as part of ip_filtering in ebtables" false fi @@ -383,8 +376,47 @@ test_container_devices_nic_bridged_filtering() { echo "Shouldn't be able to unset IPv6 address with ipv4_filtering enabled and DHCPv6 disabled" fi - # Cleanup. lxc delete -f "${ctPrefix}A" + + # Test MAC filtering on unmanaged bridge. + ip link add "${brName}2" type bridge + + lxc init testimage "${ctPrefix}A" -p "${ctPrefix}" + lxc config device add "${ctPrefix}A" eth0 nic \ + nictype=nic \ + name=eth0 \ + nictype=bridged \ + parent="${brName}2" \ + security.mac_filtering=true + lxc start "${ctPrefix}A" + + # Check MAC filter is present in ebtables. + ctAHost=$(lxc config get "${ctPrefix}A" volatile.eth0.host_name) + ctAMAC=$(lxc config get "${ctPrefix}A" volatile.eth0.hwaddr) + if ! ebtables --concurrent -L --Lmac2 --Lx | grep -e "-s ! ${ctAMAC} -i ${ctAHost} -j DROP" ; then + echo "MAC ebtables filter not applied as part of mac_filtering in ebtables" + false + fi + + # Stop container and check filters are cleaned up. + lxc stop -f "${ctPrefix}A" + if ebtables --concurrent -L --Lmac2 --Lx | grep -e "${ctAHost}" ; then + echo "MAC filter still applied as part of mac_filtering in ebtables" + false + fi + + + lxc delete -f "${ctPrefix}A" + ip link delete "${brName}2" + + # Check we haven't left any NICS lying around. + endNicCount=$(find /sys/class/net | wc -l) + if [ "$startNicCount" != "$endNicCount" ]; then + echo "leftover NICS detected" + false + fi + + # Cleanup. lxc network delete "${brName}" lxc profile delete "${ctPrefix}" }
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel