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).