puppetlabs/puppetlabs-firewall — pull request #349 by phemmer (2014-04-26 17:27:59+00:00)
Title: make extension parameter ordering easier to understand

This commit makes it easier to add extensions to the firewall module.

Currently when adding a new extension, you have to deal with this big ugly warning telling you that resources must be added in a specific order or you'll end up with puppet constantly re-applying the firewall rules. This is not true. The order of the various extensions does not matter, only the order of the options for each extension matters.
For example:

```
$ iptables -A OUTPUT -p tcp -m state --state new -m limit --limit 10 --limit-burst 100 -j ACCEPT
$ iptables-save | grep limit-burst
-A OUTPUT -p tcp -m state --state NEW -m limit --limit 10/sec --limit-burst 100 -j ACCEPT
```

```
$ iptables -A OUTPUT -p tcp -m limit --limit 10 --limit-burst 100 -m state --state new -j ACCEPT
$ iptables-save | grep limit-burst
-A OUTPUT -p tcp -m limit --limit 10/sec --limit-burst 100 -m state --state NEW -j ACCEPT
```

Notice that the output of `iptables-save` was given back in the exact same order as was used to create the rules.
But note that the order of the options for the `limit` extension does matter:

```
$ iptables -A OUTPUT -p tcp -m limit --limit-burst 100 --limit 10 -m state --state new -j ACCEPT
$ iptables-save | grep limit-burst
-A OUTPUT -p tcp -m limit --limit 10/sec --limit-burst 100 -m state --state NEW -j ACCEPT
```

The order of the target extensions does not matter either. But this is because you can only have a single target. You can't have both `-j DNAT --to-destination 1.2.3.4` and `-j LOG --log-prefix foo --log-level 7`.
But again, the order of the options to each target extension does matter.

Additionally we separate the built-in options into their own `parameters` array. The order of these does matter, but they're constant and never change.

So now when adding a new extension, you just add a line to either the `match_extensions` array, or the `target_extensions` array.

----

This is all defined by the iptables man page:

```
iptables [-t table] -I chain [rulenum] rule-specification

rule-specification = [matches...] [target]
match = -m matchname [per-match-options]
target = -j targetname [per-target-options]
```

----

But ultimately this is really just a band aid. I think the firewall module really needs proper handling of extensions. We should be able to define "here's an extension, here's the options the extension supports, and here's what each option means". Then you don't have to worry about order at all, you immediately know that the `--state` option belongs to the `state` match extension, and that `--to-destination` belongs to the `DNAT` target extension.