On 5/9/06, Ashley Moran <[EMAIL PROTECTED]> wrote:
I'm trying to put together a firewall for our DMZ and internal network.  For
some reason, a server in the DMZ can only hit the external DNS server if it
has keep state on the DMZ interface.   Basically the following (relvant
extract) blocks access:
You're way off on what you're trying to do and need to seriously
consider re-reading the PF FAQ and/or trying the examples.  This being
said...

  ext_if           = "vr0"
  dmz_if           = "em0"

  dmz_tcp_services_out = "{ http, https, ftp, ntp, domain }"
  dmz_tcp_services_in  = "{ http, https, ssh }"
  dmz_udp_services_in  = "{ ntp }"
  dmz_udp_services_out = "{ domain }"

Avoid using lists until you know what purpose they serve and are ready
to aggregate rules!

  webserv2_dmz_ad = "{ 10.0.0.4 }"
  webserv2_ext_ad=  "..."

  tcp_opts = "modulate state" # gave up on synproxy state
synproxy works fine, but you need to know why you'd want to use it and
there's no point in using it for a connection that terminates to a
service at the host running the PF ruleset itself.

  udp_opts = "keep state"
  icmp_opts = "keep state"
These are just making the waters muddy -- if you use 'flags S/SA
modulate state' for all connections, PF will interpret what you mean
for udp and icmp connections -- try it out.

  nat_proto = "{ tcp, udp, icmp }"
ew?  Don't do this.

  scrub all reassemble tcp
  scrub in all fragment reassemble
  scrub out all random-id

  nat on $ext_if proto $nat_proto \
    from $webserv2_dmz_ad -> $webserv2_ext_ad
  rdr on { $ext_if, $int_if } proto tcp \
    from any to $webserv2_ext_ad port www -> $webserv2_dmz_ad port www

  block in log (all) all
  block out log (all) all
You can just use 'block log' to simplify this -- the rest is implied
and unnecessary.

  antispoof log quick for $antispoof_if
$antispoof_if is undefined

  pass out on $ext_if proto tcp \
    from any to any $tcp_opts
  pass out on $ext_if proto udp \
    from any to any $udp_opts
  pass out on $ext_if inet proto icmp \
    from any to any $icmp_opts
Ok, so this whole mess could be rewritten as follows, though I wonder
why you would do it in such a fashion:
pass out on $ext_if proto {tcp, udp, icmp} from any to any modulate state
- or -
pass out on $ext_if proto {tcp, udp, icmp} modulate state

  pass in on $dmz_if proto tcp \
    from $dmz_ad to any port $dmz_tcp_services_out #$tcp_opts
  pass in on $dmz_if proto udp \
    from $dmz_ad to any port $dmz_udp_services_out #$udp_opts
  pass in on $dmz_if proto icmp \
    from $dmz_ad to any #$udp_opts
Blah, don't use complicating macros while you're learning PF!


Call dig with this setup and it times out; uncomment the options
(modulate/keep) state and you get a DNS result.  I was under the impression
that the state should be created as the packets leave $ext_if, so why is it
necessary to put a state option in the DMZ interface rules?

Hope someone can clear this up
I'm just not sure what it is you're trying to accomplish.  Is this
simply a two-interface firewall that is performing NAT for a web/dns
server to the outside world?

Here is a quick sample -- performs NAT on the external interface to
the dmz interface for http/https/dns and also permits dns/ntp queries
from the webserver to anyone.

#--{ Interface definitions }--
ext_if = "vr0"
dmz_if = "em0"

#--{ Host definitions }--
webserver_dmz = "10.0.0.4"
webserver_ext = "4.3.2.1"

#--{ scrub directives }--
scrub all reassemble tcp
scrub in all fragment reassemble
scrub out all random-id

#--{ NAT/RDR/BINAT }--
nat on $ext_if inet proto {tcp, udp, icmp} $webserver_dmz -> $webserver_ext
rdr on $ext_if inet proto tcp to $webserver_ext port 80 ->
$webserver_dmz port 80
rdr on $ext_if inet proto tcp to $webserver_ext port 443 ->
$webserver_dmz port 443
rdr on $ext_if inet proto {tcp, udp} to $webserver_ext port 53 ->
$webserver_dmz port 53

#--{ Default Deny }--
block log

#--{ Permit global SANITIZED traffic to exit opposing interface }--
pass out quick inet tagged SANITIZED modulate state

#--{ Permit anyone to reach the DMZ webserver with HTTP/HTTPS/DNS }--
pass in on $ext_if inet proto tcp to $webserver_dmz port {80, 443} \
 flags S/SA synproxy state tag SANITIZED
pass in on $ext_if inet proto {tcp, udp} to $webserver_dmz port 53 \
 flags S/SA synproxy state tag SANITIZED

#--{ Permit the DMZ webserver to make DNS and NTP queries }--
pass in on $dmz_if inet proto {tcp, udp} from $webserver_dmz to port 53 \
 flags S/SA modulate state tag SANITIZED
pass in on $dmz_if inet proto udp from $webserver_dmz to port 123 \
 keep state tag SANITIZED

#--{ Permit some ICMP from the webserver }--
pass in on $dmz_if inet proto icmp from $webserver_dmz \
 tag SANITIZED icmp-type { echorep, echoreq, trace, timex } keep state

pfctl -sa is your friend -- examine the changes you make before and
after ruleset load so you can see how PF expands rules.  The
policy-based routing tags will also simplify your life so you only
have to manage inbound traffic (excepting the firewall's requests
itself - ssh, ntp, dns, et al).

Reply via email to