mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-05-08 06:12:51 +00:00
seport: fix idempotency when port is covered by an existing range (#11994)
* fix(seport): handle port overlap with existing ranges Fixes idempotency when a requested port is already covered by an existing range registered for the same setype/proto. Also improves the error message when libsemanage raises FileNotFoundError on a port overlap validation failure. Fixes #10105 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(seport): add changelog fragment for #11994 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2
changelogs/fragments/11994-seport-port-overlap.yml
Normal file
2
changelogs/fragments/11994-seport-port-overlap.yml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
bugfixes:
|
||||||
|
- seport - fix idempotency when a requested port is already covered by an existing range registered for the same setype (https://github.com/ansible-collections/community.general/issues/10105, https://github.com/ansible-collections/community.general/pull/11994).
|
||||||
@@ -158,6 +158,24 @@ def semanage_port_get_ports(seport, setype, proto, local):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_port_range(port):
|
||||||
|
"""Return (low, high) integers for a port or port range string."""
|
||||||
|
parts = str(port).split("-", 1)
|
||||||
|
low = int(parts[0])
|
||||||
|
high = int(parts[1]) if len(parts) == 2 else low
|
||||||
|
return low, high
|
||||||
|
|
||||||
|
|
||||||
|
def _port_is_covered(port, existing_ports):
|
||||||
|
"""Return True if port (or range) is fully covered by an existing port entry."""
|
||||||
|
req_low, req_high = _parse_port_range(port)
|
||||||
|
for entry in existing_ports:
|
||||||
|
entry_low, entry_high = _parse_port_range(entry)
|
||||||
|
if entry_low <= req_low and req_high <= entry_high:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def semanage_port_get_type(seport, port, proto):
|
def semanage_port_get_type(seport, port, proto):
|
||||||
"""Get the SELinux type of the specified port.
|
"""Get the SELinux type of the specified port.
|
||||||
|
|
||||||
@@ -218,7 +236,7 @@ def semanage_port_add(module, ports, proto, setype, do_reload, serange="s0", ses
|
|||||||
seport.set_reload(do_reload)
|
seport.set_reload(do_reload)
|
||||||
ports_by_type = semanage_port_get_ports(seport, setype, proto, local)
|
ports_by_type = semanage_port_get_ports(seport, setype, proto, local)
|
||||||
for port in ports:
|
for port in ports:
|
||||||
if port in ports_by_type:
|
if _port_is_covered(port, ports_by_type):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
change = True
|
change = True
|
||||||
@@ -230,6 +248,11 @@ def semanage_port_add(module, ports, proto, setype, do_reload, serange="s0", ses
|
|||||||
else:
|
else:
|
||||||
seport.modify(port, proto, serange, setype)
|
seport.modify(port, proto, serange, setype)
|
||||||
|
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
module.fail_json(
|
||||||
|
msg=f"Failed to modify SELinux port policy, possibly due to a port overlap with an existing range: {e}\n",
|
||||||
|
exception=traceback.format_exc(),
|
||||||
|
)
|
||||||
except (ValueError, OSError, KeyError, RuntimeError) as e:
|
except (ValueError, OSError, KeyError, RuntimeError) as e:
|
||||||
module.fail_json(msg=f"{e.__class__.__name__}: {e}\n", exception=traceback.format_exc())
|
module.fail_json(msg=f"{e.__class__.__name__}: {e}\n", exception=traceback.format_exc())
|
||||||
|
|
||||||
@@ -271,6 +294,11 @@ def semanage_port_del(module, ports, proto, setype, do_reload, sestore="", local
|
|||||||
if not module.check_mode:
|
if not module.check_mode:
|
||||||
seport.delete(port, proto)
|
seport.delete(port, proto)
|
||||||
|
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
module.fail_json(
|
||||||
|
msg=f"Failed to modify SELinux port policy, possibly due to a port overlap with an existing range: {e}\n",
|
||||||
|
exception=traceback.format_exc(),
|
||||||
|
)
|
||||||
except (ValueError, OSError, KeyError, RuntimeError) as e:
|
except (ValueError, OSError, KeyError, RuntimeError) as e:
|
||||||
module.fail_json(msg=f"{e.__class__.__name__}: {e}\n", exception=traceback.format_exc())
|
module.fail_json(msg=f"{e.__class__.__name__}: {e}\n", exception=traceback.format_exc())
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user