Merge "Make ARP protection commands compatible with "ebtables-nft"" into stable/wallaby
This commit is contained in:
commit
02ce13761b
|
@ -73,12 +73,6 @@ def delete_arp_spoofing_protection(vifs):
|
||||||
_delete_arp_spoofing_protection(vifs, current_rules, table='nat',
|
_delete_arp_spoofing_protection(vifs, current_rules, table='nat',
|
||||||
chain='PREROUTING')
|
chain='PREROUTING')
|
||||||
|
|
||||||
# TODO(haleyb) this can go away in "R" cycle, it's here to cleanup
|
|
||||||
# old chains in the filter table
|
|
||||||
current_rules = ebtables(['-L'], table='filter').splitlines()
|
|
||||||
_delete_arp_spoofing_protection(vifs, current_rules, table='filter',
|
|
||||||
chain='FORWARD')
|
|
||||||
|
|
||||||
|
|
||||||
def _delete_arp_spoofing_protection(vifs, current_rules, table, chain):
|
def _delete_arp_spoofing_protection(vifs, current_rules, table, chain):
|
||||||
# delete the jump rule and then delete the whole chain
|
# delete the jump rule and then delete the whole chain
|
||||||
|
@ -92,10 +86,11 @@ def _delete_arp_spoofing_protection(vifs, current_rules, table, chain):
|
||||||
chain=chain)
|
chain=chain)
|
||||||
|
|
||||||
|
|
||||||
def _delete_unreferenced_arp_protection(current_vifs, table, chain):
|
@lockutils.synchronized('ebtables')
|
||||||
|
def delete_unreferenced_arp_protection(current_vifs):
|
||||||
# deletes all jump rules and chains that aren't in current_vifs but match
|
# deletes all jump rules and chains that aren't in current_vifs but match
|
||||||
# the spoof prefix
|
# the spoof prefix
|
||||||
current_rules = ebtables(['-L'], table=table).splitlines()
|
current_rules = ebtables(['-L'], table='nat').splitlines()
|
||||||
to_delete = []
|
to_delete = []
|
||||||
for line in current_rules:
|
for line in current_rules:
|
||||||
# we're looking to find and turn the following:
|
# we're looking to find and turn the following:
|
||||||
|
@ -107,19 +102,8 @@ def _delete_unreferenced_arp_protection(current_vifs, table, chain):
|
||||||
to_delete.append(devname)
|
to_delete.append(devname)
|
||||||
LOG.info("Clearing orphaned ARP spoofing entries for devices %s",
|
LOG.info("Clearing orphaned ARP spoofing entries for devices %s",
|
||||||
to_delete)
|
to_delete)
|
||||||
_delete_arp_spoofing_protection(to_delete, current_rules, table=table,
|
_delete_arp_spoofing_protection(to_delete, current_rules, table='nat',
|
||||||
chain=chain)
|
chain='PREROUTING')
|
||||||
|
|
||||||
|
|
||||||
@lockutils.synchronized('ebtables')
|
|
||||||
def delete_unreferenced_arp_protection(current_vifs):
|
|
||||||
_delete_unreferenced_arp_protection(current_vifs,
|
|
||||||
table='nat', chain='PREROUTING')
|
|
||||||
|
|
||||||
# TODO(haleyb) this can go away in "R" cycle, it's here to cleanup
|
|
||||||
# old chains in the filter table
|
|
||||||
_delete_unreferenced_arp_protection(current_vifs,
|
|
||||||
table='filter', chain='FORWARD')
|
|
||||||
|
|
||||||
|
|
||||||
@lockutils.synchronized('ebtables')
|
@lockutils.synchronized('ebtables')
|
||||||
|
@ -133,12 +117,17 @@ def _install_arp_spoofing_protection(vif, addresses, current_rules):
|
||||||
vif_chain = chain_name(vif)
|
vif_chain = chain_name(vif)
|
||||||
if not chain_exists(vif_chain, current_rules):
|
if not chain_exists(vif_chain, current_rules):
|
||||||
ebtables(['-N', vif_chain, '-P', 'DROP'])
|
ebtables(['-N', vif_chain, '-P', 'DROP'])
|
||||||
# flush the chain to clear previous accepts. this will cause dropped ARP
|
# Append a default DROP rule at the end of the chain. This will
|
||||||
# packets until the allows are installed, but that's better than leaked
|
# avoid "ebtables-nft" error when listing the chain.
|
||||||
# spoofed packets and ARP can handle losses.
|
ebtables(['-A', vif_chain, '-j', 'DROP'])
|
||||||
ebtables(['-F', vif_chain])
|
else:
|
||||||
|
# Flush the chain to clear previous accepts. This will cause dropped
|
||||||
|
# ARP packets until the allows are installed, but that's better than
|
||||||
|
# leaked spoofed packets and ARP can handle losses.
|
||||||
|
ebtables(['-F', vif_chain])
|
||||||
|
ebtables(['-A', vif_chain, '-j', 'DROP'])
|
||||||
for addr in sorted(addresses):
|
for addr in sorted(addresses):
|
||||||
ebtables(['-A', vif_chain, '-p', 'ARP', '--arp-ip-src', addr,
|
ebtables(['-I', vif_chain, '-p', 'ARP', '--arp-ip-src', addr,
|
||||||
'-j', 'ACCEPT'])
|
'-j', 'ACCEPT'])
|
||||||
# check if jump rule already exists, if not, install it
|
# check if jump rule already exists, if not, install it
|
||||||
if not vif_jump_present(vif, current_rules):
|
if not vif_jump_present(vif, current_rules):
|
||||||
|
@ -178,17 +167,22 @@ def _install_mac_spoofing_protection(vif, port_details, current_rules):
|
||||||
# mac filter chain for each vif which has a default deny
|
# mac filter chain for each vif which has a default deny
|
||||||
if not chain_exists(vif_chain, current_rules):
|
if not chain_exists(vif_chain, current_rules):
|
||||||
ebtables(['-N', vif_chain, '-P', 'DROP'])
|
ebtables(['-N', vif_chain, '-P', 'DROP'])
|
||||||
|
# Append a default DROP rule at the end of the chain. This will
|
||||||
|
# avoid "ebtables-nft" error when listing the chain.
|
||||||
|
ebtables(['-A', vif_chain, '-j', 'DROP'])
|
||||||
|
|
||||||
# check if jump rule already exists, if not, install it
|
# check if jump rule already exists, if not, install it
|
||||||
if not _mac_vif_jump_present(vif, current_rules):
|
if not _mac_vif_jump_present(vif, current_rules):
|
||||||
ebtables(['-A', 'PREROUTING', '-i', vif, '-j', vif_chain])
|
ebtables(['-I', 'PREROUTING', '-i', vif, '-j', vif_chain])
|
||||||
|
|
||||||
|
_delete_vif_mac_rules(vif, current_rules)
|
||||||
# we can't just feed all allowed macs at once because we can exceed
|
# we can't just feed all allowed macs at once because we can exceed
|
||||||
# the maximum argument size. limit to 500 per rule.
|
# the maximum argument size. limit to 500 per rule.
|
||||||
for chunk in (mac_addresses[i:i + 500]
|
for chunk in (mac_addresses[i:i + 500]
|
||||||
for i in range(0, len(mac_addresses), 500)):
|
for i in range(0, len(mac_addresses), 500)):
|
||||||
new_rule = ['-A', vif_chain, '-i', vif,
|
new_rule = ['-I', vif_chain, '-i', vif,
|
||||||
'--among-src', ','.join(sorted(chunk)), '-j', 'RETURN']
|
'--among-src', ','.join(sorted(chunk)), '-j', 'RETURN']
|
||||||
ebtables(new_rule)
|
ebtables(new_rule)
|
||||||
_delete_vif_mac_rules(vif, current_rules)
|
|
||||||
|
|
||||||
|
|
||||||
def _mac_vif_jump_present(vif, current_rules):
|
def _mac_vif_jump_present(vif, current_rules):
|
||||||
|
@ -227,7 +221,7 @@ NAMESPACE = None
|
||||||
|
|
||||||
@tenacity.retry(
|
@tenacity.retry(
|
||||||
wait=tenacity.wait_exponential(multiplier=0.02),
|
wait=tenacity.wait_exponential(multiplier=0.02),
|
||||||
retry=tenacity.retry_if_exception(lambda e: e.returncode == 255),
|
retry=tenacity.retry_if_exception(lambda e: e.returncode in [255, 4]),
|
||||||
reraise=True
|
reraise=True
|
||||||
)
|
)
|
||||||
def ebtables(comm, table='nat'):
|
def ebtables(comm, table='nat'):
|
||||||
|
|
|
@ -75,13 +75,19 @@ class TestLinuxBridgeARPSpoofing(base.BaseTestCase):
|
||||||
check_exit_code=True, extra_ok_codes=None,
|
check_exit_code=True, extra_ok_codes=None,
|
||||||
log_fail_as_error=True, run_as_root=True,
|
log_fail_as_error=True, run_as_root=True,
|
||||||
privsep_exec=True),
|
privsep_exec=True),
|
||||||
mock.ANY,
|
|
||||||
mock.call(['ebtables', '-t', 'nat', '--concurrent', '-A',
|
mock.call(['ebtables', '-t', 'nat', '--concurrent', '-A',
|
||||||
|
'neutronMAC-%s' % vif, '-j', 'DROP'],
|
||||||
|
check_exit_code=True, extra_ok_codes=None,
|
||||||
|
log_fail_as_error=True, run_as_root=True,
|
||||||
|
privsep_exec=True),
|
||||||
|
mock.ANY,
|
||||||
|
mock.call(['ebtables', '-t', 'nat', '--concurrent', '-I',
|
||||||
'PREROUTING', '-i', vif, '-j', mac_chain],
|
'PREROUTING', '-i', vif, '-j', mac_chain],
|
||||||
check_exit_code=True, extra_ok_codes=None,
|
check_exit_code=True, extra_ok_codes=None,
|
||||||
log_fail_as_error=True, run_as_root=True,
|
log_fail_as_error=True, run_as_root=True,
|
||||||
privsep_exec=True),
|
privsep_exec=True),
|
||||||
mock.call(['ebtables', '-t', 'nat', '--concurrent', '-A',
|
mock.ANY,
|
||||||
|
mock.call(['ebtables', '-t', 'nat', '--concurrent', '-I',
|
||||||
mac_chain, '-i', vif,
|
mac_chain, '-i', vif,
|
||||||
'--among-src', '%s' % ','.join(sorted(mac_addresses)),
|
'--among-src', '%s' % ','.join(sorted(mac_addresses)),
|
||||||
'-j', 'RETURN'],
|
'-j', 'RETURN'],
|
||||||
|
@ -89,21 +95,20 @@ class TestLinuxBridgeARPSpoofing(base.BaseTestCase):
|
||||||
log_fail_as_error=True, run_as_root=True,
|
log_fail_as_error=True, run_as_root=True,
|
||||||
privsep_exec=True),
|
privsep_exec=True),
|
||||||
mock.ANY,
|
mock.ANY,
|
||||||
mock.ANY,
|
|
||||||
mock.call(['ebtables', '-t', 'nat', '--concurrent', '-N',
|
mock.call(['ebtables', '-t', 'nat', '--concurrent', '-N',
|
||||||
spoof_chain, '-P', 'DROP'],
|
spoof_chain, '-P', 'DROP'],
|
||||||
check_exit_code=True, extra_ok_codes=None,
|
check_exit_code=True, extra_ok_codes=None,
|
||||||
log_fail_as_error=True, run_as_root=True,
|
log_fail_as_error=True, run_as_root=True,
|
||||||
privsep_exec=True),
|
privsep_exec=True),
|
||||||
mock.call(['ebtables', '-t', 'nat', '--concurrent', '-F',
|
mock.call(['ebtables', '-t', 'nat', '--concurrent', '-A',
|
||||||
spoof_chain],
|
spoof_chain, '-j', 'DROP'],
|
||||||
check_exit_code=True, extra_ok_codes=None,
|
check_exit_code=True, extra_ok_codes=None,
|
||||||
log_fail_as_error=True, run_as_root=True,
|
log_fail_as_error=True, run_as_root=True,
|
||||||
privsep_exec=True),
|
privsep_exec=True)
|
||||||
]
|
]
|
||||||
for addr in sorted(ip_addresses):
|
for addr in sorted(ip_addresses):
|
||||||
expected.extend([
|
expected.extend([
|
||||||
mock.call(['ebtables', '-t', 'nat', '--concurrent', '-A',
|
mock.call(['ebtables', '-t', 'nat', '--concurrent', '-I',
|
||||||
spoof_chain, '-p', 'ARP',
|
spoof_chain, '-p', 'ARP',
|
||||||
'--arp-ip-src', addr, '-j', 'ACCEPT'],
|
'--arp-ip-src', addr, '-j', 'ACCEPT'],
|
||||||
check_exit_code=True, extra_ok_codes=None,
|
check_exit_code=True, extra_ok_codes=None,
|
||||||
|
@ -167,38 +172,6 @@ class TestLinuxBridgeARPSpoofing(base.BaseTestCase):
|
||||||
check_exit_code=True, extra_ok_codes=None,
|
check_exit_code=True, extra_ok_codes=None,
|
||||||
log_fail_as_error=True, run_as_root=True,
|
log_fail_as_error=True, run_as_root=True,
|
||||||
privsep_exec=True),
|
privsep_exec=True),
|
||||||
mock.call(['ebtables', '-t', 'filter', '--concurrent', '-L'],
|
|
||||||
check_exit_code=True, extra_ok_codes=None,
|
|
||||||
log_fail_as_error=True, run_as_root=True,
|
|
||||||
privsep_exec=True),
|
|
||||||
mock.ANY,
|
|
||||||
mock.call(['ebtables', '-t', 'filter', '--concurrent', '-D',
|
|
||||||
'FORWARD', '-i', VIF, '-j', spoof_chain,
|
|
||||||
'-p', 'ARP'],
|
|
||||||
check_exit_code=True, extra_ok_codes=None,
|
|
||||||
log_fail_as_error=True, run_as_root=True,
|
|
||||||
privsep_exec=True),
|
|
||||||
mock.call(['ebtables', '-t', 'filter', '--concurrent', '-F',
|
|
||||||
spoof_chain],
|
|
||||||
check_exit_code=True, extra_ok_codes=None,
|
|
||||||
log_fail_as_error=True, run_as_root=True,
|
|
||||||
privsep_exec=True),
|
|
||||||
mock.call(['ebtables', '-t', 'filter', '--concurrent', '-X',
|
|
||||||
spoof_chain],
|
|
||||||
check_exit_code=True, extra_ok_codes=None,
|
|
||||||
log_fail_as_error=True, run_as_root=True,
|
|
||||||
privsep_exec=True),
|
|
||||||
mock.ANY,
|
|
||||||
mock.call(['ebtables', '-t', 'filter', '--concurrent', '-F',
|
|
||||||
mac_chain],
|
|
||||||
check_exit_code=True, extra_ok_codes=None,
|
|
||||||
log_fail_as_error=True, run_as_root=True,
|
|
||||||
privsep_exec=True),
|
|
||||||
mock.call(['ebtables', '-t', 'filter', '--concurrent', '-X',
|
|
||||||
mac_chain],
|
|
||||||
check_exit_code=True, extra_ok_codes=None,
|
|
||||||
log_fail_as_error=True, run_as_root=True,
|
|
||||||
privsep_exec=True),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
arp_protect.delete_arp_spoofing_protection([VIF])
|
arp_protect.delete_arp_spoofing_protection([VIF])
|
||||||
|
|
Loading…
Reference in New Issue