BSD FTP-Proxy: PF Firewall Allow Outgoing Active / Passive FTP Connections

by on August 1, 2008 · 10 comments· LAST UPDATED November 9, 2009

in , ,

Q. I've FreeBSD based Apache webserver. I need to allow outgoing ftp client requests so that BSD ports collection can download from various ftp sites. How do I allow outgoing FTP connection via PF network firewall software under FreeBSD or OpenBSD operating system?

A. You need to use ftp-proxy, which is a proxy for the Internet File Transfer Protocol. ftp-proxy is installed by default along with PF firewall.

Step # 1: Turn on ftp-proxy under FreeBSD

Open /etc/rc.conf file under FreeBSD
# vi /etc/rc.conf
Append following line:
ftpproxy_enable="YES"
If you are using OpenBSD, type the following command to start the ftp proxy on boot:
echo 'ftpproxy_flags=""' >>/etc/rc.conf.local
By default ftp proxy listen on 8021 port bind to 127.0.0.1 IP address.

Step # 2: Configure pf and ftp-proxy

Open your /etc/pf.conf file and add following into your NAT section:
To activate it, put something like this in the NAT section of pf.conf:
nat-anchor "ftp-proxy/*"
rdr-anchor "ftp-proxy/*"
rdr pass proto tcp from any to any port ftp -> 127.0.0.1 port 8021

All three rules required, even if your setup does not use NAT. Find your filtering rule and append the following rules:
anchor "ftp-proxy/*"
Save and close the file.

Sample pf.conf rules

Here is my own working sample /etc/pf.conf file that allows outgoing ftp, along with ssh, http, dns service. It only allows incomming traffic on port 53, 80:

#### First declare a couple of variables ####
# outgoing services
tcp_services = "{ ssh, smtp, domain, www, https, ntp, 43}"
udp_services = "{ domain, ntp }"
icmp_types = "{ echoreq, unreach }"
 
martians = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8, 169.254.0.0/16, 192.0.2.0/24, 0.0.0.0/8, 240.0.0.0/4 }"
 
ext_if = "em1" # Internet
int_if = "em0" # vpn / lan
 
proxy="127.0.0.1" # ftp proxy IP
proxyport="8021" # ftp proxy port
 
#### Normalization
scrub in all
 
#### NAT and RDR start
nat-anchor "ftp-proxy/*"
rdr-anchor "ftp-proxy/*"
 
# Redirect ftp traffic to proxy
rdr pass proto tcp from any to any port ftp -> $proxy port $proxyport
 
#### Start filtering 
# Drop incoming everything
block in all
 
# Default connection refused message to client 
block return
 
# keep stats of outging connections
pass out keep state
 
# We need to have an anchor for ftp-proxy
anchor "ftp-proxy/*"
 
# Unlimited traffic for lo0 and VPN/Lan interface
set skip on {lo0, $int_if}
 
# activate spoofing protection for all interfaces
block in quick from urpf-failed
 
# Antispoof is a common special case of filtering and blocking. This mechanism protects against activity from spoofed or forged IP addresses
antispoof log for $ext_if
 
#Block RFC 1918 addresses
block drop in log (all)  quick on $ext_if from $martians to any
block drop out log (all) quick on $ext_if from any to $martians
 
 
# Allow outgoing via ssh, smtp, domain, www, https, whois etc
pass out on $ext_if proto tcp to any port $tcp_services
pass out on $ext_if proto udp to any port $udp_services
 
# Allow outgoing Trace route
pass out on $ext_if inet proto udp from any to any port 33433 >< 33626 keep state
 
# Allow incomming named udp / tcp 53
pass in on $ext_if proto udp from any to any port 53
# All tcp service protected using synproxy
pass in on $ext_if proto tcp from any to any port 53 flags S/SA synproxy state
# Allow http traffic
pass in on $ext_if proto tcp from any to any port 80 flags S/SA synproxy modulate state
# SSH 
pass in on $ext_if proto tcp from any to any port 22 flags S/SA synproxy modulate state
# Allow ICMP ping
pass inet proto icmp all icmp-type $icmp_types keep state

Step # 3: Restart PF firewall

Type the following command under FreeBSD:
# /etc/rc.d/pf restart
OR type the following under OpenBSD (also works under FreeBSD):
# pfctl -nf /etc/pf.conf
# pfctl -f /etc/pf.conf

Step # 4: Start ftp-proxy

Type the following command to start ftp-proxy under, FreeBSD:
# /etc/rc.d/ftp-proxy start
Under OpenBSD, you can simply type the following to start ftp-proxy:
# /usr/sbin/ftp-proxy

Test your setup

Use ftp client to test your test, enter:
$ ftp ftp.freebsd.org

Further readings:

TwitterFacebookGoogle+PDF versionFound an error/typo on this page? Help us!

{ 10 comments… read them below or add one }

1 John Dakos July 17, 2009 at 1:06 pm

Good Job Man :) This Tutorial Help Me To Understand Ftp-Proxy and RDR. Thanks

Reply

2 John August 11, 2009 at 9:57 am

I’ve got ftp-proxy working on my firewall for all the clients behind it. However I can’t ftp (using Active or Passive) from the actual firewall itself, which is making installing/upgrading ports tedious.

For example:
#pkg_add -r ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7.2-release/Latest/ifstated.tbz
Error: FTP Unable to get ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7.2-release/Latest/ifstated.tbz: Operation not permitted
pkg_add: unable to fetch ‘ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-7.2-release/Latest/ifstated.tbz’ by URL

I’m guessing that this is because no redirection is being done as the request is being sent straight out the default route interface (I verified this by pausing the pkg_add command, and executing netstat -f inet | grep ftp).
Any suggestions as to how I can get around this. Surely this is something that others have encountered.

Reply

3 nixCraft August 11, 2009 at 10:11 am

@John,

Try:

pass out on $ext_if inet proto tcp from any to any port ftp
pass out on $ext_if inet proto tcp from any to any port >1023

Reply

4 John August 11, 2009 at 10:26 am

@Vivek
Thanks, that would make sense. Unfortunately it also means that my block out rule is essentially rendered useless. A few people here use personal laptops with the BBC iPlayer installed which can eat bandwidth. By only allowing out required traffic, it makes life a lot easier.
Any chance I can keep my cake and eat it :-)

Reply

5 SIFE September 28, 2009 at 12:54 pm

Salamo Alikom
@Vivek Gite
this rules you had sets it fix my problem , thx.

Reply

6 Colin November 8, 2009 at 8:26 pm

Hi Vivek,

I think there is an error here:

# pfctl -nf /etc/rc.conf
# pfctl -f /etc/rc.conf

Should be this:
# pfctl -nf /etc/pf.conf
# pfctl -f /etc/pf.conf

In any case, thanks for a useful page and a very useful site. I keep coming back.

-Colin

Reply

7 nixCraft November 9, 2009 at 5:43 am

@ Colin

Thanks for the heads up!

Reply

8 stiv March 31, 2010 at 10:09 am

Thank you for good article.
But if I use the rule
# keep stats of outging connections
pass out keep state
I don’t need any other rules such as
# Allow outgoing via ssh, smtp, domain, www, https, whois etc
pass out on $ext_if proto tcp to any port $tcp_services
pass out on $ext_if proto udp to any port $udp_services

Reply

9 Ben Francom November 25, 2010 at 12:29 pm

Thanks for the great article, and explanation. The comments are also very informative. It helped me recently with an instance of PF, FreeBSD and FTP.

Reply

10 Hasse January 7, 2012 at 7:07 pm

Thanks
As usual, it’s a pleasure following your tutorials. They simply works.

Reply

Leave a Comment

Tagged as: , , , , , , , , , , , ,

Previous Faq:

Next Faq: