Merge "Fixes DOS issue in instance list ip filter"

This commit is contained in:
Jenkins
2014-10-28 22:34:16 +00:00
committed by Gerrit Code Review
2 changed files with 80 additions and 24 deletions

View File

@@ -1998,6 +1998,9 @@ class API(base.Base):
sort_key, sort_dir, limit=limit, marker=marker,
expected_attrs=expected_attrs)
if 'ip6' in filters or 'ip' in filters:
inst_models = self._ip_filter(inst_models, filters)
if want_objects:
return inst_models
@@ -2008,18 +2011,29 @@ class API(base.Base):
return instances
@staticmethod
def _ip_filter(inst_models, filters):
ipv4_f = re.compile(str(filters.get('ip')))
ipv6_f = re.compile(str(filters.get('ip6')))
result_objs = []
for instance in inst_models:
nw_info = compute_utils.get_nw_info_for_instance(instance)
for vif in nw_info:
for fixed_ip in vif.fixed_ips():
address = fixed_ip.get('address')
if not address:
continue
version = fixed_ip.get('version')
if ((version == 4 and ipv4_f.match(address)) or
(version == 6 and ipv6_f.match(address))):
result_objs.append(instance)
continue
return objects.InstanceList(objects=result_objs)
def _get_instances_by_filters(self, context, filters,
sort_key, sort_dir,
limit=None,
marker=None, expected_attrs=None):
if 'ip6' in filters or 'ip' in filters:
res = self.network_api.get_instance_uuids_by_ip_filter(context,
filters)
# NOTE(jkoelker) It is possible that we will get the same
# instance uuid twice (one for ipv4 and ipv6)
uuids = set([r['instance_uuid'] for r in res])
filters['uuid'] = uuids
fields = ['metadata', 'system_metadata', 'info_cache',
'security_groups']
if expected_attrs:

View File

@@ -85,7 +85,6 @@ from nova.tests.image import fake as fake_image
from nova.tests import matchers
from nova.tests.objects import test_flavor
from nova.tests.objects import test_migration
from nova.tests.objects import test_network
from nova import utils
from nova.virt import block_device as driver_block_device
from nova.virt import event
@@ -7143,6 +7142,35 @@ class ComputeAPITestCase(BaseTestCase):
self.assertIsNone(instance['task_state'])
return instance, instance_uuid
def test_ip_filtering(self):
info = [{
'address': 'aa:bb:cc:dd:ee:ff',
'id': 1,
'network': {
'bridge': 'br0',
'id': 1,
'label': 'private',
'subnets': [{
'cidr': '192.168.0.0/24',
'ips': [{
'address': '192.168.0.10',
'type': 'fixed',
}]
}]
}
}]
info1 = objects.InstanceInfoCache(network_info=jsonutils.dumps(info))
inst1 = objects.Instance(id=1, info_cache=info1)
info[0]['network']['subnets'][0]['ips'][0]['address'] = '192.168.0.20'
info2 = objects.InstanceInfoCache(network_info=jsonutils.dumps(info))
inst2 = objects.Instance(id=2, info_cache=info2)
instances = objects.InstanceList(objects=[inst1, inst2])
instances = self.compute_api._ip_filter(instances, {'ip': '.*10'})
self.assertEqual(len(instances), 1)
self.assertEqual(instances[0].id, 1)
def test_create_with_too_little_ram(self):
# Test an instance type with too little memory.
@@ -7906,33 +7934,47 @@ class ComputeAPITestCase(BaseTestCase):
db.instance_destroy(c, instance2['uuid'])
db.instance_destroy(c, instance3['uuid'])
@mock.patch('nova.db.network_get')
@mock.patch('nova.db.fixed_ips_by_virtual_interface')
def test_get_all_by_multiple_options_at_once(self, fixed_get, network_get):
def test_get_all_by_multiple_options_at_once(self):
# Test searching by multiple options at once.
c = context.get_admin_context()
network_manager = fake_network.FakeNetworkManager(self.stubs)
fixed_get.side_effect = (
network_manager.db.fixed_ips_by_virtual_interface)
network_get.return_value = (
dict(test_network.fake_network,
**network_manager.db.network_get(None, 1)))
self.stubs.Set(self.compute_api.network_api,
'get_instance_uuids_by_ip_filter',
network_manager.get_instance_uuids_by_ip_filter)
def fake_network_info(ip):
info = [{
'address': 'aa:bb:cc:dd:ee:ff',
'id': 1,
'network': {
'bridge': 'br0',
'id': 1,
'label': 'private',
'subnets': [{
'cidr': '192.168.0.0/24',
'ips': [{
'address': ip,
'type': 'fixed',
}]
}]
}
}]
return jsonutils.dumps(info)
instance1 = self._create_fake_instance({
'display_name': 'woot',
'id': 1,
'uuid': '00000000-0000-0000-0000-000000000010'})
'uuid': '00000000-0000-0000-0000-000000000010',
'info_cache': {'network_info':
fake_network_info('192.168.0.1')}})
instance2 = self._create_fake_instance({
'display_name': 'woo',
'id': 20,
'uuid': '00000000-0000-0000-0000-000000000020'})
'uuid': '00000000-0000-0000-0000-000000000020',
'info_cache': {'network_info':
fake_network_info('192.168.0.2')}})
instance3 = self._create_fake_instance({
'display_name': 'not-woot',
'id': 30,
'uuid': '00000000-0000-0000-0000-000000000030'})
'uuid': '00000000-0000-0000-0000-000000000030',
'info_cache': {'network_info':
fake_network_info('192.168.0.3')}})
# ip ends up matching 2nd octet here.. so all 3 match ip
# but 'name' only matches one