From d4e7eb818c9f4ec51fd3a88a0e92d557867511d4 Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Mon, 17 Jan 2011 23:18:46 -0500 Subject: Add rules to database, cast refresh message and trickle down to firewall driver. --- nova/virt/connection.py | 1 + nova/virt/libvirt_conn.py | 10 ++++++++++ 2 files changed, 11 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/connection.py b/nova/virt/connection.py index 13181b730..f5a978997 100644 --- a/nova/virt/connection.py +++ b/nova/virt/connection.py @@ -54,6 +54,7 @@ def get_connection(read_only=False): * fake * libvirt * xenapi + * hyperv """ # TODO(termie): maybe lazy load after initial check for permissions # TODO(termie): check whether we can be disconnected diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index f38af5ed8..fa5dc502e 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -848,6 +848,9 @@ class LibvirtConnection(object): def refresh_security_group_members(self, security_group_id): self.firewall_driver.refresh_security_group_members(security_group_id) + def refresh_provier_fw_rules(self): + self.firewall_driver.refresh_provider_fw_rules() + class FirewallDriver(object): def prepare_instance_filter(self, instance): @@ -884,6 +887,13 @@ class FirewallDriver(object): the security group.""" raise NotImplementedError() + def refresh_provider_fw_rules(self): + """Refresh common rules for all hosts/instances from data store. + + Gets called when a rule has been added to or removed from + the list of rules (via admin api).""" + raise NotImplementedError() + class NWFilterFirewall(FirewallDriver): """ -- cgit From c58a8edb5c282f661d5be361ce68131516c741ba Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Wed, 19 Jan 2011 15:17:06 -0500 Subject: Implement provider-level firewall rules in nwfilter. --- nova/virt/libvirt_conn.py | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index b189a5b31..68503ef68 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1408,6 +1408,8 @@ class NWFilterFirewall(FirewallDriver): instance_secgroup_filter_children += [('nova-secgroup-%s' % security_group['id'])] + instance_filter_children += ['nova-provider-rules'] + self._define_filter( self._filter_container(instance_secgroup_filter_name, instance_secgroup_filter_children)) @@ -1422,6 +1424,18 @@ class NWFilterFirewall(FirewallDriver): return self._define_filter( self.security_group_to_nwfilter_xml(security_group_id)) + def refresh_provider_fw_rules(self): + """Update rules for all instances. + + This is part of the FirewallDriver API and is called when the + provider firewall rules change in the database. In the + `prepare_instance_filter` we add a reference to the + 'nova-provider-rules' filter for each instance's firewall, and + by changing that filter we update them all. + """ + xml = self.provider_fw_to_nwfilter_xml(self) + return self._define_filter(xml) + def security_group_to_nwfilter_xml(self, security_group_id): security_group = db.security_group_get(context.get_admin_context(), security_group_id) @@ -1460,6 +1474,43 @@ class NWFilterFirewall(FirewallDriver): xml += "chain='ipv4'>%s" % rule_xml return xml + def provider_fw_to_nwfilter_xml(self): + """Compose a filter of drop rules from specified cidrs.""" + rule_xml = "" + v6protocol = {'tcp': 'tcp-ipv6', 'udp': 'udp-ipv6', 'icmp': 'icmpv6'} + rules = db.provider_fw_rule_get_all(context.get_admin_context()) + for rule in rules: + rule_xml += "" + version = _get_ip_version(rule.cidr) + if(FLAGS.use_ipv6 and version == 6): + net, prefixlen = _get_net_and_prefixlen(rule.cidr) + rule_xml += "<%s srcipaddr='%s' srcipmask='%s' " % \ + (v6protocol[rule.protocol], net, prefixlen) + else: + net, mask = _get_net_and_mask(rule.cidr) + rule_xml += "<%s srcipaddr='%s' srcipmask='%s' " % \ + (rule.protocol, net, mask) + if rule.protocol in ['tcp', 'udp']: + rule_xml += "dstportstart='%s' dstportend='%s' " % \ + (rule.from_port, rule.to_port) + elif rule.protocol == 'icmp': + LOG.info('rule.protocol: %r, rule.from_port: %r, ' + 'rule.to_port: %r', rule.protocol, + rule.from_port, rule.to_port) + if rule.from_port != -1: + rule_xml += "type='%s' " % rule.from_port + if rule.to_port != -1: + rule_xml += "code='%s' " % rule.to_port + + rule_xml += '/>\n' + rule_xml += "\n" + xml = " Date: Thu, 20 Jan 2011 11:37:15 -0500 Subject: A couple of copypasta errors. --- nova/virt/libvirt_conn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index dc5a9fc06..4f3107c88 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -848,7 +848,7 @@ class LibvirtConnection(object): def refresh_security_group_members(self, security_group_id): self.firewall_driver.refresh_security_group_members(security_group_id) - def refresh_provier_fw_rules(self): + def refresh_provider_fw_rules(self): self.firewall_driver.refresh_provider_fw_rules() -- cgit From f02c9e781bdddd609601da81b97a438b6d5b9781 Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Fri, 21 Jan 2011 12:30:26 -0500 Subject: Add provider_fw_rules awareness to iptables firewall driver. --- nova/virt/libvirt_conn.py | 49 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 4f3107c88..38eddf748 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1290,7 +1290,51 @@ class IptablesFirewallDriver(FirewallDriver): our_rules = ['-A nova-fallback -j DROP'] our_chains += [':nova-local - [0:0]'] - our_rules += ['-A FORWARD -j nova-local'] + + our_chains += [':nova-provider - [0:0]'] + our_rules += ['-A FORWARD -j nova-provider'] + + rules = db.provider_fw_rule_get_all(ctxt) + for rule in rules: + logging.info('%r', rule) + version = _get_ip_version(rule.cidr) + if version != ip_version: + continue + protocol = rule.protocol + if version == 6 and rule.protocol == 'icmp': + protocol = 'icmpv6' + args = ['-A nova-provider -p', protocol, '-s', rule.cidr] + + if rule.protocol in ['udp', 'tcp']: + if rule.from_port == rule.to_port: + args += ['--dport', '%s' % (rule.from_port,)] + else: + args += ['-m', 'multiport', + '--dports', '%s:%s' % (rule.from_port, + rule.to_port)] + elif rule.protocol == 'icmp': + icmp_type = rule.from_port + icmp_code = rule.to_port + + if icmp_type == -1: + icmp_type_arg = None + else: + icmp_type_arg = '%s' % icmp_type + if not icmp_code == -1: + icmp_type_arg += '/%s' % icmp_code + + if icmp_type_arg: + if(ip_version == 4): + args += ['-m', 'icmp', '--icmp-type', + icmp_type_arg] + elif(ip_version == 6): + args += ['-m', 'icmp6', '--icmpv6-type', + icmp_type_arg] + + args += ['-j DROP'] + our_rules += [' '.join(args)] + + our_rules += ['-A nova-provider -j nova-local'] security_groups = {} # Add our chains @@ -1409,6 +1453,9 @@ class IptablesFirewallDriver(FirewallDriver): def refresh_security_group_rules(self, security_group): self.apply_ruleset() + def refresh_provider_fw_rules(self): + self.apply_ruleset() + def _security_group_chain_name(self, security_group_id): return 'nova-sg-%s' % (security_group_id,) -- cgit From d6c6d8115b9dda07716d85fb1201cde0e907a9bd Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Wed, 26 Jan 2011 22:54:39 -0800 Subject: A couple of bugfixes. --- nova/virt/libvirt_conn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 453824d82..5b5b329ed 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1171,7 +1171,7 @@ class NWFilterFirewall(FirewallDriver): 'nova-provider-rules' filter for each instance's firewall, and by changing that filter we update them all. """ - xml = self.provider_fw_to_nwfilter_xml(self) + xml = self.provider_fw_to_nwfilter_xml() return self._define_filter(xml) def security_group_to_nwfilter_xml(self, security_group_id): -- cgit From ece7d2fa493e901c2a826e42a86ca93bb0afaed4 Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Wed, 26 Jan 2011 22:56:34 -0800 Subject: Apply lp:707675 to this branch to be able to test. --- nova/virt/libvirt_conn.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 5b5b329ed..cac6a4440 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -149,13 +149,8 @@ class LibvirtConnection(object): self._wrapped_conn = None self.read_only = read_only - self.nwfilter = NWFilterFirewall(self._get_connection) - - if not FLAGS.firewall_driver: - self.firewall_driver = self.nwfilter - self.nwfilter.handle_security_groups = True - else: - self.firewall_driver = utils.import_object(FLAGS.firewall_driver) + fw_class = utils.import_class(FLAGS.firewall_driver) + self.firewall_driver = fw_class(get_connection=self._get_connection) def init_host(self, host): # Adopt existing VM's running here @@ -409,7 +404,7 @@ class LibvirtConnection(object): instance['id'], power_state.NOSTATE, 'launching') - self.nwfilter.setup_basic_filtering(instance) + self.firewall_driver.setup_basic_filtering(instance) self.firewall_driver.prepare_instance_filter(instance) self._create_image(instance, xml) self._conn.createXML(xml, 0) @@ -915,6 +910,15 @@ class FirewallDriver(object): the list of rules (via admin api).""" raise NotImplementedError() + def setup_basic_filtering(self, instance): + """Create rules to block spoofing and allow dhcp. + + This gets called when spawning an instance, before + :method:`prepare_instance_filter`. + + """ + raise NotImplementedError() + class NWFilterFirewall(FirewallDriver): """ @@ -962,7 +966,7 @@ class NWFilterFirewall(FirewallDriver): """ - def __init__(self, get_connection): + def __init__(self, get_connection, **kwargs): self._libvirt_get_connection = get_connection self.static_filters_configured = False self.handle_security_groups = False @@ -1254,9 +1258,14 @@ class NWFilterFirewall(FirewallDriver): class IptablesFirewallDriver(FirewallDriver): - def __init__(self, execute=None): + def __init__(self, execute=None, **kwargs): self.execute = execute or utils.execute self.instances = {} + self.nwfilter = NWFilterFirewall(kwargs['get_connection']) + + def setup_basic_filtering(self, instance): + """Use NWFilter from libvirt for this.""" + return self.nwfilter.setup_basic_filtering(instance) def apply_instance_filter(self, instance): """No-op. Everything is done in prepare_instance_filter""" -- cgit From d47886e16504cc92d0f9b33e02417229970d3efb Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Mon, 31 Jan 2011 16:02:29 -0500 Subject: Reorder insance rules for provider rules immediately after base, before secgroups. --- nova/virt/libvirt_conn.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 2f99a0bb1..ec6572d3f 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1161,7 +1161,8 @@ class NWFilterFirewall(FirewallDriver): instance_filter_name = self._instance_filter_name(instance) instance_secgroup_filter_name = '%s-secgroup' % (instance_filter_name,) - instance_filter_children = [base_filter, instance_secgroup_filter_name] + instance_filter_children = [base_filter, 'nova-provider-rules', + instance_secgroup_filter_name] instance_secgroup_filter_children = ['nova-base-ipv4', 'nova-base-ipv6', 'nova-allow-dhcp-server'] @@ -1185,8 +1186,6 @@ class NWFilterFirewall(FirewallDriver): instance_secgroup_filter_children += [('nova-secgroup-%s' % security_group['id'])] - instance_filter_children += ['nova-provider-rules'] - self._define_filter( self._filter_container(instance_secgroup_filter_name, instance_secgroup_filter_children)) -- cgit From d552158b19bf1652da795e1681c9dc904bdc425b Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Tue, 1 Feb 2011 12:32:58 -0500 Subject: Add and document the provider_fw method in virt/FakeConnection. --- nova/virt/fake.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 161445b86..b16d53634 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -359,6 +359,22 @@ class FakeConnection(object): """ return True + def refresh_provider_fw_rules(self): + """This triggers a firewall update based on database changes. + + When this is called, rules have either been added or removed from the + datastore. You can retrieve rules with + :method:`nova.db.api.provider_fw_rule_get_all`. + + Provider rules take precedence over security group rules. If an IP + would be allowed by a security group ingress rule, but blocked by + a provider rule, then packets from the IP are dropped. This includes + intra-project traffic in the case of the allow_project_net_traffic + flag for the libvirt-derived classes. + + """ + pass + class FakeInstance(object): -- cgit From 29b7a087efc64965e079733fe62e552fac70d13a Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Tue, 5 Apr 2011 15:17:37 -0400 Subject: Fix a giant batch of copypasta. --- nova/virt/libvirt_conn.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index f3d73103b..c5ada729a 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1790,6 +1790,11 @@ class NWFilterFirewall(FirewallDriver): else: base_filter = 'nova-base' + ctxt = context.get_admin_context() + + instance_secgroup_filter_name = \ + '%s-secgroup' % (self._instance_filter_name(instance)) + instance_secgroup_filter_children = ['nova-base-ipv4', 'nova-base-ipv6', 'nova-allow-dhcp-server'] -- cgit From cd4748abfdc5014aac1d867c2ede261060375e2e Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Tue, 5 Apr 2011 19:31:12 -0400 Subject: Don't double-apply provider fw rules in NWFilter and Iptables. Don't create provider fw rules for each instance, use a chain and jump to it. Fix docstrings. --- nova/virt/connection.py | 1 - nova/virt/libvirt_conn.py | 184 ++++++++++++++++++++++++++-------------------- 2 files changed, 105 insertions(+), 80 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/connection.py b/nova/virt/connection.py index 875d558a0..99a8849f1 100644 --- a/nova/virt/connection.py +++ b/nova/virt/connection.py @@ -57,7 +57,6 @@ def get_connection(read_only=False): * fake * libvirt * xenapi - * hyperv """ # TODO(termie): maybe lazy load after initial check for permissions # TODO(termie): check whether we can be disconnected diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index c5ada729a..9bc7ca05a 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1539,7 +1539,9 @@ class FirewallDriver(object): """Refresh common rules for all hosts/instances from data store. Gets called when a rule has been added to or removed from - the list of rules (via admin api).""" + the list of rules (via admin api). + + """ raise NotImplementedError() def setup_basic_filtering(self, instance, network_info=None): @@ -1601,7 +1603,6 @@ class NWFilterFirewall(FirewallDriver): def __init__(self, get_connection, **kwargs): self._libvirt_get_connection = get_connection self.static_filters_configured = False - self.intermediate_filters_configured = False self.handle_security_groups = False def apply_instance_filter(self, instance): @@ -1658,9 +1659,6 @@ class NWFilterFirewall(FirewallDriver): logging.info('ensuring static filters') self._ensure_static_filters() - logging.info('ensuring intermediate filters') - self._ensure_intermediate_filters() - for (network, mapping) in network_info: nic_id = mapping['mac'].replace(':', '') instance_filter_name = self._instance_filter_name(instance, nic_id) @@ -1695,20 +1693,6 @@ class NWFilterFirewall(FirewallDriver): self.static_filters_configured = True - def _ensure_intermediate_filters(self): - """Intermediate filters are filters that are configurable nova-wide. - - Unlike static filters, they must be set up and maintainted based - on the network topology of nova. They are still required to be setup - before any instance can be launched. - - """ - - if self.intermediate_filters_configured: - return - self.refresh_provider_fw_rules() - self.intermediate_filters_configured = True - def _filter_container(self, name, filters): xml = '''%s''' % ( name, @@ -1778,10 +1762,11 @@ class NWFilterFirewall(FirewallDriver): pass def prepare_instance_filter(self, instance, network_info=None): - """ - Creates an NWFilter for the given instance. In the process, - it makes sure the filters for the security groups as well as - the base filter are all in place. + """Creates an NWFilter for the given instance. + + In the process, it makes sure the filters for the provider blocks, + security groups, and base filter are all in place. + """ if not network_info: network_info = _get_network_info(instance) @@ -1790,6 +1775,8 @@ class NWFilterFirewall(FirewallDriver): else: base_filter = 'nova-base' + self.refresh_provider_fw_rules() + ctxt = context.get_admin_context() instance_secgroup_filter_name = \ @@ -1847,6 +1834,7 @@ class NWFilterFirewall(FirewallDriver): `prepare_instance_filter` we add a reference to the 'nova-provider-rules' filter for each instance's firewall, and by changing that filter we update them all. + """ xml = self.provider_fw_to_nwfilter_xml() return self._define_filter(xml) @@ -1890,7 +1878,7 @@ class NWFilterFirewall(FirewallDriver): return xml def provider_fw_to_nwfilter_xml(self): - """Compose a filter of drop rules from specified cidrs.""" + """Compose a filter of drop rules from specified cidrs.""" rule_xml = "" v6protocol = {'tcp': 'tcp-ipv6', 'udp': 'udp-ipv6', 'icmp': 'icmpv6'} rules = db.provider_fw_rule_get_all(context.get_admin_context()) @@ -1938,6 +1926,7 @@ class IptablesFirewallDriver(FirewallDriver): self.iptables = linux_net.iptables_manager self.instances = {} self.nwfilter = NWFilterFirewall(kwargs['get_connection']) + self.basicly_filtered = False self.iptables.ipv4['filter'].add_chain('sg-fallback') self.iptables.ipv4['filter'].add_rule('sg-fallback', '-j DROP') @@ -1945,10 +1934,13 @@ class IptablesFirewallDriver(FirewallDriver): self.iptables.ipv6['filter'].add_rule('sg-fallback', '-j DROP') def setup_basic_filtering(self, instance, network_info=None): - """Use NWFilter from libvirt for this.""" + """Set up provider rules and basic NWFilter.""" if not network_info: network_info = _get_network_info(instance) - return self.nwfilter.setup_basic_filtering(instance, network_info) + self.nwfilter.setup_basic_filtering(instance, network_info) + if not self.basicly_filtered: + self.refresh_provider_fw_rules() + self.basicly_filtered = True def apply_instance_filter(self, instance): """No-op. Everything is done in prepare_instance_filter""" @@ -1996,6 +1988,8 @@ class IptablesFirewallDriver(FirewallDriver): chain_name)) ipv4_rules, ipv6_rules = self.instance_rules(instance, network_info) + for rule in ipv4_rules: + self.iptables.ipv4['filter'].add_rule(chain_name, rule) for rule in ipv4_rules: self.iptables.ipv4['filter'].add_rule(chain_name, rule) @@ -2023,6 +2017,10 @@ class IptablesFirewallDriver(FirewallDriver): ipv4_rules += ['-m state --state ' 'INVALID -j DROP'] ipv6_rules += ['-m state --state ' 'INVALID -j DROP'] + # Pass through provider-wide drops + ipv4_rules += ['-j $provider'] + ipv6_rules += ['-j $provider'] + # Allow established connections ipv4_rules += ['-m state --state ESTABLISHED,RELATED -j ACCEPT'] ipv6_rules += ['-m state --state ESTABLISHED,RELATED -j ACCEPT'] @@ -2058,57 +2056,6 @@ class IptablesFirewallDriver(FirewallDriver): for cidrv6 in cidrv6s: ipv6_rules.append('-s %s -j ACCEPT' % (cidrv6,)) - # block provider-identified sources - rules = db.provider_fw_rule_get_all(ctxt) - for rule in rules: - logging.info('%r', rule) - - if not rule.cidr: - # Eventually, a mechanism to grant access for security - # groups will turn up here. It'll use ipsets. - continue - - version = _get_ip_version(rule.cidr) - if version == 4: - fw_rules = ipv4_rules - else: - fw_rules = ipv6_rules - - protocol = rule.protocol - if version == 6 and rule.protocol == 'icmp': - protocol = 'icmpv6' - - args = ['-A', 'nova-provider', '-p', protocol, '-s', rule.cidr] - - if rule.protocol in ['udp', 'tcp']: - if rule.from_port == rule.to_port: - args += ['--dport', '%s' % (rule.from_port,)] - else: - args += ['-m', 'multiport', - '--dports', '%s:%s' % (rule.from_port, - rule.to_port)] - elif rule.protocol == 'icmp': - icmp_type = rule.from_port - icmp_code = rule.to_port - - if icmp_type == -1: - icmp_type_arg = None - else: - icmp_type_arg = '%s' % icmp_type - if not icmp_code == -1: - icmp_type_arg += '/%s' % icmp_code - - if icmp_type_arg: - if version == 4: - args += ['-m', 'icmp', '--icmp-type', - icmp_type_arg] - elif version == 6: - args += ['-m', 'icmp6', '--icmpv6-type', - icmp_type_arg] - - args += ['-j DROP'] - fw_rules += [' '.join(args)] - security_groups = db.security_group_get_by_instance(ctxt, instance['id']) @@ -2118,7 +2065,7 @@ class IptablesFirewallDriver(FirewallDriver): security_group['id']) for rule in rules: - LOG.debug('%r', rule) + LOG.debug(_('Adding security group rule: %r'), rule) if not rule.cidr: # Eventually, a mechanism to grant access for security @@ -2185,7 +2132,86 @@ class IptablesFirewallDriver(FirewallDriver): self.add_filters_for_instance(instance) def refresh_provider_fw_rules(self): - self.apply_ruleset() + """See class:FirewallDriver: docs.""" + self._do_refresh_provider_fw_rules() + self.iptables.apply() + + @utils.synchronized('iptables', external=True) + def _do_refresh_provider_fw_rules(self): + """Internal, synchronized version of refresh_provider_fw_rules.""" + self.purge_provider_fw_rules(self) + self.build_provider_fw_rules(self) + + def _purge_provider_fw_rules(self): + """Remove all rules from the $provider chains.""" + self.iptables.ipv4['filter'].empty_chain('$provider') + if FLAGS.use_ipv6: + self.iptables.ipv6['filter'].empty_chain('$provider') + + def _build_provider_fw_rules(self): + """Create all rules for the provider IP DROPs.""" + ipv4_rules, ipv6_rules = self._provider_rules() + for rule in ipv4_rules: + self.iptables.ipv4['filter'].add_rule('$provider', rule) + + if FLAGS.use_ipv6: + for rule in ipv6_rules: + self.iptables.ipv6['filter'].add_rule('$provider', rule) + + def _provider_rules(self): + """Generate a list of rules from provider for IP4 & IP6.""" + ctxt = context.get_admin_context() + ipv4_rules = [] + ipv6_rules = [] + rules = db.provider_fw_rule_get_all(ctxt) + for rule in rules: + LOG.debug(_('Adding prvider rule: %r'), rule) + + if not rule.cidr: + # Eventually, a mechanism to grant access for security + # groups will turn up here. It'll use ipsets. + continue + + version = _get_ip_version(rule.cidr) + if version == 4: + fw_rules = ipv4_rules + else: + fw_rules = ipv6_rules + + protocol = rule.protocol + if version == 6 and rule.protocol == 'icmp': + protocol = 'icmpv6' + + args = ['-A', '$provider', '-p', protocol, '-s', rule.cidr] + + if rule.protocol in ['udp', 'tcp']: + if rule.from_port == rule.to_port: + args += ['--dport', '%s' % (rule.from_port,)] + else: + args += ['-m', 'multiport', + '--dports', '%s:%s' % (rule.from_port, + rule.to_port)] + elif rule.protocol == 'icmp': + icmp_type = rule.from_port + icmp_code = rule.to_port + + if icmp_type == -1: + icmp_type_arg = None + else: + icmp_type_arg = '%s' % icmp_type + if not icmp_code == -1: + icmp_type_arg += '/%s' % icmp_code + + if icmp_type_arg: + if version == 4: + args += ['-m', 'icmp', '--icmp-type', + icmp_type_arg] + elif version == 6: + args += ['-m', 'icmp6', '--icmpv6-type', + icmp_type_arg] + args += ['-j DROP'] + fw_rules += [' '.join(args)] + return ipv4_rules, ipv6_rules def _security_group_chain_name(self, security_group_id): return 'nova-sg-%s' % (security_group_id,) -- cgit From 26d2a6ca8939156e8957e31dd17906070283ff24 Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Tue, 5 Apr 2011 20:07:46 -0400 Subject: Undo use of $ in chain name where not needed. --- nova/virt/libvirt_conn.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 9bc7ca05a..0d92e2e70 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -2143,20 +2143,20 @@ class IptablesFirewallDriver(FirewallDriver): self.build_provider_fw_rules(self) def _purge_provider_fw_rules(self): - """Remove all rules from the $provider chains.""" - self.iptables.ipv4['filter'].empty_chain('$provider') + """Remove all rules from the provider chains.""" + self.iptables.ipv4['filter'].empty_chain('provider') if FLAGS.use_ipv6: - self.iptables.ipv6['filter'].empty_chain('$provider') + self.iptables.ipv6['filter'].empty_chain('provider') def _build_provider_fw_rules(self): """Create all rules for the provider IP DROPs.""" ipv4_rules, ipv6_rules = self._provider_rules() for rule in ipv4_rules: - self.iptables.ipv4['filter'].add_rule('$provider', rule) + self.iptables.ipv4['filter'].add_rule('provider', rule) if FLAGS.use_ipv6: for rule in ipv6_rules: - self.iptables.ipv6['filter'].add_rule('$provider', rule) + self.iptables.ipv6['filter'].add_rule('provider', rule) def _provider_rules(self): """Generate a list of rules from provider for IP4 & IP6.""" @@ -2182,7 +2182,7 @@ class IptablesFirewallDriver(FirewallDriver): if version == 6 and rule.protocol == 'icmp': protocol = 'icmpv6' - args = ['-A', '$provider', '-p', protocol, '-s', rule.cidr] + args = ['-p', protocol, '-s', rule.cidr] if rule.protocol in ['udp', 'tcp']: if rule.from_port == rule.to_port: -- cgit From 2b79fa82872c55368167fc7433cb28a2369f5191 Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Thu, 7 Apr 2011 01:42:49 -0400 Subject: test provider fw rules at the virt/ipteables layer. lowercase protocol names in admin api to match what the firewall driver expects. add provider fw rule chain in iptables6 as well. fix a couple of small typos and copy-paste errors. --- nova/virt/libvirt_conn.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 0d92e2e70..38ba21521 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1939,6 +1939,7 @@ class IptablesFirewallDriver(FirewallDriver): network_info = _get_network_info(instance) self.nwfilter.setup_basic_filtering(instance, network_info) if not self.basicly_filtered: + LOG.debug("Setup Basic Filtering") self.refresh_provider_fw_rules() self.basicly_filtered = True @@ -1967,6 +1968,7 @@ class IptablesFirewallDriver(FirewallDriver): chain_name = self._instance_chain_name(instance) self.iptables.ipv4['filter'].add_chain(chain_name) + self.iptables.ipv4['filter'].empty_chain(chain_name) ips_v4 = [ip['ip'] for (_, mapping) in network_info for ip in mapping['ips']] @@ -1978,6 +1980,7 @@ class IptablesFirewallDriver(FirewallDriver): if FLAGS.use_ipv6: self.iptables.ipv6['filter'].add_chain(chain_name) + self.iptables.ipv6['filter'].empty_chain(chain_name) ips_v6 = [ip['ip'] for (_, mapping) in network_info for ip in mapping['ip6s']] @@ -1991,9 +1994,6 @@ class IptablesFirewallDriver(FirewallDriver): for rule in ipv4_rules: self.iptables.ipv4['filter'].add_rule(chain_name, rule) - for rule in ipv4_rules: - self.iptables.ipv4['filter'].add_rule(chain_name, rule) - if FLAGS.use_ipv6: for rule in ipv6_rules: self.iptables.ipv6['filter'].add_rule(chain_name, rule) @@ -2042,7 +2042,7 @@ class IptablesFirewallDriver(FirewallDriver): # they're not worth the clutter. if FLAGS.use_ipv6: # Allow RA responses - gateways_v6 = [network['gateway_v6'] for (network, _) in + gateways_v6 = [network['gateway_v6'] for (network, _m) in network_info] for gateway_v6 in gateways_v6: ipv6_rules.append( @@ -2065,7 +2065,7 @@ class IptablesFirewallDriver(FirewallDriver): security_group['id']) for rule in rules: - LOG.debug(_('Adding security group rule: %r'), rule) + LOG.debug(_("Adding security group rule: %r"), rule) if not rule.cidr: # Eventually, a mechanism to grant access for security @@ -2139,8 +2139,8 @@ class IptablesFirewallDriver(FirewallDriver): @utils.synchronized('iptables', external=True) def _do_refresh_provider_fw_rules(self): """Internal, synchronized version of refresh_provider_fw_rules.""" - self.purge_provider_fw_rules(self) - self.build_provider_fw_rules(self) + self._purge_provider_fw_rules() + self._build_provider_fw_rules() def _purge_provider_fw_rules(self): """Remove all rules from the provider chains.""" @@ -2150,6 +2150,9 @@ class IptablesFirewallDriver(FirewallDriver): def _build_provider_fw_rules(self): """Create all rules for the provider IP DROPs.""" + self.iptables.ipv4['filter'].add_chain('provider') + if FLAGS.use_ipv6: + self.iptables.ipv6['filter'].add_chain('provider') ipv4_rules, ipv6_rules = self._provider_rules() for rule in ipv4_rules: self.iptables.ipv4['filter'].add_rule('provider', rule) @@ -2179,19 +2182,19 @@ class IptablesFirewallDriver(FirewallDriver): fw_rules = ipv6_rules protocol = rule.protocol - if version == 6 and rule.protocol == 'icmp': + if version == 6 and protocol == 'icmp': protocol = 'icmpv6' args = ['-p', protocol, '-s', rule.cidr] - if rule.protocol in ['udp', 'tcp']: + if protocol in ['udp', 'tcp']: if rule.from_port == rule.to_port: args += ['--dport', '%s' % (rule.from_port,)] else: args += ['-m', 'multiport', '--dports', '%s:%s' % (rule.from_port, rule.to_port)] - elif rule.protocol == 'icmp': + elif protocol == 'icmp': icmp_type = rule.from_port icmp_code = rule.to_port -- cgit From dfd6e6e3a46c2fbbb4e771d38396348c9659a0bd Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Thu, 26 May 2011 11:44:18 -0400 Subject: Remove spurious newline at end of file. --- nova/virt/libvirt/connection.py | 1 - 1 file changed, 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index dc2dd1219..dfeda3814 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -1532,4 +1532,3 @@ class LibvirtConnection(driver.ComputeDriver): def get_host_stats(self, refresh=False): """See xenapi_conn.py implementation.""" pass - -- cgit From 459864dc0a05e6a0db642e9cb80ceade7b000ce8 Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Thu, 26 May 2011 11:45:46 -0400 Subject: fix typo introduced during merge conflict resolution. --- nova/virt/libvirt/firewall.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/firewall.py b/nova/virt/libvirt/firewall.py index fd4c120a6..4e0df323d 100644 --- a/nova/virt/libvirt/firewall.py +++ b/nova/virt/libvirt/firewall.py @@ -376,7 +376,7 @@ class NWFilterFirewall(FirewallDriver): return result def _define_filters(self, filter_name, filter_children): - self._define_fitler(self._filter_container(filter_name, + self._define_filter(self._filter_container(filter_name, filter_children)) def refresh_security_group_rules(self, -- cgit From a5c9f44295df4054e9afb135aaa76c5e34cc3624 Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Thu, 26 May 2011 11:53:25 -0400 Subject: Double quotes are ugly #3. --- nova/virt/libvirt/firewall.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/firewall.py b/nova/virt/libvirt/firewall.py index 4e0df323d..5bdc0c1c6 100644 --- a/nova/virt/libvirt/firewall.py +++ b/nova/virt/libvirt/firewall.py @@ -513,7 +513,7 @@ class IptablesFirewallDriver(FirewallDriver): network_info = netutils.get_network_info(instance) self.nwfilter.setup_basic_filtering(instance, network_info) if not self.basicly_filtered: - LOG.debug(_("iptables firewall: Setup Basic Filtering")) + LOG.debug(_('iptables firewall: Setup Basic Filtering')) self.refresh_provider_fw_rules() self.basicly_filtered = True @@ -638,7 +638,7 @@ class IptablesFirewallDriver(FirewallDriver): security_group['id']) for rule in rules: - LOG.debug(_("Adding security group rule: %r"), rule) + LOG.debug(_('Adding security group rule: %r'), rule) if not rule.cidr: # Eventually, a mechanism to grant access for security -- cgit From 93bfea42bdd594030c8ae046f87291ff184ef3f6 Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Thu, 26 May 2011 12:09:04 -0400 Subject: Make a cleaner log message and use [] instead of . to get database fields. --- nova/virt/libvirt/firewall.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/firewall.py b/nova/virt/libvirt/firewall.py index 5bdc0c1c6..c4192fac0 100644 --- a/nova/virt/libvirt/firewall.py +++ b/nova/virt/libvirt/firewall.py @@ -749,29 +749,29 @@ class IptablesFirewallDriver(FirewallDriver): ipv6_rules = [] rules = db.provider_fw_rule_get_all(ctxt) for rule in rules: - LOG.debug(_('Adding prvider rule: %r'), rule) - version = netutils.get_ip_version(rule.cidr) + LOG.debug(_('Adding provider rule: %s'), rule['cidr']) + version = netutils.get_ip_version(rule['cidr']) if version == 4: fw_rules = ipv4_rules else: fw_rules = ipv6_rules - protocol = rule.protocol + protocol = rule['protocol'] if version == 6 and protocol == 'icmp': protocol = 'icmpv6' - args = ['-p', protocol, '-s', rule.cidr] + args = ['-p', protocol, '-s', rule['cidr']] if protocol in ['udp', 'tcp']: - if rule.from_port == rule.to_port: - args += ['--dport', '%s' % (rule.from_port,)] + if rule['from_port'] == rule['to_port']: + args += ['--dport', '%s' % (rule['from_port'],)] else: args += ['-m', 'multiport', - '--dports', '%s:%s' % (rule.from_port, - rule.to_port)] + '--dports', '%s:%s' % (rule['from_port'], + rule['to_port'])] elif protocol == 'icmp': - icmp_type = rule.from_port - icmp_code = rule.to_port + icmp_type = rule['from_port'] + icmp_code = rule['to_port'] if icmp_type == -1: icmp_type_arg = None -- cgit From add164c45db31baf8f12c3e5dede140c51a2e498 Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Tue, 31 May 2011 14:10:29 -0400 Subject: Add refresh_provider_fw_rules to virt/driver.py#ComputeDriver so virtualization drivers other than libvirt will raise NotImplemented. --- nova/virt/driver.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/driver.py b/nova/virt/driver.py index eb9626d08..23581ab49 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -191,6 +191,10 @@ class ComputeDriver(object): def refresh_security_group_members(self, security_group_id): raise NotImplementedError() + def refresh_provider_fw_rules(self, security_group_id): + """See: nova/virt/fake.py for docs.""" + raise NotImplementedError() + def reset_network(self, instance): """reset networking for specified instance""" raise NotImplementedError() -- cgit From 2c1dd72060fccbe7f32a6aa08c1ce67476806680 Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Tue, 31 May 2011 16:28:46 -0400 Subject: Whitespace cleanups. --- nova/virt/libvirt/firewall.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/firewall.py b/nova/virt/libvirt/firewall.py index c4192fac0..28cd9fe9c 100644 --- a/nova/virt/libvirt/firewall.py +++ b/nova/virt/libvirt/firewall.py @@ -81,7 +81,7 @@ class FirewallDriver(object): Gets called when a rule has been added to or removed from the list of rules (via admin api). - + """ raise NotImplementedError() @@ -306,7 +306,7 @@ class NWFilterFirewall(FirewallDriver): def prepare_instance_filter(self, instance, network_info=None): """Creates an NWFilter for the given instance. - + In the process, it makes sure the filters for the provider blocks, security groups, and base filter are all in place. -- cgit From 46bd8cbd1358a44534a620408b828ad08eef9cec Mon Sep 17 00:00:00 2001 From: Chuck Short Date: Mon, 6 Jun 2011 15:35:33 -0400 Subject: Remove ipy from virt code and replace with netaddr --- nova/virt/libvirt/connection.py | 3 +-- nova/virt/libvirt/netutils.py | 14 +++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index c491418ae..da5911a1a 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -38,6 +38,7 @@ Supports KVM, LXC, QEMU, UML, and XEN. import hashlib import multiprocessing +import netaddr import os import random import shutil @@ -52,8 +53,6 @@ from xml.etree import ElementTree from eventlet import greenthread from eventlet import tpool -import IPy - from nova import context from nova import db from nova import exception diff --git a/nova/virt/libvirt/netutils.py b/nova/virt/libvirt/netutils.py index 4d596078a..0bad84f7c 100644 --- a/nova/virt/libvirt/netutils.py +++ b/nova/virt/libvirt/netutils.py @@ -21,7 +21,7 @@ """Network-releated utilities for supporting libvirt connection code.""" -import IPy +import netaddr from nova import context from nova import db @@ -34,18 +34,18 @@ FLAGS = flags.FLAGS def get_net_and_mask(cidr): - net = IPy.IP(cidr) - return str(net.net()), str(net.netmask()) + net = netaddr.IPNetwork(cidr) + return str(net.ip), str(net.netmask) def get_net_and_prefixlen(cidr): - net = IPy.IP(cidr) - return str(net.net()), str(net.prefixlen()) + net = netaddr.IPNetwork(cidr) + return str(net.ip), str(net._prefixlen) def get_ip_version(cidr): - net = IPy.IP(cidr) - return int(net.version()) + net = netaddr.IPNetwork(cidr) + return int(net.version) def get_network_info(instance): -- cgit From 0bcb15317fede5c17c77c187e1cd9a68a0c8030c Mon Sep 17 00:00:00 2001 From: Todd Willey Date: Fri, 10 Jun 2011 22:32:33 -0400 Subject: Reorder firewall rules so the common path is shorter. --- nova/virt/libvirt/firewall.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/firewall.py b/nova/virt/libvirt/firewall.py index 28cd9fe9c..331c73b47 100644 --- a/nova/virt/libvirt/firewall.py +++ b/nova/virt/libvirt/firewall.py @@ -590,14 +590,14 @@ class IptablesFirewallDriver(FirewallDriver): ipv4_rules += ['-m state --state ' 'INVALID -j DROP'] ipv6_rules += ['-m state --state ' 'INVALID -j DROP'] - # Pass through provider-wide drops - ipv4_rules += ['-j $provider'] - ipv6_rules += ['-j $provider'] - # Allow established connections ipv4_rules += ['-m state --state ESTABLISHED,RELATED -j ACCEPT'] ipv6_rules += ['-m state --state ESTABLISHED,RELATED -j ACCEPT'] + # Pass through provider-wide drops + ipv4_rules += ['-j $provider'] + ipv6_rules += ['-j $provider'] + dhcp_servers = [network['gateway'] for (network, _m) in network_info] for dhcp_server in dhcp_servers: -- cgit