Solved [PF]Some guidance needed.

rigoletto@

Developer
Hello fellows,

I just built a small FreeBSD server a couple of days ago, and I had ZERO experience with it (FreeBSD) before that.

I am willing to have basically these services running on it: ssh, nextcloud/owncloud on nginx, dhcpcd server, ntp server, for personal usage.

This server is more for testing purposes in order to allow me to learn about FreeBSD in general, so I am not willing to deal with (i.e.) jails for now.

Since PF will take some time to learn and I am not a firewall guru, basically I would like to find a good example of PF rules to at least match with what I am using on my Gentoo box (iptables), what is not THAT rules but it is working fine for me.

Code:
IPT="/sbin/iptables"
IPTS="/sbin/iptables-save"
IPTR="/sbin/iptables-restore"

$IPT -F
$IPT -X
$IPT -Z

$IPT -N TCP
$IPT -N UDP

$IPT -P INPUT DROP
$IPT -P OUTPUT ACCEPT
$IPT -P FORWARD DROP

$IPT -A INPUT -i lo -j ACCEPT
$IPT -A INPUT -m conntrack --ctstate INVALID -j DROP
$IPT -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
$IPT -A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
$IPT -A INPUT -p udp -m conntrack --ctstate NEW -j UDP
$IPT -A INPUT -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP
$IPT -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
$IPT -A INPUT -p tcp -j REJECT --reject-with tcp-reset
$IPT -A INPUT -j REJECT --reject-with icmp-proto-unreachable

$IPT -A OUTPUT -p icmp -m conntrack --ctstate INVALID -j DROP

#SSH
$IPT -A TCP -s 192.168.0.0/24 -p tcp --dport 22 -j ACCEPT

For now I am using slightly modified rules from here, what is working but I do not know if they are enough to a box that will be on DMZ.

Another question is: if using just one interface, and I am, ext_if/int_if should be set with it for both, or is there another more proper way to do that.

Many thanks! :)
 
I'm no expert, but I can offer up my pf.conf as an example...
Code:
root@kif:~/firewall.d # cat pf.conf
############ Global Options #######################
ext_if="em0"
int_if="re0"
set block-policy return
set loginterface $ext_if
set skip on lo

services="{ 80, 9987 } "
icmp_types="echoreq"
localnet="192.168.1.0/24"
ext_ip="x.x.x.x"
int_ip="192.168.1.1"
LR="x.x.x.x"

table <us.blocks> persist file  "/root/firewall.d/us.blocks"
table <aliens> persist file "/root/firewall.d/aliens.blocks"
table <bruteforce> persist file "/root/firewall.d/bruteforce"
table <trusted.ips> persist file "/root/firewall.d/trusted.ips"
table <authpf_users> persist

################ End Global Options ################

########### Traffic Normalization ##################

scrub in on $ext_if all fragment reassemble
scrub out on $ext_if all fragment reassemble

####################################################


####### NAT RULE GOES BEFORE ALL FILTERS ! ! #######

nat on $ext_if from $localnet to any -> ($ext_if)

####################################################

## REDIRECT RULES AFTER NAT AND BEFORE FILTERS !! ##

#rdr on $ext_if inet proto tcp from $LR to port 22 -> 192.168.1.11
rdr-anchor "authpf/*" from <authpf_users>

####################################################

################## Filters #########################

block in log all

pass in quick on $ext_if inet proto tcp from $LR to port 2222 flags any

block drop log quick inet from <bruteforce>
block drop log quick on $ext_if inet from $localnet to <aliens>
block drop in log quick on $ext_if inet from <aliens> to $ext_ip
block drop in log quick on $ext_if inet from ! <us.blocks> to $ext_ip
block drop in log quick on $ext_if inet from <asshole.ips> to $ext_ip

pass in log on $ext_if inet proto tcp from any \
  to { $ext_ip, $localnet } port 22 \
  flags S/SA keep state \
  (max-src-conn 5, max-src-conn-rate 3/9, \
  overload <bruteforce> flush global)

pass in on $ext_if inet from { $localnet, $ext_ip } to any
pass out on $ext_if inet from $ext_ip to any
pass in on $int_if inet from any to any
pass out on $int_if inet from any to any
pass in log on $ext_if inet proto {udp, tcp} from any \
  to $ext_ip port $services

anchor "authpf/*" from <authpf_users>


####################################################
################### <END OF FILE> ##################
####################################################

I've learned quite a bit from these forums, and I'd be glad to help you anyway I can. However, I know about as much about IP Tables as my wife knows about FreeBSD PF... But, shoot questions and I'd be glad to help where I can.
 
This should do almost the same:
Code:
set skip on lo0

block in all
block return in proto tcp

pass in proto icmp all icmp-type echoreq
pass in proto tcp from 192.168.0.0/24 port 22

NB it's a bad idea to respond with ICMP port unreachable on UDP packets. Although the RFCs suggest that you should you're setting yourself up to be abused. Just drop that traffic. Although there has been quite a lot of discussions regarding a TCP RST vs. just dropping the traffic, returning a RST on closed TCP ports should be fine.
 
fullauto2012 and SirDice

Today at night I will try to make my own. Indeed PF seems to be quite more simple and interesting than IPTABLES.
I changed to DROP for UDP packages on IPTABLES.

Thanks!
 
So that was faster than I thought:

Code:
one_if = "rl0"
tcp_pass = "{ 22 53 80 }"
udp_pass = "{ 53 }"
icmp_types = "echoreq"

table <local> { 192.168.0.0/24, 192.168.1.0/24 }

set block-policy return
set loginterface $one_if
set skip on lo0

scrub out on $one_if all fragment reassemble random-id
scrub in on $one_if all fragment reassemble

antispoof log quick for $one_if inet

block log all

pass inet proto icmp all icmp-type $icmp_types keep state
pass inet proto icmp from <local> to any keep state

pass out proto tcp to $one_if port $tcp_pass keep state
pass out proto udp to $one_if port $udp_pass keep state

#anchor ftpanchor
pass out proto tcp to any port 21 keep state #to become anchor
pass out proto tcp to any port > 1023 keep state #to become anchor

pass in proto tcp from any to $one_if port 80 synproxy state
pass in quick proto tcp from <local> to $one_if port $tcp_pass
pass in quick proto udp from <local> to $one_if port $udp_pass

I hope I did nothing retard there. :)

EDIT: minor.
EDIT2: fixing several mistakes.
EDIT3: more mistakes fixed.
 
It is more or less working but I got

Code:
Fetching metadata signature for 10.3-RELEASE from update6.freebsd.org... failed.

when running freebsd-update fetch with PF running.
 
Code:
hostname="server"
ifconfig_rl0="inet 192.168.0.254 netmask 255.255.255.0"
defaultrouter="192.168.0.1"

pf_enable="YES"

local_unbound_enable="YES"
sshd_enable="YES"
ntpd_enable="YES"
powerd_enable="YES"

keymap="br275.cp850"

dumpdev="AUTO"
 
These two rules seem to be out of place:
Code:
pass out proto tcp to $one_if port $tcp_pass keep state
pass out proto udp to $one_if port $udp_pass keep state
I'm assuming this is to allow outgoing DNS requests. The rule is more or less conflicting with itself, there's no traffic going out the interface that's directed to the interface. Traffic that's destined for the IP address of the interface never actually leaves the machine, it doesn't even 'touch' the interface.

You want something like this:
Code:
pass out on $one_if proto {tcp,udp} from ($one_if) to any port 53
This allows traffic going out the one_if interface with the source address of that interface.

As you have a block all rule (this blocks everything in and out), you will also need to allow outgoing traffic (to update.freebsd.org for example). I normally trust my machines and network so I tend to only block incoming traffic and simply allow everything going out. Less fuss, easy to maintain.

NB. There's no need to use keep state, it's implied on all the rules.
 
Controlling outgoing traffic by port numbers only is harder than you think. The classic case is the BitTorrent protocol where the destination port can be just about anything imaginable because the client allows the user to set the listening port to whatever he/she wishes. If you want to control outgoing and do it right you should look at a proxy such as Squid.
 
I think this one is working fine:

Code:
one_if = "rl0"
tcp_pass = "{ 22 53 80 }"
udp_pass = "{ 53 }"
icmp_types = "echoreq"

table <local> { 192.168.0.0/24, 192.168.1.0/24 }

set block-policy
set loginterface $one_if
set skip on lo0

scrub out on $one_if all fragment reassemble random-id
scrub in on $one_if all fragment reassemble

antispoof log quick for $one_if inet

block log all

pass inet proto icmp all icmp-type $icmp_types keep state
pass inet proto icmp from <local> to any keep state

pass out all

pass in proto tcp from any to $one_if port 80 synproxy state
pass in quick proto tcp from <local> to $one_if port $tcp_pass
pass in quick proto udp from <local> to $one_if port $udp_pass

Thanks!
 
Back
Top