Solved PF Setup for DMZ

Hello everyone!

I'm trying to add a DMZ to my current home "setup".
Up to now I have managed to have (in a small fanless card) PPPoE,
Router, DHCP, DNS and Firewall. I recently added an additional nic, to
make a DMZ (nothing special, hosting a blog, and little else). At
this point, however, I would like to understand if the Firewall part
makes sense, and above all how to add some things.

Basically, of course, I want the LAN to be able to talk quietly to hosts in the DMZ, while I don't want the opposite to happen.
I came up with more or less this configuration:

Code:
### Firewall Configuration ###

##############################
# Macro
##############################

## Network Interfaces
ext_if="tun0"
int_if="re1"
dmz_if="re2"

## Hosts
lan="192.168.1.0/24"
server="192.168.1.3"
desktop="192.168.1.4"
webserver="192.168.2.10"

tcp_services = "{www, http, https}"
torrent = "{51413}"
udp_services = "{domain, ntp}"

##############################
# Options
##############################

## Skip all Pf process on interface
set block-policy drop
set skip on lo
scrub in

##############################
# NAT
##############################

nat on $ext_if inet from ! ($ext_if) to any -> ($ext_if)

#############################
# Port Forwarding
#############################

## Allow access to webserver
rdr pass on $ext_if inet proto tcp from any to any port $tcp_services -> $webserver

##############################
# Filter Rules
##############################

## Default Policy (Blacklist)
block log all

# Allow access to dmz from lan
pass in on $dmz_if from $lan to any keep state

# Allow outgoing and keep state
pass out keep state

## Allow traffic on lan
pass quick on $int_if no state

At this point i don't understand how to grant access to the internet to the DMZ, but don't let it connect to any of the hosts in the LAN.
 
Code:
rdr pass on $ext_if inet proto tcp from any to any port $tcp_services -> $webserver
I would remove the pass from here and put it in a separate rule. The downside of rdr pass is that this will always allow the traffic and will ignore any other rules. You may want to add some blocking rules later on to keep abusers out. Those rules would then get ignored.
Code:
rdr on $ext_if inet proto tcp from any to ($ext_if) port $tcp_services -> $webserver

pass in on $ext_if proto tcp from any to $webserver port $tcp_services
pass out on $dmz_if proto tcp from any to $webserver port $tcp_services


Code:
# Allow access to dmz from lan 
pass in on $dmz_if from $lan to any keep state
This doesn't make sense. You're allowing traffic to come in on $dmz_if but it has to have a $lan source address? That should never happen.
This makes more sense:
Code:
pass in on $int_if from $lan to $dmz_if:network 
pass out on $dmz_if from $lan to $dmz_if:network

I want the LAN to be able to talk quietly to hosts in the DMZ
As opposed to shouting to the hosts? What do you mean by "talk quietly"?
 
I would remove the pass from here and put it in a separate rule. The downside of rdr pass is that this will always allow the traffic and will ignore any other rules. You may want to add some blocking rules later on to keep abusers out. Those rules would then get ignored.
Code:
rdr on $ext_if inet proto tcp from any to ($ext_if) port $tcp_services -> $webserver

pass in on $ext_if proto tcp from any to $webserver port $tcp_services
pass out on $dmz_if proto tcp from any to $webserver port $tcp_services
So with rdr pass, will always allow the traffic and ignore the rest, but with rdr it will go through the other rules?
This doesn't make sense. You're allowing traffic to come in on $dmz_if but it has to have a $lan source address? That should never happen.
This makes more sense:
Code:
pass in on $int_if from $lan to $dmz_if:network
pass out on $dmz_if from $lan to $dmz_if:network
with those rules i can connect to the dmz from the lan, but cannot access internet from the dmz..
should i add some rules to allow traffic go out of the dmz?
As opposed to shouting to the hosts? What do you mean by "talk quietly"?
Ahahah Ups :| That was a "typo". I mean, i just want that the DMZ can access internet, but cannot access the LAN hosts. But obviously i want to reach the DMZ from the lan hosts.
 
So with rdr pass, will always allow the traffic and ignore the rest, but with rdr it will go through the other rules?
Correct.

with those rules i can connect to the dmz from the lan, but cannot access internet from the dmz..
should i add some rules to allow traffic go out of the dmz?
Code:
pass in on $dmz_if from $dmz_if:network to any
Or if you don't want it to allow back in on $lan:
Code:
pass in on $dmz_if from $dmz_if:network to ! $lan
 
Thanks a lot :)
I've only two questions:
1) Does this kind of "setup" sounds good for a home usage? For hosting simple services.

2) What exactly means $interface:network ?
The current ip of the interface?
 
Does this kind of "setup" sounds good for a home usage? For hosting simple services.
I have something similar. Slightly more complex but I have a lot more stuff.

What exactly means $interface:network ?
It's the network address(es) associated with that interface. So you don't have to "hardcode" them.
Code:
           Interface names and interface group names can have modifiers
           appended:

           :network      Translates to the network(s) attached to the
                         interface.
           :broadcast    Translates to the interface's broadcast address(es).
           :peer         Translates to the point-to-point interface's peer
                         address(es).
           :0            Do not include interface aliases.
 
I have something similar. Slightly more complex but I have a lot more stuff.
Great! Thanks :)
Also I would like (for "didactic" reasons) to try to put the various services in the dmz in jails.
If i have a jail ( for a webserver ) with a static IP (192.168.2.11)
can i redirect traffic directly in the jail?

It's the network address(es) associated with that interface. So you don't have to "hardcode" them.
Code:
           Interface names and interface group names can have modifiers
           appended:

           :network      Translates to the network(s) attached to the
                         interface.
           :broadcast    Translates to the interface's broadcast address(es).
           :peer         Translates to the point-to-point interface's peer
                         address(es).
           :0            Do not include interface aliases.
Oki Thanks :)
 
If i have a jail ( for a webserver ) with a static IP (192.168.2.11)
can i redirect traffic directly in the jail?
Sure. But keep in mind that you can redirect a port only to one machine. So it's not possible to use redirection on port 80 for example and have it redirect to two different websites. It will work but it's going to use a round-robin style redirection (first request will go to server 1, second to server 2, third to server 1, etc), which is no good if there's two different websites. In that case you can set up something like net/haproxy, this is a so-called "reverse" proxy and it can switch to different backends based on the HTTP host header. That way you can run different websites on one IP address and have it "forward" the request to different backends based on the URL.
 
Sure. But keep in mind that you can redirect a port only to one machine. So it's not possible to use redirection on port 80 for example and have it redirect to two different websites. It will work but it's going to use a round-robin style redirection (first request will go to server 1, second to server 2, third to server 1, etc), which is no good if there's two different websites. In that case you can set up something like net/haproxy, this is a so-called "reverse" proxy and it can switch to different backends based on the HTTP host header. That way you can run different websites on one IP address and have it "forward" the request to different backends based on the URL.
Oh nice :) Actually it's not a problem, but thanks for the suggestion :)
i've setup a jail ( i want to try obhttpd ) but somehow i can't access internet within the jail:

(host) rc.conf:
Code:
jail_enable="YES"
jail_list="httpd"

(host) jail.conf:
Code:
$jail_path="/jail";
path="$jail_path/$name";

# 2. begin - default configuration for all jails

# Some applications might need access to devfs
mount.devfs;

# Clear environment variables
exec.clean;

# Initialisation scripts
exec.start="sh /etc/rc";
exec.stop="sh /etc/rc.shutdown";

# Specific jail configuratin
httpd {
    host.hostname = webserver;
    ip4.addr = 192.168.2.11;
}

(jail) rc.conf:

Code:
sshd_enable="YES"
powerd_enable="YES"
dumpdev="AUTO"
obhttpd_enable="YES"

Am i missing something?
 
Add an interface = so the jail is bound to the external interface of the host. For LAN situations that's the easiest way as you can easily connect more IP addresses to the external interface of the host. Then it'll be just another host on the network.
 
Add an interface = so the jail is bound to the external interface of the host. For LAN situations that's the easiest way as you can easily connect more IP addresses to the external interface of the host. Then it'll be just another host on the network.
You mean something like:
(host) rc.conf:
Code:
cloned_interfaces = "lo1"
And then in jails.conf

Code:
jail {
  ip4.addr = "lo1|192.168.2.11";
}

?

P.S: Should i have pf running also in the dmz machines ?
My question is more a matter of good practice..
 
No, don't clone the interface. That's a solution if you only have one external IP address on the host. But this requires setting up NAT and redirections on it too. In your case that's not necessary, your host is running on a LAN and you can easily add another IP address to that host.

So if the host for example has this:
Code:
ifconfig_em0="inet 192.168.2.2 netmask 255.255.255.0"
You use em0 on the jail to bind to:
Code:
myjail {
  ip4.addr = 192.168.2.11;
  interface = em0;
...
}

There's no need to add another NAT layer here, that will only complicate things.
 
No, don't clone the interface. That's a solution if you only have one external IP address on the host. But this requires setting up NAT and redirections on it too. In your case that's not necessary, your host is running on a LAN and you can easily add another IP address to that host.
Oh should i clone the interface if i'm in a VPS for example right?

So if the host for example has this:
Code:
ifconfig_em0="inet 192.168.2.2 netmask 255.255.255.0"
You use em0 on the jail to bind to:
Code:
myjail {
  ip4.addr = 192.168.2.11;
  interface = em0;
...
}

There's no need to add another NAT layer here, that will only complicate things.
That works neat! you are a kind of magician, you always solved any problem for me!
Thanks :)
 
Oh should i clone the interface if i'm in a VPS for example right?
Yes, then you only have one external IP address, so you can't easily add a new IP address to the interface. Then you use the trick with a cloned lo1 interface to circumvent that limitation.
 
Back
Top