Solved pf redirect LAN users to DMZ when accessing external IP

Hello,

I have an internal web server ip: 10.1.2.2, that is placed in a DMZ. It is exposed to the internet by binating it to an external ip: 123.123.123.3. I want LAN users to be able to access it when they use that external ip. (In this case, by using a domain name, service.mywebsite.com which resolves to 123.123.123.3

My example setup (FreeBSD 10):

Code:
ifconfig em0 inet 123.123.123.2/24 # WAN
ifconfig em0 inet 123.123.123.3/24 # Web server external address for BINAT
ifconfig em1 inet 10.1.1.1/24 # LAN
ifconfig em2 inet 10.1.2.1/24 # DMZ
route add default 123.123.123.1 # gateway

pf.conf
Code:
WAN=em0
LAN=em1
DMZ=em2

set skip on lo0

scrub in all fragment reassemble

nat on $WAN from 10.1.1.0/24 to any -> 123.123.123.2 # NAT LAN
nat on $WAN from 10.1.2.0/24 to any -> 123.123.123.2 # NAT DMZ
binat on $WAN from 10.1.2.2 to any -> 123.123.123.3 # BINAT DMZ web server

rdr pass on $LAN proto tcp from any to 123.123.123.3 port http -> 10.1.2.2 port http # redirect LAN users to an internal ip when they access the external ip

block in all
block out all

antispoof quick for $WAN
antispoof quick for $LAN
antispoof quick for $DMZ

pass in quick on $WAN proto icmp from any to $WAN icmp-type echoreq keep state # allow ping to router
pass in quick on $WAN proto tcp from any to $WAN port ssh keep state # allow ssh to router
pass in quick on $WAN from any to 10.1.2.2 keep state # allow traffic to enter to internal ip after binat

pass out quick on $WAN

pass in quick on $LAN from $LAN:network to any keep state # LAN users access
pass out quick on $LAN from $LAN:network to any keep state

pass out quick on $DMZ from $LAN:network to any keep state # allow LAN users to access DMZ
pass out quick on $DMZ from $DMZ to any keep state # router access to DMZ

The problem:

This setup works, however I am totally confused how to make it to work without using the pass keyword on the rdr rule:

Code:
rdr pass on $LAN proto tcp from any to 123.123.123.3 port http -> 10.1.2.2 port http

I want to do further processing on the packet in my ruleset and not unconditionally let it through as it is the case with pass

It would seem to me that I can easily drop the pass keyword, because I do let such traffic in these rules:

Code:
pass in quick on $LAN from $LAN:network to any keep state # LAN users access
pass out quick on $LAN from $LAN:network to any keep state

pass out quick on $DMZ from $LAN:network to any keep state # allow LAN users to access DMZ

An IP packet like e.g this:

Code:
iface: em1, src: 10.1.1.3, dst: 123.123.123.3

should simply be turned to this:

Code:
iface: em1, src: 10.1.13, dst: 10.1.2.2

Unfortunately it doesn't work if I remove pass from it.

I do have a very restrictive ruleset (default-deny) so is there anything I should additionally allow to make the rdr rule work without pass?

Thank you!
 
Last edited by a moderator:
The rule can be rewritten as separate rules, one rdr rule and one pass rule:

Code:
rdr on $LAN proto tcp from any to 123.123.123.3 port http -> 10.1.2.2
...

# Filter rules
...
pass in on $LAN proto tcp from any to 10.1.2.2 port http

Now you can tighten/loosen the pass rule as you like.

Your pass out rule is not enough because it only covers traffic leaving out via the DMZ interface, there must be a rule that allows traffic in via the LAN interface.
 
Back
Top