Quoting Terry Linhardt <linhardt@xxxxxxxxxx>
Date: Sat, 11 Dec 2004 10:17:30
I am attempting to set up an ftp server on an internal network. (All
hosts are 192.168.1.*) I am using vsftp, but stumbling over an iptables
related issue. Also, this is Fedora Core 3.
[snip]
I am guessing that I am getting blocked by a closed port. I've done
some research, and generally understand the concept, but don't
understand how to get past what appears to be a closed port issue
without opening up a large range of ports. While that may not be
distasteful on my private network, it is not desirable if I eventually
make this machine available to the outside world.
You need to use FTP helper module. If you are using NAT, make sure ip_nat_ftp
is loaded (it will also automatically trigger loading of ip_conntrack_ftp). If
you don't use/need NAT, ip_conntrack_ftp is sufficient. To load it when
iptables are started, just add it to IP_TABLES_MODULES in
/etc/sysconfig/iptables-conf:
IP_TABLES_MODULES="ip_nat_ftp"
What this module will do, it will monitor what is going on the FTP command
channel's port 21 (PORT and PASV commands, plus their variations, as well as
replies to those commands), parse them, and couse first seen packet of every FTP
data connection (either active or passive) to be in state RELATED (instead of
NEW). All you need to do now is to allow those RELATED packets in. How you are
going to do it, depends on how you prefere to configure your firewall.
[Remainder deleted]
Of course, if your command channel is encrypted (for example, if you use FTP
over SSL), this will not work!
An example of using ip_conntract_ftp and RELATED state is given bellow. While
this is full working example, I strongly advise against cut&pasting it into your
firewall configuratin. This is just example to ilustrate the principle. When
you understand what and how it works, adapt it to your configuration. Port
ranges given can be tightened for example, you can limit rules to specific
interface, and specify source and destination addresses.
# All time favorite, allow all packets from established connections
-A INPUT -m state --state ESTABLISHED -j ACCEPT
-A OUTPUT -m state --state ESTABLISHED -j ACCEPT
-A FORWARD -m state --state ESTABLISHED -j ACCEPT
# Allow related ICMPs (can be tightened to allow only certain types)
-A INPUT -p icmp -m state --state RELATED -j ACCEPT
-A OUTPUT -p icmp -m state --state RELATED -j ACCEPT
-A FORWARD -p icmp -m state --state RELATED -j ACCEPT
# Allow command channel, port 21
-A INPUT -p tcp --dport 21 -m state --state NEW -j ACCEPT
# Allow data connection in for passive FTP (high to high port connection)
-A INPUT -p tcp -m state --state RELATED -m helper --helper ftp -j ACCEPT
# Allow data connection out for active FTP (always made *from* port)
-A OUTPUT -p tcp --sport 20 -m state --state RELATED -m helper --helper ftp -j
ACCEPT
Note:
-m helper --helper ftp does not call the FTP helper! It checks if the packet
was marked as RELATED by FTP helper module. You still need to load module by
hand (or let the /etc/init.d/iptables load it by specifying it in
/etc/sysconfig/iptables-conf).
If you use encryption, for example FTP over SSL, this will not work, since FTP
helper module will not be able to monitor encrypted command channel. If this is
the case, you'll need to have different approach (a bit more liberal firewall
rules). You can still make it thight. In this case, make sure you do not load
the ip_conntrack_ftp (and ip_nat_ftp_ modules. Last three lines of your
firewall rules will than look something like:
-A INPUT -p tcp --dport 21 -m state --state NEW -j ACCEPT
-A INPUT -p tcp --dport low_port:high_port -m state -state NEW -j ACCPET
-A OUTPUT -p tcp --sport 20 -m state --state NEW -j ACCEPT
Replace low_port:high_port with port range used for passive FTP. Almost every
FTP server lets you choose port ranges for passive data transfers. Configure
same numbers in your FTP server's configuration and in iptables. 49152:65534,
the IANA-registered ephemeral port range is a good choice.
Of course, FTP SSL example will work for non-encrypted case too (if you don't
have module loaded). But if you don't use encryption, simply load the module
and use more strict rules from first example.