PF: can't get ftp to work

I've started learning of, and have manse some simple pf.conf
Everything works, except ftp. I even got torrents to work :)
I've read http://www.openbsd.org/faq/pf/ftp.html but somehow I can't get ftp to work....

/etc/pf.conf
Code:
ext_if = "rl0"
ext_ip = "192.168.128.100"
lo_if = "lo0"
net_type = "inet"

ssh_port = "60386"
torrent_tcp_port = "6890"
torrent_udp_port = "6881"

common_pass = "{ http, https, domain, ftp, ftp-data, imaps, nameserver, nicname, xmpp-client, silc, ntp," $ssh_port "}"
tcp_pass = "{ ircd, ftp-proxy }"
[color="Gray"]#udp_pass = "{ }"[/color]

common_block = "{ ssh, telnet }"
[color="Gray"]#tcp_block = "{ }"
#udp_block = "{ }"[/color]



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

antispoof log for $ext_if


[color="Gray"]# Block and log everything[/color]
block log all
[color="Gray"]# excetp lo0[/color]
pass quick on $lo_if all
[color="Gray"]# blcok default ssh port and telnet port[/color]
block quick log on $ext_if proto { tcp, udp } from any to any port $common_block


[color="Gray"]# Enable Torrents tcp[/color]
pass in quick on $ext_if $net_type proto tcp from any to $ext_ip port $torrent_tcp_port keep state
pass out quick on $ext_if $net_type proto tcp from $ext_ip port $torrent_tcp_port to any keep state
[color="Gray"]# Enable Torrents udp[/color]
pass in quick on $ext_if $net_type proto udp from any to $ext_ip port $torrent_udp_port keep state
pass out quick on $ext_if $net_type proto udp from $ext_ip port $torrent_udp_port to any keep state
[color="Gray"]# Enable Torrents listen for incoming connections[/color]
pass in on $ext_if $net_type proto tcp from any to $ext_ip port 10000:65000 keep state


[color="Gray"]# Enable services on TCP and UDP[/color]
pass in log on $ext_if $net_type proto { tcp, udp } from any to $ext_ip port $common_pass
pass out log on $ext_if $net_type proto { tcp, udp } from $ext_ip to any port $common_pass

[color="Gray"]# Enable services on TCP[/color]
pass in log on $ext_if $net_type proto tcp from any to $ext_ip port $tcp_pass
pass out log on $ext_if $net_type proto tcp from $ext_ip to any port $tcp_pass

/etc/rc.conf
Code:
ifconfig_rl0="inet 192.168.128.100 netmask 0xffffff00"
defaultrouter="192.168.128.1"
hostname="killasmurf86.homepc"

pf_enable="YES"
pflog_enable="YES"
ftpproxy_enable="YES"

Here's what's happening after I try to connect to my ISP ftp server
Code:
# tcpdump -ttt -n -e -r /var/log/pflog | grep 83.241.1.212             
reading from file /var/log/pflog, link-type PFLOG (OpenBSD pflog file)
00:00:00.001914 rule 50/0(match): pass out on rl0: 192.168.128.100.64961 > 83.241.1.212.21: Flags [S], seq 3701767531, win 65535, options [mss 1460,nop,wscale 3,sackOK,TS[|tcp]>
00:00:00.164179 rule 8/0(match): [color="Red"]block out[/color] on rl0: 192.168.128.100.24090 > 83.241.1.212.12912: Flags [S], seq 680468111, win 65535, options [mss 1460,nop,wscale 3,sackOK,TS[|tcp]>
00:00:00.004795 rule 8/0(match): [color="Red"]block out[/color] on rl0: 192.168.128.100.53138 > 83.241.1.212.8637: Flags [S], seq 803526260, win 65535, options [mss 1460,nop,wscale 3,sackOK,TS[|tcp]>


Any iseas what did I do wrong? I'm already hitting my head against wall
:OOO

This is my desktop PC behind wireless router.
 
Here is what I've my system
Code:
# Outgoing ftp
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
 
Did you tried out above rules? They are working for me.. I had exactly same problem you have. make install clean wasn't working coz it cannot download. After adding above two lines it worked out for me.
 
Yes, that should work, but what's the point of firewalling, if you allow traffic in and out on almost all ports

In your code you allow out, I had to enable traffic in for torrents
 
yes, that is main problem with ftp, especially when you don't have dedicated bsd router to do NAT. With nat and proxy it will be more easy as specified in openbsd PF faq.
 
Well, currently I see only 3 options
1) what you said
2) make script, that would extract list of ftp servers, from ports, and make white list, that would be loged, That is not elegant solution, but it's better, than opening 99+% ports for everyone
3) do what you said + add log to your line, and keep it last rule, other rules, that pass, should be quick

EDIT:
appended text for 2
 
It looks like it's already passive, since the client is making all the outgoing connections (see flags on 'block out' lines).

However, I thought passive FTP always used ports between 49152 and 65535, making much more restrictive rules possible.
 
You redirect all connections to port 21/tcp on your >>external<< interface. I'm not sure if this works as you redirect on the external interface (back) to loopback.

These are the moments where I miss special "service objects" in pf for protocols like (t)ftp, rpc and so on, where the firewall needs to inspect the communication to allow further communication...

cheers,
honk
 
I'm guessing pf's rdr can't redirect packets generated by the local machine. You can use ipfw's divert and natd's -punch_fw parameter instead.

Or disable passive mode and just permit incoming tcp:20 -> tcp:49152-65535
 
I have mine something like this, maybe you miss the keep state and anchor

Code:
nat on $ext_if from !($ext_if) -> ($ext_if:0)

nat-anchor "ftp-proxy/*"
rdr-anchor "ftp-proxy/*"

rdr pass on $int_if proto tcp from any to any port ftp -> 127.0.0.1 \
    port 8021

rdr pass on $int_if proto tcp from any to any port www -> 192.168.2.1 port 3128

# Filter
block in

pass out keep state
pass out quick on $int_if from any to any keep state
pass in quick on $int_if from any to any keep state

anchor "ftp-proxy/*"
 
DutchDaemon said:
However, I thought passive FTP always used ports between 49152 and 65535, making much more restrictive rules possible.

I don't know, will look in to that

FryShadow said:
Code:
# Filter
block in

pass out keep state
pass out quick on $int_if from any to any keep state
pass in quick on $int_if from any to any keep state

Man you don't block anything at all
Do you have more than 1 network card?
if $int_if doesn't contain lo0, then you're blocking it as well (not a good idea, as far as I understand)
 
Yes I have 2 network card, allow all at top from $int_if and I have several filtering rule besides that :)

block in will block anything coming into $ext_if and as per below rules will pass in my $ext_if :

Code:
tcp_services="{ ssh, http }"

pass in on $ext_if inet proto tcp from any to ($ext_if) port $tcp_services flags S/SA keep state

Some blocking rules that prevent connection from my network to outside :

Code:
test="{ pop3, pop3s, smtp }"

# Sample block
block out on $ext_if inet proto tcp from any to any port $test
 
I wrote a little, ugly, dirty, slow script, that generated list of ftp servers used in ports...

Had to remove 1 fake entry.... manually (will investigate).
I will improve this script later, when I have better mood

Code:
#!/usr/bin/perl

system("find /usr/ports -name Makefile -or -name bsd.*.mk > /tmp/file_list");
system("find /usr/ports/Mk -name bsd.*.mk >> /tmp/file_list");
system('for i in `cat /tmp/file_list`; do grep -e \'ftp://\' $i >> /tmp/ftp_list; done');

open(LIST, '<', "/tmp/ftp_list");

my @wlist;
my $i=0;
my $unique;
readitem: while (my $item = <LIST>) {
	unless ($item =~ /^#/) {
		chomp $item;
		$item =~ s/^.*ftp:\/\///;
		$item =~ s/\/.*$//;
		foreach $unique (@wlist) {
			next readitem if ( $item eq $unique );
		}

		print "$item\n";
		push(@wlist, $item);

	}
}
close LIST;

system("rm -f /tmp/file_list /tmp/ftp_list");

exit 0;
Ye, it's ugly

save it as and when you run it, redirect output to some file, that will be ftp white list.


I've attached my output....
This white list has 1497 unique ftp servers
I find this way better, than letting everyone out :)
IF you use other servers not in ports, you can add them to list, or make additional, list, where you keep them.

Also do you think maintaining such list could be useful? It could installed as port... or maintained by fresh ports....

EDIT:
attachment removed....
see below for new attachment
 
killasmurf86 said:
Well, currently I see only 3 options
1) what you said
2) make script, that would extract list of ftp servers, from ports, and make white list, that would be loged, That is not elegant solution, but it's better, than opening 99+% ports for everyone
3) do what you said + add log to your line, and keep it last rule, other rules, that pass, should be quick

There's 4th option, turn on and of specific rule (for ftp) every time you need it
 
@killasmurf86: Have you seen /usr/ports/ftp/ftpsesame ? Might help but I don't know how secure the code is (the state engine for parsing the ftp command channel).
 
Code:
#!/bin/sh
# Copyright (c) 2009, Aldis Berjoza <killasmurf86@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
#   notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
#   copyright notice, this list of conditions and the following disclaimer
#   in the documentation and/or other materials provided with the
#   distribution.
# * Neither the name of the  nor the names of its
#   contributors may be used to endorse or promote products derived from
#   this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# This scrip will create 'wlist' file, that will contain IP of all
#   ftp servers found in ports collection
# You may use this script to generate ftp server whitlist for pf
#
# http://killasmurf86.blogspot.com

find /usr/ports -name Makefile > /tmp/.ftp_list_1
find /usr/ports/Mk -name bsd.*.mk >> /tmp/.ftp_list_1

for i in `cat /tmp/.ftp_list_1`; do 
	grep -e 'ftp://' $i >> /tmp/.ftp_list_2
done

sed 's/#.*$//g' /tmp/.ftp_list_2 | sed 's/^.*ftp:\/\///' | sed 's/\/.*$//' | sort | uniq - /tmp/.ftp_list_3

grep -E -e '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' /tmp/.ftp_list_3 > /tmp/.ftp_list_4

for i in `cat /tmp/.ftp_list_3`; do
	dig +short "$i" | grep -E -e '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' >> /tmp/.ftp_list_4
done

sort /tmp/.ftp_list_4 | uniq - wlist
rm -f /tmp/.ftp_list_[1234]

exit

This generates list of ftp servers used in ports.

I've uploaded resulting list of ip's.
 

Attachments

  • wlist.gz
    6 KB · Views: 256
Here's what I came up with:

Code:
ext_if = "rl0"
table <ext_ip> persist { 192.168.128.100, 192.168.128.99 }
net_type = "inet"

table <ftp_wlist> persist { ftp.some.other, ftp.servers.that.i.use }
table <ftp_ports_wlist> const file "/etc/wlist"

block log all
...
...

# Enable passive ftp
pass out log on $ext_if inet proto tcp from <ext_ip> port >1023 to { <ftp_ports_wlist>, <ftp_wlist> } port { ftp, >1023 } keep state
#pass in log on $ext_if inet proto tcp from { <ftp_ports_wlist>, <ftp_wlist> } port {ftp, >1023} to <ext_ip> port >1023 keep state
 
Code:
/etc/wlist
/etc/ is for base, for all user needs use /usr/local/etc. This is suggested practice.
 
Killasmurf,

looking at your code:

killasmurf86 said:
Here's what I came up with:

Code:
# Enable passive ftp
pass out log on $ext_if inet proto tcp from <ext_ip> port >1023 to { <ftp_ports_wlist>, <ftp_wlist> } port { ftp, >1023 } keep state
pass in log on $ext_if inet proto tcp from { <ftp_ports_wlist>, <ftp_wlist> } port {ftp, >1023} to <ext_ip> port >1023 keep state

I see no reason why you need the second rule,whatsoever. In order to allow outgoing ftp connections from your machine to your white list's ftp servers, the first rule, is adequate.

The second rule allows incoming traffic from your whitelist's servers having source port {ftp, >1023}, to your machine on port > 1023 (?!?!?!). Why?!!?!? You do not need this rule. If you use it, you just open your firewall with no reason. And this time you *really* open your firewall for incoming connections for all ports > 1023. Your first rule is statefull, so your job is done.

Lastly, if you place a firewall on your personal machine (and not a router or a server), there is no worry to allow outgoing connections statefully. You just block all incoming traffic and allow all outgoing traffic statefully. That is, of course, if you trust your personal machine..:)
 
mamalos said:
Lastly, if you place a firewall on your personal machine (and not a router or a server), there is no worry to allow outgoing connections statefully. You just block all incoming traffic and allow all outgoing traffic statefully. That is, of course, if you trust your personal machine..:)

It is much more convenient this way, but it has a higher risk. Occasionally, some programs will have vulnerabilities, and when they do, someone might take advantage of them and send some nasty stuff.
 
Back
Top