mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-03 04:12:31 +01:00
CLOUDSTACK-676: IPv6 Basic Security Grouping for KVM
This commit implements basic Security Grouping for KVM in Basic Networking. It does not implement full Security Grouping yet, but it does: - Prevent IP-Address source spoofing - Allow DHCPv6 clients, but disallow DHCPv6 servers - Disallow Instances to send out Router Advertisements The Security Grouping allows ICMPv6 packets as described by RFC4890 as they are essential for IPv6 connectivity. Following RFC4890 it allows: - Router Solicitations - Router Advertisements (incoming only) - Neighbor Advertisements - Neighbor Solicitations - Packet Too Big - Time Exceeded - Destination Unreachable - Parameter Problem - Echo Request ICMPv6 is a essential part of IPv6, without it connectivity will break or be very unreliable. For now it allows any UDP and TCP packet to be send in to the Instance which effectively opens up the firewall completely. Future commits will implement Security Grouping further which allows controlling UDP and TCP ports for IPv6 like can be done with IPv4. Regardless of the egress filtering (which can't be done yet) it will always allow outbound DNS to port 53 over UDP or TCP. Signed-off-by: Wido den Hollander <wido@widodh.nl>
This commit is contained in:
parent
c0e7766713
commit
84e496b4f9
@ -41,6 +41,7 @@ public class SecurityGroupRulesCmd extends Command {
|
||||
private static final Logger LOGGER = Logger.getLogger(SecurityGroupRulesCmd.class);
|
||||
|
||||
private final String guestIp;
|
||||
private final String guestIp6;
|
||||
private final String vmName;
|
||||
private final String guestMac;
|
||||
private final String signature;
|
||||
@ -93,6 +94,7 @@ public class SecurityGroupRulesCmd extends Command {
|
||||
|
||||
public SecurityGroupRulesCmd(
|
||||
final String guestIp,
|
||||
final String guestIp6,
|
||||
final String guestMac,
|
||||
final String vmName,
|
||||
final Long vmId,
|
||||
@ -102,6 +104,7 @@ public class SecurityGroupRulesCmd extends Command {
|
||||
final IpPortAndProto[] egressRuleSet,
|
||||
final List<String> secIps) {
|
||||
this.guestIp = guestIp;
|
||||
this.guestIp6 = guestIp6;
|
||||
this.vmName = vmName;
|
||||
setIngressRuleSet(ingressRuleSet);
|
||||
this.setEgressRuleSet(egressRuleSet);
|
||||
@ -148,6 +151,10 @@ public class SecurityGroupRulesCmd extends Command {
|
||||
return guestIp;
|
||||
}
|
||||
|
||||
public String getGuestIp6() {
|
||||
return guestIp6;
|
||||
}
|
||||
|
||||
public List<String> getSecIps() {
|
||||
return secIps;
|
||||
}
|
||||
|
||||
@ -45,6 +45,7 @@ public class SecurityGroupRulesCmdTest {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final String guestIp = "10.10.10.10";
|
||||
final String guestIp6 = "2001:db8::cad:40ff:fefd:75c4";
|
||||
final String guestMac = "aa:aa:aa:aa:aa:aa";
|
||||
final String vmName = "vm";
|
||||
final Long vmId = 1L;
|
||||
@ -57,7 +58,7 @@ public class SecurityGroupRulesCmdTest {
|
||||
final IpPortAndProto[] ingressRuleSet = new IpPortAndProto[]{new IpPortAndProto(proto, startPort, endPort, allowedCidrs)};
|
||||
final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{new IpPortAndProto(proto, startPort, endPort, allowedCidrs)};
|
||||
final List<String> secIps = new Vector<String>();
|
||||
securityGroupRulesCmd = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps);
|
||||
securityGroupRulesCmd = new SecurityGroupRulesCmd(guestIp, guestIp6, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
2
debian/control
vendored
2
debian/control
vendored
@ -9,7 +9,7 @@ Homepage: http://www.cloudstack.org/
|
||||
|
||||
Package: cloudstack-common
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}, ${python:Depends}, genisoimage, nfs-common
|
||||
Depends: ${misc:Depends}, ${python:Depends}, genisoimage, nfs-common, python-netaddr
|
||||
Conflicts: cloud-scripts, cloud-utils, cloud-system-iso, cloud-console-proxy, cloud-daemonize, cloud-deps, cloud-python, cloud-setup
|
||||
Description: A common package which contains files which are shared by several CloudStack packages
|
||||
|
||||
|
||||
@ -97,6 +97,7 @@ management, and intelligence in CloudStack.
|
||||
Summary: Apache CloudStack common files and scripts
|
||||
Requires: python
|
||||
Requires: python-argparse
|
||||
Requires: python-netaddr
|
||||
Obsoletes: cloud-test < 4.1.0
|
||||
Obsoletes: cloud-scripts < 4.1.0
|
||||
Obsoletes: cloud-utils < 4.1.0
|
||||
|
||||
@ -92,6 +92,7 @@ management, and intelligence in CloudStack.
|
||||
Summary: Apache CloudStack common files and scripts
|
||||
Requires: python
|
||||
Requires: python-argparse
|
||||
Requires: python-netaddr
|
||||
Group: System Environment/Libraries
|
||||
%description common
|
||||
The Apache CloudStack files shared between agent and management server
|
||||
|
||||
@ -3254,6 +3254,9 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||
if (nic.getIp() != null) {
|
||||
cmd.add("--vmip", nic.getIp());
|
||||
}
|
||||
if (nic.getIp6Address() != null) {
|
||||
cmd.add("--vmip6", nic.getIp6Address());
|
||||
}
|
||||
cmd.add("--vmmac", nic.getMac());
|
||||
cmd.add("--vif", vif);
|
||||
cmd.add("--brname", brname);
|
||||
@ -3316,7 +3319,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean addNetworkRules(final String vmName, final String vmId, final String guestIP, final String sig, final String seq, final String mac, final String rules, final String vif, final String brname,
|
||||
public boolean addNetworkRules(final String vmName, final String vmId, final String guestIP, final String guestIP6, final String sig, final String seq, final String mac, final String rules, final String vif, final String brname,
|
||||
final String secIps) {
|
||||
if (!_canBridgeFirewall) {
|
||||
return false;
|
||||
@ -3328,6 +3331,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||
cmd.add("--vmname", vmName);
|
||||
cmd.add("--vmid", vmId);
|
||||
cmd.add("--vmip", guestIP);
|
||||
cmd.add("--vmip6", guestIP6);
|
||||
cmd.add("--sig", sig);
|
||||
cmd.add("--seq", seq);
|
||||
cmd.add("--vmmac", mac);
|
||||
|
||||
@ -54,7 +54,7 @@ public final class LibvirtSecurityGroupRulesCommandWrapper extends CommandWrappe
|
||||
return new SecurityGroupRuleAnswer(command, false, e.toString());
|
||||
}
|
||||
|
||||
final boolean result = libvirtComputingResource.addNetworkRules(command.getVmName(), Long.toString(command.getVmId()), command.getGuestIp(), command.getSignature(),
|
||||
final boolean result = libvirtComputingResource.addNetworkRules(command.getVmName(), Long.toString(command.getVmId()), command.getGuestIp(), command.getGuestIp6(), command.getSignature(),
|
||||
Long.toString(command.getSeqNum()), command.getGuestMac(), command.stringifyRules(), vif, brname, command.getSecIpsString());
|
||||
|
||||
if (!result) {
|
||||
|
||||
@ -2912,6 +2912,7 @@ public class LibvirtComputingResourceTest {
|
||||
@Test
|
||||
public void testSecurityGroupRulesCmdFalse() {
|
||||
final String guestIp = "127.0.0.1";
|
||||
final String guestIp6 = "2001:db8::cad:40ff:fefd:75c4";
|
||||
final String guestMac = "00:00:00:00";
|
||||
final String vmName = "Test";
|
||||
final Long vmId = 1l;
|
||||
@ -2923,7 +2924,7 @@ public class LibvirtComputingResourceTest {
|
||||
final List<String> cidrs = new Vector<String>();
|
||||
cidrs.add("0.0.0.0/0");
|
||||
|
||||
final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps);
|
||||
final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestIp6, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps);
|
||||
|
||||
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class);
|
||||
final Connect conn = Mockito.mock(Connect.class);
|
||||
@ -2967,6 +2968,7 @@ public class LibvirtComputingResourceTest {
|
||||
@Test
|
||||
public void testSecurityGroupRulesCmdTrue() {
|
||||
final String guestIp = "127.0.0.1";
|
||||
final String guestIp6 = "2001:db8::cad:40ff:fefd:75c4";
|
||||
final String guestMac = "00:00:00:00";
|
||||
final String vmName = "Test";
|
||||
final Long vmId = 1l;
|
||||
@ -2978,7 +2980,7 @@ public class LibvirtComputingResourceTest {
|
||||
final List<String> cidrs = new Vector<String>();
|
||||
cidrs.add("0.0.0.0/0");
|
||||
|
||||
final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps);
|
||||
final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestIp6, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps);
|
||||
|
||||
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class);
|
||||
final Connect conn = Mockito.mock(Connect.class);
|
||||
@ -3011,7 +3013,7 @@ public class LibvirtComputingResourceTest {
|
||||
when(egressRuleSet[0].getEndPort()).thenReturn(22);
|
||||
when(egressRuleSet[0].getAllowedCidrs()).thenReturn(cidrs);
|
||||
|
||||
when(libvirtComputingResource.addNetworkRules(command.getVmName(), Long.toString(command.getVmId()), command.getGuestIp(), command.getSignature(),
|
||||
when(libvirtComputingResource.addNetworkRules(command.getVmName(), Long.toString(command.getVmId()), command.getGuestIp(), command.getGuestIp6(), command.getSignature(),
|
||||
Long.toString(command.getSeqNum()), command.getGuestMac(), command.stringifyRules(), vif, brname, command.getSecIpsString())).thenReturn(true);
|
||||
|
||||
final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance();
|
||||
@ -3032,6 +3034,7 @@ public class LibvirtComputingResourceTest {
|
||||
@Test
|
||||
public void testSecurityGroupRulesCmdException() {
|
||||
final String guestIp = "127.0.0.1";
|
||||
final String guestIp6 = "2001:db8::cad:40ff:fefd:75c4";
|
||||
final String guestMac = "00:00:00:00";
|
||||
final String vmName = "Test";
|
||||
final Long vmId = 1l;
|
||||
@ -3041,7 +3044,7 @@ public class LibvirtComputingResourceTest {
|
||||
final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)};
|
||||
final List<String> secIps = new Vector<String>();
|
||||
|
||||
final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps);
|
||||
final SecurityGroupRulesCmd command = new SecurityGroupRulesCmd(guestIp, guestIp6, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps);
|
||||
|
||||
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class);
|
||||
final Connect conn = Mockito.mock(Connect.class);
|
||||
|
||||
@ -743,6 +743,7 @@ public class CitrixRequestWrapperTest {
|
||||
final XsHost xsHost = Mockito.mock(XsHost.class);
|
||||
|
||||
final String guestIp = "127.0.0.1";
|
||||
final String guestIp6 = "2001:db8::cad:40ff:fefd:75c4";
|
||||
final String guestMac = "00:00:00:00";
|
||||
final String vmName = "Test";
|
||||
final Long vmId = 1l;
|
||||
@ -752,7 +753,7 @@ public class CitrixRequestWrapperTest {
|
||||
final IpPortAndProto[] egressRuleSet = new IpPortAndProto[]{Mockito.mock(IpPortAndProto.class)};
|
||||
final List<String> secIps = new Vector<String>();
|
||||
|
||||
final SecurityGroupRulesCmd sshCommand = new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps);
|
||||
final SecurityGroupRulesCmd sshCommand = new SecurityGroupRulesCmd(guestIp, guestIp6, guestMac, vmName, vmId, signature, seqNum, ingressRuleSet, egressRuleSet, secIps);
|
||||
|
||||
final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance();
|
||||
assertNotNull(wrapper);
|
||||
|
||||
@ -28,6 +28,9 @@ import re
|
||||
import libvirt
|
||||
import fcntl
|
||||
import time
|
||||
from netaddr import IPAddress
|
||||
from netaddr.core import AddrFormatError
|
||||
|
||||
|
||||
logpath = "/var/run/cloud/" # FIXME: Logs should reside in /var/log/cloud
|
||||
lock_file = "/var/lock/cloudstack_security_group.lock"
|
||||
@ -178,6 +181,14 @@ def virshdumpxml(domain):
|
||||
|
||||
return xml
|
||||
|
||||
|
||||
def ipv6_link_local_addr(mac=None):
|
||||
eui64 = re.sub(r'[.:-]', '', mac).lower()
|
||||
eui64 = eui64[0:6] + 'fffe' + eui64[6:]
|
||||
eui64 = hex(int(eui64[0:2], 16) ^ 2)[2:].zfill(2) + eui64[2:]
|
||||
return IPAddress('fe80::' + ':'.join(re.findall(r'.{4}', eui64)))
|
||||
|
||||
|
||||
def destroy_network_rules_for_vm(vm_name, vif=None):
|
||||
vmchain = vm_name
|
||||
vmchain_egress = egress_chain_name(vm_name)
|
||||
@ -193,18 +204,21 @@ def destroy_network_rules_for_vm(vm_name, vif=None):
|
||||
for chain in filter(None, chains):
|
||||
try:
|
||||
execute("iptables -F " + chain)
|
||||
execute('ip6tables -F ' + chain)
|
||||
except:
|
||||
logging.debug("Ignoring failure to flush chain: " + chain)
|
||||
|
||||
for chain in filter(None, chains):
|
||||
try:
|
||||
execute("iptables -X " + chain)
|
||||
execute('ip6tables -X ' + chain)
|
||||
except:
|
||||
logging.debug("Ignoring failure to delete chain: " + chain)
|
||||
|
||||
try:
|
||||
execute("ipset -F " + vm_name)
|
||||
execute("ipset -X " + vm_name)
|
||||
for ipset in [vm_name, vm_name + '-6']:
|
||||
execute('ipset -F ' + ipset)
|
||||
execute('ipset -X ' + ipset)
|
||||
except:
|
||||
logging.debug("Ignoring failure to delete ipset " + vmchain)
|
||||
|
||||
@ -371,16 +385,16 @@ def write_secip_log_for_vm (vmName, secIps, vmId):
|
||||
|
||||
return result
|
||||
|
||||
def create_ipset_forvm (ipsetname):
|
||||
def create_ipset_forvm(ipsetname, type='iphash', family='inet'):
|
||||
result = True
|
||||
try:
|
||||
logging.debug("Creating ipset chain .... " + ipsetname)
|
||||
execute("ipset -F " + ipsetname)
|
||||
execute("ipset -X " + ipsetname)
|
||||
execute("ipset -N " + ipsetname + " iphash")
|
||||
except:
|
||||
logging.debug("ipset chain not exists creating.... " + ipsetname)
|
||||
execute("ipset -N " + ipsetname + " iphash")
|
||||
finally:
|
||||
execute('ipset -N ' + ipsetname + ' ' + type + ' family ' + family)
|
||||
|
||||
return result
|
||||
|
||||
@ -388,10 +402,10 @@ def add_to_ipset(ipsetname, ips, action):
|
||||
result = True
|
||||
for ip in ips:
|
||||
try:
|
||||
logging.debug("vm ip " + ip)
|
||||
execute("ipset " + action + " " + ipsetname + " " + ip)
|
||||
logging.debug("vm ip " + str(ip))
|
||||
execute("ipset " + action + " " + ipsetname + " " + str(ip))
|
||||
except:
|
||||
logging.debug("vm ip already in ip set " + ip)
|
||||
logging.debug("vm ip already in ip set " + str(ip))
|
||||
continue
|
||||
|
||||
return result
|
||||
@ -427,7 +441,7 @@ def ebtables_rules_vmip (vmname, ips, action):
|
||||
except:
|
||||
logging.debug("Failed to program ebtables rules for secondary ip %s for vm %s with action %s" % (ip, vmname, action))
|
||||
|
||||
def default_network_rules(vm_name, vm_id, vm_ip, vm_mac, vif, brname, sec_ips):
|
||||
def default_network_rules(vm_name, vm_id, vm_ip, vm_ip6, vm_mac, vif, brname, sec_ips):
|
||||
if not addFWFramework(brname):
|
||||
return False
|
||||
|
||||
@ -438,23 +452,20 @@ def default_network_rules(vm_name, vm_id, vm_ip, vm_mac, vif, brname, sec_ips):
|
||||
vmchain = vm_name
|
||||
vmchain_egress = egress_chain_name(vm_name)
|
||||
vmchain_default = '-'.join(vmchain.split('-')[:-1]) + "-def"
|
||||
ipv6_link_local = ipv6_link_local_addr(vm_mac)
|
||||
|
||||
destroy_ebtables_rules(vmName, vif)
|
||||
|
||||
try:
|
||||
execute("iptables -N " + vmchain)
|
||||
except:
|
||||
execute("iptables -F " + vmchain)
|
||||
for chain in [vmchain, vmchain_egress, vmchain_default]:
|
||||
try:
|
||||
execute('iptables -N ' + chain)
|
||||
except:
|
||||
execute('iptables -F ' + chain)
|
||||
|
||||
try:
|
||||
execute("iptables -N " + vmchain_egress)
|
||||
except:
|
||||
execute("iptables -F " + vmchain_egress)
|
||||
|
||||
try:
|
||||
execute("iptables -N " + vmchain_default)
|
||||
except:
|
||||
execute("iptables -F " + vmchain_default)
|
||||
try:
|
||||
execute('ip6tables -N ' + chain)
|
||||
except:
|
||||
execute('ip6tables -F ' + chain)
|
||||
|
||||
action = "-A"
|
||||
vmipsetName = vm_name
|
||||
@ -509,6 +520,79 @@ def default_network_rules(vm_name, vm_id, vm_ip, vm_mac, vif, brname, sec_ips):
|
||||
if write_rule_log_for_vm(vmName, vm_id, vm_ip, domID, '_initial_', '-1') == False:
|
||||
logging.debug("Failed to log default network rules, ignoring")
|
||||
|
||||
vm_ip6_set_name = vm_name + '-6'
|
||||
|
||||
if not create_ipset_forvm(vm_ip6_set_name, family='inet6', type='hash:net'):
|
||||
logging.debug(" failed to create ivp6 ipset for rule " + str(tokens))
|
||||
return 'false'
|
||||
|
||||
vm_ip6_addr = [ipv6_link_local]
|
||||
try:
|
||||
ip6 = IPAddress(vm_ip6)
|
||||
if ip6.version == 6:
|
||||
vm_ip6_addr.append(ip6)
|
||||
except AddrFormatError:
|
||||
pass
|
||||
|
||||
add_to_ipset(vm_ip6_set_name, vm_ip6_addr, action)
|
||||
|
||||
try:
|
||||
execute('ip6tables -A ' + brfw + '-OUT' + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -j ' + vmchain_default)
|
||||
execute('ip6tables -A ' + brfw + '-IN' + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -j ' + vmchain_default)
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m state --state RELATED,ESTABLISHED -j ACCEPT')
|
||||
|
||||
# Allow Instances to receive Router Advertisements, send out solicitations, but block any outgoing Advertisement from a Instance
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' --src fe80::/64 --dst ff02::1 -p icmpv6 --icmpv6-type router-advertisement -j ACCEPT')
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' --dst ff02::2 -p icmpv6 --icmpv6-type router-solicitation -j RETURN')
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type router-advertisement -j DROP')
|
||||
|
||||
# Allow neighbor solicitations and advertisements
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type neighbor-solicitation -j RETURN')
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -p icmpv6 --icmpv6-type neighbor-solicitation -j ACCEPT')
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type neighbor-advertisement -m set --match-set ' + vm_ip6_set_name + ' src -j RETURN')
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -p icmpv6 --icmpv6-type neighbor-advertisement -j ACCEPT')
|
||||
|
||||
# Packets to allow as per RFC4890
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type packet-too-big -m set --match-set ' + vm_ip6_set_name + ' src -j RETURN')
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT')
|
||||
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type destination-unreachable -m set --match-set ' + vm_ip6_set_name + ' src -j RETURN')
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT')
|
||||
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type time-exceeded -m set --match-set ' + vm_ip6_set_name + ' src -j RETURN')
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -p icmpv6 --icmpv6-type time-exceeded -j ACCEPT')
|
||||
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p icmpv6 --icmpv6-type parameter-problem -m set --match-set ' + vm_ip6_set_name + ' src -j RETURN')
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -p icmpv6 --icmpv6-type parameter-problem -j ACCEPT')
|
||||
|
||||
# Allow Instances to send out DHCPv6 client messages, but block server messages
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p udp --sport 546 --dst ff02::1:2 --src ' + str(ipv6_link_local) + ' -j RETURN')
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -p udp --src fe80::/64 --dport 546 --dst ' + str(ipv6_link_local) + ' -j ACCEPT')
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p udp --sport 547 ! --dst fe80::/64 -j DROP')
|
||||
|
||||
# Always allow outbound DNS over UDP and TCP
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p udp --dport 53 -m set --match-set ' + vm_ip6_set_name + ' src -j RETURN')
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -p tcp --dport 53 -m set --match-set ' + vm_ip6_set_name + ' src -j RETURN')
|
||||
|
||||
# Prevent source address spoofing
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -m set ! --match-set ' + vm_ip6_set_name + ' src -j DROP')
|
||||
|
||||
# Send proper traffic to the egress chain of the Instance
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-in ' + vif + ' -m set --match-set ' + vm_ip6_set_name + ' src -j ' + vmchain_egress)
|
||||
|
||||
execute('ip6tables -A ' + vmchain_default + ' -m physdev --physdev-is-bridged --physdev-out ' + vif + ' -j ' + vmchain)
|
||||
|
||||
# For now allow ICMPv6 echo-request, UDP and TCP traffic to the Unicast address of the Instance
|
||||
execute('ip6tables -A ' + vmchain + ' -p icmpv6 --icmpv6-type echo-request -m set --match-set ' + vm_ip6_set_name + ' dst -j ACCEPT')
|
||||
execute('ip6tables -A ' + vmchain + ' -p udp -m set --match-set ' + vm_ip6_set_name + ' dst -j ACCEPT')
|
||||
execute('ip6tables -A ' + vmchain + ' -p tcp -m set --match-set ' + vm_ip6_set_name + ' dst -j ACCEPT')
|
||||
|
||||
# Drop all other traffic into the Instance
|
||||
execute('ip6tables -A ' + vmchain + ' -j DROP')
|
||||
except:
|
||||
logging.debug('Failed to program default rules for vm ' + vm_name)
|
||||
return 'false'
|
||||
|
||||
logging.debug("Programmed default rules for vm " + vm_name)
|
||||
return 'true'
|
||||
|
||||
@ -541,6 +625,7 @@ def post_default_network_rules(vm_name, vm_id, vm_ip, vm_mac, vif, brname, dhcpS
|
||||
pass
|
||||
if write_rule_log_for_vm(vm_name, vm_id, vm_ip, domID, '_initial_', '-1') == False:
|
||||
logging.debug("Failed to log default network rules, ignoring")
|
||||
|
||||
def delete_rules_for_vm_in_bridge_firewall_chain(vmName):
|
||||
vm_name = vmName
|
||||
if vm_name.startswith('i-'):
|
||||
@ -556,6 +641,14 @@ def delete_rules_for_vm_in_bridge_firewall_chain(vmName):
|
||||
except:
|
||||
logging.exception("Ignoring failure to delete rules for vm " + vmName)
|
||||
|
||||
delcmd = """ip6tables-save | awk '/BF(.*)physdev-is-bridged(.*)%s/ { sub(/-A/, "-D", $1) ; print }'""" % vmchain
|
||||
delcmds = filter(None, execute(delcmd).split('\n'))
|
||||
for cmd in delcmds:
|
||||
try:
|
||||
execute('ip6tables ' + cmd)
|
||||
except:
|
||||
logging.exception("Ignoring failure to delete rules for vm " + vmName)
|
||||
|
||||
def rewrite_rule_log_for_vm(vm_name, new_domid):
|
||||
logfilename = logpath + vm_name + ".log"
|
||||
if not os.path.exists(logfilename):
|
||||
@ -638,6 +731,8 @@ def network_rules_for_rebooted_vm(vmName):
|
||||
for v in vifs:
|
||||
execute("iptables -A " + getBrfw(brName) + "-IN " + " -m physdev --physdev-is-bridged --physdev-in " + v + " -j "+ vmchain_default)
|
||||
execute("iptables -A " + getBrfw(brName) + "-OUT " + " -m physdev --physdev-is-bridged --physdev-out " + v + " -j "+ vmchain_default)
|
||||
execute("ip6tables -A " + getBrfw(brName) + "-IN " + " -m physdev --physdev-is-bridged --physdev-in " + v + " -j " + vmchain_default)
|
||||
execute("ip6tables -A " + getBrfw(brName) + "-OUT " + " -m physdev --physdev-is-bridged --physdev-out " + v + " -j " + vmchain_default)
|
||||
|
||||
#change antispoof rule in vmchain
|
||||
try:
|
||||
@ -809,7 +904,7 @@ def remove_rule_log_for_vm(vmName):
|
||||
def egress_chain_name(vm_name):
|
||||
return vm_name + "-eg"
|
||||
|
||||
def add_network_rules(vm_name, vm_id, vm_ip, signature, seqno, vmMac, rules, vif, brname, sec_ips):
|
||||
def add_network_rules(vm_name, vm_id, vm_ip, vm_ip6, signature, seqno, vmMac, rules, vif, brname, sec_ips):
|
||||
try:
|
||||
vmName = vm_name
|
||||
domId = getvmId(vmName)
|
||||
@ -822,7 +917,7 @@ def add_network_rules(vm_name, vm_id, vm_ip, signature, seqno, vmMac, rules, vif
|
||||
return 'true'
|
||||
|
||||
if changes[0] or changes[1] or changes[2] or changes[3]:
|
||||
default_network_rules(vmName, vm_id, vm_ip, vmMac, vif, brname, sec_ips)
|
||||
default_network_rules(vmName, vm_id, vm_ip, vm_ip6, vmMac, vif, brname, sec_ips)
|
||||
|
||||
if rules == "" or rules == None:
|
||||
lines = []
|
||||
@ -837,7 +932,7 @@ def add_network_rules(vm_name, vm_id, vm_ip, signature, seqno, vmMac, rules, vif
|
||||
execute("iptables -F " + egress_vmchain)
|
||||
except:
|
||||
logging.debug("Error flushing iptables rules for " + vmchain + ". Presuming firewall rules deleted, re-initializing." )
|
||||
default_network_rules(vm_name, vm_id, vm_ip, vmMac, vif, brname, sec_ips)
|
||||
default_network_rules(vm_name, vm_id, vm_ip, vm_ip6, vmMac, vif, brname, sec_ips)
|
||||
egressrule = 0
|
||||
for line in lines:
|
||||
tokens = line.split(':')
|
||||
@ -1005,8 +1100,27 @@ def addFWFramework(brname):
|
||||
execute("iptables -N " + brfwin)
|
||||
|
||||
try:
|
||||
refs = execute("""iptables -n -L %s | awk '/%s(.*)references/ {gsub(/\(/, "") ;print $3}'""" % (brfw,brfw)).strip()
|
||||
if refs == "0":
|
||||
execute('ip6tables -L ' + brfw)
|
||||
except:
|
||||
execute('ip6tables -N ' + brfw)
|
||||
|
||||
brfwout = brfw + "-OUT"
|
||||
try:
|
||||
execute('ip6tables -L ' + brfwout)
|
||||
except:
|
||||
execute('ip6tables -N ' + brfwout)
|
||||
|
||||
brfwin = brfw + "-IN"
|
||||
try:
|
||||
execute('ip6tables -L ' + brfwin)
|
||||
except:
|
||||
execute('ip6tables -N ' + brfwin)
|
||||
|
||||
try:
|
||||
refs = int(execute("""iptables -n -L %s | awk '/%s(.*)references/ {gsub(/\(/, "") ;print $3}'""" % (brfw,brfw)).strip())
|
||||
refs6 = int(execute("""ip6tables -n -L %s | awk '/%s(.*)references/ {gsub(/\(/, "") ;print $3}'""" % (brfw,brfw)).strip())
|
||||
|
||||
if refs == 0:
|
||||
execute("iptables -I FORWARD -i " + brname + " -j DROP")
|
||||
execute("iptables -I FORWARD -o " + brname + " -j DROP")
|
||||
execute("iptables -I FORWARD -i " + brname + " -m physdev --physdev-is-bridged -j " + brfw)
|
||||
@ -1016,10 +1130,23 @@ def addFWFramework(brname):
|
||||
execute("iptables -A " + brfw + " -m physdev --physdev-is-bridged --physdev-is-in -j " + brfwin)
|
||||
execute("iptables -A " + brfw + " -m physdev --physdev-is-bridged --physdev-is-out -j " + brfwout)
|
||||
execute("iptables -A " + brfw + " -m physdev --physdev-is-bridged --physdev-out " + phydev + " -j ACCEPT")
|
||||
|
||||
if refs6 == 0:
|
||||
execute('ip6tables -I FORWARD -i ' + brname + ' -j DROP')
|
||||
execute('ip6tables -I FORWARD -o ' + brname + ' -j DROP')
|
||||
execute('ip6tables -I FORWARD -i ' + brname + ' -m physdev --physdev-is-bridged -j ' + brfw)
|
||||
execute('ip6tables -I FORWARD -o ' + brname + ' -m physdev --physdev-is-bridged -j ' + brfw)
|
||||
phydev = execute("brctl show | awk '/^%s[ \t]/ {print $4}'" % brname ).strip()
|
||||
execute('ip6tables -A ' + brfw + ' -m state --state RELATED,ESTABLISHED -j ACCEPT')
|
||||
execute('ip6tables -A ' + brfw + ' -m physdev --physdev-is-bridged --physdev-is-in -j ' + brfwin)
|
||||
execute('ip6tables -A ' + brfw + ' -m physdev --physdev-is-bridged --physdev-is-out -j ' + brfwout)
|
||||
execute('ip6tables -A ' + brfw + ' -m physdev --physdev-is-bridged --physdev-out ' + phydev + ' -j ACCEPT')
|
||||
|
||||
return True
|
||||
except:
|
||||
try:
|
||||
execute("iptables -F " + brfw)
|
||||
execute('ip6tables -F ' + brfw)
|
||||
except:
|
||||
return False
|
||||
return False
|
||||
@ -1029,6 +1156,7 @@ if __name__ == '__main__':
|
||||
parser = OptionParser()
|
||||
parser.add_option("--vmname", dest="vmName")
|
||||
parser.add_option("--vmip", dest="vmIP")
|
||||
parser.add_option("--vmip6", dest="vmIP6")
|
||||
parser.add_option("--vmid", dest="vmID")
|
||||
parser.add_option("--vmmac", dest="vmMAC")
|
||||
parser.add_option("--vif", dest="vif")
|
||||
@ -1059,7 +1187,7 @@ if __name__ == '__main__':
|
||||
if cmd == "can_bridge_firewall":
|
||||
can_bridge_firewall(args[1])
|
||||
elif cmd == "default_network_rules":
|
||||
default_network_rules(option.vmName, option.vmID, option.vmIP, option.vmMAC, option.vif, option.brname, option.nicSecIps)
|
||||
default_network_rules(option.vmName, option.vmID, option.vmIP, option.vmIP6, option.vmMAC, option.vif, option.brname, option.nicSecIps)
|
||||
elif cmd == "destroy_network_rules_for_vm":
|
||||
destroy_network_rules_for_vm(option.vmName, option.vif)
|
||||
elif cmd == "default_network_rules_systemvm":
|
||||
@ -1067,7 +1195,7 @@ if __name__ == '__main__':
|
||||
elif cmd == "get_rule_logs_for_vms":
|
||||
get_rule_logs_for_vms()
|
||||
elif cmd == "add_network_rules":
|
||||
add_network_rules(option.vmName, option.vmID, option.vmIP, option.sig, option.seq, option.vmMAC, option.rules, option.vif, option.brname, option.nicSecIps)
|
||||
add_network_rules(option.vmName, option.vmID, option.vmIP, option.vmIP6, option.sig, option.seq, option.vmMAC, option.rules, option.vif, option.brname, option.nicSecIps)
|
||||
elif cmd == "network_rules_vmSecondaryIp":
|
||||
network_rules_vmSecondaryIp(option.vmName, option.nicSecIps, option.action)
|
||||
elif cmd == "cleanup_rules":
|
||||
|
||||
@ -496,7 +496,7 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro
|
||||
return affectedVms;
|
||||
}
|
||||
|
||||
protected SecurityGroupRulesCmd generateRulesetCmd(String vmName, String guestIp, String guestMac, Long vmId, String signature, long seqnum,
|
||||
protected SecurityGroupRulesCmd generateRulesetCmd(String vmName, String guestIp, String guestIp6, String guestMac, Long vmId, String signature, long seqnum,
|
||||
Map<PortAndProto, Set<String>> ingressRules, Map<PortAndProto, Set<String>> egressRules, List<String> secIps) {
|
||||
List<IpPortAndProto> ingressResult = new ArrayList<IpPortAndProto>();
|
||||
List<IpPortAndProto> egressResult = new ArrayList<IpPortAndProto>();
|
||||
@ -516,7 +516,7 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro
|
||||
egressResult.add(ipPortAndProto);
|
||||
}
|
||||
}
|
||||
return new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqnum, ingressResult.toArray(new IpPortAndProto[ingressResult.size()]),
|
||||
return new SecurityGroupRulesCmd(guestIp, guestIp6, guestMac, vmName, vmId, signature, seqnum, ingressResult.toArray(new IpPortAndProto[ingressResult.size()]),
|
||||
egressResult.toArray(new IpPortAndProto[egressResult.size()]), secIps);
|
||||
}
|
||||
|
||||
@ -1005,7 +1005,7 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro
|
||||
nicSecIps = _nicSecIpDao.getSecondaryIpAddressesForNic(nic.getId());
|
||||
}
|
||||
}
|
||||
SecurityGroupRulesCmd cmd = generateRulesetCmd(vm.getInstanceName(), vm.getPrivateIpAddress(), vm.getPrivateMacAddress(), vm.getId(),
|
||||
SecurityGroupRulesCmd cmd = generateRulesetCmd(vm.getInstanceName(), nic.getIPv6Address(), vm.getPrivateIpAddress(), vm.getPrivateMacAddress(), vm.getId(),
|
||||
generateRulesetSignature(ingressRules, egressRules), seqnum, ingressRules, egressRules, nicSecIps);
|
||||
Commands cmds = new Commands(cmd);
|
||||
try {
|
||||
|
||||
@ -186,7 +186,7 @@ public class SecurityGroupManagerImpl2 extends SecurityGroupManagerImpl {
|
||||
}
|
||||
}
|
||||
SecurityGroupRulesCmd cmd =
|
||||
generateRulesetCmd(vm.getInstanceName(), vm.getPrivateIpAddress(), vm.getPrivateMacAddress(), vm.getId(), null, work.getLogsequenceNumber(),
|
||||
generateRulesetCmd(vm.getInstanceName(), vm.getPrivateIpAddress(), nic.getIPv6Address(), vm.getPrivateMacAddress(), vm.getId(), null, work.getLogsequenceNumber(),
|
||||
ingressRules, egressRules, nicSecIps);
|
||||
cmd.setMsId(_serverId);
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user