Things I'd do if I ever have time

Wish list

Please help a man further his career by donating expensive hardware. Cash works too.



Active vs. Passive FTP

Published: 05/23/2010

Reference trace files:

ftp_active.cap
ftp_active_attempt_filezilla.cap
ftp_pasv_filezilla.cap
ftp_pasv_attempt.cap

File Transfer Protocol has been around since ... well, before my time, but it's still plenty-used today. From a general firewall rule creation perspective, this sometimes creates headaches in network management. Most decent firewalls these days are sufficiently-intelligent enough to examine and understand FTP in order to accommodate connections between private and public networks without the need for incorporating complicated (and potentially risky) rule sets. However, old-school static packet filters are still used in some places (for example, basic Cisco IOS extended ACLs) which makes FTP connectivity not-so-straightforward. A misconfigured firewall may also prevent legitimate FTP connections from forming.

We'll look at a Windows 7 machine located in a private network trying to connect to an FTP server on the Internet. Windows has always included a built-in command-line FTP client (ftp.exe), but in some cases a third-party client will be required for a functioning download.

Active and passive - these are the two FTP modes that historically caused four-letter words to be carefully articulated by enterprise network administrators. Let's have a look at the differences...


Active FTP

In the first trace, ftp.exe is used to connect to OpenBSD's public FTP server on port 21, the FTP control channel. The first two packets show the DNS request and response for ftp.openbsd.org. This hostname is actually a CNAME reference to openbsd.sunsite.ualberta.ca which in turn resolves to 129.128.5.191.

Once the TCP handshake is completed, in packet 6 the server responds and tells the client that it's ready to do business and the CLI window presents me with a login prompt. Since this is a public server, I decide to use the username "anonymous," shown in packet 8. The server responds with the message, "Guest login ok, send your email address as password" and then I'm prompted to enter a password. I can really enter anything here, and since I'm lazy I just hit the Enter key.

The server doesn't mind this and allows me to proceed. I'm now logged in, as confirmed in packet 12 with the message, "Welcome to ftp.openbsd.org at the University of Alberta." It then sends me the login banner with accompanying ASCII ART:

   Show packet content

In packet 17, I now enter the command "cd pub/OpenBSD/4.7/i386." The next packet shows the server confirming the directory change. In packet 20, I use the "bin" command in order to make the download type a binary (type I). Generally not necessary since the automatic detection usually works, but sometimes it's better safe than sorry since on a rare occasion the binary gets downloaded as an ASCII.

At packet 23, the client initiates the PORT command to the server. This tells the server that it should now initiate a FTP-DATA connection back to the client on the specified port (in this example, port 1058). Packet 24 shows the server confirming this. The next packet shows the client making a "get" request for a specific file which I specified at the CLI.

Now this is the critical part - in order for this transaction to proceed, the firewall / router at the edge of the private network (facing the Internet) has to allow this new connection from the FTP server. While many firewalls these days might automatically permit this since it understands the nuances of the FTP protocol, recognizes the issued PORT command from the client, and temporarily creates a rule on-the-fly to permit the expected traffic, if you're using router IOS extended ACLs it won't work unless there's an explicit rule allowing an inbound TCP connection on source port 20. The "established" keyword for an existing ACE won't cut it since it's technically a different traffic stream from the original FTP control channel. It doesn't realize the two are related.

So for the sake of this demonstration, I temporarily set up an IOS rule like the following:


access-list 101 permit tcp host 129.128.5.191 eq 20 any


This is why in this first trace the FTP session proceeds normally. Since the FTP client now has to serve as a listening daemon, Windows might prompt you with a notification implying that an application may need to be unblocked by Windows Firewall in order for the connection to succeed. Here's an example if the FileZilla FTP client was used:

In packet 26, the server initiates a TCP handshake with the client (Cisco IOS's NAT function still allows this connection between these two hosts). The server's source TCP port is 20 while the client's port is the one specified earlier via the PORT command: 1058. Packet 29 is just a response on the control channel to the client's older request at packet 25.

In packet 30 and 31 we see the client pulling down the file index.txt, then acknowledging receipt of the download, followed by the FTP-DATA channel closure by both sides in the next 4 packets (note the FIN-ACK and ACK flags). At packet 37, the client ACKs the server on the FTP original control channel over port 21 and the server notifies the client with a "Transfer complete" message.

Now that the download is complete, I could just let the session idle and go cook dinner while it eventually times out ... or I could be a good citizen and issue the "bye" command and properly close the FTP session, as shown in packets 40 and 41.

But what happens if the IOS ACL had never been updated to allow the inbound server connection to the client's proposed port in the first place? Let's take a look at the second trace file. Here we have essentially an identical scenario with the exception of the router ACL not being updated. The FTP client software is also different - I used FileZilla which uses a GUI interface (which folks who are scared by the mysteries of the CLI might prefer), however the traffic exchange is essentially the same. FileZilla does use the password "anon@localhost" when logging in, but that doesn't really make a difference here.

At packet 20, the client initiates a command to get a directory listing on the server. This is where the server now initiates that inbound FTP connection to the client over the client-requested port (in this case, that's port 1122 as specified in packet 18). However, the router's ACL is dropping this traffic at the front-end and if the IOS is set to log properly, you'll notice the dropped traffic from the server when consoled into the router.

Eventually, FTP times out after 75 seconds and the server responds with "Can't build data connection: Operation timed out." over the FTP control channel. FileZilla sees this and immediately (and ungracefully) tears down the connection by sending a RST-ACK to the server like making a getaway at a blind date. The server then responds with, "You could at least say goodbye." I'm not kidding - it's in packet 26. Windows' ftp.exe isn't so rude.


Passive FTP

So now let's explore the other option: passive mode (sometimes referred to as PASV). This is more firewall-friendly in that unlike active mode where the client tells the server which port to connect back to, passive mode allows the client to initiate the FTP-DATA connection to the server. This way, firewalls which are configured to allow all outbound connections initiated from the private network (very common these days) will permit successful FTP connections with little maintenance.

Within the third trace file, we see the same initial sequence of events as when we were doing active mode with the FileZilla client. A slight difference is in packet 16 where binary transfer mode was not specified, but this is irrelevant in the context of this article. In packet 18 the client issues the PASV command, indicating to the server that passive mode should be used because active mode is no longer trendy.

In packet 19, the server responds with confirmation of passive mode switchover and specifies the IP address and port that the client should connect to for the data transfer. The IP address remains the same as the original, but the port is 57305. There is no port 20 involved this time around.

The client then makes a "get" request for index.txt on the control channel. Then immediately after it initiates the second connection to the server over port 57305 with a source port that is one number higher than the source port used for the control channel.

The download is then performed over the FTP-DATA channel port (57305) and once done, the TCP connection is closed in packets 28 - 31. Once the client sends an ACK for all this over the FTP control channel, the server responds with a "Transfer complete" message. Everyone's happy.

Now what if we wanted to do this with the built-in Windows client, ftp.exe? Let's observe the fourth trace file for this one.

We see that everything hums along as expected. At packet 20, I enter in the command LITERAL PASV on the command-line. This supposedly sets the mode to passive. We can see in this packet that the client sends this proposition to the server and in packet 21 the server confirms receipt of it. We have the server's suggested IP and port to connect to for the actual data download.

However, in packet 23, the client then sends out a PORT command with the suggested active mode port that the server should initiate a connection to. The server then confirms this and when the client attempts to get a directory listing, we see that roughly 75 seconds pass by until the server comes back with a "Can't build data connection: Operation timed out" message. This is because while the PASV command was made, the client still decided to follow-up with a request that's active-mode specific, thus causing the server to switch back to it.

So does the built-in Windows FTP client support passive mode or not? I haven't looked into this too much, so if someone can provide me with a definitive answer, I'd appreciate it.



Go back to the main articles list.