pf gateway - having a little trouble

Hey guys,

First off, I would like to tell you all this is my first experience with pf. So I apologise if the solution is a simply and blatantly obvious fix :e

Now I am trying to set up a new gateway to replace the old FreeBSD 6.x version that we have running. While doing the upgrade I thought it would be a good time to implement a new firewall, and had read that pf was a good alternative for performance and features. The gateway is to be used in a school environment so controlling outgoing connections is as important as incoming ones. We don't want the little kiddies to be able to get out on the internet without using the proxy server.

The problem I am having with my firewall rules is I cannot get certain IP addresses to 'bypass' the stricter filtering rules. These addresses include servers will need direct access to the net as things just don't work well through the proxy.

Code:
####################################################################################
#
#	St Martins Lutheran College PF Firewall
#	Version: 1.0
#	Author: Shayne Jellesma (donotpostemailaddresses@forumsplease)
#
#####################################################################################

# define macros and some settings
ext_if="tun0"
int_if="em1"

set skip on lo0
scrub in

# Load the tables
table <blocked_ips> file "/usr/local/etc/pf/blocked_ips"
table <full_access_ips> file "/usr/local/etc/pf/full_access_ips"
table <fail2ban> persist


# Ports allowed to be contacted from the outside world
tcpAllowedINServices="{ 22, 25, 80, 143, 110, 993, 995, 1723, 1701, 4500,500 }"
udpAllowedINServices="{ 500, 4500, 1701 }"
tcpAllowedOUTServices="{ 3128, 110, 25, 443 }"
udpAllowedOUTServices="{ 80 }"



# External Port Forwarding - VPN Stuff
rdr proto {udp tcp} from any to ($ext_if:0) port 500 -> 192.168.3.1
rdr proto gre from any to ($ext_if:0) -> 192.168.3.1
rdr proto {udp tcp} from any to ($ext_if:0) port 1723 -> 192.168.3.1
rdr proto {tcp udp} from any to ($ext_if:0) port 1701 -> 192.168.3.1
rdr proto {tcp udp} from any to ($ext_if:0) port 4500 -> 192.168.3.1


# Remote desktop redirections
rdr pass proto {udp tcp} from 203.122.192.41 to ($ext_if:0) port 27587 -> 192.168.0.55 port 3389 	# Shayne Jellesma - ITOFFICE
rdr pass proto {udp tcp} from 150.101.96.136 to ($ext_if:0) port 27168 -> 192.168.0.135 port 3389	# Wendy Button - FINANCE
rdr pass proto {udp tcp} from 121.215.177.246 to ($ext_if:0) port 29126 -> 192.168.0.118 port 3389	# Carroll Cailler - ARKOFFICE


# Do NAT for anything leaving the external interface
nat on $ext_if from !($ext_if) -> ($ext_if:0)


##
##
# Filters
##
##


# Fail2Ban blocking and other permenant blocking
block in quick on $ext_if from <fail2ban>
block in quick on $ext_if from <blocked_ips>


# Default block policy and antispoof
block log (all, to pflog0) all
block return
antispoof for $ext_if


# Allow public services
pass in on $ext_if inet proto tcp from any to any port $tcpAllowedINServices keep state
pass in on $ext_if inet proto udp from any to any port $udpAllowedINServices keep state
pass in on $ext_if proto {tcp udp} from { 192.231.203.132, 192.231.203.3 } to any port 53 keep state
pass in on $ext_if proto {icmp gre} from any to any
pass in on $ext_if from <full_access_ips> to any


# Allow LAN to do anything
pass in on $int_if from $int_if:network to any keep state
pass out on $int_if from any to $int_if:network keep state


# Allow certain outbound traffic and block the rest
pass out on $ext_if proto tcp from any to any port $tcpAllowedOUTServices keep state
pass out on $ext_if proto udp from any to any port $udpAllowedOUTServices keep state
pass out on $ext_if proto icmp all keep state
pass out on $ext_if proto esp from any to any keep state
pass out on $ext_if proto {udp tcp} from any to { 192.231.203.132, 192.231.203.3 } keep state

# Allow certain hosts to have no restrictions through the firewall
pass out on $ext_if from <full_access_ips> to any keep state

The full_access_ips table is pulled in from a file which has a list of local IP addresses and it is being populated.

Code:
david# pfctl -t full_access_ips -T show
No ALTQ support in kernel
ALTQ related functions disabled
   192.168.0.55
   192.168.3.253
david#

So I am trying to allow 192.168.0.55 to have full access to the outside world. They can open up a connection on any port.
The rest of the network I want restricted to only use ports in the $xxxAllowedOUTServices macros.


It doesn't matter if I put a specific rule at the bottom such as
Code:
pass out on $ext_if from 192.168.0.55 keep state
If I use a pass out on $ext_if rule than it all works like it should.

I am at a loss and have spent many hours looking reading examples and documentation to see what's going on and have come up empty. Hopefully I have provided enough information and haven't gone out on a tangent somewhere (which I have a tendency to do)

Anyone got any ideas?
 
You need to keep in mind with PF that if it hits a matching rule the processing doesn't stop.

For example:
Code:
pass out from 1.2.3.4 to any keep state
block out from any to any

Traffic from 1.2.3.4 to any matches the first rule. However the processing doesn't stop so the next rule is also checked. That also matches and the last 'state' is used so the traffic is blocked.

There are two ways to solve this, the first is to change the order:
Code:
block out from any to any
pass out from 1.2.3.4 to any keep state

The other solution is to use the quick keyword. This will 'short-circuit' the rules i.e. it will stop processing the other rules if it matches:
Code:
pass out quick from 1.2.3.4 to any keep state
block out from any to any

So if you want to force all your user to a proxy except a few servers use something like this:
Code:
pass in on $int_if from any to $proxy_server keep state
pass in on $int_if from $servers to any keep state
This will force all traffic to $proxy_server except traffic from $servers.
 
Thanks SirDice for your reply.

Though, correct me if I am wrong, doesn't my rules follow the order for the first solution?

In the 'Filters' section I have the following which blocks all:
Code:
# Default block policy and antispoof
block log (all, to pflog0) all
block return
antispoof for $ext_if

Then at the bottom of the rules (last line) I have the explicit rule which allows the servers out on $ext_if
Code:
# Allow certain hosts to have no restrictions through the firewall
pass out on $ext_if from <full_access_ips> to any keep state


And I have tried to place a rule with the quick option which also has no effect. Its like the rule is not getting evaluated as if I put a pass out on $ext_if from any to any keep state rule after on the last line then all traffic os obviously allowed out. Even if I try a rule which only allows my computer out without using the table it still does not work.
 
Hm, sounds odd. The rules look ok. Although this one doesn't make sense, if I understand your intentions correctly:
Code:
pass in on $ext_if from <full_access_ips> to any
Your IPs in that table are local ones, and ext_if is using NAT, so those IPs will never be valid from outside. That's got nothing to do with your problem, though ;)

Have you checked what...
Code:
tcpdump -i em1 -n -vv host 192.168.0.55
...has to say?

That IP is definitely correct, too? (Sometimes problems are that simple to solve, but you don't see it when you've looked at it for a long time)

The fact that you get blocked, when you specify the client IP explicitly, but get through when you don't, makes me suspicious there. :) How exactly have you established that anyway? Just ping or any other protocols/ports, too?
 
The IP is definitely correct.

I cannot gain access to the internet on port 80. I have blocked this port so people would be forced to use the proxy server or it simply won't work. The IPs in the table are meant to bypass all that and be allowed full access without any firewall intervention. On the way out at least.

That tcpdump command managed to capture 11k packets in about 15 seconds, what should I be looking for in there?
 
Still have not found a solution. I have simplified the rules for testing, hoping that it would work and i could then work backwards to find out what I did wrong. Unfortunately no.

Provided some more info in hoping that something will jump out at someone.

ifconfig on the gateway:
Code:
david# ifconfig
em0: flags=8802<BROADCAST,SIMPLEX,MULTICAST> metric 0 mtu 1500
        options=219b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,TSO4,WOL_MAGIC>
        ether f4:ce:46:31:e9:15
        media: Ethernet autoselect
        status: no carrier
em1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        options=209b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,WOL_MAGIC>
        ether 00:1b:21:6d:6b:50
        inet 10.65.43.254 netmask 0xfffffc00 broadcast 10.65.43.255
        media: Ethernet autoselect (1000baseT <full-duplex>)
        status: active
em2: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        options=209b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,WOL_MAGIC>
        ether 00:1b:21:6d:6b:4e
        media: Ethernet autoselect (100baseTX <full-duplex>)
        status: active
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
        options=3<RXCSUM,TXCSUM>
        inet6 fe80::1%lo0 prefixlen 64 scopeid 0x4
        inet6 ::1 prefixlen 128
        inet 127.0.0.1 netmask 0xff000000
        nd6 options=3<PERFORMNUD,ACCEPT_RTADV>
pflog0: flags=141<UP,RUNNING,PROMISC> metric 0 mtu 33152
tun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1492
        options=80000<LINKSTATE>
        inet 150.xxx.xxx.xxx --> 203.xxx.xxx.xxx netmask 0xffffffff
        Opened by PID 473
david#

ipconfig on the windows machine which is meant to bypass the firewall:
Code:
Connection-specific DNS Suffix  . : smlc.int
   Link-local IPv6 Address . . . . . : fe80::3549:3d1a:6fed:cb8%11
   IPv4 Address. . . . . . . . . . . : 10.65.40.101
   Subnet Mask . . . . . . . . . . . : 255.255.252.0
   Default Gateway . . . . . . . . . : 10.65.43.254

Current simplified rules:
Code:
# Macros
ext_if="tun0"
int_if="em1"

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

# Default rule block all
block log all

# Allow lan traffic
pass in on $int_if from $int_if:network to any keep state
pass out on $int_if from any to $int_if:network keep state

# Outbound rules
pass out on $ext_if from 10.65.40.101 to any keep state

# Inbond rules
pass in on $ext_if proto tcp from any to any port mail

Freebsd uname -a:
Code:
david# uname -a
FreeBSD david.stmartins.sa.edu.au 8.1-RELEASE FreeBSD 8.1-RELEASE #0: Mon Jul 19 02:36:49 UTC 2010     root@mason.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  amd64
david#
 
Back
Top