Skip to content

Commit c4ff054

Browse files
committed
Firewalld: Add functionality to set source_port
1 parent ea6ef5c commit c4ff054

File tree

4 files changed

+196
-4
lines changed

4 files changed

+196
-4
lines changed

plugins/modules/firewalld.py

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828
- Name of a port or port range to add/remove to/from firewalld.
2929
- Must be in the form PORT/PROTOCOL or PORT-PORT/PROTOCOL for port ranges.
3030
type: str
31+
source_port:
32+
description:
33+
- Name of a source port or port range to add/remove to/from firewalld.
34+
- Must be in the form PORT/PROTOCOL or PORT-PORT/PROTOCOL for port ranges.
35+
type: str
3136
port_forward:
3237
description:
3338
- Port and protocol to forward using firewalld.
@@ -185,6 +190,13 @@
185190
permanent: true
186191
state: enabled
187192
193+
- name: Permit traffic in home zone from port 20561/udp
194+
ansible.posix.firewalld:
195+
source_port: 20561/udp
196+
zone: home
197+
permanent: true
198+
state: enabled
199+
188200
- name: Permit traffic in dmz zone on http service
189201
ansible.posix.firewalld:
190202
zone: dmz
@@ -552,6 +564,43 @@ def set_disabled_permanent(self, port, protocol, timeout):
552564
self.update_fw_settings(fw_zone, fw_settings)
553565

554566

567+
class SourcePortTransaction(FirewallTransaction):
568+
"""
569+
SourcePortTransaction
570+
"""
571+
572+
def __init__(self, module, action_args=None, zone=None, desired_state=None, permanent=False, immediate=False):
573+
super(SourcePortTransaction, self).__init__(
574+
module, action_args=action_args, desired_state=desired_state, zone=zone, permanent=permanent, immediate=immediate
575+
)
576+
577+
def get_enabled_immediate(self, port, protocol, timeout):
578+
if self.fw_offline:
579+
dummy, fw_settings = self.get_fw_zone_settings()
580+
return fw_settings.querySourcePort(port=port, protocol=protocol)
581+
return self.fw.querySourcePort(zone=self.zone, port=port, protocol=protocol)
582+
583+
def get_enabled_permanent(self, port, protocol, timeout):
584+
dummy, fw_settings = self.get_fw_zone_settings()
585+
return fw_settings.querySourcePort(port=port, protocol=protocol)
586+
587+
def set_enabled_immediate(self, port, protocol, timeout):
588+
self.fw.addSourcePort(zone=self.zone, port=port, protocol=protocol, timeout=timeout)
589+
590+
def set_enabled_permanent(self, port, protocol, timeout):
591+
fw_zone, fw_settings = self.get_fw_zone_settings()
592+
fw_settings.addSourcePort(port=port, protocol=protocol)
593+
self.update_fw_settings(fw_zone, fw_settings)
594+
595+
def set_disabled_immediate(self, port, protocol, timeout):
596+
self.fw.removeSourcePort(zone=self.zone, port=port, protocol=protocol)
597+
598+
def set_disabled_permanent(self, port, protocol, timeout):
599+
fw_zone, fw_settings = self.get_fw_zone_settings()
600+
fw_settings.removeSourcePort(port=port, protocol=protocol)
601+
self.update_fw_settings(fw_zone, fw_settings)
602+
603+
555604
class InterfaceTransaction(FirewallTransaction):
556605
"""
557606
InterfaceTransaction
@@ -879,6 +928,7 @@ def main():
879928
service=dict(type='str'),
880929
protocol=dict(type='str'),
881930
port=dict(type='str'),
931+
source_port=dict(type='str'),
882932
port_forward=dict(type='list', elements='dict'),
883933
rich_rule=dict(type='str'),
884934
zone=dict(type='str'),
@@ -900,8 +950,8 @@ def main():
900950
source=('permanent',),
901951
),
902952
mutually_exclusive=[
903-
['icmp_block', 'icmp_block_inversion', 'service', 'protocol', 'port', 'port_forward', 'rich_rule',
904-
'interface', 'forward', 'masquerade', 'source', 'target']
953+
['icmp_block', 'icmp_block_inversion', 'service', 'protocol', 'port', 'source_port', 'port_forward',
954+
'rich_rule', 'interface', 'forward', 'masquerade', 'source', 'target']
905955
],
906956
)
907957

@@ -957,6 +1007,17 @@ def main():
9571007
else:
9581008
port_protocol = None
9591009

1010+
source_port = None
1011+
if module.params['source_port'] is not None:
1012+
if '/' in module.params['source_port']:
1013+
source_port, source_port_protocol = module.params['source_port'].strip().split('/')
1014+
else:
1015+
source_port_protocol = None
1016+
if not source_port_protocol:
1017+
module.fail_json(msg='improper source_port format (missing protocol?)')
1018+
else:
1019+
source_port_protocol = None
1020+
9601021
port_forward_toaddr = ''
9611022
port_forward = None
9621023
if module.params['port_forward'] is not None:
@@ -973,7 +1034,7 @@ def main():
9731034
port_forward_toaddr = port_forward['toaddr']
9741035

9751036
modification = False
976-
if any([icmp_block, icmp_block_inversion, service, protocol, port, port_forward, rich_rule,
1037+
if any([icmp_block, icmp_block_inversion, service, protocol, port, source_port, port_forward, rich_rule,
9771038
interface, forward, masquerade, source, target]):
9781039
modification = True
9791040
if modification and desired_state in ['absent', 'present'] and target is None:
@@ -1079,6 +1140,26 @@ def main():
10791140
)
10801141
)
10811142

1143+
if source_port is not None:
1144+
1145+
transaction = SourcePortTransaction(
1146+
module,
1147+
action_args=(source_port, source_port_protocol, timeout),
1148+
zone=zone,
1149+
desired_state=desired_state,
1150+
permanent=permanent,
1151+
immediate=immediate,
1152+
)
1153+
1154+
changed, transaction_msgs = transaction.run()
1155+
msgs = msgs + transaction_msgs
1156+
if changed is True:
1157+
msgs.append(
1158+
"Changed source_port %s to %s" % (
1159+
"%s/%s" % (source_port, source_port_protocol), desired_state
1160+
)
1161+
)
1162+
10821163
if port_forward is not None:
10831164
transaction = ForwardPortTransaction(
10841165
module,

tests/integration/targets/firewalld/tasks/run_all_tests.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
- name: Include port test cases for firewalld module
2222
ansible.builtin.include_tasks: port_test_cases.yml
2323

24+
# firewalld source_port operation test cases
25+
- name: Include source_port test cases for firewalld module
26+
ansible.builtin.include_tasks: source_port_test_cases.yml
27+
2428
# firewalld source operation test cases
2529
- name: Include source test cases for firewalld module
2630
ansible.builtin.include_tasks: source_test_cases.yml
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
# Test playbook for the firewalld module - source_port operations
3+
4+
- name: Firewalld source_port range test permanent enabled
5+
ansible.posix.firewalld:
6+
source_port: 5500-6850/tcp
7+
permanent: true
8+
state: enabled
9+
register: result
10+
11+
- name: Assert firewalld source_port range test permanent enabled worked
12+
ansible.builtin.assert:
13+
that:
14+
- result is changed
15+
16+
- name: Firewalld source_port range test permanent enabled rerun (verify not changed)
17+
ansible.posix.firewalld:
18+
source_port: 5500-6850/tcp
19+
permanent: true
20+
state: enabled
21+
register: result
22+
23+
- name: Assert firewalld source_port range test permanent enabled rerun worked (verify not changed)
24+
ansible.builtin.assert:
25+
that:
26+
- result is not changed
27+
28+
- name: Firewalld source_port test permanent enabled
29+
ansible.posix.firewalld:
30+
source_port: 6900/tcp
31+
permanent: true
32+
state: enabled
33+
register: result
34+
35+
- name: Assert firewalld source_port test permanent enabled worked
36+
ansible.builtin.assert:
37+
that:
38+
- result is changed
39+
40+
- name: Firewalld source_port test permanent enabled
41+
ansible.posix.firewalld:
42+
source_port: 6900/tcp
43+
permanent: true
44+
state: enabled
45+
register: result
46+
47+
- name: Assert firewalld source_port test permanent enabled worked
48+
ansible.builtin.assert:
49+
that:
50+
- result is not changed
51+
52+
- name: Firewalld source_port test disabled
53+
ansible.posix.firewalld:
54+
source_port: "{{ item }}"
55+
permanent: true
56+
state: disabled
57+
loop:
58+
- 6900/tcp
59+
- 5500-6850/tcp
60+
61+
- name: Firewalld source_port test permanent enabled
62+
ansible.posix.firewalld:
63+
source_port: 8081/tcp
64+
permanent: true
65+
state: enabled
66+
register: result
67+
68+
- name: Assert firewalld source_port test permanent enabled worked
69+
ansible.builtin.assert:
70+
that:
71+
- result is changed
72+
73+
- name: Firewalld source_port test permanent enabled rerun (verify not changed)
74+
ansible.posix.firewalld:
75+
source_port: 8081/tcp
76+
permanent: true
77+
state: enabled
78+
register: result
79+
80+
- name: Assert firewalld source_port test permanent enabled rerun worked (verify not changed)
81+
ansible.builtin.assert:
82+
that:
83+
- result is not changed
84+
85+
- name: Firewalld source_port test permanent disabled
86+
ansible.posix.firewalld:
87+
source_port: 8081/tcp
88+
permanent: true
89+
state: disabled
90+
register: result
91+
92+
- name: Assert firewalld source_port test permanent disabled worked
93+
ansible.builtin.assert:
94+
that:
95+
- result is changed
96+
97+
- name: Firewalld source_port test permanent disabled rerun (verify not changed)
98+
ansible.posix.firewalld:
99+
source_port: 8081/tcp
100+
permanent: true
101+
state: disabled
102+
register: result
103+
104+
- name: Assert firewalld source_port test permanent disabled rerun worked (verify not changed)
105+
ansible.builtin.assert:
106+
that:
107+
- result is not changed

tests/integration/targets/firewalld/tasks/source_test_cases.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,4 @@
8585
- result is not changed
8686
- >
8787
result.msg == 'parameters are mutually exclusive:
88-
icmp_block|icmp_block_inversion|service|protocol|port|port_forward|rich_rule|interface|forward|masquerade|source|target'
88+
icmp_block|icmp_block_inversion|service|protocol|port|source_port|port_forward|rich_rule|interface|forward|masquerade|source|target'

0 commit comments

Comments
 (0)