@ -126,6 +126,11 @@ options:
- Apply the rule to routed / forwarded packets .
- Apply the rule to routed / forwarded packets .
required : false
required : false
choices : [ ' yes ' , ' no ' ]
choices : [ ' yes ' , ' no ' ]
comment :
description :
- Add a comment to the rule . Requires UFW version > = 0.35 .
required : false
version_added : " 2.4 "
'''
'''
EXAMPLES = '''
EXAMPLES = '''
@ -194,12 +199,13 @@ EXAMPLES = '''
- 172.16 .0 .0 / 12
- 172.16 .0 .0 / 12
- 192.168 .0 .0 / 16
- 192.168 .0 .0 / 16
# Deny access to udp port 514 from host 1.2.3.4 :
# Deny access to udp port 514 from host 1.2.3.4 and include a comment :
- ufw :
- ufw :
rule : deny
rule : deny
proto : udp
proto : udp
src : 1.2 .3 .4
src : 1.2 .3 .4
port : 514
port : 514
comment : " Block syslog "
# Allow incoming access to eth0 from 1.2.3.5 port 5469 to 1.2.3.4 port 5469
# Allow incoming access to eth0 from 1.2.3.5 port 5469 to 1.2.3.4 port 5469
- ufw :
- ufw :
@ -250,7 +256,8 @@ def main():
to_ip = dict ( default = ' any ' , aliases = [ ' dest ' , ' to ' ] ) ,
to_ip = dict ( default = ' any ' , aliases = [ ' dest ' , ' to ' ] ) ,
to_port = dict ( default = None , aliases = [ ' port ' ] ) ,
to_port = dict ( default = None , aliases = [ ' port ' ] ) ,
proto = dict ( default = None , aliases = [ ' protocol ' ] , choices = [ ' any ' , ' tcp ' , ' udp ' , ' ipv6 ' , ' esp ' , ' ah ' ] ) ,
proto = dict ( default = None , aliases = [ ' protocol ' ] , choices = [ ' any ' , ' tcp ' , ' udp ' , ' ipv6 ' , ' esp ' , ' ah ' ] ) ,
app = dict ( default = None , aliases = [ ' name ' ] )
app = dict ( default = None , aliases = [ ' name ' ] ) ,
comment = dict ( default = None , type = ' str ' )
) ,
) ,
supports_check_mode = True ,
supports_check_mode = True ,
mutually_exclusive = [ [ ' app ' , ' proto ' , ' logging ' ] ]
mutually_exclusive = [ [ ' app ' , ' proto ' , ' logging ' ] ]
@ -267,6 +274,33 @@ def main():
if rc != 0 :
if rc != 0 :
module . fail_json ( msg = err or out )
module . fail_json ( msg = err or out )
def ufw_version ( ) :
"""
Returns the major and minor version of ufw installed on the system .
"""
rc , out , err = module . run_command ( " %s --version " % ufw_bin )
if rc != 0 :
module . fail_json (
msg = " Failed to get ufw version. " , rc = rc , out = out , err = err
)
lines = [ x for x in out . split ( ' \n ' ) if x . strip ( ) != ' ' ]
if len ( lines ) == 0 :
module . fail_json ( msg = " Failed to get ufw version. " , rc = 0 , out = out )
matches = re . search ( r ' ^ufw.+( \ d+) \ .( \ d+)(?: \ .( \ d+))?.*$ ' , lines [ 0 ] )
if matches is None :
module . fail_json ( msg = " Failed to get ufw version. " , rc = 0 , out = out )
# Convert version to numbers
major = int ( matches . group ( 1 ) )
minor = int ( matches . group ( 2 ) )
rev = 0
if matches . group ( 3 ) is not None :
rev = int ( matches . group ( 3 ) )
return major , minor , rev
params = module . params
params = module . params
# Ensure at least one of the command arguments are given
# Ensure at least one of the command arguments are given
@ -284,7 +318,7 @@ def main():
# Save the pre state and rules in order to recognize changes
# Save the pre state and rules in order to recognize changes
( _ , pre_state , _ ) = module . run_command ( ufw_bin + ' status verbose ' )
( _ , pre_state , _ ) = module . run_command ( ufw_bin + ' status verbose ' )
( _ , pre_rules , _ ) = module . run_command ( " grep ' ^### tuple ' /lib/ufw/user * .rules" )
( _ , pre_rules , _ ) = module . run_command ( " grep ' ^### tuple ' /lib/ufw/user .rules /lib/ufw/user6.rules /etc/ufw/user.rules /etc/ufw/user6 .rules" )
# Execute commands
# Execute commands
for ( command , value ) in commands . items ( ) :
for ( command , value ) in commands . items ( ) :
@ -306,7 +340,7 @@ def main():
#
#
# ufw [--dry-run] [delete] [insert NUM] [route] allow|deny|reject|limit [in|out on INTERFACE] [log|log-all] \
# ufw [--dry-run] [delete] [insert NUM] [route] allow|deny|reject|limit [in|out on INTERFACE] [log|log-all] \
# [from ADDRESS [port PORT]] [to ADDRESS [port PORT]] \
# [from ADDRESS [port PORT]] [to ADDRESS [port PORT]] \
# [proto protocol] [app application]
# [proto protocol] [app application] [comment COMMENT]
cmd . append ( [ module . boolean ( params [ ' delete ' ] ) , ' delete ' ] )
cmd . append ( [ module . boolean ( params [ ' delete ' ] ) , ' delete ' ] )
cmd . append ( [ module . boolean ( params [ ' route ' ] ) , ' route ' ] )
cmd . append ( [ module . boolean ( params [ ' route ' ] ) , ' route ' ] )
cmd . append ( [ params [ ' insert ' ] , " insert %s " % params [ ' insert ' ] ] )
cmd . append ( [ params [ ' insert ' ] , " insert %s " % params [ ' insert ' ] ] )
@ -322,11 +356,16 @@ def main():
value = params [ key ]
value = params [ key ]
cmd . append ( [ value , template % ( value ) ] )
cmd . append ( [ value , template % ( value ) ] )
ufw_major , ufw_minor , _ = ufw_version ( )
# comment is supported only in ufw version after 0.35
if ( ufw_major == 0 and ufw_minor > = 35 ) or ufw_major > 0 :
cmd . append ( [ params [ ' comment ' ] , " comment ' %s ' " % params [ ' comment ' ] ] )
execute ( cmd )
execute ( cmd )
# Get the new state
# Get the new state
( _ , post_state , _ ) = module . run_command ( ufw_bin + ' status verbose ' )
( _ , post_state , _ ) = module . run_command ( ufw_bin + ' status verbose ' )
( _ , post_rules , _ ) = module . run_command ( " grep ' ^### tuple ' /lib/ufw/user*.rules " )
( _ , post_rules , _ ) = module . run_command ( " grep ' ^### tuple ' /lib/ufw/user .rules /lib/ufw/user6.rules /etc/ufw/user.rules /etc/ufw/user6 .rules" )
changed = ( pre_state != post_state ) or ( pre_rules != post_rules )
changed = ( pre_state != post_state ) or ( pre_rules != post_rules )
return module . exit_json ( changed = changed , commands = cmds , msg = post_state . rstrip ( ) )
return module . exit_json ( changed = changed , commands = cmds , msg = post_state . rstrip ( ) )