wiki.ipfire.org

The community-maintained documentation platform of IPFire

User Tools

Site Tools


optimization:setting_up_dmz

Setting up a DMZ has confused me for a while. I'm starting this article as a place keeper, with some notes from what I have been doing. I hope to flesh it out later.

A DMZ allows your servers to respond to public IP addresses. The difference between placing a server in a DMZ and placing directly on the red (public) network is that you can limit traffic into and out of the server, using your firewall to limit access so traffic never even gets to your servers. You can even use the built in QOS to limit the amount of traffic overall for all machines; important where you pay for bandwidth.

This document assumes you have multiple public (red) IP's. For convenience, I map the last octet of my public IP addresses to the corresponding DMZ IP addresses, though that is not necessary.

Note: There are two parts to setting up firewall rules for your DMZ network. The first part will use NAT to translate the external IP address to the firewall IP address, allowing your internal server to respond. However, when you do this, any traffic initiated from your DMZ server will still appear to come from the public IP of your router. If this is not what you want, you can write a second rule using SNAT (source network address translation).

First, assume your IPFire is set up for the external IP range of 192.168.50.192/28 (aka 192.168.50.192/255.255.255.240). That gives you 16 IP addresses, two of which are used by the network stack (192.168.50.192 and 207), giving you the range 192.168.50.193-206 to work with. Let's assume 192.168.50.193 is the IP address of the router provided by your provider (your Default Route), and 192.168.50.194 will be the public IP of your router. The other 12 addresses are available to your servers.

When you configure your router, set it's external network as: Address: 192.168.50.194 Netmask: 255.255.255.240 Gateway: 192.168.50.193

Also, create the DMZ (orange) to be in the range 10.150.150.0/24 (10.150.150.0/255.255.255.0). Thus, your usable addresses are 10.150.150.1-254. That is a lot larger than your public IP range, but doesn't hurt anything.

Following is an outline of the actions to take for each external IP to be redirected to your DMZ server.

  1. Under Network | Aliases, create a new alias. Name can be the FQDN of the server, and alias IP should be the public IP of the server
  2. Under Firewall | Rules, create one or two rules, depending on your circumstances
    1. NAT rule (required) to forward all traffic to the correct DMZ IP address.
      1. Source: Standard Networks: All
      2. NAT: Use Network Address Translation (NAT): Destination NAT (Port Forwarding): Choose Alias
      3. Destination: Destination address (IP address or network): Type in DMZ IP address
      4. Protocol: All, or a specific port/range
    2. SNAT rule (optional, without this all traffic intiated by DMZ server will come from the router's public IP address)
      1. Source: Source address( MAC/IP address or network): Type in DMZ IP address
      2. NAT: Use Network Address Translation (NAT): Source NAT: New source IP address: Choose Alias
      3. Destination: Standard Networks: Any
      4. Protocol: All, or a specific port/range

Building this for one or two DMZ machines is pretty easy, but when you have many more machines (in my case, 30+), it is easier to simply write a script to do this. The script below is not completed, but I'm including it anyway.

maniuplateIPs.pl
#! /usr/bin/perl -w
 
# Name: manipulateIPs.pl
# 
# Copyright (c) 2016, R. W. Rodolico
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without modification, 
# are permitted provided that the following conditions are met:
# 
# 1. Redistributions of source code must retain the above copyright notice, 
#    this list of conditions and the following disclaimer.
# 
# 2. Redistributions in binary form must reproduce the above copyright notice, 
#    this list of conditions and the following disclaimer in the documentation 
#    and/or other materials provided with the distribution.
# 
# 3. Neither the name of the copyright holder nor the names of its contributors 
#    may be used to endorse or promote products derived from this software without
#    specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
# script to assist in setting up multiple external IP addresses for IPFire Firewall
# (http://ipfire.org).
#
# set the first four variables to match your setup, then put any pre-defined
# values into the %servers hash
#
# run the script and capture the output. The first section will be placed in
# /var/ipfire/ethernet/aliases, and the second in /var/ipfire/firewall/config
#
# MAKE A BACKUP OF THOSE FILES.
#
# Bugs:
#    For some reason I haven't tracked down, the first firewall rule is 11,
#    not 1, so you must edit that.
#    
#    For some reason, NAT is sometimes not automatically checked when you activate
#    the firewall rules. You may need edit the firewall rules manually through
#    the webUI and put a check in the NAT rule. It is then correct.
 
my $IPStart = '192.168.50.195'; # first public IP to use
my $IPEnd = '192.168.50.206'; # last public IP to use
my $DMZNet = '10.150.150.'; # first three octets of DMZ IP range
my $unusedName = 'unused'; # any unassigned IP's will be called unused#
 
# Servers with already assigned IP's. The following hash
# has the last octet of the public IP as the key, and the
# name of the server as the value.
my %servers = (
               196 => 'mail.example.com',
               200 => 'ns.example.com',
               200 => 'web.example.com'
              );
 
 
 
# name: IP2int
# parameters: $ip - dotted IP address, ie ###.###.###.###
# returns: integer value of IP address
sub IP2int {
   my $ip = shift;
   # grab each octet into array
   my @octets = split( /\./, $ip );
   my $sum = 0;
   # for each octet
   while ( $octet = shift @octets ) {
      $sum *= 256; # shift current contents over by two bytes
      $sum += $octet; # add this value
   }
   return $sum;
}
 
# name: int2IP
# parameters: $ip - integer IP address
# returns: dotted IP address (###.###.###.###)
sub int2IP {
   my $ip = shift;
   my @octets = ( 0,0,0,0 ); # preseed, allows for leading zeros
   my $octet = 4; # start at the end
   while ( $ip && $octet-- ) { # stop when no more octets or IP is 0
      $octets[$octet] = $ip % 256; # get the last two bytes
      $ip /= 256; # then, remove the last two bytes
   }
   return join( '.', @octets ); # return them as dotted octets
}
 
# name: lastOctet
# parameters: $ip - IP address in integer form
# returns: last octect of the IP address
sub lastOctet {
   my $ip = shift;
   # this is easy, grab last two bytes
   return $ip % 256;
}
 
my @aliases; # we'll store our aliases here
my @firewall; # and our firewall rules here
my $firewallCount = 1; # just an index for the firewall rules
my $unusedCount = 1; # we'll have unused1, unused2, ...
 
# Convert dotted notation to an integer for easy of maniuplation
my $start = &IP2int( $IPStart );
my $end = &IP2int( $IPEnd );
 
# we'll create a set of rules for each IP
while ( $start <= $end ) {
   # grab the last octet
   my $lastOctet = &lastOctet( $start );
   # is this pre-defined? If not, set the name to indexed unused string
   my $name = $servers{$lastOctet} ? $servers{$lastOctet} : $unusedName . $unusedCount++;
   # create an entry in the aliases file
   push @aliases, &int2IP( $start ) . ",off,$name";
   # create two entries (dnat and snat) in the firewall file. I just copied/pasted
   # some of the rules, so I have no idea what they mean.
   push @firewall, $firewallCount++ . ",ACCEPT,FORWARDFW,OFF,std_net_src,ALL,tgt_addr,$DMZNet" . &lastOctet( $start ) . "/32,,,,,,,,,,dmz $name,,,,,,,,,,00:00,00:00,ON,$name,,dnat,,,,,second";
   push @firewall, $firewallCount++ . ",ACCEPT,FORWARDFW,OFF,src_addr,$DMZNet" . &lastOctet( $start ) . "/32,std_net_tgt,ALL,,,,,,,,,,snat $name,,,,,,,,,,00:00,00:00,ON,$name,,snat,,,,,second";
   $start++;
}
 
my $divider = "\n" . '='x40 . "\n"; # just makes the output easier to read
# dump all the data to STDOUT so they can be copied/pasted
print "$divider Place the following in /var/ipfire/ethernet/aliases$divider";
print join( "\n", @aliases );
print print "$divider Place the following in /var/ipfire/firewall/config$divider";
print join( "\n", @firewall );
print $divider;
 
1;
optimization/setting_up_dmz.txt · Last modified: 2016/08/19 06:19 by rodolico