Iptables Connection Tracking - FTP
Firstly, you need to load the ip_conntrack_ftp module.Assuming you have a single-homed box, a simple ruleset to allow an ftp connection would be:
iptables -A INPUT -p tcp — sport 21 -m state — state ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp — dport 21 -m state — state NEW,ESTABLISHED -j ACCEPT
(Please note, I am assuming here you have a separate ruleset to allow any icmp RELATED to the conection. Please see my example ruleset for this).
This is not the whole story. An ftp connection also needs a data-channel, which can be provided in one of two ways:
(1) Active Ftp
The ftp client sends a port number over the ftp channel via a PORT command to the ftp server. The ftp server then connects from port 20 to this port to send data, such as a file, or the output from an ls command. The ftp-data connection is in the opposite sense
from the original ftp connection.
To allow active ftp without knowing the port number that has been passed we need a general rule which allows connections from port 20 on remote ftp servers to high ports (port numbers > 1023) on ftp clients. This is simply too general to ever be secure.
Enter the ip_conntrack_ftp module. This module is able to recognize the PORT command and pick-out the port number. As such, the ftp-data connection can be classified as RELATED to the original outgoing connection to port 21 so we don’t need NEW as a state match for the connection in the INPUT chain. The following rules will serve our purposes grandly:
iptables -A INPUT-p tcp — sport 20 -m state — state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -p tcp — dport 20 -m state — state ESTABLISHED -j ACCEPT
(2) Passive Ftp
A PORT command is again issued, but this time it is from the server to the client. The client connects to the server for data transfer. Since the connection is in the same sense as the original ftp connection, passive ftp is inherently more secure than active ftp, but note that this time we know even less about the port numbers. Now we have a connection between almost arbitrary port numbers.
Enter the ip_conntrack_ftp module once more. Again, this module is able to recognize the PORT command and pick-out the port number. Instead of NEW in the state match for the OUTPUT chain, we can use RELATED. The following rules will suffice:
iptables -A INPUT -p tcp — sport 1024: — dport 1024: -m state — state ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp — sport 1024: — dport 1024: -m state — state ESTABLISHED,RELATED -j ACCEPT


In passive-ftp connection tracking rules you have small error:
instead of
iptables -A OUTPUT -p tcp –sport 1024: –dport 1024 -m state –state ESTABLISHED,RELATED -j ACCEPT
there should be (I think)
iptables -A OUTPUT -p tcp –sport 1024: –dport 1024: -m state –state ESTABLISHED,RELATED -j ACCEPT
Otherwise only single dport 1024 would be valid. BTW, I’m not sure, but should not it be –dport / –sport / –state? With double “–”, not single “-”…
Comment by Jarry — February 22, 2006 @ 3:57 am
Jarry,
You’re absolutely right. I missed off a : there. At least it was correct it was correct in the downloadable ruleset.
It should be — sport etc like you say. The html formatting is making two dashes together look like one. I managed to tweak it to get a longer dash and I hope people will realise it is meant to be two …. c’est la vie.
Thanks very much for picking up on these things.
Best,
James
Comment by James Stephens — February 22, 2006 @ 6:00 am
I believe this rules apply to a client trying to ftp an external server.
What would be the rules for the opposite case? I’m running an FTP server and firewall is dropping the passive connetion data packets…
Comment by FNC — March 25, 2006 @ 5:46 am
Hello.
All you have to do is swap INPUT for OUTPUT and vice versa in the above rules for the case where the ftp server is local.
Best,
James
Comment by James Stephens — March 25, 2006 @ 3:19 pm
One more note here: To put it on a firewall with NAT you have to add all these rule also to the FORWARD chain.
Comment by David Gabel — May 15, 2006 @ 9:15 am
I was using your rules for ftp, active mode, and did a simple “ls”, causing the following:
Aug 12 12:53:35 panda kernel: firewall: IN=eth0 OUT= MAC=00:a0:24:0e:48:8e:00:10:5a:09:5e:45:08:00 SRC=64.50.236.52 DST=192.168.1.110 LEN=60 TOS=0×00 PREC=0×00 TTL=54 ID=65353 DF PROTO=TCP SPT=60683 DPT=1042 WINDOW=5840 RES=0×00 SYN URGP=0
I found adding RELATED to the INPUT for the ephemeral ports fixed it, but I’m not too happy about it. It would seem to open up ports which might be used by other connections, say bad websites. (Yep, it’s related to the connection on port 80, let it through.) I’m wondering if the ftp connections could use conntrack marks to separate them from everything else that might try to use the ephemeral ports and should be dropped.
Comment by Paul Rogers — August 13, 2006 @ 12:31 am
[...] http://www.sns.ias.edu/~jns/wp/2006/01/24/iptables-how-does-it-work/?p=20 [...]
Pingback by Chris Cruft » Blog Archive » More FTP failure investigation — October 28, 2006 @ 5:19 pm
That passive ftp rule scares me as well. It just feels too general, like it allows (potentially) more than I really need to allow. I know it’s the client making the connection out, and I understand that RELATED means *something* that’s allowed has indicated it, but I would really feel much better about it if I could say something along the lines of -m state –state RELATED -m relatedto –relatedto ftp (with a separate rule for ESTABLISHED traffic).
I know, call me paranoid, but isn’t it the network administrator’s *job* to be paranoid about such things?
Comment by Nathan Eady — May 17, 2007 @ 11:45 am
There is no problem for me with external connections to my server but trying configure a very closed internal network, with all ports close except the necessary ones, FTP does not work.
I try create special rules to handle FTP but the download does not starts.
Any help???
(CLIENTS is a FORWARD chain)
-A CLIENTS -p tcp -m tcp -m multiport -s 192.168.0.0/16 –dports 21,443,1863 -j ACCEPT
-A CLIENTS -p tcp -m tcp -m multiport -d 192.168.0.0/16 –sports 21,443,1863 -j ACCEPT
-A CLIENTS -p tcp -m tcp -m state -s 192.168.0.0/16 –dport 20 –state ESTABLISHED -j ACCEPT
-A CLIENTS -p tcp -m tcp -m state -d 192.168.0.0/16 –sport 20 –state ESTABLISHED,RELATED -j ACCEPT
Comment by Marcello Fontolan — June 9, 2007 @ 8:53 am