Iceditch Command Reference: Difference between revisions
(→Target keyword: log: clarified difference log/ulog) |
(→Target keyword: nojump: started) |
||
Line 232: | Line 232: | ||
It is still possible to use the MASQUERADE target instead of SNAT even though you do have a static IP; however, it is not favorable since it will add extra overhead, and there may be inconsistencies in the future which will thwart your existing scripts and render them "unusable".<br> | It is still possible to use the MASQUERADE target instead of SNAT even though you do have a static IP; however, it is not favorable since it will add extra overhead, and there may be inconsistencies in the future which will thwart your existing scripts and render them "unusable".<br> | ||
Note that the MASQUERADE target is only valid within the POSTROUTING chain in the nat table, just as the SNAT target. | Note that the MASQUERADE target is only valid within the POSTROUTING chain in the nat table, just as the SNAT target. | ||
== Target keyword: nojump == | |||
'''''nojump [log [msg <message>]] <matches>'''''<br> | |||
''nojump'' creates an iptables rule with an empty jump target. This means that the match is made, but no action is undertaken on the match. OK, so why do we even ''need'' a "nojump" target if it doesn't create an IPtables jump? As far as we know, two valid reasons might be:<br> | |||
=== using nojump for auditing === | |||
A ''nojump'' rule can be used for '''auditing'''. Say you want to know how often you are pinged from IP 1.2.3.4 - without logging each and every ping request to the firewall logfile. You could write | |||
context INPUT filter | |||
nojump -p icmp --icmp-type 8 -s 1.2.3.4</pre> | |||
This rule could be checked in IPtables with ''iptables -n -L'' as <pre> | |||
Chain INPUT (policy DROP 1713K packets, 119M bytes) | |||
pkts bytes target prot opt in out source destination | |||
0 0 icmp -- * * 1.2.3.4 0.0.0.0/0 icmp type 8</pre> | |||
Good to know you haven't been pinged by 1.2.3.4 yet, eh?!<br> | |||
=== using nojump to apply matches without using targets === | |||
A ''nojump'' rule can be used to '''apply matches''' like ''recent'', that may just happily act on their own. Say you want to block spurious SSH login attempts; if "spurious" to you means "more than two connection attempts per minute", then you could try: | |||
context INPUT filter | |||
nojump -p tcp --dport 22 -i $inetIF -m state --state NEW -m recent --name SSHers --set | |||
drop -p tcp --dport 22 -i $inetIF -m state --state NEW -m recent --name SSHers --update --seconds 60 --hitcount 3 | |||
This causes Iceditch to add the IP of every connection attempt to your SSH port to a list named "SSHers", and consecutively, that every packet that fits this description AND has seen two more hits from the same source address in the last 60 seconds gets dropped. Essentially, this limits brute-force attackers on your SSH to trying 2 logins per minute at most. But you see that the nojump rule gets translated to | |||
iptables -A INPUT -t filter -p tcp --dport 22 -i $inetIF -m state --state NEW -m recent --name SSHers --set | |||
No ''--jump'' in that line - hence the name of the Iceditch target: ''nojump''. | |||
== Target keyword: redirect == | == Target keyword: redirect == |
Revision as of 18:23, 14 August 2008
Parameter: log
target log [(msg|message) <message>] <matches>
After most keywords, a "log" parameter can be added (see below). If the "log" parameter is followed by "msg" (or "message"), then the parameter following "msg" is read and used as log-prefix. The parameter is not allowed to have whitespace (that limitation is Iceditch-specific, not IPtables-related), and the maximum length of the log-prefix is determined by your version of netfilter/IPtables and your choice of IPtables logging utility (syslogemu or ulog); this limit is usually some 29 characters. Note that Iceditch does not perform any sanity checks on the message.
Thus a packet matching the <matches> part of the rule will be logged with the default setting of the "log" target.
If the "log" parameter is not followed by "msg", then the packet will be logged with a default log message, being "<table>_<chain>_<target>" and all the other default setting of the "log" target. Thus, should you want to log a packet with more control over the logging parameters, then you need an extra line, beginning with the target keyword "log", instead of just following the target keyword with parameter log. For more information, see the target keyword "log" below.
Context keyword: context
context <chain> <table>
Every IPtables rule is written to a chain in a table; with Iceditch, you don't have to specify the chain and table in every line. Just precede the lines with the context statement. Example:
context POSTROUTING nat
Notes: the order of chain and table does not matter; context nat POSTROUTING works just as well. Furthermore, <chain> and <table> have been made case-insensitive; whatever you specify as chain will be translated to uppercase, whatever you specify as table will be translated to lowercase. This gives you the possibility to write the context as you like to read it, e.g. context Postrouting Nat; after processing this, Iceditch will have two variables $CHAIN="POSTROUTING" and $TABLE="nat" that it will use in every following command. For example:
context "Input" "fIlTeR" accept -p tcp --dport 22
will result in the following IPtables call:
iptables -A INPUT -t filter -p tcp --dport 22 --jump ACCEPT
If you do NOT specify a valid combination of chain and table, the execution of Iceditch will halt with a fatal error. It is allowed (but not recommended) to call context multiple times for the same combination of chain and table; the order in which the rules are added to that chain in that table, is the same in which they appear in your rulefile, top to bottom. This is not recommended, because we feel it decreases readability, and thus maintainability, of the rules file. But hey, it's going to be your rulefile anyway...
Note: you cannot create custom chains by the names of mangle, nat or filter, since Iceditch will always interpret these names as those of tables.
Context keyword: create_chain
create_chain <chain> [<table>]
This command creates a new chain named <chain>, in the specified table <table>. If no table is specified, then the filter table is assumed. Just as with the context command, the <chain> name you specify will be translated to all uppercase.
The name for your new chain must be unique, although just like the built-in chains, you can specify the same name in different tables. If you create "fun-filter" in table filter, and then create a "fun-filter" in table nat, then you actually have two different chains. But remember: since Iceditch translates every chain name to uppercase, you can't create "Fun-filter" AND "fun-FILTER" in the same table - they're the same chain.
NOTE: after you've run create_chain, you still have to switch context to create rules in the new chain! example:
create_chain fun-filter context fun-filter filter accept -p tcp --dport 22
This will result in
iptables -N FUN-FILTER -t filter iptables -A FUN-FILTER -t filter -p tcp --dport 22 --jump ACCEPT
Target keyword: accept
accept [log [msg <message>]] <matches>
If a network packet fits the <matches>, then it will be accepted (passed) through the table/chain defined in the context where you put the accept rule. Example:
context Input Filter accept –p tcp --dport 22
Iceditch works this out to
iptables –t filter –A INPUT –p tcp –-dport 22 –-jump ACCEPT
Should you want to log the packet, you’d use
context Input Filter accept log –p tcp --dport 22
Iceditch works this out to
iptables –t filter –A INPUT –p tcp –-dport 22 \ –-jump LOG --log-prefix accept_INPUT_filter iptables –t filter –A INPUT –p tcp –-dport 22 –-jump ACCEPT
Note: the ACCEPT target is valid in any user-manipulable table/chain combination
Target keyword: classify
classify <classval> [log [msg <message>]] <matches>
If a packet travelling through the mangle table in the POSTROUTING chain matches the <matches>, then it will be classified with the <classval> specified. An example:
classify 2:11 –p tcp --dport 22
The script works this out to
iptables –t mangle –A POSTROUTING –p tcp –-dport 22 –-jump CLASSIFY --setclass 2:11
Should you want to also log the packet, you’d use
classify 2:11 log msg classified_2:11 –p tcp --dport 22
The script works this out to
iptables –t mangle –A POSTROUTING –p tcp –-dport 22 –-jump LOG \ --log-prefix classified_2:11: iptables –t mangle –A POSTROUTING –p tcp –-dport 22 –-jump CLASSIFY \ --setclass 2:11
Should you not give a msg, then the log-prefix becomes classify_POSTROUTING_mangle. Because of how iptables handles the CLASSIFY target, you can only use it in contexts where the chain is "POSTROUTING" and the table is "mangle".
Target keyword: dnat
dnat [to] <a1[-a2][:p1[-p2]]> [log [msg <message>]] <matches>
In the above, a1 and a2 are used to specify a (range of) IP address(es); for TCP and UDP protocols, a destination port or port range can be provided. Note that the "to" in the command is optional, and serves only readability.
If a packet matches the qualifiers, then it will be destination-NATted to the provided IP address or address range. For example, if you want to DNAT port 81 on your external interface eth1 to an internal webserver on 10.0.0.1, you could use
context "PREROUTING" "nat" dnat to 10.0.0.1:80 –p tcp –i eth1 –-dport 81
If you give a range of IP addresses, then the DNAT logic of IPtables will randomly pick an address and DNAT the packet there. However, note that a single stream will always use the same IP address from that range, and that each stream will randomly be given an IP address that it will always be destined for, within that stream.
Furthermore, note that the DNAT target is only available within the PREROUTING and OUTPUT chains in the nat table, and any of the chains called upon from any of those listed chains. Note that chains containing DNAT targets may not be used from any other chains, such as the POSTROUTING chain. However, the bad news is that Iceditch currently does not know how to check for the latter case, so the dnat keyword only works from contexts "PREROUTING" "nat" and "OUTPUT" "nat".
Target keyword: drop
drop [log [msg <message>]] <matches>
In essence, this does the same as the "accept" target keyword, only it jumps to DROP instead of ACCEPT. Thus any packet matching the <matches> gets discarded; it will not get sent on to its final destination (or next hop), it will not get processed by any other firewall rule, and the sender of the packet is unaware of your treatment of his packet.
Should you want to also log the packet, you’d use
context "FORWARD" "filter" drop log –p tcp -s 10.0.0.0/16
The script works this out to
iptables –t filter –A FORWARD –p tcp -s 10.0.0.0/16 –-jump LOG \ --log-prefix drop_FORWARD_filter: iptables –t filter –A FORWARD –p tcp -s 10.0.0.0/16 –-jump DROP
However, be advised that using DROP may leave dead sockets on either the sending or receiving host. If you do not wish that, you might be better of using REJECT. On the other hand, dropping packets is a nice way of appearing like a black hole, so it's the weapon of choice against port scanners and the likes.
The DROP target can be used in any chain in any table.
Target keyword: ipv4optsstrip
ipv4optsstrip [log [msg <message>]] <matches>
This target takes any packet that fits the <matches>, and then strips off all IPv4 options from its header. It can only be used in the mangle table. For example, the following rule strips the IPv4 options from any packet incoming on eth0:
context PREROUTING mangle ipv4optsstrip -i eth0
Target keyword: tochain
tochain <customchain> [log [msg <message>]] <matches>
If you've created a custom chain within a certain table, then you can jump to this custom chain using tochain, as long as the tochain invocation appears in a context with the same table. For example:
create_chain FTPtraffic filter (...) context INPUT filter (...) tochain FTPtraffic -p tcp --dport 20
In this example, any TCP packet that appears in table filter, chain INPUT and is directed at port 20, is sent on through to the previously created chain FTPTRAFFIC (keep in mind that Iceditch will always translate any chain name to all uppercase). Rule matching and packet processing will continue in that chain, until an ACCEPT or DROP is encountered, or a RETURN, or all rules in the custom chain have been exhausted. After that, the implicit return policy on your custom chain will return the packet to whence it came (context INPUT filter, the line below the tochain invocation).
Target keyword: log
for LOG target: log [(msg|message) <message>] [ip-options|ipopt] [(lvl|level) <loglevel>] [tcp-options|tcpopt] [tcp-sequence|tcpseq] <matches>
for ULOG target: log [(msg|message) <message>] [cprange <range>] [qtreshold|qtresh <treshold>] <matches>
Sometimes, the standard log parameter is just not enough. This can be the case when you want to log a packet with one or more of the extra options beside --log-prefix. Or maybe you want to just log a certain type or class of packets, without performing an action on those packets just yet, so that you can't use log as a parameter to one of the other Iceditch keywords.
For this reason, AND for flexibility and clarity, Iceditch has the dedicated target keyword log.
Just as when you use the log parameter after another target keyword, the use of the log target will make Iceditch call upon the logging daemon specified in the Iceditch config file. Standard this is LOG, but optionally you could specify ULOG in the config file. Note that an explicit call on target keyword log gives one the option to specify extra parameters, but also note that the choice of which parameters you can use depends on your configured choice of logging daemon.
The message to log
Now the message that gets logged is treated the same by Iceditch, no matter which logging daemon you use. Somewhere after the target keyword log (but before any of the <matches>) you specify msg <message> (or message <message>). The <message> can be any string between 1 and some 29 characters max (letters, numbers and underscores; no spaces, not empty). If you do NOT specify a message, Iceditch will always create a default log message: <chain>_<table>_log. This means that
context INPUT filter log -p tcp --dport 22
will result in either one of the iptables lines shown below, depending on your choice of logging daemon:
iptables -A INPUT -t filter -p tcp --dport 22 --jump LOG --log-prefix INPUT_filter_log --log-level 4 iptables -A INPUT -t filter -p tcp --dport 22 --jump ULOG --ulog-prefix INPUT_filter_log
(note the default log level when using the syslog logging daemon).
Log parameters when using the syslog logging daemon
Besides a log message, there are four more options that you can also specify. All five options are shown in the table below:
LOG options | ||
---|---|---|
Iceditch option | IPtables option | Description |
ip-options / ipopt | --log-ip-options | Makes Netfilter include the IP options in the log entry |
lvl / level <loglevel> | --log-level <loglevel> | Makes Netfilter log with the specified <loglevel> |
msg / message <logmessage> | --log-prefix <logmessage> | Makes Netfilter prepend <logmessage> to the log entry |
tcp-options / tcpopt | --log-tcp-options | Makes Netfilter include the TCP options in the log entry |
tcp-sequence / tcpseq | --log-tcp-sequence | Makes Netfilter include the TCP sequence number in the log entry |
On the log-level: when using the syslog daemon (IPtables target LOG), it is possible to specify a log level. The log level can be specified numerically or by name; Iceditch will translate it to its numerical value. However, if you do NOT specify a log level, Iceditch will include a default log level, being 4 (warn). For completeness, we here reproduce the list of logging levels that log understands:
Level | Description |
---|---|
0 | emerg or panic |
1 | alert |
2 | crit |
3 | err |
4 | warn (default) |
5 | notice |
6 | info |
7 | debug |
Log parameters when using the ulog user space logging daemon
ULOG options | ||
---|---|---|
Iceditch option | IPtables option | Description |
cprange <size> | --ulog-cprange <size> | log the first size bytes of each packet |
msg / message <logmessage> | --log-prefix <logmessage> | Makes Netfilter prepend <logmessage> to the log entry |
qtreshold / qtresh <value> | --ulog-qthreshold <value> | Queue value packets before sending them to ulogd (default = 1, max = 50) |
Now an example:
context "INPUT" "filter" log lvl info msg SSH_incoming -p tcp --dport 22 -i $inetIF
Iceditch works this out into
iptables -A INPUT -t filter -p tcp --dport 22 -i $inetIF --jump ULOG --ulog-prefix "SSH_incoming" --log-level 6
Target keyword: mark
mark <markval> [log [msg <message>]] <matches>
If a packet matches the <matches>, then it will be marked with the <markval> specified. An example from the context PREROUTING mangle:
mark 2 –p tcp --dport 22
Iceditch works this out to
iptables –t mangle –A PREROUTING –p tcp –-dport 22 –-jump MARK --setmark 2
Should you want to also log the packet, you’d use
mark 2 log –p tcp --dport 22
Iceditch works this out to
iptables –t mangle –A PREROUTING –p tcp –-dport 22 –-jump LOG \ --log-prefix mark_PREROUTING_mangle: iptables –t mangle –A PREROUTING –p tcp –-dport 22 –-jump MARK --setmark 2
Because of how iptables handles the MARK target, you can only use it in contexts where the table is mangle.
Target keyword: masquerade
masquerade <iface> [to <p1[-p2]>] [log [msg <message>]] <matches>
<iface> is the (outward facing) network interface that we want to masquerade on.
The MASQUERADE target is used basically the same as the SNAT target, but it does not require any --to-source option. The reason for this is that the MASQUERADE target was made to work with connections which get dynamic IP addresses when connecting to the network in question, for example dial-up connections, or DHCP connections. This means that you should only use the MASQUERADE target with dynamically assigned IP connections, which we don't know the actual IP address of in advance. If you have a static IP connection, you should instead use the SNAT target.
When you masquerade a connection, it means that we set the IP address used on a specific network interface, instead of getting it from the --to-source option. The necessary IP address is automatically grabbed from the information about the specific interface. Using the masquerade keyword also has the advantage that connections are forgotten when an interface goes down, which is extremely good if we, for example, kill a specific interface. If we would have used the SNAT target, we may have been left with a lot of old connection tracking data, which would be kept in connection tracking memory for days. forgetting about connections is, in general, the correct behavior when dealing with dial-up lines that are probably assigned a different IP every time they are brought up. In case we are assigned a different IP, the connection is lost anyways, and it is more or less idiotic to keep the entry around.
It is still possible to use the MASQUERADE target instead of SNAT even though you do have a static IP; however, it is not favorable since it will add extra overhead, and there may be inconsistencies in the future which will thwart your existing scripts and render them "unusable".
Note that the MASQUERADE target is only valid within the POSTROUTING chain in the nat table, just as the SNAT target.
Target keyword: nojump
nojump [log [msg <message>]] <matches>
nojump creates an iptables rule with an empty jump target. This means that the match is made, but no action is undertaken on the match. OK, so why do we even need a "nojump" target if it doesn't create an IPtables jump? As far as we know, two valid reasons might be:
using nojump for auditing
A nojump rule can be used for auditing. Say you want to know how often you are pinged from IP 1.2.3.4 - without logging each and every ping request to the firewall logfile. You could write
context INPUT filter
nojump -p icmp --icmp-type 8 -s 1.2.3.4 This rule could be checked in IPtables with iptables -n -L as
Chain INPUT (policy DROP 1713K packets, 119M bytes) pkts bytes target prot opt in out source destination 0 0 icmp -- * * 1.2.3.4 0.0.0.0/0 icmp type 8
Good to know you haven't been pinged by 1.2.3.4 yet, eh?!
using nojump to apply matches without using targets
A nojump rule can be used to apply matches like recent, that may just happily act on their own. Say you want to block spurious SSH login attempts; if "spurious" to you means "more than two connection attempts per minute", then you could try:
context INPUT filter nojump -p tcp --dport 22 -i $inetIF -m state --state NEW -m recent --name SSHers --set drop -p tcp --dport 22 -i $inetIF -m state --state NEW -m recent --name SSHers --update --seconds 60 --hitcount 3
This causes Iceditch to add the IP of every connection attempt to your SSH port to a list named "SSHers", and consecutively, that every packet that fits this description AND has seen two more hits from the same source address in the last 60 seconds gets dropped. Essentially, this limits brute-force attackers on your SSH to trying 2 logins per minute at most. But you see that the nojump rule gets translated to
iptables -A INPUT -t filter -p tcp --dport 22 -i $inetIF -m state --state NEW -m recent --name SSHers --set
No --jump in that line - hence the name of the Iceditch target: nojump.
Target keyword: redirect
redirect [to <to-ports>] [log [msg <message>]] <matches>
If a packet matches the <matches>, then it will be redirected to the local machine, by setting the destination IP to a fitting IP address of the local machine (i.e. 127.0.0.1, or the first-bound IP address of the interface over which it came in. Additionally, by specifying “to <to-ports>” you can have the destination ports redirected to a port or portrange. <to-ports> can either be a port number (e.g. 8080) or a port range (e.g. 6661-6669; the latter is inclusive). Example for a transparent HTTP proxy:
context "OUTPUT" "nat" redirect to 8080 –p tcp --dport 80
Iceditch works this out to
iptables –t nat –A OUTPUT –p tcp –-dport 80 –-jump REDIRECT –to-ports 8080
Should you want to log the packet, you could use
redirect to 8080 log –p tcp --dport 80
Iceditch works this out to
iptables –t nat –A OUTPUT –p tcp –-dport 80 –-jump LOG \ --log-prefix OUTPUT_REDIRECT_to_8080: iptables –t nat –A OUTPUT –p tcp –-dport 80 –-jump REDIRECT –-to-ports 8080
Because of how iptables handles the REDIRECT target, you can only use it in contexts where the table is "nat" and the chain is PREROUTING or OUTPUT.
Target keyword: reject
reject [with <type>] [log [msg <message>]] <matches>
In essence, this does the same as the "drop" target keyword, only it jumps to REJECT instead of DROP. This means the packet is discarded (just as with DROP), but the sender is notified using ICMP (by default, your machine will send an ICMP-packet of type "icmp-port-unreachable"). Because of how iptables handles the REJECT target, you can only use it in contexts where the table is "filter".
Optionally, you can follow "reject" with the keyword "with", and then use one of the following rejection types:
Type | Description |
---|---|
icmp-host-prohibited | will send an ICMP-message "host prohibited" |
icmp-host-unreachable | will send an ICMP-message "host unreachable" |
icmp-net-prohibited | will send an ICMP-message "net prohibited" |
icmp-net-unreachable | will send an ICMP-message "net unreachable" |
icmp-port-unreachable | DEFAULT; will send an ICMP-message "port unreachable" |
icmp-proto-unreachable | DEFAULT; will send an ICMP-message "protocol unreachable" |
tcp-reset | will send a TCP reset, a packet with the RST flag set (as a response to a TCP packet only) |
host-prohib | synonymous to icmp-host-prohibited |
host-unreach | synonymous to icmp-host-unreachable |
net-prohib | synonymous to icmp-net-prohibited |
net-unreach | synonymous to icmp-net-unreachable |
port-unreach | synonymous to icmp-port-unreachable |
proto-unreach | synonymous to icmp-proto-unreachable |
If you don’t specify "with <type>", then netfilter will assume icmp-port-unreachable. Thus, should you want to reject a packet in context filter INPUT (and log it) with reason net-prohib, you’d use
reject with net-prohib log –p tcp –i eth0 --dport 22
Iceditch works this out to
iptables –t filter –A INPUT –p tcp –i eth0 –-dport 22 –-jump LOG \ --log-prefix INPUT_REJECT_with_net-prohib: iptables –t filter –A INPUT –p tcp –i eth0 –-dport 22 \ –-jump REJECT –-reject-with net-prohib –p tcp –i eth0 –-dport 22
Target keyword: route
route {<iface>|<ifaceindex>} [log [msg <message>]] <matches>
The route target lets you route a received packet through an interface or towards a host, even if the regular destination of the packet is the router itself. The ROUTE target is also able to change the incoming interface of a packet. Packets are directly put on the wire and do not traverse any other table.
route takes one mandatory option, which may be either the interface name over which to route the packet that matches the <matches>, or the index number of that interface (based on the order in /proc/net/dev). Iceditch is pretty lazy in how to interpret that option: if it's all numerals, Iceditch treats it as the interface index number, if it contains any other character, it is considered the interface name (e.g. eth0); and no sanity check is performed on the specified <iface|ifaceindex>.
Target keyword: same
same [to <a1[-a2]> [to <a3[-a4]>] ] [nodest] [log [msg <message>] ] <matches>
same only works in the nat table, in the POSTROUTING chain. It is very closely related to snat (see below), because it does virtually the same thing. Basically, the same target will try to always use the same outgoing IP address for all connections initiated by a single host on your network. For example, say you have one "internal" /24 network (192.168.1.0) and 3 "external" IP addresses (10.5.6.11-13) on your firewall/router machine. Now, if internal machine 192.168.1.20 went out through the .11 address the first time, then the firewall will try to keep that machine always going out through that same IP address. So basically same might be a better fit than snat if you have multiple external IP addresses.
However, there is also functionality lacking in same that snat has, namely the specification of (TCP and UDP) ports or port ranges to use for the NATting operation. See snat for its port possibilities.
Furthermore, same has an extra option that snat does not have: under normal action, the same target is calculating the followup connections based on both destination and source IP addresses. Using the nodest option (which corresponds with --nodst in the actual IPtables command), it uses only the source IP address to find out which outgoing IP the NAT function should use for the specific connection. Without this argument, it uses a combination of the destination and source IP address.
Target keyword: snat
snat [to <a1[-a2][:p1-p2]]> [to <a3[-a4][:p3-p4]]>] ] [log [msg <message>] ] <matches>
This keyword is only valid in the chain POSTROUTING, table nat. And ofcourse, source NATting does you little good if you haven't enabled forwarding (e.g. use this machine as a router for other machines on your network).
Calling snat with the right parameters will create a Source NATting rule for you, whereby a packet matching the <matches> will be source NATted using the source IP address a1 (or the range a1-a2). Ofcourse, a1[-a2] should be valid IP address(es) of the firewalling machine.
Furthermore, if a port range p1-p2 is specified, then you'll limit the range of ports that snat will use outbound (only valid for TCP or UDP packets).
Finally, it is possible to specify multiple IP address ranges and port ranges, using multiple to <a1[-a2][:p1-p2]] declarations in succession.
An example would be:
context "POSTROUTING" "nat" snat to $inetIP -o $inetIF ! --src $inetIP
If the variable $inetIP contains your public IP (e.g. 212.238.151.72), and $inetIF your interface connected to the Internet (e.g. eth0), then this rule would expand to
iptables -A POSTROUTING -t nat -o eth0 ! --src 212.238.151.72 -j SNAT --to-source 212.238.151.72
This would cause Iceditch to source NAT any outbound packet that is NOT sent by your firewall itself; in effect your server is now a nice fullblown NAT router for all machines on your private network.