%include "default.mgp" %default 1 bgrad %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page #%nodefault %size 7, font "standard", fore "white", center Basic Iptables tutorial %size 4 Martin Josefsson gandalf@wlug.westbo.se %font "typewriter" http://www.netfilter.org/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page How packets used to go through ipchains ----> INPUT ----> FORWARD ----> OUTPUT ----> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page How packets go through iptables --------> FORWARD --------> | ^ | | V | INPUT OUTPUT %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Summary Packets destined for the local machine go in via the INPUT chain Packets destined for some other machine go through the FORWARD chain Packets generated on the local machine go out via the OUTPUT chain %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page The Logical structure of iptables Iptables contains tables and tables contains chains Each table contain some predefined chains Tables filter INPUT FORWARD OUTPUT nat PREROUTING POSTROUTING OUTPUT mangle PREROUTING INPUT FORWARD OUTPUT POSTROUTING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page For the moment we will only concentrate on the filter table. This is the table used for normal filtering of packets For example DROPing and ACCEPTing packets. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page The filter table has 3 chains. INPUT, FORWARD, OUTPUT These are the chains used in the packet traversal picture in one of the first slides. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page #iptables -t filter -L Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Chains are traversed from the top down. Every rule is checked in the order they appear in the chain. If a rule matches the packet that's traversing the chain the action the matched rule specifies is performed. It can be a DROP or ACCEPT action ore one of the many other actions availiable. If a packet traverses a chain but no rule matches the packet the default policy is performed, this policy can be ACCEPT or DROP %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page So how do we add a rule that DROP's all packets from evil haxxor Nisse? We've determined that Nisse has ipaddress 192.168.45.3 iptables -t filter -A INPUT -s 192.168.45.3 -j DROP iptables program used to modify iptables rules -t filter -t specifies which table we want to modify filter is the default table if not specified -A INPUT -A is used to add a rule to the end of a chain INPUT is the chain we want to add a rule to. -s 192.168.45.3 sourceaddress we want to match -j DROP -j specifies the action we want performed if this rule matches DROP is the action and it just drops the packet to the floor %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Now all packets from Nisse will be dropped, all other packets are still allowed just like before. This is because the default policy of the INPUT chain is still set to ACCEPT (default) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Maybe we want to see what our current rules look like in the INPUT chain? iptables -nL INPUT Chain INPUT (policy ACCEPT) target prot opt source destination DROP all -- 192.168.45.3 0.0.0.0/0 -n species that we do not want to resolve ipaddresses to hostnames -L list INPUT chain we want to list %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page A small list of some commonly used options -p protocol to match, can be a name that's defined in /etc/protocols or the ip-protocol number -i input interface to match, only works in INPUT and FORWARD -o output interface to match, only works in FORWARD and OUTPUT -s sourceaddress to match, ie. 192.168.1.1 or 192.168.1.0/24 -d ditto for destinationaddress -m an external match module, more on this soon -j action to perform if packet matches rule ! negate the option that follows %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Now we know how to filter on ipaddresses and interfaces Time to learn the fun stuff... stateful filtering. Stateful filtering is a concept where we know filter on the state of connections. ip_conntrack this is the kernelmodule that implements the connectiontracking. We can filter on diffrent states of a connection. NEW packet that's about to create a new connection ESTABLISHED packets that's part of an already existing connection RELATED packets that's related to another connection, ie the dataconnections in a ftp session ... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Typical ruleset to open a few ports and block the rest. iptables -P INPUT DROP iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT iptables -A INPUT -p tcp --dport 22 -j ACCEPT iptables -A INPUT -p tcp --dport 25 -j ACCEPT iptables -A INPUT -p tcp --dport 80 -j ACCEPT %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page This approach has a small problem... What if we want to use active ftp? With active ftp the server opens connections back to you when you make a request And it uses dynamic ports so we can't specify which ports to open because we don't know which ports will be used. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page There is a simple solution! Since we are using a stateful firewall and iptables has a connectiontracking module for keeping track of ftp sessions it's very easy to fix. The module is called ip_conntrack_ftp and it keeps track of ftpsessions and marks the first packet in an ftp-data connection as RELATED So replace the --state ESTABLISHED with --state ESTABLISHED,RELATED in the previous ruleset. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page Now over to NAT! NAT = Network Address Translation there was a very limited implementation in kernel 2.2 called ip_masquerade NAT in iptables is a lot more powerful. There's two main NAT usages SNAT Source NAT, changes the sourceaddress of a connection DNAT Destination NAT, the same but changes the destinationaddress (also called RNAT (Reverse NAT) in some implementations) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page SNAT SNAT is used ie. for sharing a internetconnection. SNAT also has two variations called MASQUERADE and SAME MASQUERADE this is the same as ip_masquerade in ipchains a connections sourceaddress is replaced with the address of the interface the connection goes out via SAME a version of SNAT that make sure a client always get the same sourceaddress on all it's connections So how to we setup a simple MASQUERADE with iptables? %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page SNAT Now we are going to move from the filter table to the nat table. Only the first packet in a connection traverses the nat table. The nat table has three chains PREROUTING performed before the routinglookup is performed used for DNAT where we want to change the destination before the packets are routed POSTROUTING performed after the routinglookup is performed used for SNAT (and it's variations) OUTPUT used when we want to DNAT locally generated connections. SNAT of locally generated connections is performed in POSTROUTING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %page SNAT Now to add the rule iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE or iptables -t nat -A POSTROUTING -o ppp0 -j SNAT --to 192.168.99.22 This will perform SNAT (or MASQUERADE) on all connections going out via ppp0 (determined by the routinglookup)