Anatomy of an IPTables Incantation

Most commands you run with iptables are going to look something like this:

iptables [-t table] [mode] [chain] [rulenum] [rule-specification] [options]

Let's break this down part by part:

Rule Specifications

An iptables rule specification consists of some number of parameters given as options to the iptables command. Remember that each rule in a firewall consists of some number of conditions and an action to be taken if all the conditions match. So when specifying a rule, one of the parameters is supposed to give the action and all the rest give conditions. It's usually good practice to put the action parameter last, since it makes it clear when reading the rule specification that the conditions are checked first, although iptables isn't picky about how the parameters are ordered. (One exception: a module must be loaded before any of its commands are used. I'll discuss this later.)

So what are these parameters?

Action Parameters

Most rules should have one action parameter. IPTables will accept rules that have no action, but obviously they won't do anything. However, packet and byte counters are still maintained for rules with no action, so you can use actionless rules to see how many packets are matching a particular set of conditions.

-j, --jump [target]
This action specifies that if the rule matches, IPTables should jump to the specified target. The target can be a terminating target, which means that it stops processing that packet immediately, or a non-terminating target, which means that, well, it doesn't stop processing that packet immediately. You can also give the name of a user-defined chain as a target, which means that IPTables will start checking the packet against the rules in that chain. If none of them match and the chain has no defined policy, it will return and continue checking in the current chain starting with the next rule after the jump.
-g, --goto [target]
This actions specifies that if the rule matches, IPTables should jump to the specified target. The difference between this and -j or --jump is that if the target is a user-defined chain and none of its rules match, IPTables will skip the rest of the current chain.

Builtin Condition Parameters

All the condition parameters are optional. By default, if no conditions are specified, the rule will match all packets, so use conditions to restrict the set of packets you want the rule to match.

Most conditions can be inverted by using an exclamation mark after the condition option but before the value; for example, -p ! tcp will match any packet that is not a TCP packet.

-p, --protocol [!] [protocol]
This specifies the Internet Protocol the packet must have to match the condition. Typically, if you specify this at all, the protocol will be one of tcp, udp, or icmp, but any protocol listed in /etc/protocols (either the lowercase protocol name, column 1, or the numeric code, column 2) is acceptable.
-s, --src, --source [!] [address[/mask]]
This specifies the source IP address that must be contained in the packet for it to match the condition. The /mask is optional, but if given, it specifies which bits should be considered in the match; for example, 255.255.255.0 is 11111111111111111111111100000000 in binary, so only the leftmost 24 bits of the address will be considered. Keep in mind that source IP addresses can be faked.
-d, --dst, --destination [!] [address[/mask]]
This specifies the destination IP address that must be contained in the packet for it to match the condition. The mask works the same way as in --source. Keep in mind that destination IP addresses can be faked, although it's harder to do so than with source IP addresses.
-i, --in-interface [!] [name]
This specifies the interface, the physical network connection, that the packet should have been received on in order for this rule to match. Many computers have multiple interfaces; for example, a laptop might have an ethernet card which you connect a cable to, which corresponds to an interface named eth0, and a wireless networking card, which corresponds to an interface named wlan0. A server might have two ethernet cards with two connected cables, eth0 for the internet at large and eth1 for a private network. All Linux computers also have an interface called lo, the loopback interface, which is usable only for sending packets from that computer to itself. Note that if you give the --in-interface option for a chain which only handles outgoing packets (namely OUTPUT or POSTROUTING), iptables will complain!
-o, --out-interface [!] [name]
This specifies the interface that the packet should be going out on in order for this rule to match. As with --in-interface, if you give this option for a chain which only handles incoming packets (INPUT or PREROUTING), iptables will complain!
[!] -f, --fragment
Packets can sometimes be received in fragments. Since the information other conditions check, like the source address, is at the beginning of a packet, only the first fragment will include it, so any rules involving other conditions will only match the first fragment. The -f condition exists to allow you to catch the rest of the packet, although in practice it's not usually necessary to do this. Note that unlike most other parameters, if you want to negate this condition you put the exclamation mark before the -f.
-c, --set-counters [pkts] [bytes]
This doesn't really act like a condition, but the iptables man page lists it with the conditions so I'm including it here for completeness. This just lets you set the initial values of the packet and byte counters when you're inserting, appending, or replacing a rule.

Condition Parameters from Modules

Just like the builtin conditions, these are optional and can be used to restrict the set of packets that the rule matches. The difference is that these conditions aren't built in to the main iptables program; rather, they're programmed in modules which you will need to load before you can use the commands. There are two ways to load a module:

Note that since the parts of the rule specification are evaluated in order from left to right, if you're going to use a module, you need to give the option to load it before you use any of its options. For example, -p tcp --dport 1779 will work, but --dport 1779 -p tcp will give an error.

There are a lot of modules available, and they're all described in the iptables man page, but here's a selection of the most useful ones:

limit
--limit [number[/interval]]
Limits the rule to matching a certain number of packets in the specified time interval, which can be "second," "minute," "hour," or "day." This is typically used with the LOG target to prevent iptables from spending all its time trying to write to the disk. Example: --limit 3/hour (which is the default).
--limit-burst [number]
Allows the rate of matching to temporarily exceed the limit specified with the --limit parameter, if you specify a number higher than the number in --limit.
multiport
This module can only be used in a rule that only matches TCP or UDP packets (since those are the only protocols that define ports).
--sports, --source-ports [!] [port,port,..]
Matches any packet whose source port is any of the given values. The list of ports is a comma-separated list of single port numbers and/or colon-separated ranges (as in the --source-port and similar options). Example: --source-ports 1907:1909,2156,7703.
--dports, --destination-ports [!] [port,port,..]
Matches any packet whose destination port is any of the given values. As with --source-ports, the list of ports is a comma-separated list of single port numbers and/or colon-separated ranges.
--ports, --ports [!] [port,port,..]
Matches any packet whose port, either source or destination, is any of the given values. As with --source-ports, the list of ports is a comma-separated list of single port numbers and/or colon-separated ranges.
state
--state [state]
Matches any packet with the specified state. [state] can actually be a comma-separated list of states, in which case any packet that has any one of those states will match the condition. There are four possible states:
INVALID
The packet couldn't be identified
ESTABLISHED
The packet is part of an existing connection that has already been established by having packets successfully sent in both directions
RELATED
The packet is starting a new connection which is related to an existing connection (some protocols use multiple separate connections)
NEW
The packet is starting a new connection which is not related to any existing connection (as far as IPTables can tell)
The --state condition is important so that when a program on your computer sends an outgoing packet to start a connection, the responses from the other computer aren't blocked by the firewall. For that reason, you'll see a rule like this near the beginning of every firewall configuration:
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
tcp
--sport, --source-port [!] [port[:port]]
Matches any TCP packet with the specified source port. The value can be just a single number, in which case the condition matches only that port, or it can include a colon, which specifies a range of ports. You can leave out either port number to make the range extend all the way to the lowest port (0) or the highest port (65535). Examples: --source-port 5509 or --source-port 7795:7799.
--dport, --destination-port [!] [port[:port]]
Matches any TCP packet with the specified destination port. You can specify a single port or a range, as with --source-port. This is by far the most useful option from the tcp module.
--tcp-flags [!] [mask] [comp]
Matches any packet with the specified TCP flags. The first argument [mask] specifies which flags to check, and the second one [comp] specifies which should be set.
[!] --syn
A shortcut for --tcp-flags SYN,ACK,FIN,RST SYN, which will check the SYN, ACK, FIN, and RST flags and match if, out of those, only the SYN flag is set. This is useful for picking out the packets that start new connections.
--tcp-option [!] [number]
Matches any TCP packet with the specified option set.
udp
--sport, --source-port [!] [port[:port]]
Matches any UDP packet with the specified source port. The value can be just a single number, in which case the condition matches only that port, or it can include a colon, which specifies a range of ports. You can leave out either port number to make the range extend all the way to the lowest port (0) or the highest port (65535). Examples: --source-port 5509 or --source-port 7795:7799.
--dport, --destination-port [!] [port[:port]]
Matches any UDP packet with the specified destination port. You can specify a single port or a range, as with --source-port. This is by far the most useful option from the udp module.