BSD DevCenter
oreilly.comSafari Books Online.Conferences.

advertisement


Changes in pf: More on NAT
Pages: 1, 2

If you have limited resources, you could run multiple servers on the same machine residing in the DMZ network segment, but that increases the odds of someone finding a vulnerability, so you must weigh the odds for yourself.



  • dmz_domain_pr = "{tcp, udp}": packets sent to the DNS server port 53 on the firewall's external interface using the protocols listed in this macro definition will be redirected to the DNS server residing in your DMZ segment. (The DMZ DNS server should not be listening on a port lower than 1024.) In this case, we are redirecting TCP and UDP packets, but not all services need both tcp and udp packets. DNS is something of an exception, because it uses both. Most popular services use TCP, and you should block UDP packets sent to servers that only use TCP. If you do not know which services use which protocol, check /etc/protocols. This file is current as of the time of release of the OpenBSD system you are using. The latest and freshest listings are always in the IANA's online database, though it rarely changes much between consecutive OpenBSD releases.

  • dmz_www_pr = "{tcp}": packets sent to the HTTP server port on the firewall's external interface using the protocols listed in this macro definition will be redirected to the HTTP server residing in your DMZ segment. In this case, we are redirecting only TCP packets. Redirecting UDP packets to an HTTP server is asking for trouble. Again, the HTTP server should not be listening on an unprivileged port (< 1024).

  • dmz_smtp_pr = "{tcp}": packets sent to the SMTP server port on the firewall's external interface using the protocols listed in this macro definition will be redirected to the SMTP server residing in your DMZ segment. Also, see notes on dmz_domain_pr and dmz_www_pr.

  • dmz_ftp_pr = "{tcp}": packets sent to the FTP server port on the firewall's external interface using the protocols listed in this macro definition will be redirected to the FTP server residing in your DMZ segment. Also, see notes on dmz_domain_pr and dmz_www_pr.

  • Related Reading

    BGP
    Building Reliable Networks with the Border Gateway Protocol
    By Iljitsch van Beijnum

  • dmz_nntp_pr = "{tcp}": packets sent to the NNTP server port on the firewall's external interface using the protocols listed in this macro definition will be redirected to the NNTP server residing in your DMZ segment. Also, see notes on dmz_domain_pr and dmz_www_pr.

  • dmz_domain_pt = "2053": the port on which the DMZ DNS server is listening. You can choose another port, of course, as long as your DNS server software allows it.

  • dmz_www_pt = "8080": the port on which the DMZ HTTP server is listening. You can choose another port, as long as your HTTP server software allows it.

  • dmz_smtp_pt = "2025": the port on which the DMZ SMTP server is listening. You can choose another port, as long as your SMTP server software allows it.

  • dmz_ftp_pt = "2020": the port on which the DMZ FTP server is listening. You can choose another port, as long as your FTP server software allows it.

  • dmz_nntp_pt = "2119": the port on which the DMZ NNTP server is listening. You can choose another port, as long as your NNTP server software allows it.

  • set limit { frags 10000, states 10000 }: these values must be set experimentally, depending on the amount of RAM in your firewall. Consult the previous article for additional information on these limits. You do not need to set these limits in all circumstances, but it is prudent to do so.

  • set loginterface $ext_if: use this rule to collect statistics on a particular interface. Change $ext_if to $prv_if or $dmz_if if you want to collect these stats on interfaces other than $ext_if. The new pf(4), coming in OpenBSD 3.3, will allow multiple set loginterface rules. Consult the previous article for additional information on these rules. You do not need to set this rule in all circumstances, but it is handy.

  • set optimization default: consult the previous article for additional information on these and timeout rules. You do not need to set this rule in all circumstances.

  • scrub in all fragment reassemble: you need this rule for incoming packets. Consult the previous article for additional information.

  • scrub out all fragment reassemble: in a perfect world, you'd always scrub packets leaving your network, but this costs memory and CPU time, and you may not always afford to be a good net citizen. Again, the previous article contains additional information on this rule.

  • nat on $ext_if from $prv_ad to any -> $ext_ad: the NAT rule for the private network segment. You need this rule.

  • nat on $ext_if from $dmz_ad to any -> $ext_ad: the NAT rule for the DMZ network segment. You only need this rule if you have a DMZ network segment.

  • rdr on $ext_if proto $dmz_domain_pr from any to $ext_ad port domain -> $dmz_domain_ad port $dmz_domain_pt: the redirection rule for the DNS queries sent to port 53 on the firewall's external interface. This rule redirects packets to a non-privileged port on the network interface of the DNS server residing in the DMZ. You only need this rule if you run a DNS server in the DMZ network segment.

  • rdr on {$ext_if, $prv_if} proto $dmz_www_pr from any to $ext_ad port www -> $dmz_www_ad port $dmz_www_pt: the redirection rule for the HTTP traffic sent to port 80 on the firewall's external interface. This rule redirects packets to a non-privileged port on the network interface of the HTTP server residing in the DMZ. Two interfaces {$ext_if, $prv_if} listed in this rule allow access to the HTTP server from the private network segment, as well as from the outside. You only need this rule if you run a HTTP server in the DMZ network segment.

  • rdr on {$ext_if, $prv_if} proto $rdr_smtp_pr from any to $ext_ad port smtp -> $dmz_smtp_ad port $rdr_smtp_pt: the redirection rule for the SMTP traffic sent to port 25 on the firewall's external interface. This rule redirects packets to a non-privileged port on the network interface of the SMTP server residing in the DMZ. Two interfaces {$ext_if, $prv_if} listed in this rule allow access to the SMTP server from the private network segment, as well as from the outside. You only need this rule if you run a SMTP server in the DMZ network segment.

  • rdr on {$ext_if, $prv_if} proto $rdr_ftp_pr from any to $ext_ad port ftp -> $dmz_ftp_ad port $rdr_ftp_pt: the redirection rule for the FTP traffic sent to port 20 on the firewall's external interface. This rule redirects packets to a non-privileged port on the network interface of the FTP server residing in the DMZ. Two interfaces {$ext_if, $prv_if} listed in this rule allow access to the FTP server from the private network segment, as well as from the outside. You only need this rule if you run a FTP server in the DMZ network segment.

  • rdr on $prv_if proto $rdr_nntp_pr from any to $ext_ad port nntp -> $dmz_nntp_ad port $rdr_nntp_pt: the redirection rule for the NNTP traffic sent to port 119 on the firewall's external interface from the private network segment only. This rule assumes that you forbid NNTP access from the outside and only run a caching news server for your own private use. This rule redirects packets to a non-privileged port on the network interface of the NNTP server residing in the DMZ. You only need this rule if you run a NNTP server in the DMZ network segment.

Because the list shown above is rather lengthy, I will list the rules that you do not need if you are not offering any services to the public and have just one private network segment behind the firewall:

  • dmz_if
  • dmz_ad
  • dmz_domain_ad
  • dmz_www_ad
  • dmz_smtp_ad
  • dmz_ftp_ad
  • dmz_nntp_ad
  • dmz_domain_prs
  • dmz_www_pr
  • dmz_smtp_pr
  • dmz_ftp_pr
  • dmz_nntp_pr
  • dmz_domain_pt
  • dmz_www_pt
  • dmz_smtp_pt
  • dmz_ftp_pt
  • dmz_nntp_pt
  • nat on $ext_if from $dmz_ad to any -> $ext_ad
  • rdr on $ext_if proto $dmz_domain_pr from any to $ext_ad port domain -> $dmz_domain_ad port $dmz_domain_pt
  • rdr on {$ext_if, $prv_if} proto $dmz_www_pr from any to $ext_ad port www -> $dmz_www_ad port $dmz_www_pt
  • rdr on {$ext_if, $prv_if} proto $dmz_smtp_pr from any to $ext_ad port smtp -> $dmz_smtp_ad port $dmz_smtp_pt
  • rdr on {$ext_if, $prv_if} proto $dmz_ftp_pr from any to $ext_ad port ftp -> $dmz_ftp_ad port $dmz_ftp_pt
  • rdr on $prv_if proto $dmz_nntp_pr from any to $ext_ad port nntp -> $dmz_nntp_ad port $dmz_nntp_pt

Things get more complicated when you have multiple external interfaces or multiple IP addresses assigned to the same interface. In such cases, you will be dealing with a more complex set of rules, and it is difficult to give a single answer that fits all possible questions. For example, if you have two external IP addresses, you can assign them to the external interface, using one for NAT of the private network addresses and one for NAT of the DMZ network addresses. In such case, you need to replace ext_ad with:

ext1_ad = "x.x.x.x/32"
ext2_ad = "y.y.y.y/32"

then, replace

nat on $ext_if from $prv_ad to any -> $ext_ad
nat on $ext_if from $dmz_ad to any -> $ext_ad

with

nat on $ext_if from $prv_ad to any -> $ext1_ad 
nat on $ext_if from $dmz_ad to any -> $ext2_ad

And, finally, replace:

rdr on $ext_if proto $dmz_domain_pr from any \
 to $ext_ad port domain -> $dmz_domain_ad port $dmz_domain_pt

rdr on {$ext_if, $prv_if} proto $dmz_www_pr from any \
 to $ext_ad port www    -> $dmz_www_ad port $dmz_www_pt

rdr on {$ext_if, $prv_if} proto $dmz_smtp_pr from any \
 to $ext_ad port smtp   -> $dmz_smtp_ad port $dmz_smtp_pt

rdr on {$ext_if, $prv_if} proto $dmz_ftp_pr from any \
 to $ext_ad port ftp    -> $dmz_ftp_ad port $dmz_ftp_pt

rdr on $prv_if proto $dmz_nntp_pr from any \
 to $ext_ad port nntp   -> $dmz_nntp_ad port $dmz_nntp_pt

with

rdr on $ext_if proto $dmz_domain_pr from any \
 to $ext2_ad port domain -> $dmz_domain_ad port $dmz_domain_pt

rdr on {$ext_if, $prv_if} proto $dmz_www_pr from any \
 to $ext2_ad port www    -> $dmz_www_ad port $dmz_www_pt

rdr on {$ext_if, $prv_if} proto $dmz_smtp_pr from any \
 to $ext2_ad port smtp   -> $dmz_smtp_ad port $dmz_smtp_pt

rdr on {$ext_if, $prv_if} proto $dmz_ftp_pr from any \
 to $ext2_ad port ftp    -> $dmz_ftp_ad port $dmz_ftp_pt

rdr on $prv_if proto $dmz_nntp_pr from any \
 to $ext2_ad port nntp   -> $dmz_nntp_ad port $dmz_nntp_pt

What if you have two external interfaces? Assuming that you have one IP address assigned to one external interface, the changes to the original ruleset would be as follows. Replace:

ext_if = "ne1"

with

ext1_if = "ne1"
ext2_if = "ne4"

(where the actual interface names will differ), and

ext_ad = "x.x.x.x/32"

with

ext1_ad = "x.x.x.x/32"
ext2_ad = "y.y.y.y/32"

If your external IP addresses are dynamically allocated by your ISP, delete these lines and use $ext1_if/32 and $ext2_if/32 instead of $ext1_ad and $ext2_ad shown below. Next, change:

nat on $ext_if from $prv_ad to any -> $ext_ad
nat on $ext_if from $dmz_ad to any -> $ext_ad

to

nat on $ext1_if from $prv_ad to any -> $ext1_ad
nat on $ext2_if from $dmz_ad to any -> $ext2_ad

And, finally, replace:

rdr on $ext_if proto $dmz_domain_pr from any \
 to $ext_ad port domain -> $dmz_domain_ad port $dmz_domain_pt

rdr on {$ext_if, $prv_if} proto $dmz_www_pr from any \
 to $ext_ad port www    -> $dmz_www_ad port $dmz_www_pt

rdr on {$ext_if, $prv_if} proto $dmz_smtp_pr from any \
 to $ext_ad port smtp   -> $dmz_smtp_ad port $dmz_smtp_pt

rdr on {$ext_if, $prv_if} proto $dmz_ftp_pr from any \
 to $ext_ad port ftp    -> $dmz_ftp_ad port $dmz_ftp_pt

rdr on $prv_if proto $dmz_nntp_pr from any \
 to $ext_ad port nntp   -> $dmz_nntp_ad port $dmz_nntp_pt

with

rdr on $ext_if proto $dmz_domain_pr from any \
 to $ext2_ad port domain -> $dmz_domain_ad port $dmz_domain_pt

rdr on {$ext_if, $prv_if} proto $dmz_www_pr from any \
 to $ext2_ad port www    -> $dmz_www_ad port $dmz_www_pt

rdr on {$ext_if, $prv_if} proto $dmz_smtp_pr from any \
 to $ext2_ad port smtp   -> $dmz_smtp_ad port $dmz_smtp_pt

rdr on {$ext_if, $prv_if} proto $dmz_ftp_pr from any \
 to $ext2_ad port ftp    -> $dmz_ftp_ad port $dmz_ftp_pt

rdr on $prv_if proto $dmz_nntp_pr from any \
 to $ext2_ad port nntp   -> $dmz_nntp_ad port $dmz_nntp_pt

While you might be tempted to add another ADSL to your network to increase throughput, you should not fall into thinking that this is an easy way to implement load balancing. It doesn't work that way -- if you were thinking of connecting a dozen DSL modems to your firewall to increase bandwidth, you can forget it. To make a long story short, you need to talk to your ISP and see if they can help. Having said that, if you use two DSL modems you can separate traffic generated by hosts in the private network segment from the traffic generated by external hosts connecting to the DMZ network. This is not true load balancing, but it can help, in some cases.

The nat rules that work so well when there are only two network segments, DMZ and private, can be a problem when you add more private network segments that ought to communicate freely with each other. The rdr rules that do such a fine job in simpler setups cannot be used in this case. There is a simpler solution: add no nat rules before nat rules for each private network pair, e.g.:

no nat on $ext_if from $prv_ad to $prv2_ad
no nat on $ext_if from $prv2_ad to $prv_ad

nat on $ext_if from $prv_ad to any  -> $ext_ad
nat on $ext_if from $prv2_ad to any -> $ext_ad
nat on $ext_if from $dmz_ad to any  -> $ext_ad

Well, that's is for today. Next time we'll look at pf(4) filtering rules.

Until next time.

Jacek Artymiak started his adventure with computers in 1986 with Sinclair ZX Spectrum. He's been using various commercial and Open Source Unix systems since 1991. Today, Jacek runs devGuide.net, writes and teaches about Open Source software and security, and tries to make things happen.


Read more Securing Small Networks with OpenBSD columns.

Return to the BSD DevCenter.






Sponsored by: