A quick run down on iptables rules
What is it?
iptables is a cli frontend to netfilter, the Linux kernel firewall/nat implementation for OSI layer 3 and 4.
Okay, give me more details
- When you run "iptables", the actual file being executed is "xtables-multi". That is, because the file name "iptables" is symlinked to "xtables-multi".
- What is xtables-multi? A binary that contains code for a couple of utilities, like ip6tables, ip(6)tables-restore, ip(6)tables-save
- The rules in a chain are applied top to bottom.
- The *nat table is only called for connections with ctstate NEW
- There are terminating and non-terminating targets in iptables. If a packet hits a terminating target. the rule examination for that packet ends there.
- NAT relies on conntrack. Untracked packets can not be natted.
- The order of calling for the different chains and tables is defined here (png link)
- iptables -L lies. Use iptables-save instead.
iptables rules actually only contain anything after the binary name and the table name. This is how they are referred to in this document. That is, because it corresponds to how the kernel actually stores them and how "iptables-save" prints them.
An iptables rule is structured like this:
<OPERATION> <CHAIN NAME> [builtin matches [builtin matches parameters]] [<-m> <match module> [<match module parameters> ]] [<-j> <TARGET> [<TARGET PARAMETERS>]]
- <> denote a mandatory parameter
-  denote optional parameters
- You can structure differently, but I strongly suggest you structure them as described above to make it readable and understandable.
- Anything between <CHAIN NAME> and the "-j" is a selector which restricts which packets are handled by the target. All of its parts have to evaluate to TRUE for the packet to be handled by the target.
- You can invert certain matches by prepending an exclamation mark (!) to the match. The corresponding section in the man page for iptables-extensions explicitely mention what you can invert.
Rules that would fullfill the structure requirements could look like this:
- (in filter table) -A INPUT -i lo -j ACCEPT Other common rules that fullfill this criteria:
- (in filter table) -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
- (in nat table) -A PREROUTING -i eth0 -d 18.104.22.168 -p tcp --dport 443 -j DNAT --to-destination 192.168.68.4
- (in filter table) -A FORWARD -i eth0 -m policy --pol none --dir in -j DROP
Explanation of rule ...
- In the INPUT chain, ACCEPT anything where the input interface is "lo".
- In the INPUT chain, ACCEPT anything where the match module "conntrack" with the parameters "--ctstate" and "RELATED,ESTABLISHED" evaluate to "true"
- In the PREROUTING chain, DNAT anything to the IP 192.168.68.4, where the input interface is "eth0", the destination is "22.214.171.124", the protocol is "tcp" and the destination port is "443".
- In the FORWARD chain, DROP anything where the input interface is "eth0" and the "policy" match module with the parameters "--pol", "none" "--dir" and "in".
Interpretation of rule ...
- Accept anything from the loopback adapter
- Accept any packet that is a reply to a connection, for which conntrack has already seen a reply (basically a connection which conntrack considers established, e.g. a TCP SYN+ACK, when the previous packet was a TCP SYN) or any packet that relates to an already established connection. The "established" in the latter does not refer to the mentioning of the ESTABLISHED parameter before!
- DNAT any packet to 192.168.68.4 that is received on eth0, is destined to 126.96.36.199 and is a tcp packet to port 443.
What types of packets can I filter using iptables?
"iptables" itself is for IPv4 traffic. There is the equivalent "ip6tables", which is for IPv6 traffic.
How do I load my rules the best way?
Write them in "iptables-save" format and then load them using "iptables-restore". Why? See here (Mirror)
Where's the documentation?
There are man pages for "iptables" and "iptables-extensions". The order of chains and tables is explained here (png link) and upstream kernel description of sysctl ip options is here
Can I use aliases for interface filters?
Nope. Aliases aren't real interfaces.
What about bridging?
The behaviour of bridging depends on the exact settings. Sometimes, the input and output interfaces that you expect aren't what the kernel actually thinks it is.
Invalid TCP flag filtering?
Conntrack does that for you already. It does not filter explicitely, but such packets are considered "invalid". "-m conntrack --ctstate INVALID" matches on such packets.
Do I need to filter packets from wrong sources, like packets where the source IP is a private IP, but I get them on the interface towards the Internet?
That depends on the family and if you use policy based routing or not. For IPv4, the kernel uses the main routing table to figure out if a packet is a martian (comes from an unexpected direction) or not. If you use policy based routing, that obviously does not work anymore. In that case, you need to disable the rp_filter (reverse path filter) or set it to 2 for the interfaces that take part in the policy based routing. If you do not use policy based routing, the kernel drops martians (packets coming from an unexpected direction) by default already.
For IPv6, you unconditionally need to, because there is no builtin rp_filter for it.
You can use the "rpfilter" match module in iptables to figure out if a packet comes from an unexpected direction. ee the man page for iptables-extensions for details.
Where do I find good rule sets to start with?
Take a look here
How do I log packets?
You can use the LOG target for that. You can send packets to userspace using the NFLOG target and an application listening on the NFLOG group, for example tcpdump or dumpcap.
How do I debug my rule set?
You can either use strategically set rules with the LOG target or use the TRACE target in the *raw table to get a line in the kernel log for every chain policy or rule that matched the packet.
What IS conntrack?
Conntrack is first and foremost a subsystem of the netfilter system of the kernel which tracks all sorts of packets and interprets them as connections, to which packets are correlated against. It gives you the essential component to build stateful firewall rules. It is also the name of a match module, which uses the kernel subsystem to figure out the state of the connection the packet belongs to.
Can I do if-else statements?
Yes, use custom chains for that and call them, like you would a target. You return from custom chains by using the RETURN target or by reaching the end of the custom chain.