reverse ftp-proxy with pf and OpenBSD
Imagine you have a FTP server behind your NAT/firewall server and you want to (or rather have to, because why would you really _want_ to do it?) give access to this FTP from outside world.
As FTP is a really crazy old protocol it’s not as easy as with HTTP or POP3 where you only have to redirect one port. With FTP there are actually two connections established, one on port 21 which is used to control the FTP session and is used to send commands, and the other connection is used to transfer data. The problem is with the other connection, which doesn’t usually have one set port that it would use, instead it’s port is negotiated everytime you want to download something. So what you need is a tool that will open and redirect ports needed for data session based on what’s being negotiated in the control session.
Here’s how to do it on OpenBSD using ftp-proxy and a few simple pf rules.
My internal network is 172.21.33.0/24 and my gateway’s IP on this network is 172.21.33.1. FTP server’s IP is 172.21.33.5. First, we have to set up ftp-proxy daemon in reverse-proxy mode. It’s option -R with FTP server’s IP, so add
ftpprooxy_flags="-R 172.21.33.5"
to /etc/rc.conf.local and starting the deamon manually (it will start automatically after the next reboot)
# /usr/sbin/ftp-proxy -R 172.21.33.5
Now all you have to do is to edit your /etc/pf.conf file and add
rdr-anchor "ftp-proxy/*" rdr pass on $ext_if proto tcp from any to $ext_if port 21 -> 127.0.0.1 port 8021
before your redirection rules
nat-anchor "ftp-proxy/*"
before your nat rules
and finally, before your filtering rules:
anchor "ftp-proxy/*"
pf will use these anchors to dynamically create rules needed for new FTP sessions. That’s it, reload pf and test everything.