# PF configuration for FTP on FreeBSD 9.1



## FREERFb (Apr 29, 2014)

I have the following in my pf.conf, all works nice so far, except FTP, what do I need to add to this to get FTP working?

I tried many things already, but am getting nowhere because apparently I am doing stuff wrong in the order of things.


```
# ----------------------- simple server pf.conf ----------------------
# For FreeBSD 9.1
# j65nko 2011, 2012, 2013
#
# If you adapt this ruleset for a resolving caching name server please
# make sure you don't allow the whole world to use your name server
# Creating an open resolving name server can allow the bad guys to use your nameserver
# in an DNS amplification attack

ext_if="vtnet0"
icmp_types="echoreq"

# Custom port for ssh
SSH_CUSTOM = xxxx

scrub in on $ext_if all fragment reassemble

set skip on lo0
#set skip on lo1

antispoof for $ext_if

# --- EXTERNAL INTERFACE
# --- INCOMING -------------------------------------------------------------------

# --- TCP
pass in  quick on $ext_if inet proto tcp from any to $ext_if  port http
pass in  quick on $ext_if inet proto tcp from any to $ext_if  port https
pass in  quick on $ext_if inet proto tcp from xx.xx.xx.xx to $ext_if  port $SSH_CUSTOM
pass in  quick on $ext_if inet proto tcp from any to $ext_if  port smtp
pass in  quick on $ext_if inet proto tcp from xx.xx.xx.xx to $ext_if  port pop3
pass in  quick on $ext_if inet proto tcp from xx.xx.xx.xx to $ext_if  port 2222

# --- for authoritative DNS server
#pass in  quick on $ext_if inet proto udp from any to $ext_if  port domain

# --- UDP
# --- for authoritative DNS server
#pass in  quick on $ext_if inet proto udp from any to $ext_if  port domain

# --- ICMP
pass in  quick on $ext_if inet proto icmp from any to $ext_if icmp-type $icmp_types

# --- EXTERNAL INTERFACE
# --- OUTGOING --------------------------------------------------------------------

anchor TMP

# --- TCP
pass  out quick log on $ext_if inet proto tcp from $ext_if to any port smtp
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port domain
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port http
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port https
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port whois
pass  out quick     on $ext_if inet proto tcp from $ext_if to xx.xx.xx.xx port $SSH_CUSTOM
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port smtp
pass  out quick     on $ext_if inet proto tcp from $ext_if to xx.xx.xx.xx port pop3
pass  out quick     on $ext_if inet proto tcp from $ext_if to xx.xx.xx.xx port 2222

# --- UDP
pass  out quick on $ext_if inet proto udp from $ext_if to any port domain
pass  out quick on $ext_if inet proto udp from $ext_if to any port ntp

# --- ICMP
pass  out quick on $ext_if inet proto icmp  from $ext_if to any

# ------------------------------------------------------
# --- DEFAULT POLICY
# ------------------------------------------------------
block log all
# ----- end of pf.conf
```


----------



## asteriskRoss (Apr 29, 2014)

Handling FTP is tricky due to the ways (plural) the protocol works, whether you are hosting an FTP server, acting as a gateway or as an FTP client.  Have a look at section 29.3.3.2. "Creating an FTP Proxy" in the handbook and Peter Hansteen's "Firewalling with PF", which is referenced from the handbook.  The configuration file you posted didn't include any rules relating to FTP so it would be useful if you can tell us more about what you want to do and what you've already tried.


----------



## FREERFb (Apr 29, 2014)

Hi @asteriskRoss, thanks for answering.

I first did this:


> To enable the FTP proxy, add this line to /etc/rc.conf:
> 
> ```
> ftpproxy_enable="YES"
> ...



Then I added the following to pf.conf:

```
nat-anchor "ftp-proxy/*"
rdr-anchor "ftp-proxy/*"
rdr pass on $ext_if proto tcp from any to any port ftp -> 127.0.0.1 port 8021
pass out proto tcp from $proxy to any port ftp
```

And then things just stopped working, I do not know where to put the above lines in the first mentioned file.

I hope this makes it more clear.


----------



## junovitch@ (Apr 29, 2014)

Per pf.conf(), "By default pfctl(8) enforces an ordering of the statement types in the ruleset to: options, normalization, queueing, translation, filtering." So the first three lines are your "translation" and could go after antispoof and before your first pass rule.  The fourth line is a "filtering" rule and could go anywhere below that.

EDIT:
You should put your block line right at the top of your filtering, as in before all the pass rules.  Remember that PF is last match wins.  I see you are trying to get around this by using quick on all your rules but really you should put your least specific rules like that generic block line right at the top and whittle it down as you go.


----------



## FREERFb (Apr 30, 2014)

Thanks @junovitch, I now tried the following, but still can not get in, anybody see what I do wrong?


```
# ----------------------- simple server pf.conf ----------------------
# For FreeBSD 9.1
# j65nko 2011, 2012, 2013
#
# If you adapt this ruleset for a resolving caching name server please
# make sure you don't allow the whole world to use your name server
# Creating an open resolving name server can allow the bad guys to use your nameserver
# in an DNS amplification attack

ext_if="vtnet0"
icmp_types="echoreq"

# Custom port for ssh
SSH_CUSTOM = xxxx

scrub in on $ext_if all fragment reassemble

set skip on lo0
#set skip on lo1

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/*"

antispoof for $ext_if

# --- EXTERNAL INTERFACE
# --- INCOMING -------------------------------------------------------------------

# --- TCP
pass in  quick on $ext_if inet proto tcp from any to $ext_if  port http
pass in  quick on $ext_if inet proto tcp from any to $ext_if  port https
pass in  quick on $ext_if inet proto tcp from any to $ext_if  port $SSH_CUSTOM
pass in  quick on $ext_if inet proto tcp from any to $ext_if  port smtp
pass in  quick on $ext_if inet proto tcp from 85.150.217.242 to $ext_if  port pop3
pass in  quick on $ext_if inet proto tcp from 85.150.217.242 to $ext_if  port 2222

# --- for authoritative DNS server
#pass in  quick on $ext_if inet proto udp from any to $ext_if  port domain

# --- UDP
# --- for authoritative DNS server
#pass in  quick on $ext_if inet proto udp from any to $ext_if  port domain

# --- ICMP
pass in  quick on $ext_if inet proto icmp from any to $ext_if icmp-type $icmp_types

# --- EXTERNAL INTERFACE
# --- OUTGOING --------------------------------------------------------------------

anchor TMP

# --- TCP
pass  out quick log on $ext_if inet proto tcp from $ext_if to any port smtp
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port domain
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port http
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port https
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port whois
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port $SSH_CUSTOM
pass  out quick     on $ext_if inet proto tcp from $ext_if to any port smtp
pass  out quick     on $ext_if inet proto tcp from $ext_if to 85.150.217.242 port pop3
pass  out quick     on $ext_if inet proto tcp from $ext_if to 85.150.217.242 port 2222

# --- UDP
pass  out quick on $ext_if inet proto udp from $ext_if to any port domain
pass  out quick on $ext_if inet proto udp from $ext_if to any port ntp

# --- ICMP
pass  out quick on $ext_if inet proto icmp  from $ext_if to any

# ------------------------------------------------------
# --- DEFAULT POLICY
# ------------------------------------------------------
block all

# ----- end of pf.conf
```


----------



## asteriskRoss (May 4, 2014)

Peter Hansteen's "Firewalling with PF" mentions a rule that doesn't appear in your pf.conf:


> Finally, add a pass rule to let the packets pass from the proxy to the rest of the world:
> 
> ```
> pass out proto tcp from $proxy to any port ftp
> ...



However, as I understand it, this is intended for gateways, where the firewall protects other hosts on the network.  Your firewall rules appear to show that you're running PF on the server it is protecting, and not using it as a gateway.  As I understand it, ftp-proxy cannot be used to handle FTP traffic originating from the host; it is intended where you are running a gateway for other network clients.  From pf.conf(8):


> [...]
> the rdr rules	are evaluated on an
> inbound packet or the nat rules on	an outbound packet.
> [...]
> ...



What I take from that is therefore that packets originating from the host running PF will never be redirected since they can never be considered to be incoming.  The approach I use to restrict outbound FTP connections where PF is protecting the machine it is running on is to use a table of allowed FTP servers with the following rule, noting that I use the normal PF rule ordering and don't have "quick" rules like your configuration:

```
pass out inet proto tcp from <myhostandjails> to <ftpservers> port {ftp, >1023}
```

This allows the initial outgoing FTP connection and then permits traffic relating to passive mode to connect to the random port the server allocates.  You could be less restrictive and allow such connections to any host, rather than a list you need to maintain, though that will also allow TCP connections to any host on all ports from 1024 upwards, which may be more permissive than you need.


----------



## wblock@ (May 4, 2014)

These threads should always include the suggestion that it's time to stop using FTP if at all possible.  sftp(1), for example, is more secure and less painful.


----------

