36

I want to allow incoming FTP traffic.

CentOS 5.4:

This is my /etc/sysconfig/iptables file.

# Generated by iptables-save v1.3.5 on Thu Oct  3 21:23:07 2013
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [133:14837]
-A INPUT -p tcp -m tcp --dport 21 -j ACCEPT
-A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-port-unreachable
-A OUTPUT -p tcp -m tcp --sport 20 -j ACCEPT
COMMIT
# Completed on Thu Oct  3 21:23:07 2013

Also, by default, ip_conntrack_netbios_n module is getting loaded.

#service iptables restart

Flushing firewall rules:                                   [  OK  ]
Setting chains to policy ACCEPT: filter                    [  OK  ]
Unloading iptables modules:                                [  OK  ]
Applying iptables firewall rules:                          [  OK  ]
Loading additional iptables modules: ip_conntrack_netbios_n[  OK  ]

But the problem is not with that module, as I tried unloading it and still no luck.

If I disable iptables, I am able to transfer my backup from another machine to FTP. If iptables is enforcing, then transfer failed.

6 Answers 6

30

Your ftp server needs a channel to transfer data. Port 21 is used to establish the connection. So to make data transfer possible you'd need to enable port 20 as well. See the following configuraton

First load the following module to make sure passive ftp connections are not rejected

modprobe ip_conntrack_ftp

Allow FTP connections on port 21 incoming and outgoing

iptables -A INPUT  -p tcp -m tcp --dport 21 -m conntrack --ctstate ESTABLISHED,NEW -j ACCEPT -m comment --comment "Allow ftp connections on port 21"
iptables -A OUTPUT -p tcp -m tcp --dport 21 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT -m comment --comment "Allow ftp connections on port 21"

Allow FTP port 20 for active connections incoming and outgoing

iptables -A INPUT  -p tcp -m tcp --dport 20 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow ftp connections on port 20"
iptables -A OUTPUT -p tcp -m tcp --dport 20 -m conntrack --ctstate ESTABLISHED -j ACCEPT -m comment --comment "Allow ftp connections on port 20"

Finally allow FTP passive inbound traffic

iptables -A INPUT  -p tcp -m tcp --sport 1024: --dport 1024: -m conntrack --ctstate ESTABLISHED -j ACCEPT -m comment --comment "Allow passive inbound connections"
iptables -A OUTPUT -p tcp -m tcp --sport 1024: --dport 1024: -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow passive inbound connections"

For more on FTP and firewall problems see: http://slacksite.com/other/ftp.html#active

Edit: Added NEW to the port 21 input rule.

8
  • 2
    I forgot to mention that --sport 1024: and --dport 1024: mean that we are including all ports in the range 1024:32535 which are unprivileged ports, meaning that users with no privilege access can use these ports to test their applications. Oct 4, 2013 at 12:11
  • @Being Gokul, That's correct. We can control our server on what ports it should listen for client connections. However in a passive mode, we must use --sport to be an unprivileged mode to privent firewall problems and let clients connect to the server. Oct 4, 2013 at 12:21
  • 2
    Well, you can add NEW,ESTABLISHED but that shouldn't matter. A connection is first always in a NEW state then it jumps to RELATED which indicates that this connection is related to an already permitted connection. When the connection changes to ESTABLISHED state it informs us that a connection has been established on both sides (server / client). You might try -m state --state ... instead. Oct 4, 2013 at 12:50
  • 1
    The NEW does indeed matter. It doesn't seem to work without it.
    – Leandros
    Dec 15, 2015 at 9:40
  • 2
    @val0x00ff I don't understand the need for --sport 1024:. Why would the client's port be useful for the rule? If he connects from a port 80 to the server's passive ports, he must be allowed to connect too.
    – Yvan
    Feb 16, 2018 at 19:48
22

I saw such extensive rules already in several Blogs etc. and wondered why not simply use

iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 21 -j ACCEPT

together with the nf_conntrack_ftp module. This is more concise and readable, which is generally a good thing, especially with firewalls...

FWIW, it seems that there was a change in kernel 4.7, so that you either need to set net.netfilter.nf_conntrack_helper=1 via sysctl (e.g. put it in /etc/sysctl.d/conntrack.conf) or use

iptables -A PREROUTING -t raw -p tcp --dport 21 -j CT --helper ftp

(see here for more details)

4
9

FTP Client:

lsmod | grep ftp
modprobe nf_conntrack_ftp
lsmod | grep ftp
iptables -A INPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -p tcp -m tcp --sport 21 -m conntrack --ctstate ESTABLISHED -j ACCEPT
iptables -A INPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -p tcp -m tcp --sport 20 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -p tcp -m tcp --sport 1024: --dport 1024: -m conntrack --ctstate ESTABLISHED -j ACCEPT
iptables -A OUTPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -p tcp -m tcp --dport 21 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -p tcp -m tcp --dport 20 -m conntrack --ctstate ESTABLISHED -j ACCEPT
iptables -A OUTPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -p tcp -m tcp --sport 1024:65535 --dport 1024:65535 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

FTP SERVER:

lsmod | grep ftp
modprobe nf_conntrack_ftp
lsmod | grep ftp
iptables -A INPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -p tcp -m tcp --dport 21 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -p tcp -m tcp --dport 20 -m conntrack --ctstate ESTABLISHED -j ACCEPT
iptables -A INPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -p tcp -m tcp --sport 1024: --dport 1024: -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -p tcp -m tcp --sport 21 -m conntrack --ctstate ESTABLISHED -j ACCEPT
iptables -A OUTPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -p tcp -m tcp --sport 20 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -p tcp -m tcp --sport 1024:65535 --dport 1024:65535 -m conntrack --ctstate ESTABLISHED -j ACCEPT

To toggle between passive and active mode on the client side

ftp> passive
Passive mode on.
ftp> passive
Passive mode off.
1
  • 3
    You definitely deserve some upvotes for this. Forgetting to load the nf_conntrack_ftp module is a source of headaches when troubleshooting passive FTP connections and iptables connection tracking. Using this module allows you to remove the "NEW" type so that these ports are protected from arbitrary connections without a previous FTP session being established. Apr 8, 2016 at 21:11
5

Adding NEW fixed it, I believe.

Now, my iptables file look like this..

# Generated by iptables-save v1.3.5 on Thu Oct  3 22:25:54 2013
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [824:72492]

-A INPUT -p tcp -m tcp --dport 21 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 20 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --sport 1024:65535 --dport 20:65535 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-port-unreachable
-A OUTPUT -p tcp -m tcp --dport 21 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 20 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 1024:65535 --dport 20:65535 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
COMMIT
# Completed on Thu Oct  3 22:25:54 2013

Typing it as answer, since too many characters are not allowed in comment.. Thank you so much for your help.

2
  • 2
    Cool it worked and glad I pointed you to the right direction. Please mark your own answer as solved so you help other people who seek for the right answer. Oct 4, 2013 at 13:08
  • 1
    I believe there is a typo in the accepted answer. I believe that --dport 20:65535 is leaving all ports from 20 - 65535 open from any source port between 1024:65535, which leaves many services exposed that probably shouldn't be, unless explicitly allowed. I believe what was intended is --dport 1024:65535
    – itnAAnti
    Jun 7, 2016 at 22:28
1

If you need both active and passive connections, and already accept ESTABLISHED connections, such as:

iptables -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT

Then you only need to open port 21 and add a special rule for passive ports. No rule is needed for port 20 as it's already accepted by the ESTABLISHED rule above.

First accept new connections on port 21:

iptables -A INPUT -p tcp --dport 21 -j ACCEPT

Then add the CT helper for passive ports 1024::

iptables -A PREROUTING -t raw -p tcp --dport 21 -j CT --helper ftp
iptables -A INPUT -p tcp -m conntrack --ctstate RELATED -m helper --helper ftp --dport 1024: -j ACCEPT

See also:

Note: you must set the 1024: as in your FTP server: search for the default passive ports in your FTP configuration. Else you'd open too many ports that may not be FTP relative.

Important note: I didn't add OUTPUT rules as my defaults go with iptables -P OUTPUT ACCEPT. Meaning that I trust what is going out of my box. That may not be a good option, especially in a NAT setup.

Very important note: FTPS won't work with such a setup, as the passive port is hidden (encrypted), hence there's no way for iptables to guess the good port. See Changing IPTables to Allow FTP over TLS Using Passive Ports and https://serverfault.com/questions/811431/are-my-iptables-for-ftps-with-tls-ok

1

I am adding an answer because rules should be simple, short, and readable. The accepted answer has security holes in it, IMHO.

For active FTP, all that is needed is:

sudo iptables -A INPUT -p tcp --dport 21 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 20 -j ACCEPT

And if one wants passive FTP, one needs to add:

sudo iptables -A INPUT -p tcp --dport 1024:65535 -m conntrack --ctstate RELATED -j ACCEPT

From the iptables-extensions manual pages:

RELATED The packet is starting a new connection, but is associated with an existing connection, such as an FTP data transfer or an ICMP error.

But, as remarked by @jakob the kernel needs this configuration:

sudo sysctl net.netfilter.nf_conntrack_helper=1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .