[Previous: Performance] [Contents] [Next: Authpf: User Shell for Authenticating Gateways]
You can use FTP in one of two ways: passive or active. Generally, the choice of active or passive is made to determine who has the problem with firewalling. Realistically, you will have to support both to have happy users.
With active FTP, when a user connects to a remote FTP server and requests information or a file, the FTP server makes a new connection back to the client to transfer the requested data. This is called the data connection. To start, the FTP client chooses a random port to receive the data connection on. The client sends the port number it chose to the FTP server and then listens for an incoming connection on that port. The FTP server then initiates a connection to the client's address at the chosen port and transfers the data. This is a problem for users attempting to gain access to FTP servers from behind a NAT gateway. Because of how NAT works, the FTP server initiates the data connection by connecting to the external address of the NAT gateway on the chosen port. The NAT machine will receive this, but because it has no mapping for the packet in its state table, it will drop the packet and won't deliver it to the client.
With passive mode FTP (the default mode with OpenBSD's ftp(1) client), the client requests that the server pick a random port to listen on for the data connection. The server informs the client of the port it has chosen, and the client connects to this port to transfer the data. Unfortunately, this is not always possible or desirable because of the possibility of a firewall in front of the FTP server blocking the incoming data connection. OpenBSD's ftp(1) uses passive mode by default; to force active mode FTP, use the -A flag to ftp, or set passive mode to "off" by issuing the command "passive off" at the "ftp>" prompt.
Packet Filter provides a solution for this situation by redirecting FTP traffic through an FTP proxy server. This process acts to "guide" your FTP traffic through the NAT gateway/firewall. The FTP proxy used by OpenBSD and PF is ftp-proxy(8). To activate it, put something like this in the NAT section of pf.conf:
rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 \
port 8021
The explanation of this line is: "Traffic on the internal interface is redirected to the proxy server running on this machine which is listening at port 8021".
Hopefully it is apparent the proxy server has to be started and running on the OpenBSD box. This is done by inserting the following line in /etc/inetd.conf:
127.0.0.1:8021 stream tcp nowait root /usr/libexec/ftp-proxy \
ftp-proxy
and either rebooting the system or sending a 'HUP' signal to inetd(8). One way to send the 'HUP' signal is with the command:
kill -HUP `cat /var/run/inetd.pid`
You will note that ftp-proxy is listening on port 8021, the same port the above rdr statement is sending FTP traffic to. The choice of port 8021 is arbitrary, though 8021 is a good choice as it is not defined for any other application.
Please note that ftp-proxy(8) is to help FTP clients behind a PF filter; it is not used to handle an FTP server behind a PF filter.
pass in on $ext_if proto tcp from any to any port 21 keep state
pass in on $ext_if proto tcp from any to any port > 49151 \
keep state
Note that if you desire, you can tighten up that range of ports considerably. In the case of the OpenBSD ftpd(8) program, that is done using the sysctl(8) variables net.inet.ip.porthifirst and net.inet.ip.porthilast.
Here is an example subset of rules which would accomplish this:
ftp_server = "10.0.3.21"
rdr on $ext_if proto tcp from any to any port 21 -> $ftp_server \
port 21
rdr on $ext_if proto tcp from any to any port 49152:65535 -> \
$ftp_server port 49152:65535
# in on $ext_if
pass in quick on $ext_if proto tcp from any to $ftp_server \
port 21 keep state
pass in quick on $ext_if proto tcp from any to $ftp_server \
port > 49151 keep state
# out on $int_if
pass out quick on $int_if proto tcp from any to $ftp_server \
port 21 keep state
pass out quick on $int_if proto tcp from any to $ftp_server \
port > 49151 keep state
[Previous: Performance] [Contents] [Next: Authpf: User Shell for Authenticating Gateways]