Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 40 additions & 9 deletions src/xcp_storage/network/iptables.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,48 @@ def _save_iptables_changes() -> None:

# ------------------------------------------------------------------------------

def _is_fatal_iptables_code(code: int) -> bool:
# Documented by manual of iptables:
# 0 for correct exit.
# 2 for invalid command.
# 3 for incompatibility between kernel and user space.
# 4 for busy lock, failing memory allocation or error messages from kernel.
# 1 for other errors.
return code not in (0, 1)

# ------------------------------------------------------------------------------

def has_iptables_rule(rule: List[str]) -> bool:
code: Optional[int]
try:
_stdout, reason, code = run_command([_EXEC_PATH_IPTABLES, "-C"] + rule, simple=False)
if not _is_fatal_iptables_code(code):
return not code
except CommandError as e:
reason, code = e.reason, e.code
raise IptablesError(f"Failed to test existence of iptables rule `{rule}`: `{reason}`.", code)

# ------------------------------------------------------------------------------

def _ensure_iptables_chain_exists(chain: str) -> bool:
try:
_stdout, _stderr, ret_code = run_command([_EXEC_PATH_IPTABLES, "-C"] + rule, simple=False)
return not ret_code
_stdout, _stderr, ret_code = run_command([_EXEC_PATH_IPTABLES, "-N", chain], simple=False)
if _is_fatal_iptables_code(ret_code):
raise IptablesError(f"Failed to test existence of iptables chain `{chain}`: `{_stderr}`.", ret_code)
updated = not ret_code

return_rule = [chain, "-j", "RETURN"]
if not has_iptables_rule(return_rule):
run_command([_EXEC_PATH_IPTABLES, "-A"] + return_rule, expected_ret_code=0)
updated = True

jump_rule = [_MAIN_FIREWALL_INPUT_CHAIN, "-j", chain]
if not has_iptables_rule(jump_rule):
run_command([_EXEC_PATH_IPTABLES, "-I"] + jump_rule, expected_ret_code=0)
updated = True
except CommandError as e:
raise IptablesError(e.reason, e.code) from None
raise IptablesError(f"Failed to set up iptables chain `{chain}`: `{e.reason}`.", e.code) from None
return updated

# ------------------------------------------------------------------------------

Expand All @@ -69,13 +105,8 @@ def _update_iptables_ports(protocol: str, str_ports: str, *, open_ports: bool, s

# 2. Open or close.
if open_ports:
_ensure_iptables_chain_exists(chain)
try:
_stdout, _stderr, ret_code = run_command([_EXEC_PATH_IPTABLES, "-N", chain], simple=False)
if not ret_code:
# Create chain if necessary.
run_command([_EXEC_PATH_IPTABLES, "-A", chain, "-j", "RETURN"], expected_ret_code=0)
run_command([_EXEC_PATH_IPTABLES, "-I", _MAIN_FIREWALL_INPUT_CHAIN, "-j", chain], expected_ret_code=0)
# Create rule.
run_command([_EXEC_PATH_IPTABLES, "-I"] + rule, expected_ret_code=0)
except CommandError as e:
raise IptablesError(
Expand Down
Loading
Loading