Commit 09671cd3 authored by Vitaly Lipatov's avatar Vitaly Lipatov

gateway: bound firewall command execution time

parent cd1b93a4
...@@ -120,6 +120,15 @@ def redis_connection_options(config): ...@@ -120,6 +120,15 @@ def redis_connection_options(config):
options['ssl'] = True options['ssl'] = True
return options return options
def run_command(command, **kwargs):
"""Run an external firewall command without allowing the switcher to hang."""
kwargs.setdefault('timeout', 10)
try:
return subprocess.run(command, **kwargs).returncode
except (OSError, subprocess.SubprocessError):
return 1
def restore_legacy_ipsets(): def restore_legacy_ipsets():
"""One-time migration fallback for snapshots made by older releases.""" """One-time migration fallback for snapshots made by older releases."""
global ipset_eterban_1, ipset_eterban_1_ipv6, ipset_firehol global ipset_eterban_1, ipset_eterban_1_ipv6, ipset_firehol
...@@ -139,12 +148,12 @@ def load_whitelist(): ...@@ -139,12 +148,12 @@ def load_whitelist():
targets.append((ipset_eterban_white_ipv6, 'inet6')) targets.append((ipset_eterban_white_ipv6, 'inet6'))
temporary = {name: name + '_new' for name, family in targets} temporary = {name: name + '_new' for name, family in targets}
for name, family in targets: for name, family in targets:
subprocess.call(['ipset', 'destroy', temporary[name]], stdout=subprocess.DEVNULL, run_command(['ipset', 'destroy', temporary[name]], stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL) stderr=subprocess.DEVNULL)
command = ['ipset', 'create', temporary[name], 'hash:net'] command = ['ipset', 'create', temporary[name], 'hash:net']
if family == 'inet6': if family == 'inet6':
command.extend(['family', 'inet6']) command.extend(['family', 'inet6'])
if subprocess.call(command) != 0: if run_command(command) != 0:
raise OSError('unable to create temporary whitelist set ' + temporary[name]) raise OSError('unable to create temporary whitelist set ' + temporary[name])
loaded = 0 loaded = 0
skipped = 0 skipped = 0
...@@ -163,15 +172,15 @@ def load_whitelist(): ...@@ -163,15 +172,15 @@ def load_whitelist():
if name not in temporary: if name not in temporary:
skipped += 1 skipped += 1
continue continue
if subprocess.call(['ipset', 'add', temporary[name], str(net), '-exist']) != 0: if run_command(['ipset', 'add', temporary[name], str(net), '-exist']) != 0:
raise OSError('unable to add whitelist entry ' + str(net)) raise OSError('unable to add whitelist entry ' + str(net))
loaded += 1 loaded += 1
for name, family in targets: for name, family in targets:
if subprocess.call(['ipset', 'swap', name, temporary[name]]) != 0: if run_command(['ipset', 'swap', name, temporary[name]]) != 0:
raise OSError('unable to activate whitelist set ' + name) raise OSError('unable to activate whitelist set ' + name)
finally: finally:
for name in temporary.values(): for name in temporary.values():
subprocess.call(['ipset', 'destroy', name], stdout=subprocess.DEVNULL, run_command(['ipset', 'destroy', name], stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL) stderr=subprocess.DEVNULL)
info = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) info = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
info += " whitelist: loaded " + str(loaded) + " entries from " + whitelist_file info += " whitelist: loaded " + str(loaded) + " entries from " + whitelist_file
...@@ -189,16 +198,16 @@ def ensure_firewall_rule(command): ...@@ -189,16 +198,16 @@ def ensure_firewall_rule(command):
try: try:
check_command[check_command.index('-I')] = '-C' check_command[check_command.index('-I')] = '-C'
except ValueError: except ValueError:
return subprocess.call(command) return run_command(command)
if subprocess.call(check_command) != 0: if run_command(check_command) != 0:
return subprocess.call(command) return run_command(command)
return 0 return 0
def remove_firewall_rule(command): def remove_firewall_rule(command):
"""Remove all duplicate copies of a rule during cleanup.""" """Remove all duplicate copies of a rule during cleanup."""
result = 0 result = 0
while subprocess.call(command) == 0: while run_command(command) == 0:
result = 0 result = 0
return result return result
...@@ -216,7 +225,7 @@ def is_whitelisted(ip_str): ...@@ -216,7 +225,7 @@ def is_whitelisted(ip_str):
setname = ipset_eterban_white_ipv6 setname = ipset_eterban_white_ipv6
else: else:
setname = ipset_eterban_white setname = ipset_eterban_white
rc = subprocess.call(['ipset', 'test', setname, ip_str], rc = run_command(['ipset', 'test', setname, ip_str],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return rc == 0 return rc == 0
...@@ -292,7 +301,7 @@ def destroy_iptables_rules (): ...@@ -292,7 +301,7 @@ def destroy_iptables_rules ():
# Destroy ipsets # Destroy ipsets
for name in [ipset_eterban_1, ipset_firehol, ipset_eterban_white]: for name in [ipset_eterban_1, ipset_firehol, ipset_eterban_white]:
subprocess.call(['ipset', 'destroy', name]) run_command(['ipset', 'destroy', name])
# Internal interface: remove outgoing block rules # Internal interface: remove outgoing block rules
if internal_interface: if internal_interface:
...@@ -319,7 +328,7 @@ def destroy_ip6tables_rules (): ...@@ -319,7 +328,7 @@ def destroy_ip6tables_rules ():
# Destroy ipsets # Destroy ipsets
for name in [ipset_eterban_1_ipv6, ipset_eterban_white_ipv6]: for name in [ipset_eterban_1_ipv6, ipset_eterban_white_ipv6]:
subprocess.call(['ipset', 'destroy', name]) run_command(['ipset', 'destroy', name])
if internal_interface: if internal_interface:
commands=[ commands=[
...@@ -619,7 +628,7 @@ def process_message_inner(message): ...@@ -619,7 +628,7 @@ def process_message_inner(message):
ban = ['ipset', '-A', ipset_eterban_1, ip] ban = ['ipset', '-A', ipset_eterban_1, ip]
print (ban) print (ban)
print (message) print (message)
if subprocess.call(ban) != 0: if run_command(ban) != 0:
log_redis_error("Unable to add ban to ipset: " + ip) log_redis_error("Unable to add ban to ipset: " + ip)
return False return False
if not persist_ban(ip): if not persist_ban(ip):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment