Fix IP spoofing filter blocking all packets.
Implement IP spoofing filter by adding yet another chain to iptables with RETURN rule for each of IP addresses assigned to port and DROP rule at the end of the chain. Fixes: bug #1190613 Change-Id: I2e7a0f8dd4c3519c57d28e87a44735a3482624b1
This commit is contained in:
parent
a36f2373d2
commit
531ff2fb34
@ -28,8 +28,10 @@ LOG = logging.getLogger(__name__)
|
||||
SG_CHAIN = 'sg-chain'
|
||||
INGRESS_DIRECTION = 'ingress'
|
||||
EGRESS_DIRECTION = 'egress'
|
||||
IP_SPOOF_FILTER = 'ip-spoof-filter'
|
||||
CHAIN_NAME_PREFIX = {INGRESS_DIRECTION: 'i',
|
||||
EGRESS_DIRECTION: 'o'}
|
||||
EGRESS_DIRECTION: 'o',
|
||||
IP_SPOOF_FILTER: 's'}
|
||||
LINUX_DEV_LEN = 14
|
||||
|
||||
|
||||
@ -94,6 +96,7 @@ class IptablesFirewallDriver(firewall.FirewallDriver):
|
||||
for port in self.filtered_ports.values():
|
||||
self._remove_chain(port, INGRESS_DIRECTION)
|
||||
self._remove_chain(port, EGRESS_DIRECTION)
|
||||
self._remove_chain(port, IP_SPOOF_FILTER)
|
||||
self._remove_chain_by_name_v4v6(SG_CHAIN)
|
||||
|
||||
def _setup_chain(self, port, DIRECTION):
|
||||
@ -175,15 +178,32 @@ class IptablesFirewallDriver(firewall.FirewallDriver):
|
||||
def _arp_spoofing_rule(self, port):
|
||||
return ['-m mac ! --mac-source %s -j DROP' % port['mac_address']]
|
||||
|
||||
def _setup_ip_spoof_filter_chain(self, port, table, addresses, rules):
|
||||
if len(addresses) == 1:
|
||||
rules.append('! -s %s -j DROP' % addresses[0])
|
||||
elif addresses:
|
||||
chain_name = self._port_chain_name(port, IP_SPOOF_FILTER)
|
||||
table.add_chain(chain_name)
|
||||
for ip in addresses:
|
||||
table.add_rule(chain_name, '-s %s -j RETURN' % ip)
|
||||
table.add_rule(chain_name, '-j DROP')
|
||||
rules.append('-j $%s' % chain_name)
|
||||
|
||||
def _ip_spoofing_rule(self, port, ipv4_rules, ipv6_rules):
|
||||
#Note(nati) allow dhcp or RA packet
|
||||
ipv4_rules += ['-p udp --sport 68 --dport 67 -j RETURN']
|
||||
ipv6_rules += ['-p icmpv6 -j RETURN']
|
||||
ipv4_addresses = []
|
||||
ipv6_addresses = []
|
||||
for ip in port['fixed_ips']:
|
||||
if netaddr.IPAddress(ip).version == 4:
|
||||
ipv4_rules += ['! -s %s -j DROP' % ip]
|
||||
ipv4_addresses.append(ip)
|
||||
else:
|
||||
ipv6_rules += ['! -s %s -j DROP' % ip]
|
||||
ipv6_addresses.append(ip)
|
||||
self._setup_ip_spoof_filter_chain(port, self.iptables.ipv4['filter'],
|
||||
ipv4_addresses, ipv4_rules)
|
||||
self._setup_ip_spoof_filter_chain(port, self.iptables.ipv6['filter'],
|
||||
ipv6_addresses, ipv6_rules)
|
||||
|
||||
def _drop_dhcp_rule(self):
|
||||
#Note(nati) Drop dhcp packet from VM
|
||||
|
@ -839,6 +839,7 @@ class IptablesFirewallTestCase(base.BaseTestCase):
|
||||
call.add_rule('sg-chain', '-j ACCEPT'),
|
||||
call.ensure_remove_chain('ifake_dev'),
|
||||
call.ensure_remove_chain('ofake_dev'),
|
||||
call.ensure_remove_chain('sfake_dev'),
|
||||
call.ensure_remove_chain('sg-chain'),
|
||||
call.add_chain('sg-chain'),
|
||||
call.add_chain('ifake_dev'),
|
||||
@ -889,6 +890,7 @@ class IptablesFirewallTestCase(base.BaseTestCase):
|
||||
call.add_rule('sg-chain', '-j ACCEPT'),
|
||||
call.ensure_remove_chain('ifake_dev'),
|
||||
call.ensure_remove_chain('ofake_dev'),
|
||||
call.ensure_remove_chain('sfake_dev'),
|
||||
call.ensure_remove_chain('sg-chain'),
|
||||
call.add_chain('sg-chain')]
|
||||
|
||||
@ -914,3 +916,62 @@ class IptablesFirewallTestCase(base.BaseTestCase):
|
||||
pass
|
||||
self.iptables_inst.assert_has_calls([call.defer_apply_on(),
|
||||
call.defer_apply_off()])
|
||||
|
||||
def test_ip_spoofing_filter_with_multiple_ips(self):
|
||||
port = {'device': 'tapfake_dev',
|
||||
'mac_address': 'ff:ff:ff:ff',
|
||||
'fixed_ips': ['10.0.0.1', 'fe80::1', '10.0.0.2']}
|
||||
self.firewall.prepare_port_filter(port)
|
||||
calls = [call.add_chain('sg-fallback'),
|
||||
call.add_rule('sg-fallback', '-j DROP'),
|
||||
call.ensure_remove_chain('sg-chain'),
|
||||
call.add_chain('sg-chain'),
|
||||
call.add_chain('ifake_dev'),
|
||||
call.add_rule('FORWARD',
|
||||
'-m physdev --physdev-is-bridged '
|
||||
'--physdev-out tapfake_dev '
|
||||
'-j $sg-chain'),
|
||||
call.add_rule('sg-chain',
|
||||
'-m physdev --physdev-is-bridged '
|
||||
'--physdev-out tapfake_dev '
|
||||
'-j $ifake_dev'),
|
||||
call.add_rule(
|
||||
'ifake_dev', '-m state --state INVALID -j DROP'),
|
||||
call.add_rule(
|
||||
'ifake_dev',
|
||||
'-m state --state ESTABLISHED,RELATED -j RETURN'),
|
||||
call.add_rule('ifake_dev', '-j $sg-fallback'),
|
||||
call.add_chain('ofake_dev'),
|
||||
call.add_rule('FORWARD',
|
||||
'-m physdev --physdev-is-bridged '
|
||||
'--physdev-in tapfake_dev '
|
||||
'-j $sg-chain'),
|
||||
call.add_rule('sg-chain',
|
||||
'-m physdev --physdev-is-bridged '
|
||||
'--physdev-in tapfake_dev '
|
||||
'-j $ofake_dev'),
|
||||
call.add_rule('INPUT',
|
||||
'-m physdev --physdev-is-bridged '
|
||||
'--physdev-in tapfake_dev '
|
||||
'-j $ofake_dev'),
|
||||
call.add_chain('sfake_dev'),
|
||||
call.add_rule('sfake_dev', '-s 10.0.0.1 -j RETURN'),
|
||||
call.add_rule('sfake_dev', '-s 10.0.0.2 -j RETURN'),
|
||||
call.add_rule('sfake_dev', '-j DROP'),
|
||||
call.add_rule(
|
||||
'ofake_dev', '-m mac ! --mac-source ff:ff:ff:ff -j DROP'),
|
||||
call.add_rule(
|
||||
'ofake_dev',
|
||||
'-p udp --sport 68 --dport 67 -j RETURN'),
|
||||
call.add_rule('ofake_dev', '-j $sfake_dev'),
|
||||
call.add_rule(
|
||||
'ofake_dev',
|
||||
'-p udp --sport 67 --dport 68 -j DROP'),
|
||||
call.add_rule(
|
||||
'ofake_dev', '-m state --state INVALID -j DROP'),
|
||||
call.add_rule(
|
||||
'ofake_dev',
|
||||
'-m state --state ESTABLISHED,RELATED -j RETURN'),
|
||||
call.add_rule('ofake_dev', '-j $sg-fallback'),
|
||||
call.add_rule('sg-chain', '-j ACCEPT')]
|
||||
self.v4filter_inst.assert_has_calls(calls)
|
||||
|
Loading…
x
Reference in New Issue
Block a user