Problems with FTP

I've spent the last couple of days trying to fix this issue and have decided to give up looking and ask for help.

I'm using the pf firewall with the following config (scraped together from a few forums):
/etc/pf.conf

Code:
# Pf Firewall Rules

# Set external Interface
ext_if="sis0"

#Proxy Ports
proxy="127.0.0.1"
proxyport="8021"

#Macros
tcp_out_services = "{ ssh, smtp, domain, www, pop3, auth, https, imap, ntp, 3000, ftp, 5999, 2401, 3690 }"
udp_out_services = "{ domain, ntp, ftp }"

tcp_in_services = "{ ssh, 3000 }"

udp_in_services = "{ }"

#Tables
table <fail2ban> persist

#NAT and RDR start
nat-anchor "ftp-proxy/*"
rdr-anchor "ftp-proxy/*"

# Redirect FTP to proxy
rdr pass proto tcp from any to any port ftp -> $proxy port $proxyport

#Block By Default
block all

# FTP anchor
anchor "ftp-proxy/*"
pass in quick inet proto tcp to port 21 divert-to 127.0.0.1 port 8021

#Fail2Ban
block in quick on $ext_if from <fail2ban>

# Pass out Selected Macros
pass out proto tcp to port $tcp_out_services
pass proto udp to port $udp_out_services
pass in proto tcp to port $tcp_in_services

I have also tried the following configuration from the Book of PF:

Code:
# cat /etc/pf.conf 
# Pf Firewall Rules

# Set external Interface
ext_if="sis0"

#Proxy Ports
proxy="127.0.0.1"
proxyport="8021"

#Macros
tcp_out_services = "{ ssh, smtp, domain, www, pop3, auth, https, imap, ntp, 3000, ftp, 5999, 2401, 3690 }"
udp_out_services = "{ domain, ntp, ftp }"

tcp_in_services = "{ ssh, 3000 }"

udp_in_services = "{ }"

#Tables
table <fail2ban> persist

#NAT and RDR start
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

#Handle ICMP - Ping
#icmp_types = "{ echoreq, unreach }"

#Block By Default
block all

# FTP anchor
anchor "ftp-proxy/*"

# Redirect FTP to proxy
pass out proto tcp from $proxy to any port ftp

#Fail2Ban
block in quick on $ext_if from <fail2ban>

# Pass out Selected Macros
pass out proto tcp to port $tcp_out_services
pass proto udp to port $udp_out_services
pass in proto tcp to port $tcp_in_services
pass out proto tcp from $proxy to any port ftp

# Pass out ICMP properly
#pass out proto icmp-type $icmp_types

I just can't seem to get ftp to work in either passive or active mode.

Active fails almost instantly, passive shows the following:

Code:
# pkg_add -rv xmonad
scheme:   [ftp]
user:     []
password: []
host:     [ftp.freebsd.org]
port:     [0]
document: [/pub/FreeBSD/ports/i386/packages-9.0-release/Latest/xmonad.tbz]
---> ftp.freebsd.org:21
looking up ftp.freebsd.org
connecting to ftp.freebsd.org:21
<<< 220 Welcome to freebsd.isc.org.
>>> USER anonymous
<<< 331 Please specify the password.
>>> PASS llawwehttam@zippo.localhost
<<< 230 Login successful.
>>> PWD
<<< 257 "/"
>>> CWD pub/FreeBSD/ports/i386/packages-9.0-release/Latest
<<< 250 Directory successfully changed.
>>> MODE S
<<< 200 Mode set to S.
>>> TYPE I
<<< 200 Switching to Binary mode.
setting passive mode
>>> PASV
<<< 227 Entering Passive Mode (204,152,184,73,247,217).
opening data connection
Error: Unable to get ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-9.0-release/Latest/xmonad.tbz: Operation not permitted
pkg_add: unable to fetch 'ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-9.0-release/Latest/xmonad.tbz' by URL
pkg_add: 1 package addition(s) failed

/etc/rc.conf:

Code:
# cat /etc/rc.conf 
hostname="zippo.localhost"
keymap="uk.iso.kbd"
ifconfig_sis0="DHCP" # Router using Mac address allocation
sshd_enable="YES"
ntpd_enable="YES"
# Set dumpdev to "AUTO" to enable crash dumps, "NO" to disable
dumpdev="AUTO"

pf_enable="YES"
pf_rules="/etc/pf.conf"
pf_flags=""
pflog_enable="YES"
pflog_logfile="/var/log/pflog"
pflog_flags=""

ftpproxy_enable="YES"
ftpproxy_flags=""

fail2ban_enable="YES"

Before anyone asks, yes it works when PF is disabled.

I'm very new to FreeBSD and have only written firewall rules using UFW in Linux so the chances are I'll have done something stupid.

Any help is much appreciated.
 
That's very difficult to get right, a passive mode ftp connection needs a secondary connection (the "DATA" connection) to a port on the destination host that is not known in advance. You're restricting outbound connections to only known destination ports and that's why the secondary connection fails.

An ftp proxy will solve the problem for hosts behind the proxy host (if the proxy host is also a router) but for connections initiated from the host with proxy it's not possible to redirect the outgoing connections back to an interface with the proxy listening on it(at least not with pf(4), if I remember right this is possible in Linux iptables).
 
kpa said:
That's very difficult to get right, a passive mode ftp connection needs a secondary connection (the "DATA" connection) to a port on the destination host that is not known in advance. You're restricting outbound connections to only known destination ports and that's why the secondary connection fails.

An ftp proxy will solve the problem for hosts behind the proxy host (if the proxy host is also a router) but for connections initiated from the host with proxy it's not possible to redirect the outgoing connections back to an interface with the proxy listening on it(at least not with pf(4), if I remember right this is possible in Linux iptables).

Thanks for the explanation.

I did consider adding something along the lines of:
Code:
pass out on $ext_if inet proto tcp from any to any port >1023
but I don't really want all those ports open.

I suppose I could write a script to do that before an ftp connection is requested and remove it afterwards.
 
razrx said:
I would start by defining some log statements in your pf(4)() ruleset.
Then use tcpdump(1)() to check what's happening.

# tcpdump -n -ttt -i pflog0 port ftp

and:

# pfctl -vvsr
to get a more detailed view of what's going on.

Thanks, I've added log practically everywhere but this is all I pick up for the ftp port:

Code:
00:00:00.000000 IP 192.168.1.6.31540 > 204.152.184.73.21: Flags [S], seq 3881366838, win 65535, options [mss 1460,nop,wscale 6,sackOK,TS val 15236185 ecr 0], length 0

I can see this being too much work ;)

pfctl -vvsr didn't really tell me anything I didn't already know.
 
Looking at this:
Code:
# FTP anchor
anchor "ftp-proxy/*"
pass in quick inet proto tcp to port 21 divert-to 127.0.0.1 port 8021

I think this should be:
Code:
# FTP anchor
anchor "ftp-proxy/*"
pass out quick inet proto tcp to port 21 divert-to 127.0.0.1 port 8021

Give that a try. Also, it goes without saying, you need to start the ftp-proxy daemon as well (in case you haven't).
 
gordon@ said:
Looking at this:
Code:
# FTP anchor
anchor "ftp-proxy/*"
pass in quick inet proto tcp to port 21 divert-to 127.0.0.1 port 8021

I think this should be:
Code:
# FTP anchor
anchor "ftp-proxy/*"
pass out quick inet proto tcp to port 21 divert-to 127.0.0.1 port 8021

Give that a try. Also, it goes without saying, you need to start the ftp-proxy daemon as well (in case you haven't).

Sadly no luck with that either.

Looking at the output of a verbose ftp it's almost as if the redirects are being completely ignored.
 
That's unfortunately the case, the redirects do not work for outgoing traffic. Anything that want to with route-to or divert-to must be done when the traffic arrives in via a network interface.
 
kpa said:
That's unfortunately the case, the redirects do not work for outgoing traffic. Anything that want to with route-to or divert-to must be done when the traffic arrives in via a network interface.

I'm not sure whether to bother trying further as I can just temporary allow FTP traffic while I update etc.

Also I'm considering rack-mounting my machines and it would be easy to just set up a firewall to handle all of them.

Thanks for all the help though, I'm definitely going to stick around in this community.
 
Hi all,

I have the same trouble with PF with FTP access. My rules:
Code:
ext_if = "em0"
icmp_types="{ echoreq, unreach }"
admin="{178.14.1.2, 77.1.1.1}"
set timeout { interval 10, frag 30 }
set timeout { tcp.first 120, tcp.opening 30, tcp.established 86400 }
set timeout { tcp.closing 900, tcp.finwait 45, tcp.closed 90 }
set timeout { udp.first 60, udp.single 30, udp.multiple 60 }
set timeout { icmp.first 20, icmp.error 10 }
set timeout { other.first 60, other.single 30, other.multiple 60 }
set timeout { adaptive.start 0, adaptive.end 0 }
set limit { states 15000, frags 30000 }
set optimization normal
set block-policy drop
set loginterface rl0
scrub in on $ext_if all fragment reassemble
block log all
set skip on lo0
antispoof for $ext_if inet
block in from urpf-failed to any
block in quick on $ext_if from any to 255.255.255.255
block in log quick on $ext_if from { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 255.255.255.255/32 } to any
block in quick on $ext_if proto tcp flags FUP/WEUAPRSF
block in quick on $ext_if proto tcp flags WEUAPRSF/WEUAPRSF
block in quick on $ext_if proto tcp flags SRAFU/WEUAPRSF
block in quick on $ext_if proto tcp flags /WEUAPRSF
block in quick on $ext_if proto tcp flags SR/SR
block in quick on $ext_if proto tcp flags SF/SF
pass out on $ext_if proto { tcp, udp} from any to any modulate state
pass in log on $ext_if inet proto icmp from $admin to $ext_if icmp-type $icmp_types
pass in on $ext_if proto tcp from $admin to $ext_if port 22 flags S/SA synproxy state
pass in on $ext_if proto tcp from any to $ext_if port 80 flags S/SA synproxy state
pass in on $ext_if proto tcp from any to any port 443 flags S/SA synproxy state
pass in on $ext_if proto tcp from any to $ext_if port 993 flags S/SA synproxy state
pass in on $ext_if proto tcp from any to $ext_if port 587 flags S/SA synproxy state
pass in on $ext_if proto tcp from any to $ext_if port {20,21,49152:65535} flags S/SA synproxy state
I need passive FTP functionality.
 
Back
Top