From 826adc2569413b4852b5536d43a34ec15484b205 Mon Sep 17 00:00:00 2001 From: Rob Hoes Date: Thu, 20 Oct 2016 15:19:13 +0100 Subject: [PATCH] CA-226099: setup-vif-rules: drop all traffic on disabled VIFs This was previously achieved by bringing down the netback device, but that turned out to be problematic (see 1e0eb8734849186ca3f2d8be12dd6f6e5a36f1e7). Signed-off-by: Rob Hoes --- scripts/setup-vif-rules | 162 ++++++++++++++++++++-------------------- 1 file changed, 83 insertions(+), 79 deletions(-) diff --git a/scripts/setup-vif-rules b/scripts/setup-vif-rules index 854c8263e..5edc0e09c 100755 --- a/scripts/setup-vif-rules +++ b/scripts/setup-vif-rules @@ -75,33 +75,36 @@ def clear_bridge_rules(vif_name): do_chain_action(ebtables, "-X", vif_chain) def create_bridge_rules(vif_name, config): - vif_chain = get_chain_name(vif_name) - # Forward all traffic on this VIF to a new chain, with default policy DROP. - do_chain_action(ebtables, "-N", vif_chain) - do_chain_action(ebtables, "-A", "FORWARD", ["-i", vif_name, "-j", vif_chain]) - do_chain_action(ebtables, "-A", "FORWARD", ["-o", vif_name, "-j", vif_chain]) - do_chain_action(ebtables, "-P", vif_chain, ["DROP"]) - # We now need to create rules to allow valid traffic. - mac = config["mac"] - # We only fully support IPv4 multitenancy with bridge. - # We allow all IPv6 traffic if any IPv6 addresses are associated with the VIF. - ipv4_allowed = config["ipv4_allowed"] - ipv6_allowed = config["ipv6_allowed"] - # Accept all traffic going to the VM. - do_chain_action(ebtables, "-A", vif_chain, ["-o", vif_name, "-j", "ACCEPT"]) - # Drop everything not coming from the correct MAC. - do_chain_action(ebtables, "-A", vif_chain, ["-s", "!", mac, "-i", vif_name, "-j", "DROP"]) - # Accept DHCP. - do_chain_action(ebtables, "-A", vif_chain, ["-p", "IPv4", "-i", vif_name, "--ip-protocol", "UDP", "--ip-dport", "67", "-j", "ACCEPT"]) - for ipv4 in ipv4_allowed: - # Accept ARP travelling from known IP addresses, also filtering ARP replies by MAC. - do_chain_action(ebtables, "-A", vif_chain, ["-p", "ARP", "-i", vif_name, "--arp-opcode", "Request", "--arp-ip-src", ipv4, "-j", "ACCEPT"]) - do_chain_action(ebtables, "-A", vif_chain, ["-p", "ARP", "-i", vif_name, "--arp-opcode", "Reply", "--arp-ip-src", ipv4, "--arp-mac-src", mac, "-j", "ACCEPT"]) - # Accept IP travelling from known IP addresses. - do_chain_action(ebtables, "-A", vif_chain, ["-p", "IPv4", "-i", vif_name, "--ip-src", ipv4, "-j", "ACCEPT"]) - if ipv6_allowed != []: - # Accept all IPv6 traffic. - do_chain_action(ebtables, "-A", vif_chain, ["-p", "IPv6", "-i", vif_name, "-j", "ACCEPT"]) + locking_mode = config["locking_mode"] + if locking_mode == "locked" or locking_mode == "disabled": + vif_chain = get_chain_name(vif_name) + # Forward all traffic on this VIF to a new chain, with default policy DROP. + do_chain_action(ebtables, "-N", vif_chain) + do_chain_action(ebtables, "-A", "FORWARD", ["-i", vif_name, "-j", vif_chain]) + do_chain_action(ebtables, "-A", "FORWARD", ["-o", vif_name, "-j", vif_chain]) + do_chain_action(ebtables, "-P", vif_chain, ["DROP"]) + if locking_mode == "locked": + # We now need to create rules to allow valid traffic. + mac = config["mac"] + # We only fully support IPv4 multitenancy with bridge. + # We allow all IPv6 traffic if any IPv6 addresses are associated with the VIF. + ipv4_allowed = config["ipv4_allowed"] + ipv6_allowed = config["ipv6_allowed"] + # Accept all traffic going to the VM. + do_chain_action(ebtables, "-A", vif_chain, ["-o", vif_name, "-j", "ACCEPT"]) + # Drop everything not coming from the correct MAC. + do_chain_action(ebtables, "-A", vif_chain, ["-s", "!", mac, "-i", vif_name, "-j", "DROP"]) + # Accept DHCP. + do_chain_action(ebtables, "-A", vif_chain, ["-p", "IPv4", "-i", vif_name, "--ip-protocol", "UDP", "--ip-dport", "67", "-j", "ACCEPT"]) + for ipv4 in ipv4_allowed: + # Accept ARP travelling from known IP addresses, also filtering ARP replies by MAC. + do_chain_action(ebtables, "-A", vif_chain, ["-p", "ARP", "-i", vif_name, "--arp-opcode", "Request", "--arp-ip-src", ipv4, "-j", "ACCEPT"]) + do_chain_action(ebtables, "-A", vif_chain, ["-p", "ARP", "-i", vif_name, "--arp-opcode", "Reply", "--arp-ip-src", ipv4, "--arp-mac-src", mac, "-j", "ACCEPT"]) + # Accept IP travelling from known IP addresses. + do_chain_action(ebtables, "-A", vif_chain, ["-p", "IPv4", "-i", vif_name, "--ip-src", ipv4, "-j", "ACCEPT"]) + if ipv6_allowed != []: + # Accept all IPv6 traffic. + do_chain_action(ebtables, "-A", vif_chain, ["-p", "IPv6", "-i", vif_name, "-j", "ACCEPT"]) def acquire_lock(path): lock_file = open(path, 'w') @@ -123,9 +126,7 @@ def handle_bridge(vif_name, domuuid, devid, action): clear_bridge_rules(vif_name) if action == "filter": config = get_locking_config(domuuid, devid) - locking_mode = config["locking_mode"] - if locking_mode == "locked": - create_bridge_rules(vif_name, config) + create_bridge_rules(vif_name, config) ip_link_set(vif_name, "up") ############################################################################### @@ -143,53 +144,58 @@ def add_flow(bridge_name, args): doexec([ofctl, "add-flow", bridge_name, "cookie=1," + args]) def create_vswitch_rules(bridge_name, port, config): - mac = config["mac"] - ipv4_allowed = config["ipv4_allowed"] - ipv6_allowed = config["ipv6_allowed"] - # Allow DHCP traffic (outgoing UDP on port 67). - add_flow(bridge_name, "in_port=%s,priority=8000,dl_type=0x0800,nw_proto=0x11," - "tp_dst=67,dl_src=%s,idle_timeout=0,action=normal" % (port, mac)) - # Filter ARP requests. - add_flow(bridge_name, "in_port=%s,priority=7000,dl_type=0x0806,dl_src=%s,arp_sha=%s," - "nw_src=0.0.0.0,idle_timeout=0,action=normal" % (port, mac, mac)) - for ipv4 in ipv4_allowed: - # Filter ARP responses. + locking_mode = config["locking_mode"] + if locking_mode == "locked": + mac = config["mac"] + ipv4_allowed = config["ipv4_allowed"] + ipv6_allowed = config["ipv6_allowed"] + # Allow DHCP traffic (outgoing UDP on port 67). + add_flow(bridge_name, "in_port=%s,priority=8000,dl_type=0x0800,nw_proto=0x11," + "tp_dst=67,dl_src=%s,idle_timeout=0,action=normal" % (port, mac)) + # Filter ARP requests. add_flow(bridge_name, "in_port=%s,priority=7000,dl_type=0x0806,dl_src=%s,arp_sha=%s," - "nw_src=%s,idle_timeout=0,action=normal" % (port, mac, mac, ipv4)) - # Allow traffic from specified ipv4 addresses. - add_flow(bridge_name, "in_port=%s,priority=6000,dl_type=0x0800,nw_src=%s," - "dl_src=%s,idle_timeout=0,action=normal" % (port, ipv4, mac)) - for ipv6 in ipv6_allowed: - # Neighbour solicitation. - add_flow(bridge_name, "in_port=%s,priority=8000,dl_src=%s,icmp6,ipv6_src=%s," - "icmp_type=135,nd_sll=%s,idle_timeout=0,action=normal" % (port, mac, ipv6, mac)) - # Neighbour advertisement. - add_flow(bridge_name, "in_port=%s,priority=8000,dl_src=%s,icmp6,ipv6_src=%s," - "icmp_type=136,nd_target=%s,idle_timeout=0,action=normal" % (port, mac, ipv6, ipv6)) - # Allow traffic from specified ipv6 addresses. - add_flow(bridge_name, "in_port=%s,priority=5000,dl_src=%s,ipv6_src=%s,icmp6,action=normal" % (port, mac, ipv6)) - add_flow(bridge_name, "in_port=%s,priority=5000,dl_src=%s,ipv6_src=%s,tcp6,action=normal" % (port, mac, ipv6)) - add_flow(bridge_name, "in_port=%s,priority=5000,dl_src=%s,ipv6_src=%s,udp6,action=normal" % (port, mac, ipv6)) - # Drop all other neighbour discovery. - add_flow(bridge_name, "in_port=%s,priority=7000,icmp6,icmp_type=135,action=drop" % port) - add_flow(bridge_name, "in_port=%s,priority=7000,icmp6,icmp_type=136,action=drop" % port) - # Drop other specific ICMPv6 types. - # Router advertisement. - add_flow(bridge_name, "in_port=%s,priority=6000,icmp6,icmp_type=134,action=drop" % port) - # Redirect gateway. - add_flow(bridge_name, "in_port=%s,priority=6000,icmp6,icmp_type=137,action=drop" % port) - # Mobile prefix solicitation. - add_flow(bridge_name, "in_port=%s,priority=6000,icmp6,icmp_type=146,action=drop" % port) - # Mobile prefix advertisement. - add_flow(bridge_name, "in_port=%s,priority=6000,icmp6,icmp_type=147,action=drop" % port) - # Multicast router advertisement. - add_flow(bridge_name, "in_port=%s,priority=6000,icmp6,icmp_type=151,action=drop" % port) - # Multicast router solicitation. - add_flow(bridge_name, "in_port=%s,priority=6000,icmp6,icmp_type=152,action=drop" % port) - # Multicast router termination. - add_flow(bridge_name, "in_port=%s,priority=6000,icmp6,icmp_type=153,action=drop" % port) - # Drop everything else. - add_flow(bridge_name, "in_port=%s,priority=4000,idle_timeout=0,action=drop" % port) + "nw_src=0.0.0.0,idle_timeout=0,action=normal" % (port, mac, mac)) + for ipv4 in ipv4_allowed: + # Filter ARP responses. + add_flow(bridge_name, "in_port=%s,priority=7000,dl_type=0x0806,dl_src=%s,arp_sha=%s," + "nw_src=%s,idle_timeout=0,action=normal" % (port, mac, mac, ipv4)) + # Allow traffic from specified ipv4 addresses. + add_flow(bridge_name, "in_port=%s,priority=6000,dl_type=0x0800,nw_src=%s," + "dl_src=%s,idle_timeout=0,action=normal" % (port, ipv4, mac)) + for ipv6 in ipv6_allowed: + # Neighbour solicitation. + add_flow(bridge_name, "in_port=%s,priority=8000,dl_src=%s,icmp6,ipv6_src=%s," + "icmp_type=135,nd_sll=%s,idle_timeout=0,action=normal" % (port, mac, ipv6, mac)) + # Neighbour advertisement. + add_flow(bridge_name, "in_port=%s,priority=8000,dl_src=%s,icmp6,ipv6_src=%s," + "icmp_type=136,nd_target=%s,idle_timeout=0,action=normal" % (port, mac, ipv6, ipv6)) + # Allow traffic from specified ipv6 addresses. + add_flow(bridge_name, "in_port=%s,priority=5000,dl_src=%s,ipv6_src=%s,icmp6,action=normal" % (port, mac, ipv6)) + add_flow(bridge_name, "in_port=%s,priority=5000,dl_src=%s,ipv6_src=%s,tcp6,action=normal" % (port, mac, ipv6)) + add_flow(bridge_name, "in_port=%s,priority=5000,dl_src=%s,ipv6_src=%s,udp6,action=normal" % (port, mac, ipv6)) + # Drop all other neighbour discovery. + add_flow(bridge_name, "in_port=%s,priority=7000,icmp6,icmp_type=135,action=drop" % port) + add_flow(bridge_name, "in_port=%s,priority=7000,icmp6,icmp_type=136,action=drop" % port) + # Drop other specific ICMPv6 types. + # Router advertisement. + add_flow(bridge_name, "in_port=%s,priority=6000,icmp6,icmp_type=134,action=drop" % port) + # Redirect gateway. + add_flow(bridge_name, "in_port=%s,priority=6000,icmp6,icmp_type=137,action=drop" % port) + # Mobile prefix solicitation. + add_flow(bridge_name, "in_port=%s,priority=6000,icmp6,icmp_type=146,action=drop" % port) + # Mobile prefix advertisement. + add_flow(bridge_name, "in_port=%s,priority=6000,icmp6,icmp_type=147,action=drop" % port) + # Multicast router advertisement. + add_flow(bridge_name, "in_port=%s,priority=6000,icmp6,icmp_type=151,action=drop" % port) + # Multicast router solicitation. + add_flow(bridge_name, "in_port=%s,priority=6000,icmp6,icmp_type=152,action=drop" % port) + # Multicast router termination. + add_flow(bridge_name, "in_port=%s,priority=6000,icmp6,icmp_type=153,action=drop" % port) + # Drop everything else. + add_flow(bridge_name, "in_port=%s,priority=4000,idle_timeout=0,action=drop" % port) + elif locking_mode == "disabled": + # Drop everything coming in on this port. + add_flow(bridge_name, "in_port=%s,priority=4000,idle_timeout=0,action=drop" % port) def get_bridge_name_vswitch(vif_name): '''return bridge vif belong to''' @@ -208,9 +214,7 @@ def handle_vswitch(vif_name, domuuid, devid, action): clear_vswitch_rules(bridge_name, port) if action == "filter": config = get_locking_config(domuuid, devid) - locking_mode = config["locking_mode"] - if locking_mode == "locked": - create_vswitch_rules(bridge_name, port, config) + create_vswitch_rules(bridge_name, port, config) ip_link_set(vif_name, "up") ###############################################################################