Dynamic Host Configuration Protocol (DHCP)

network

The Dynamic Host Configuration Protocol (DHCP) is an Internet protocol for automating the configuration of computers that use TCP/IP. DHCP can be used to automatically assign IP addresses, to deliver TCP/IP stack configuration parameters such as the subnet mask and default router, and to provide other configuration information such as the addresses for printer, time and news servers.

For the DHCP client (dhclient), we have to edit the file /etc/dhclient.conf. The DHCP server my ISP is using wants to know my hostname, so we send this. In addition to our IP address we want to know the subnet mask, the broadcast address and the gateway.

send host-name "hostname";
request subnet-mask, broadcast-address, routers;

OpenBSD automatically runs dhclient if a network interface is configured to use DHCP. For example, to use DHCP on the interface xl0, edit /etc/hostname.xl0

dhcp

For the DHCP server (dhcpd), we have to edit the file /etc/dhcpd.conf. Assume dhcpd is located at a machine that is gateway for two LANs, the first being 192.168.0.0/24 and the second 10.0.0.0/24. There is a nameserver at 192.168.0.1 which serves the example.com domain.

option domain-name "example.com";
option domain-name-servers 192.168.0.1;

subnet 192.168.0.0 netmask 255.255.255.0 {
   option routers 192.168.0.1;
   range 192.168.0.10 192.168.0.99;
}

subnet 10.0.0.0 netmask 255.255.255.0 {
   option routers 10.0.0.1;
   range 10.0.0.128 10.0.0.254;
}

OpenBSD does not start dhcpd automatically, so we have to edit /etc/rc.conf.local

dhcpd_flags="-q"

BIND DNS server

network

BIND (Berkeley Internet Name Domain) is an implementation of the Domain Name System (DNS) protocols and provides an openly redistributable reference implementation of the major components of DNS, including a DNS server (named), a DNS resolver library and tools for verifying the proper operation of the DNS server. The BIND DNS Server is used on the vast majority of name serving machines on the Internet, providing a robust and stable architecture on top of which an organization’s naming architecture can be built. The resolver library included in the BIND distribution provides the standard APIs for translation between domain names and Internet addresses and is intended to be linked with applications requiring name service.

Assume we want to run DNS services for the domain example.com. Note that we need to register this domain name and tell the registrar that the DNS server for this domain is the machine running BIND. We also want to run DNS services for the IP range 192.168.0.0/24. Note that we would use more than one nameserver in real-life situations, but for this example we only use one nameserver. On OpenBSD with BIND 9, the first file we edit is /var/named/etc/named.conf

zone "example.com" {
   type master;
   file "master/example.com";
};

zone "0.168.192.in-addr.arpa" {
   type master;
   file "master/0.168.192.in-addr.arpa";
};

The file /var/named/master/example.com contains the translation from names to IP addresses in the example.com domain.

@ IN  SOA  ns.example.com.  hostmaster.example.com. (
   2003060101 ; Serial (yyyymmddxx)
   86400      ; Refresh (1 day)
   7200       ; Retry (2 hours)
   604800     ; Expire (7 days)
   86400 )    ; Minimum (1 day)

IN      NS      ns.example.com.

example.com.    IN      A       192.168.0.1
www     IN      CNAME   example.com.
ftp     IN      CNAME   example.com.

host1   IN      A       192.168.0.1
host2   IN      A       192.168.0.2
host3   IN      A       192.168.0.3

The file /var/named/master/0.168.192.in-addr.arpa contains translations from IP addresses in the range 192.168.0.0/24 to names (in our case in example.com).

@ IN  SOA  ns.example.com.  hostmaster.yahoo.com. (
   2003060101 ; Serial (yyyymmddxx)
   86400      ; Refresh (1 day)
   7200       ; Retry (2 hours)
   604800     ; Expire (7 days)
   86400 )    ; Minimum (1 day)

IN      NS      ns.example.com.

1       IN      PTR     host1.example.com.
2       IN      PTR     host2.example.com.
3       IN      PTR     host3.example.com.

Apache virtual hosts

apache

Assume we want to serve webpages for two domains, example.com and example.org and these pages should be available with and without the ‘www’, so from www.example.com, example.com, www.example.org and example.org. In addition, clients connecting directly to our IP address, instead of using these domain names, should get an error message (404 Not Found) or short warning html message. These clients are probably just worms trying to spread through our webserver, so we don’t want to waste bandwidth on them. We start off by making some directories.

mkdir /var/www/htdocs/ip_address
mkdir /var/www/htdocs/example.com
mkdir /var/www/htdocs/example.org

Last thing we have to do is edit the configuration file. On OpenBSD, the Apache configuration can be found in /var/www/conf/httpd.conf.

NameVirtualHost *

<VirtualHost *>
   DocumentRoot /htdocs/ip_address
   ErrorLog logs/ip_address-error_log
   CustomLog logs/ip_address-access_log common
</VirtualHost>

<VirtualHost *>
   ServerAdmin webmaster@example.com
   DocumentRoot /htdocs/example.com
   ServerName www.example.com
   ErrorLog logs/example.com-error_log
   CustomLog logs/example.com-access_log common
</VirtualHost>

<VirtualHost *>
   ServerAdmin webmaster@example.com
   DocumentRoot /htdocs/example.com
   ServerName example.com
   ErrorLog logs/example.com-error_log
   CustomLog logs/example.com-access_log common
</VirtualHost>

<VirtualHost *>
   ServerAdmin webmaster@example.org
   DocumentRoot /htdocs/example.org
   ServerName www.example.org
   ErrorLog logs/example.org-error_log
   CustomLog logs/example.org-access_log common
</VirtualHost>

<VirtualHost *>
   ServerAdmin webmaster@example.org
   DocumentRoot /htdocs/example.org
   ServerName example.org
   ErrorLog logs/example.org-error_log
   CustomLog logs/example.org-access_log common
</VirtualHost>

Multiple webservers behind one IP address

This article was featured on Daemon News 2002-02.

Overview

This article discusses a network setup where multiple webservers reside behind one IP address. Such a situation may arise when you need a specific webserver for one task and a different webserver for another task, running different operating systems or webserver software. With only one IP address available from the Internet, you could simply use Network Address Translation (NAT) with port forwarding. However, this forces you to give each webserver an ugly URL with a non-standard port number. Luckily, there is a better way. In the setup described in this article, each webserver can be reached via its own fully qualified domainname on the standard HTTP port (80).

All machines discussed in this article are running FreeBSD 4.4. The NAT machine has two interfaces, one connected to the Cable or xDSL modem, and one to the hub of the LAN. The nameserver, proxyserver and webserver machines all have one interface, which is connected to the hub. The webserver machines will not be discussed any further in this article, because they might be running different operating systems and webserver software. That was the whole point, wasn’t it?

multiple-webservers-setup

Theory

Let’s start with some theory about URLs and the HTTP protocol.

Theory: URLs and HTTP

A URL consists of four parts:

  • The protocol, in our case HTTP
  • The hostname, e.g. www.example.com
  • The port number, mostly omitted, default 80 for HTTP
  • The file location, e.g. /directory/file.html

A number of steps are performed when somebody asks for a certain URL in a webbrowser. First, the webbrowser does a DNS lookup to find the IP address associated with the hostname. The webbrowser then sends a HTTP request to this IP address. In HTTP 1.0, the webbrowser just sent the file location part of the URL in the request. This resulted in a one-to-one link between domainnames and IP addresses, making it impossible to serve more than one domain on one IP address. In HTTP 1.1, the webbrowser also sends the hostname part of the URL, which removes this limitation. The webserver can now serve multiple domains with just one IP address.

Theory: Our setup

Let’s use the following data for our setup. We have a webserver called webserver1 in our domain example.com with IP address 10.0.0.4. The public IP address of our NAT machine is 216.136.204.21. Now, somebody wants to view a webpage located on this webserver from the Internet.

The webbrowser first performs a DNS lookup to find the IP address of the webserver. Because the webbrowser is not located on the LAN, but somewhere on the Internet, we want this to be the public IP address of our NAT machine. The webbrowser then sends a request to this IP address on the standard HTTP port (80). We now have to decide which server on the LAN to forward this request to. The NAT machine has no knowledge about the HTTP protocol, so it can’t forward the request to a webserver based on the HTTP request the webbrowser made. Therefore, it has to forward all HTTP requests to a specific server. This can’t be a webserver, because it would limit our number of webservers to one!

To solve this problem, we shouldn’t have the NAT machine forward HTTP requests to a specific webserver, but to a proxyserver. This proxyserver does have knowledge about the HTTP protocol, so it can fetch webpages for the webbrowser based on the hostname present in the request. There is one problem however, the proxyserver must not fetch the webpage from the NAT machine (216.136.204.21), but from the webserver (10.0.0.4). So, the proxyserver should get another result (10.0.0.4) then the webbrowser (216.136.204.21) when looking up the IP address of webserver1.example.com.

This leads us to setting up two nameservers. The first one listens to DNS requests on the standard DNS port (53) on the LAN, giving IP addresses in the 10.0.0.0/24 range. The second one listens to DNS requests on a non-standard port (let’s use 1053), always giving the IP address 216.136.204.21. The NAT machine should then forward DNS requests on its port 53 to port 1053 on the nameserver machine.

Theory: Summary

To summarize, here are the steps performed when somebody requests the URL http://webserver1.example.com/directory/file.html from a webbrowser on the Internet. We assume that 216.136.204.21 has been made authorative nameserver for the domain example.com:

multiple-webservers-sequence

  1. The webbrowser sends a DNS request to 216.136.204.21 on port 53 for the IP address of webserver1.example.com.
  2. The NAT machine forwards this DNS request to port 1053 on the nameserver.
  3. The nameserver replies with 216.136.204.21.
  4. The NAT machine sends this reply to the webbrowser.
  5. The webbrowser sends a HTTP request to 216.136.204.21 on port 80 for the hostname and the file location.
  6. The NAT machine forwards this HTTP request to the proxyserver on port 1080.
  7. The proxyserver sends a DNS request to port 53 on the nameserver.
  8. The nameserver replies with 10.0.0.4.
  9. The proxyserver sends the HTTP request to 10.0.0.4.
  10. The webserver replies with the right webpage.
  11. The proxyserver replies with this webpage.
  12. The NAT machine sends this reply to the webbrowser.

If we want to fetch the same file from webserver2 instead of webserver1, the main differences will be in steps 8 and 9. The nameserver will reply with 10.0.0.5 instead of 10.0.0.4 in step 8. In step 9, the proxyserver will fetch the URL from 10.0.0.5.

Implementation

Now that we’ve seen the theory, let’s shift our attention to the implementation.

Implementation: Network Address Translator (NAT)

multiple-webservers-nat

Kernel

We want to be able to divert and filter IP packets. The FreeBSD generic kernel doesn’t allow this, so we have to make our own kernel. We do this by making a copy of the generic kernel:

cd /usr/src/sys/i386/conf
cp GENERIC NAT

Then we add the following lines to the NAT file:

options IPDIVERT
options IPFIREWALL

Now we can compile our new kernel and install it:

config NAT
cd ../../compile/NAT
make depend
make
make install

Configuration

We should now edit some configuration files to really enable the capabilities just added to the kernel. The first file is /etc/rc.conf which contains the network interface configuration as well as the services configuration:

# Host- and domainname
hostname="nat.example.com"

# Network interface connected to the Cable or xDSL modem
ifconfig_xl0="inet 216.136.204.21 netmask 255.255.248.0"

# Network interface connected to the hub of the LAN
ifconfig_rl0="inet 10.0.0.1 netmask 255.255.255.0"

# Default router on network interface xl0
defaultrouter="216.136.204.1"

# Enable firewall capabilities
firewall_enable="YES"

# Enable gateway capabilities
gateway_enable="YES"

# Enable network address translation
natd_enable="YES"
natd_interface="xl0"
natd_flags="-f /etc/natd.conf"

The second file is /etc/natd.conf which contains the rules for the NAT daemon:

# Redirect DNS packets to the nameserver
redirect_port udp 10.0.0.2:1053 53

# Redirect HTTP packets to the proxyserver
redirect_port tcp 10.0.0.3:1080 80

The third file is /etc/rc.firewall which contains the rules for the packet filter. In our case we first divert all IP packets to the NAT daemon. After that, we make sure that IP packets can only go where they are supposed to go.

# Flush all previous firewall rules
/sbin/ipfw -f flush

# Divert all IP packets to the NAT daemon
/sbin/ipfw add divert natd ip from any to any via xl0

# Allow all IP packets through the loopback interface by the localhost
/sbin/ipfw add allow ip from 127.0.0.1 to 127.0.0.1 via lo0

# Allow DNS and HTTP packets through the public interface to LAN machines
/sbin/ipfw add allow udp from any to 10.0.0.2 1053 in recv xl0
/sbin/ipfw add allow tcp from any to 10.0.0.3 1080 in recv xl0

# Allow all IP packets through the public interface from this machine
/sbin/ipfw add allow ip from 216.136.204.21 to any out xmit xl0

# Allow all IP packets through the private interface from and to LAN machines
/sbin/ipfw add allow ip from 10.0.0.1/24 to any in recv rl0
/sbin/ipfw add allow ip from any to 10.0.0.1/24 out xmit rl0

# Deny all IP packets not allowed until this point
/sbin/ipfw add deny ip from any to any

Nameserver

multiple-webservers-nameserver

Configuration

For our nameserver machine we will use BIND 8.2.4. This software is pre-installed on FreeBSD, so we just have to configure it. As mentioned earlier, we have to set up and run two seperate instances of BIND. Let’s start with the one that serves our LAN. The first file to edit is /etc/namedb/named-lan.conf which contains the general configuration of BIND. To avoid very long listings, just the additions to the original file are shown:

zone "example.com" {
   type master;
   file "db-lan.example.com";
};

zone "0.0.10.in-addr.arpa" {
   type master;
   file "rev.0.0.10";
};

The second file is /etc/namedb/db-lan.example.com which contains the mapping from names in the example.com domain to IP addresses:

$TTL 86400

@  IN  SOA  nameserver.example.com.  hostmaster.example.com. (
   2002011501 ; Serial (yyyymmddxx)
   86400      ; Refresh (1 day)
   7200       ; Retry (2 hours)
   604800     ; Expire (7 days)
   86400 )    ; Minimum (1 day)

@     IN   NS  nameserver.example.com.

nat   IN   A   10.0.0.1
nameserver    IN   A   10.0.0.2
proxyserver   IN   A   10.0.0.3
webserver1    IN   A   10.0.0.4
webserver2    IN   A   10.0.0.5
webserver3    IN   A   10.0.0.6

The third file is /etc/namedb/rev.0.0.10 which contains the reverse mapping, from IP addresses to names in the example.com domain:

$TTL 86400

@  IN  SOA  nameserver.example.com.  hostmaster.example.com. (
   2002011501 ; Serial (yyyymmddxx)
   86400      ; Refresh (1 day)
   7200       ; Retry (2 hours)
   604800     ; Expire (7 days)
   86400 )    ; Minimum (1 day)

@   IN   NS    nameserver.example.com.

1   IN   PTR   nat.example.com.
2   IN   PTR   nameserver.example.com.
3   IN   PTR   proxyserver.example.com.
4   IN   PTR   webserver1.example.com.
5   IN   PTR   webserver2.example.com.
6   IN   PTR   webserver3.example.com.

Let’s continue with the BIND that serves the Internet. The fourth file to edit is /etc/namedb/named-internet.conf. Just the changes and additions to the original file are shown:

options {
   directory "/etc/namedb";
   listen-on port 1053 { 10.0.0.2; };
};

zone "example.com" {
   type master;
   file "db-internet.example.com";
};

Note that we tell this BIND to listen to a non-standard port number, 1053 in our case. The fifth file is /etc/namedb/db-internet.example.com which contains the mapping from names in the example.com domain to the public IP address of our NAT machine. Just the changes to the LAN file are shown:

webserver1   IN   A   216.136.204.21
webserver2   IN   A   216.136.204.21
webserver3   IN   A   216.136.204.21

The entries for nat.example.com, nameserver.example.com and proxyserver.example.com are left out, because they won’t be serving webpages. We have left out the file that contains the reverse mapping, because the reverse mapping for the public IP address is usually done by the ISP. Finally, we will start the two BIND instances:

/usr/sbin/named -u bind -g bind -c /etc/namedb/named-lan.conf
/usr/sbin/named -u bind -g bind -c /etc/namedb/named-internet.conf

Proxyserver

multiple-webservers-proxyserver

Installation

For our proxyserver machine we will use Squid 2.4.6. This comes as a port on FreeBSD, so we have to install it first:

cd /usr/ports/www/squid24
make
make install

Configuration

In its normal function, Squid is a real proxyserver. This means that webbrowsers have to be told to access certain (or all) webservers via this proxyserver. Because we want this setup to work without modifications to the webbrowser, we need to change Squids default behaviour. If we want Squid to act as a transparent proxyserver, we have to set it to accelerator mode. The only file to edit here is /usr/local/etc/squid.conf which contains all configuration options for Squid. To avoid very long listings, just the changes and additions to the original file are shown:

# Port Squid listens on
http_port 1080

# Allow all clients access
http_access allow all

# Proxy for several virtual hosts, each on port 80
httpd_accel_host virtual
httpd_accel_port 80

# Use host header in requests
httpd_accel_uses_host_header on

To start Squid, we will use the startup script that came along when we performed the installation:

/usr/local/etc/rc.d/squid.sh start

Testing

We will test our setup from within our LAN (internal) and from the Internet (external).

Internal

From a client connected to the LAN we will start the test of our configuration. Let’s try to fetch a HTML page from one of the webservers:

http://webserver1.example.com/directory/file.html

If the webserver doesn’t use virtual hosts, we would get the same result if we asked for this URL:

http://10.0.0.4/directory/file.html

External

Now try the same thing from a client on the Internet:

http://webserver1.example.com/directory/file.html

The following test will (and should) fail hopelessly, because the proxyserver can’t fetch the HTML page from itself:

http://216.136.204.21/directory/file.html

A secure network setup with FreeBSD and OpenBSD

This article was featured on Daemon News 2001-09.

Overview

This article discusses a network setup which might prove useful for people who like to put some extra effort into connecting their machines to the Internet. The goal is to build a secure client and server farm on a single IP address. Next to the clients and servers, the network contains two other components. The first one is a Network Address Translator (NAT), which makes it possible to connect more than one machine to the Internet using just one IP address. The second one is a Packet Filtering Bridge (PFB) that transparently filters IP traffic from and to the Internet.

secure-network-setup

The PFB machine – running OpenBSD 2.9 – is the only machine connected directly to the Internet. Two of its network interfaces are for the bridge itself (p1 and p2) and one is the management interface (p3). Interface p3 makes it possible for the PFB to output its logs to another server, or for an administrator to log into it to check its logs. This might not seem very secure at first sight, but the interface is actually protected as well as the clients on the LAN.

The NAT machine – running FreeBSD 4.3 – is connected with one interface to the PFB machine (n1). The other two interfaces are connected to the hubs of the clients (n2) and servers (n3). This seperation between a client and a server LAN has at least one obvious advantage. If a weakness is found in one of the services of a server, the clients are still relatively safe from attack. Otherwise, the clients would be on the same network as the compromised server and would have made an easy target for the attacker.

Theory

Let’s start with some theory about Network Address Translators (NAT) and Packet Filtering Bridges (PFB).

Theory: Network Address Translator (NAT)

Commonly, your Cable or xDSL ISP assigns you a very limited number of IP addresses (usually just one). You run into trouble if you want to connect more machines to the Internet than the number of IP addresses given to you. NAT is a technology which you can use to solve this problem to some extent. With NAT, multiple internal IP address (on the LAN) are aliased to a single public IP address (on the Internet). Requests from machines on the LAN to machines on the Internet are transformed by the NAT machine. It modifies the source address in the IP packet and sends the request in its name to the machine on the Internet. Once it gets a reply, it modifies the destination address in the IP packet to the client on the LAN.

secure-network-nat-theory

Typically, a NAT machine has two network interfaces, one on the Internet and one on the LAN. The public IP address on the Internet is assigned to you by your ISP, so you assign this IP address to the interface connected to the public network. But what about the private IP addresses on the LAN? There are some IP addresses which are available for exactly this situation. You can choose between three IP ranges:

  • 10.0.0.0/8
  • 172.16.0.0/12
  • 192.168.0.0/16

Let’s say you are using the third IP range. You would then assign one of the IP addresses in this range (e.g. 192.168.0.1) to the interface connected to the private network. Every other machine on this network is assigned one of the remaining addresses in the range. Here’s an example of the complete IP configuration of the machines involved:

IP address Subnet mask Gateway
NAT public 216.136.204.21 255.255.248.0 216.136.204.1
NAT private 192.168.0.1 255.255.255.0 No gateway
LAN machine 1 192.168.0.2 255.255.255.0 192.168.0.1
LAN machine 2 192.168.0.3 255.255.255.0 192.168.0.1

Theory: Packet Filtering Bridge

A bridge is used to connect two network segments to create a single, larger network. This is normally done to create the appearance of a single network when there are in fact two physically seperate networks. The bridge in this article is not just a simple bridge, but it functions as a packet filter as well. Devices that filter packets have rulesets that tell them which packets should be allowed and which should be blocked. Typically, a firewall is used for this job, but a disadvantage of this setup is, that the firewall is visible on the Internet. This makes it a great target to anyone trying to get into your network. If the firewall gets compromised, alle machines within the LAN are in the open, waiting to be compromised as well.

secure-network-pfb-theory

In our case, the packet filtering is done by the bridge. A normal bridge takes all packets from the network on one interface and copies them to the interface on the other network and vice versa. Our PFB examines each of these packets before they are copied to the other interface. It checks its ruleset to see if a packet should be allowed to pass or should be blocked. Unlike the NAT machine, the PFB machine doesn’t change anything in the packets themselves.

The IP configuration of the PFB and the machines on both networks is really simple. The PFB is not assigned an IP address at all. This ensures that machines on either side of the PFB are not aware of its existence. Because of this, the machines on both networks should be configured as if the two networks were really one larger one. The cool thing about this, is that the PFB can’t be reached from the Internet, making it impossible to attack it on the IP level.

Implementation

Now that we’ve seen the theory, let’s shift our attention to the implementation. As mentioned before, we are using FreeBSD 4.3 for the NAT machine and OpenBSD 2.9 for the PFB machine. We won’t go into much depth with regard to the client and server machines, although we will discuss the IP settings of these machines.

Implementation: Network Address Translator (NAT)

secure-network-nat-setup
Kernel

We want to be able to divert and filter IP packets. The FreeBSD generic kernel doesn’t allow this, so we have to make our own kernel. We do this by making a copy of the generic kernel:

cd /usr/src/sys/i386/conf
cp GENERIC NAT

Then we add the following lines to the NAT file:

options IPDIVERT
options IPFIREWALL

Now we can compile our new kernel and install it:

config NAT
cd ../../compile/NAT
make depend
make
make install

Configuration

We should now edit some configuration files to really enable the capabilities just added to the kernel. The first file is /etc/rc.conf which contains the network interface configuration as well as the services configuration:

# Host- and domainname
hostname="nat.example.com"

# Network interface connected to the PFB (n1)
ifconfig_xl0="inet 216.136.204.21 netmask 255.255.248.0"

# Network interface connected to the client LAN (n2)
ifconfig_rl0="inet 192.168.0.1 netmask 255.255.255.0"

# Network interface connected to the server LAN (n3)
ifconfig_rl1="inet 10.0.0.1 netmask 255.255.255.0"

# Default router on network interface n1
defaultrouter="216.136.204.1"

# Enable firewall capabilities
firewall_enable="YES"

# Enable gateway capabilities
gateway_enable="YES"

# Enable network address translation
natd_enable="YES"
natd_interface="xl0"
natd_flags="-f /etc/natd.conf"

The second file is /etc/natd.conf which contains the rules for the NAT daemon:

# Redirect SSH packets to the SSH server
redirect_port tcp 10.0.0.3:22 22

# Redirect HTTP packets to the HTTP server
redirect_port tcp 10.0.0.4:80 80

The third file is /etc/rc.firewall which contains the rules for the packet filter. In our case we first divert all IP packets to the NAT daemon. After that, we make sure that IP packets can only go where they are supposed to go. Strictly speaking, we don’t need the rules below the one that diverts IP packets to the NAT daemon. However, we would otherwise have to allow all IP packets, and that is something we don’t like doing:

# Flush all previous firewall rules
/sbin/ipfw -f flush

# Divert all IP packets to the NAT daemon
/sbin/ipfw add divert natd ip from any to any via xl0

# Allow all IP packets through the loopback interface by the localhost
/sbin/ipfw add allow ip from 127.0.0.1 to 127.0.0.1 via lo0

# Allow all IP packets through the public interface (n1) from and to this machine
/sbin/ipfw add allow ip from any to 216.136.204.21 in recv xl0
/sbin/ipfw add allow ip from 216.136.204.21 to any out xmit xl0

# Allow all IP packets through the client interface (n2) from and to client machines
/sbin/ipfw add allow ip from 192.168.0.1/24 to any in recv rl0
/sbin/ipfw add allow ip from any to 192.168.0.1/24 out xmit rl0

# Allow all IP packets through the server interface (n3) from and to server machines
/sbin/ipfw add allow ip from 10.0.0.1/24 to any in recv rl1
/sbin/ipfw add allow ip from any to 10.0.0.1/24 out xmit rl1

# Deny all IP packets not allowed until this point
/sbin/ipfw add deny ip from any to any

Implementation: Packet Filtering Bridge

secure-network-pfb-setup
Kernel

We want to be able to divert and filter IP packets. The OpenBSD generic kernel has support for both these features, so there is no need to make our own kernel.

Configuration

The first configuration files to edit are the ones that set the parameters for the network interfaces. File /etc/hostname.ne0 is for the network interface connected to the client LAN (p3):

inet 192.168.0.2 255.255.255.0 NONE

Files /etc/hostname.ne1 and /etc/hostname.ne2 are for the network interfaces connected to the Cable / xDSL modem and NAT machine respectively (p1 and p2). Because we won’t be giving them IP addresses, the content of these files is simply:

up

Now we should edit the file /etc/bridgename.bridge0 to enable the bridge at startup:

add ne1
add ne2
up

The last configuration file to edit is /etc/ipf.rules which contains the rules for the packet filter. As with the NAT machine, we make sure that IP packets can only go where they are supposed to go. There is a difference however: we want to protect our network from the Internet. We tell the packet filter that it is okay for the NAT machine to send IP packets to the Internet and receive replies on these packets. We also want to offer SSH and HTTP services to the Internet, so we explicitly open these ports on our bridge:

# Allow all IP through the loopback interface by the localhost
pass in quick on lo0 from 127.0.0.1 to 127.0.0.1

# Allow all IP through the LAN interface from and to LAN addresses
pass in quick on ne0 from 192.168.0.0/24 to 192.168.0.2
pass out quick on ne0 from 192.168.0.2 to 192.168.0.0/24

# Allow all IP through the bridge from the NAT machine
pass in quick on ne2 proto tcp/udp from 216.136.204.21 to any keep state
pass in quick on ne2 proto icmp from 216.136.204.21 to any keep state

# Allow SSH and HTTP through the bridge from the Internet to the NAT machine
pass in quick on ne1 proto tcp from any to 216.136.204.21 port = 22 flags S keep state
pass in quick on ne1 proto tcp from any to 216.136.204.21 port = 80 flags S keep state

# Deny IP not allowed until this point
block in quick all

Implementation: Clients and servers

secure-network-clients-servers

To complete our setup we must configure the clients and servers. Our client LAN is connected through a hub to interface n2 of the NAT machine, so all clients should be in the same subnet as n1. For the same reason, all servers should be in the same subnet as n3. The configuration looks like this:

IP address Subnet mask Gateway
Client 1 192.168.0.3 255.255.255.0 192.168.0.1
Client 2 192.168.0.4 255.255.255.0 192.168.0.1
Server 1 10.0.0.3 255.255.255.0 10.0.0.1
Server 2 10.0.0.4 255.255.255.0 10.0.0.1

Testing

From one of the client machines we will now start the test of our configuration. Let’s see if one of our clients (192.168.0.3) can reach the NAT machine (192.168.0.1):

%ping 192.168.0.1
PING 192.168.0.1 (192.168.0.1): 56 data bytes
64 bytes from 192.168.0.1: icmp_seq=0 ttl=255 time=0.560 ms
64 bytes from 192.168.0.1: icmp_seq=1 ttl=255 time=0.435 ms
...

We expect about the same result if we try to reach the NAT machine (10.0.0.1) from one of our servers (10.0.0.3). If this works OK, we should try the PFB. We can do this from the NAT machine by pinging the gateway of our ISP:

%ping 216.136.204.1
PING 216.136.204.1 (216.136.204.1): 56 data bytes
64 bytes from 216.136.204.1: icmp_seq=0 ttl=255 time=20.340 ms
64 bytes from 216.136.204.1: icmp_seq=1 ttl=255 time=21.636 ms
...

We can repeat this test from one of our clients or servers to test the NAT daemon. Notice that the Time To Live (ttl) value is 1 lower than before. This is because the NAT machine is now a hop the IP packets have to pass to reach the gateway. Our final test for our setup will be the HTTP server, which we will assume is on IP address 10.0.0.4. First, try to fetch an HTML page from the terminal of the NAT machine itself with this URL:

http://10.0.0.4/directory/file.html

If this succeeds, you can try to fetch the same HTML page from a machine on the Internet with this URL:

http://216.136.204.21/directory/file.html

The NAT machine should redirect this request to the HTTP server on IP address 10.0.0.4 and give you the same result as the test above.