Iptables enhancements (#2789)

* Add the flush parameter.

When specified the flush parameter indicates that this module should remove all
rules from the specified table. If no table parameter is specified then the
default filter table is flushed.

* Add support for setting chain policies.

The module supports setting the policy of a given chain and table to the
following target values, ACCEPT, DROP, QUEUE, and RETURN. This parameter ignores
all other unrelated parameters.

* Fix pep8 issues.

* Fix missing quotation.

* Make 'flush' and 'policy' parameters mutually exclusive.

This combination is not supported by the wrapped iptables command. 'flush' and
'policy' however, can both take the 'chain' argument.
This commit is contained in:
Mike Liu 2016-08-30 10:16:10 -04:00 committed by Matt Clay
parent 41713d0819
commit 73cf1f2755

View file

@ -74,8 +74,8 @@ options:
description: description:
- "Chain to operate on. This option can either be the name of a user - "Chain to operate on. This option can either be the name of a user
defined chain or any of the builtin chains: 'INPUT', 'FORWARD', defined chain or any of the builtin chains: 'INPUT', 'FORWARD',
'OUTPUT', 'PREROUTING', 'POSTROUTING', 'SECMARK', 'CONNSECMARK'" 'OUTPUT', 'PREROUTING', 'POSTROUTING', 'SECMARK', 'CONNSECMARK'."
required: true required: false
protocol: protocol:
description: description:
- The protocol of the rule or of the packet to check. The specified - The protocol of the rule or of the packet to check. The specified
@ -240,13 +240,18 @@ options:
default: null default: null
ctstate: ctstate:
description: description:
- "ctstate is a list of the connection states to match in the conntrack module. - "ctstate is a list of the connection states to match in the conntrack
Possible states are: 'INVALID', 'NEW', 'ESTABLISHED', 'RELATED', 'UNTRACKED', 'SNAT', 'DNAT'" module.
Possible states are: 'INVALID', 'NEW', 'ESTABLISHED', 'RELATED',
'UNTRACKED', 'SNAT', 'DNAT'"
required: false required: false
default: [] default: []
limit: limit:
description: description:
- "Specifies the maximum average number of matches to allow per second. The number can specify units explicitly, using `/second', `/minute', `/hour' or `/day', or parts of them (so `5/second' is the same as `5/s')." - "Specifies the maximum average number of matches to allow per second.
The number can specify units explicitly, using `/second', `/minute',
`/hour' or `/day', or parts of them (so `5/second' is the same as
`5/s')."
required: false required: false
default: null default: null
limit_burst: limit_burst:
@ -268,10 +273,24 @@ options:
icmp_type: icmp_type:
version_added: "2.2" version_added: "2.2"
description: description:
- "This allows specification of the ICMP type, which can be a numeric ICMP type, - "This allows specification of the ICMP type, which can be a numeric
type/code pair, or one of the ICMP type names shown by the command ICMP type, type/code pair, or one of the ICMP type names shown by the
'iptables -p icmp -h'" command 'iptables -p icmp -h'"
required: false required: false
flush:
version_added: "2.2"
description:
- "Flushes the specified table and chain of all rules. If no chain is
specified then the entire table is purged. Ignores all other
parameters."
required: false
policy:
version_added: "2.2"
description:
- "Set the policy for the chain to the given target. Valid targets are
ACCEPT, DROP, QUEUE, RETURN. Only built in chains can have policies.
This parameter requires the chain parameter. Ignores all other
parameters."
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -337,7 +356,11 @@ def construct_rule(params):
append_param(rule, params['destination_port'], '--destination-port', False) append_param(rule, params['destination_port'], '--destination-port', False)
append_param(rule, params['to_ports'], '--to-ports', False) append_param(rule, params['to_ports'], '--to-ports', False)
append_param(rule, params['set_dscp_mark'], '--set-dscp', False) append_param(rule, params['set_dscp_mark'], '--set-dscp', False)
append_param(rule, params['set_dscp_mark_class'], '--set-dscp-class', False) append_param(
rule,
params['set_dscp_mark_class'],
'--set-dscp-class',
False)
append_match(rule, params['comment'], 'comment') append_match(rule, params['comment'], 'comment')
append_param(rule, params['comment'], '--comment', False) append_param(rule, params['comment'], '--comment', False)
append_match(rule, params['ctstate'], 'state') append_match(rule, params['ctstate'], 'state')
@ -353,11 +376,12 @@ def construct_rule(params):
return rule return rule
def push_arguments(iptables_path, action, params): def push_arguments(iptables_path, action, params, make_rule=True):
cmd = [iptables_path] cmd = [iptables_path]
cmd.extend(['-t', params['table']]) cmd.extend(['-t', params['table']])
cmd.extend([action, params['chain']]) cmd.extend([action, params['chain']])
cmd.extend(construct_rule(params)) if make_rule:
cmd.extend(construct_rule(params))
return cmd return cmd
@ -382,15 +406,39 @@ def remove_rule(iptables_path, module, params):
module.run_command(cmd, check_rc=True) module.run_command(cmd, check_rc=True)
def flush_table(iptables_path, module, params):
cmd = push_arguments(iptables_path, '-F', params, make_rule=False)
module.run_command(cmd, check_rc=True)
def set_chain_policy(iptables_path, module, params):
cmd = push_arguments(iptables_path, '-P', params, make_rule=False)
cmd.append(params['policy'])
module.run_command(cmd, check_rc=True)
def main(): def main():
module = AnsibleModule( module = AnsibleModule(
supports_check_mode=True, supports_check_mode=True,
argument_spec=dict( argument_spec=dict(
table=dict(required=False, default='filter', choices=['filter', 'nat', 'mangle', 'raw', 'security']), table=dict(
state=dict(required=False, default='present', choices=['present', 'absent']), required=False,
action=dict(required=False, default='append', type='str', choices=['append', 'insert']), default='filter',
ip_version=dict(required=False, default='ipv4', choices=['ipv4', 'ipv6']), choices=['filter', 'nat', 'mangle', 'raw', 'security']),
chain=dict(required=True, default=None, type='str'), state=dict(
required=False,
default='present',
choices=['present', 'absent']),
action=dict(
required=False,
default='append',
type='str',
choices=['append', 'insert']),
ip_version=dict(
required=False,
default='ipv4',
choices=['ipv4', 'ipv6']),
chain=dict(required=False, default=None, type='str'),
protocol=dict(required=False, default=None, type='str'), protocol=dict(required=False, default=None, type='str'),
source=dict(required=False, default=None, type='str'), source=dict(required=False, default=None, type='str'),
to_source=dict(required=False, default=None, type='str'), to_source=dict(required=False, default=None, type='str'),
@ -406,8 +454,8 @@ def main():
source_port=dict(required=False, default=None, type='str'), source_port=dict(required=False, default=None, type='str'),
destination_port=dict(required=False, default=None, type='str'), destination_port=dict(required=False, default=None, type='str'),
to_ports=dict(required=False, default=None, type='str'), to_ports=dict(required=False, default=None, type='str'),
set_dscp_mark=dict(required=False,default=None, type='str'), set_dscp_mark=dict(required=False, default=None, type='str'),
set_dscp_mark_class=dict(required=False,default=None, type='str'), set_dscp_mark_class=dict(required=False, default=None, type='str'),
comment=dict(required=False, default=None, type='str'), comment=dict(required=False, default=None, type='str'),
ctstate=dict(required=False, default=[], type='list'), ctstate=dict(required=False, default=[], type='list'),
limit=dict(required=False, default=None, type='str'), limit=dict(required=False, default=None, type='str'),
@ -415,9 +463,16 @@ def main():
uid_owner=dict(required=False, default=None, type='str'), uid_owner=dict(required=False, default=None, type='str'),
reject_with=dict(required=False, default=None, type='str'), reject_with=dict(required=False, default=None, type='str'),
icmp_type=dict(required=False, default=None, type='str'), icmp_type=dict(required=False, default=None, type='str'),
flush=dict(required=False, default=False, type='bool'),
policy=dict(
required=False,
default=None,
type='str',
choices=['ACCEPT', 'DROP', 'QUEUE', 'RETURN']),
), ),
mutually_exclusive=( mutually_exclusive=(
['set_dscp_mark', 'set_dscp_mark_class'], ['set_dscp_mark', 'set_dscp_mark_class'],
['flush', 'policy'],
), ),
) )
args = dict( args = dict(
@ -426,12 +481,30 @@ def main():
ip_version=module.params['ip_version'], ip_version=module.params['ip_version'],
table=module.params['table'], table=module.params['table'],
chain=module.params['chain'], chain=module.params['chain'],
flush=module.params['flush'],
rule=' '.join(construct_rule(module.params)), rule=' '.join(construct_rule(module.params)),
state=module.params['state'], state=module.params['state'],
) )
insert = (module.params['action'] == 'insert')
ip_version = module.params['ip_version'] ip_version = module.params['ip_version']
iptables_path = module.get_bin_path(BINS[ip_version], True) iptables_path = module.get_bin_path(BINS[ip_version], True)
# Check if chain option is required
if args['flush'] is False and args['chain'] is None:
module.fail_json(
msg="Either chain or flush parameter must be specified.")
# Flush the table
if args['flush'] is True:
flush_table(iptables_path, module, module.params)
module.exit_json(**args)
# Set the policy
if module.params['policy']:
set_chain_policy(iptables_path, module, module.params)
module.exit_json(**args)
insert = (module.params['action'] == 'insert')
rule_is_present = check_present(iptables_path, module, module.params) rule_is_present = check_present(iptables_path, module, module.params)
should_be_present = (args['state'] == 'present') should_be_present = (args['state'] == 'present')
@ -443,7 +516,7 @@ def main():
module.exit_json(changed=args['changed']) module.exit_json(changed=args['changed'])
# Target is already up to date # Target is already up to date
if args['changed'] == False: if args['changed'] is False:
module.exit_json(**args) module.exit_json(**args)
if should_be_present: if should_be_present: