+++ /dev/null
-From 4dde0ffdddeaddef219d0ff6d131d474ec190167 Mon Sep 17 00:00:00 2001
-From: Sylvain Afchain <sylvain.afchain@enovance.com>
-Date: Thu, 12 Dec 2013 23:20:17 +0100
-Subject: [PATCH] Add parameter and iptables rules to protect dnsmasq ports
-
-Add a paramater to the configuration file of the dhcp
-agent. With this new param set as true, iptables rules
-are inserted to limit dns requests to dnsmasq only to
-the clients which are on the same subnet.
-
-Change-Id: Iac3635326cb81d5de51b903510ff31cb6164aa86
-Closes-bug: #1260731
-Last-Update: 2014-06-30
----
- etc/dhcp_agent.ini | 5 +
- neutron/agent/linux/dhcp.py | 159 ++++++++++++++++++++
- neutron/tests/unit/test_linux_dhcp.py | 259 ++++++++++++++++++++++++++++++++-
- 3 files changed, 421 insertions(+), 2 deletions(-)
-
-Index: neutron/etc/dhcp_agent.ini
-===================================================================
---- neutron.orig/etc/dhcp_agent.ini 2014-09-19 18:00:01.000000000 +0800
-+++ neutron/etc/dhcp_agent.ini 2014-09-19 18:10:15.000000000 +0800
-@@ -86,3 +86,8 @@
- # Timeout for ovs-vsctl commands.
- # If the timeout expires, ovs commands will fail with ALARMCLOCK error.
- # ovs_vsctl_timeout = 10
-+
-+# Limits the dns requests to dnsmasq only to clients which are on its subnet.
-+# Useful when a subnet is routed to another one or in the case of an
-+# external network.
-+# isolate_dns_requests = False
-Index: neutron/neutron/agent/linux/dhcp.py
-===================================================================
---- neutron.orig/neutron/agent/linux/dhcp.py 2014-09-19 18:09:42.000000000 +0800
-+++ neutron/neutron/agent/linux/dhcp.py 2014-09-19 18:10:15.000000000 +0800
-@@ -26,6 +26,7 @@
- import six
-
- from neutron.agent.linux import ip_lib
-+from neutron.agent.linux import iptables_manager
- from neutron.agent.linux import utils
- from neutron.common import constants
- from neutron.common import exceptions
-@@ -57,6 +58,9 @@
- 'dnsmasq_lease_max',
- default=(2 ** 24),
- help=_('Limit number of leases to prevent a denial-of-service.')),
-+ cfg.BoolOpt('isolate_dns_requests', default=False,
-+ help=_("Allow dns requests to dnsmasq only from clients "
-+ "on its subnet.")),
- ]
-
- IPV4 = 4
-@@ -73,6 +77,7 @@
- METADATA_PORT = 80
- WIN2k3_STATIC_DNS = 249
- NS_PREFIX = 'qdhcp-'
-+DNS_CHAIN_PREFIX = 'dns-'
-
-
- class DictModel(dict):
-@@ -775,7 +780,67 @@
- sock.close()
-
-
-+class NamespaceIptablesManagerCache(object):
-+ def __init__(self):
-+ self.iptables_managers = {}
-+ self.subnets = {}
-+
-+ def get_or_create(self, network, root_helper):
-+ ns = network.namespace
-+
-+ im = self.iptables_managers.get(ns)
-+ if not im:
-+ im = iptables_manager.IptablesManager(
-+ root_helper=root_helper,
-+ use_ipv6=True,
-+ namespace=network.namespace)
-+ self.iptables_managers[ns] = im
-+
-+ return im
-+
-+ def is_up_to_date(self, network):
-+ subnets = self.subnets.get(network.id)
-+ current_subnets = set([subnet.id for subnet in network.subnets])
-+ return subnets == current_subnets
-+
-+ def get(self, network):
-+ return self.iptables_managers.get(network.namespace)
-+
-+ def remove(self, network):
-+ self.subnets.pop(network.id, None)
-+ self.iptables_managers.pop(network.namespace, None)
-+
-+ def apply(self, network):
-+ im = self.iptables_managers.get(network.namespace)
-+ if not im:
-+ LOG.warn(_("apply called on a non existant iptables_manager "
-+ "for network %s, get_or_create has to be called "
-+ "before"), network.id)
-+ return
-+
-+ self.subnets[network.id] = set([subnet.id
-+ for subnet in network.subnets])
-+
-+ im.apply()
-+
-+
-+class InterfaceNameCache(object):
-+ def __init__(self):
-+ self.interface_names = {}
-+
-+ def set(self, network, interface_name):
-+ self.interface_names[network.id] = interface_name
-+
-+ def get(self, network):
-+ return self.interface_names.get(network.id)
-+
-+ def remove(self, network):
-+ self.interface_names.pop(network.id, None)
-+
-+
- class DeviceManager(object):
-+ iptables_manager_cache = NamespaceIptablesManagerCache()
-+ interface_name_cache = InterfaceNameCache()
-
- def __init__(self, conf, root_helper, plugin):
- self.conf = conf
-@@ -924,6 +989,87 @@
-
- return dhcp_port
-
-+ @staticmethod
-+ def _get_isolation_rule(proto, chain, interface):
-+ return ('-p %(proto)s -m %(proto)s '
-+ '--dport %(port)s -i %(interface)s '
-+ '-j $%(chain)s') % {'port': DNS_PORT,
-+ 'proto': proto,
-+ 'chain': chain,
-+ 'interface': interface}
-+
-+ def _remove_dns_isolation(self, network):
-+ interface_name = DeviceManager.interface_name_cache.get(network)
-+ if not interface_name:
-+ LOG.warn(_("Error unable to get interface name for network: %s"),
-+ network.id)
-+ return
-+
-+ im = DeviceManager.iptables_manager_cache.get(network)
-+ if not im:
-+ LOG.error(_("Error unable get the iptables manager created "
-+ "for network %s"), network.id)
-+ return
-+
-+ rules_chain = iptables_manager.get_chain_name(DNS_CHAIN_PREFIX +
-+ network.id)
-+
-+ for tables in [im.ipv4, im.ipv6]:
-+ tables['filter'].remove_chain(rules_chain)
-+
-+ im.apply()
-+
-+ DeviceManager.iptables_manager_cache.remove(network)
-+
-+ def _apply_dns_isolation(self, network, interface_name=None):
-+ if DeviceManager.iptables_manager_cache.is_up_to_date(
-+ network):
-+ return
-+
-+ im = DeviceManager.iptables_manager_cache.get_or_create(
-+ network, self.root_helper)
-+ if not im:
-+ LOG.error(_("Error unable to create or get an iptables manager "
-+ "for network %s"), network.id)
-+ return
-+
-+ if not interface_name:
-+ interface_name = DeviceManager.interface_name_cache.get(network)
-+ if not interface_name:
-+ LOG.error(_("Error unable to get interface name for network: %s"),
-+ network.id)
-+ return
-+
-+ rules_chain = iptables_manager.get_chain_name(DNS_CHAIN_PREFIX +
-+ network.id)
-+
-+ for tables in [im.ipv4, im.ipv6]:
-+ tables['filter'].add_chain(rules_chain)
-+
-+ # empty_chain has to be called since a previous subnet
-+ # could be now removed, with an empty chain only current subnet
-+ # rules will be present.
-+ tables['filter'].empty_chain(rules_chain)
-+ tables['filter'].add_rule(rules_chain, '-j DROP')
-+
-+ for proto in [UDP, TCP]:
-+ rule = self._get_isolation_rule(proto, rules_chain,
-+ interface_name)
-+ tables['filter'].add_rule('INPUT', rule)
-+
-+ # allow traffic from subnets everything else will be denied
-+ for subnet in network.subnets:
-+ if not subnet.enable_dhcp:
-+ continue
-+
-+ tables = im.ipv4 if subnet.ip_version == IPV4 else im.ipv6
-+
-+ rule = '-s ' + subnet.cidr + ' -j RETURN'
-+ tables['filter'].add_rule(rules_chain,
-+ rule, top=True)
-+
-+ DeviceManager.iptables_manager_cache.apply(network)
-+
- def setup(self, network):
- """Create and initialize a device for network's DHCP on this host."""
- port = self.setup_dhcp_port(network)
-@@ -962,6 +1108,9 @@
- if self.conf.use_namespaces:
- self._set_default_route(network, interface_name)
-
-+ if self.conf.isolate_dns_requests:
-+ self._apply_dns_isolation(network, interface_name)
-+
- return interface_name
-
- def update(self, network, device_name):
-@@ -969,9 +1118,17 @@
- if self.conf.use_namespaces:
- self._set_default_route(network, device_name)
-
-+ if self.conf.isolate_dns_requests:
-+ self._apply_dns_isolation(network)
-+
- def destroy(self, network, device_name):
- """Destroy the device used for the network's DHCP on this host."""
-+ if self.conf.isolate_dns_requests:
-+ self._remove_dns_isolation(network)
-+
- self.driver.unplug(device_name, namespace=network.namespace)
-
- self.plugin.release_dhcp_port(network.id,
- self.get_device_id(network))
-+
-+ DeviceManager.interface_name_cache.remove(network)
+++ /dev/null
-Description: Better config default
- This patch makes it possible for the config file to be parsed and edited with
- sed and grep.
-Author: Thomas Goirand <zigo@debian.org>
-Forwarded: not-needed
-Last-Update: 2014-10-04
-
-Index: neutron/etc/l3_agent.ini
-===================================================================
---- neutron.orig/etc/l3_agent.ini 2014-10-03 19:07:30.000000000 +0800
-+++ neutron/etc/l3_agent.ini 2014-10-03 19:11:29.000000000 +0800
-@@ -4,11 +4,10 @@
-
- # L3 requires that an interface driver be set. Choose the one that best
- # matches your plugin.
--# interface_driver =
-
- # Example of interface_driver option for OVS based plugins (OVS, Ryu, NEC)
- # that supports L3 agent
--# interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver
-+interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver
-
- # Use veth for an OVS interface or not.
- # Support kernels with limited namespace support
-Index: neutron/etc/neutron.conf
-===================================================================
---- neutron.orig/etc/neutron.conf 2014-10-03 19:07:30.000000000 +0800
-+++ neutron/etc/neutron.conf 2014-10-03 19:11:29.000000000 +0800
-@@ -60,8 +60,8 @@
- # previous versions, the class name of a plugin can be specified instead of its
- # entrypoint name.
- #
--# core_plugin =
- # Example: core_plugin = ml2
-+core_plugin = neutron.plugins.ml2.plugin.Ml2Plugin
-
- # (ListOpt) List of service plugin entrypoints to be loaded from the
- # neutron.service_plugins namespace. See setup.cfg for the entrypoint names of
-@@ -69,8 +69,8 @@
- # with previous versions, the class name of a plugin can be specified instead
- # of its entrypoint name.
- #
--# service_plugins =
- # Example: service_plugins = router,firewall,lbaas,vpnaas,metering
-+service_plugins = neutron.services.loadbalancer.plugin.LoadBalancerPlugin,neutron.services.metering.metering_plugin.MeteringPlugin,neutron.services.l3_router.l3_router_plugin.L3RouterPlugin
-
- # Paste configuration file
- # api_paste_config = api-paste.ini
-@@ -340,7 +340,7 @@
-
- # The RabbitMQ broker address where a single node is used.
- # (string value)
--#rabbit_host=localhost
-+rabbit_host=localhost
-
- # The RabbitMQ broker port where a single node is used.
- # (integer value)
-@@ -353,10 +353,10 @@
- #rabbit_use_ssl=false
-
- # The RabbitMQ userid. (string value)
--#rabbit_userid=guest
-+rabbit_userid=guest
-
- # The RabbitMQ password. (string value)
--#rabbit_password=guest
-+rabbit_password=guest
-
- # the RabbitMQ login method (string value)
- #rabbit_login_method=AMQPLAIN
-@@ -543,7 +543,7 @@
- # Use "sudo neutron-rootwrap /etc/neutron/rootwrap.conf" to use the real
- # root filter facility.
- # Change to "sudo" to skip the filtering and just run the comand directly
--# root_helper = sudo
-+root_helper = sudo neutron-rootwrap /etc/neutron/rootwrap.conf
-
- # =========== items for agent management extension =============
- # seconds between nodes reporting state to server; should be less than
-@@ -563,14 +563,13 @@
- [database]
- # This line MUST be changed to actually run the plugin.
- # Example:
--# connection = mysql://root:pass@127.0.0.1:3306/neutron
- # Replace 127.0.0.1 above with the IP address of the database used by the
- # main neutron server. (Leave it as is if the database runs on this host.)
--# connection = sqlite://
- # NOTE: In deployment the [database] section and its connection attribute may
- # be set in the corresponding core plugin '.ini' file. However, it is suggested
- # to put the [database] section and its connection attribute in this
- # configuration file.
-+connection = sqlite:///var/lib/neutron/neutrondb
-
- # Database engine for which script will be generated when using offline
- # migration
-Index: neutron/etc/lbaas_agent.ini
-===================================================================
---- neutron.orig/etc/lbaas_agent.ini 2014-10-03 19:03:50.000000000 +0800
-+++ neutron/etc/lbaas_agent.ini 2014-10-03 19:11:29.000000000 +0800
-@@ -9,11 +9,10 @@
-
- # LBaas requires an interface driver be set. Choose the one that best
- # matches your plugin.
--# interface_driver =
-
- # Example of interface_driver option for OVS based plugins (OVS, Ryu, NEC, NVP,
- # BigSwitch/Floodlight)
--# interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver
-+interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver
-
- # Use veth for an OVS interface or not.
- # Support kernels with limited namespace support
-Index: neutron/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini
-===================================================================
---- neutron.orig/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini 2014-10-03 19:03:50.000000000 +0800
-+++ neutron/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini 2014-10-03 19:11:29.000000000 +0800
-@@ -30,22 +30,22 @@
- # point setting tunnel_type below will be required to enable
- # tunneling.
- #
--# enable_tunneling = False
-+enable_tunneling = True
-
- # (StrOpt) The type of tunnel network, if any, supported by the plugin. If
- # this is set, it will cause tunneling to be enabled. If this is not set and
- # the option enable_tunneling is set, this will default to 'gre'.
- #
--# tunnel_type =
- # Example: tunnel_type = gre
- # Example: tunnel_type = vxlan
-+tunnel_type = gre
-
- # (ListOpt) Comma-separated list of <tun_min>:<tun_max> tuples
- # enumerating ranges of GRE or VXLAN tunnel IDs that are available for
- # tenant network allocation if tenant_network_type is 'gre' or 'vxlan'.
- #
--# tunnel_id_ranges =
- # Example: tunnel_id_ranges = 1:1000
-+tunnel_id_ranges = 1:1000
-
- # Do not change this parameter unless you have a good reason to.
- # This is the name of the OVS integration bridge. There is one per hypervisor.
-@@ -70,7 +70,7 @@
- # empty for the server. Set local-ip to be the local IP address of
- # this hypervisor.
- #
--# local_ip =
-+local_ip = 127.0.0.1
-
- # (ListOpt) Comma-separated list of <physical_network>:<bridge> tuples
- # mapping physical network names to the agent's node-specific OVS
-@@ -151,40 +151,10 @@
-
- [securitygroup]
- # Firewall driver for realizing neutron security group function.
--# firewall_driver = neutron.agent.firewall.NoopFirewallDriver
- # Example: firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
-+# Example2: neutron.agent.firewall.NoopFirewallDriver
-+firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
-
- # Controls if neutron security group is enabled or not.
- # It should be false when you use nova security group.
- # enable_security_group = True
--
--#-----------------------------------------------------------------------------
--# Sample Configurations.
--#-----------------------------------------------------------------------------
--#
--# 1. With VLANs on eth1.
--# [ovs]
--# network_vlan_ranges = default:2000:3999
--# tunnel_id_ranges =
--# integration_bridge = br-int
--# bridge_mappings = default:br-eth1
--#
--# 2. With GRE tunneling.
--# [ovs]
--# network_vlan_ranges =
--# tunnel_id_ranges = 1:1000
--# integration_bridge = br-int
--# tunnel_bridge = br-tun
--# local_ip = 10.0.0.3
--#
--# 3. With VXLAN tunneling.
--# [ovs]
--# network_vlan_ranges =
--# tenant_network_type = vxlan
--# tunnel_type = vxlan
--# tunnel_id_ranges = 1:1000
--# integration_bridge = br-int
--# tunnel_bridge = br-tun
--# local_ip = 10.0.0.3
--# [agent]
--# tunnel_types = vxlan