Building an OpenBSD router/firewall.

preamble

In this tutorial our goal is to acquaint ourselves with the most basic routing concepts. I will be running my router and firewall on OpenBSD 4.1. We will also be introduced to the OpenBSD firewall system called Packet Filter. There will be a further tutorial that will look at Packet Filter in greater detail.

You will require at least three machines. The router/firewall will need to have two network interfaces installed. Either side of the router will be a different network. I will be using 192.168.1.0 and 192.168.2.0.

Here are the steps:

  1. set up networking
  2. configure the router
  3. configure the firewall
  4. advertisement

set up networking

Once you have chosen an appropriate machine to act as your router, you will need to have its two network interfaces recognized and configured. In OpenBSD, network interfaces are designated by the drivers they use as opposed to the Linux approach which employs a generic naming convention. For example, OBSD may have interfaces “rl0″ and “ne3″ (for the Realtek and NE2000 drivers) whereas Linux will use eth0 and eth1 (for ethernet 0 and ethernet 1). For this tutorial I will use interfaces rl0 and ne3.

Plug each interface into their respective networks.

You can check the status of each interface using the ifconfig command:

$ ifconfig rl0
$ ifconfig ne3

Now from the router, attempt to contact machines on both networks using the ping utitlity. Do not go any further until you have successfully set up the router’s connectivity to both networks.

Other noteworthy files related to network configuration on OpenBSD:

/etc/hosts
/etc/mygate
/etc/resolv.conf
/etc/hostname.rl0
/etc/hostname.ne3
/etc/netstart
{forward name resolution}
{your default gateway}
{your nameservers}
{interface rl0 configuration}
{interface ne3 configuration}
{global network activation file}

configure the router

What is a router?

A router is a device that resides between networks and passes (routes) traffic from one to the other. Both the sender (client) and receiver (router) requires a routing table in order to do this.

Use the route command to establish default and/or static routes.

This needs to be done on both the computer intending to pass its packets (the “client”) through your router as well as on the router itself. Of course, the values will be different for each as it’s all relative. Also, the route command has slightly different syntax depending on the platform it’s running on. Here, thankfully for you, I have a mix of boxes:

If you are here then that means all adjacent networks/interfaces can ping each other. For example:

and so on.

Again, do not proceed unless this is the case.

Here, I will examine the following routes:

Presently, this is what happens on A:

# ping 192.168.2.20
PING 192.168.2.20 (192.168.2.20): 56 data bytes
ping: sendto: No route to host

So we need to tell A that if it wants to contact E it must first go through D1. D2 alreadys know how to contact E so that part is not looked at.

# route add -net 192.168.2.0 192.168.1.60
add net 192.168.2.0: gateway 192.168.1.60

Depending on the state of your (intended) router machine, this may not be sufficient. Routing itself must be activated on it. Do this by changing the state of its kernel in real-time (without rebooting) using the sysctl command:

# sysctl -w net.inet.ip.forwarding=1

We are almost done. What is commonly misunderstood when learning about simple routing is that computer communication involves requests and replies. We now need to ensure that machine E can reply back to machine A.

So on E we will set up a default route (or a default gateway). This means that any destination not on the client’s network will be sent there. This makes sense given that it is the only machine completely on the 192.168.2.0 subnet.

So here goes:

# route add default gw 192.168.2.60

Now we should be able to ping.

Check routing tables on A using the netstat command (or alternatively, the route command):

# nestat -rn
.
.
192.168.2/24       192.168.1.60       UGS         0       13   1500   vr0
.
.
# route -n show
.
.
192.168.2.0      192.168.1.60       UG
.
.

That’s it. We now have a router. But the changes we made to the router and client A are not permanent. We say that such changes will not survive a reboot. To make both these changes permanent…

…on the router,

# vi -c /forwarding /etc/sysctl.conf {and uncomment the appropriate line}

…on the A machine, you simply add the route command we used to a file. There are a number of files we can use (/etc/rc.conf; /etc/rc.local; /etc/netstart) but I place my static routes in the appropriate /etc/hostname.* file. So go ahead and do that.

Let’s look at the other connections now.

In Windows 2000, open a command line window and issue the following:

C:\> route -p add 192.168.2.0 mask 255.255.255.0 192.168.1.60

Here we set up a static route. We could of also defined a default gateway as we did on machine A. The “p” option makes this route permanent.

Use the ping command to test.

In Slackware, display the routing table like so:

# route -n

Now add a static route:

# route add -net 192.168.2.0 netmask 255.255.255.0 gw 192.168.1.60

Now the routing table is like this:

# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.2.0     192.168.1.60    255.255.255.0   UG    0      0        0 eth0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0
127.0.0.0       0.0.0.0         255.0.0.0       U     0      0        0 lo

Again, let’s make the change permanent. Edit the file /etc/rc.d/rc.inet1 for this. This is what the bottom of this file looks like after making the change:

   # If there is a gateway defined, then set it up:
   if [ ! "$GATEWAY" = "" ]; then
      /sbin/route add default gw ${GATEWAY} netmask 0.0.0.0 metric 1
   fi
fi

# Set up a static route:
route add -net 192.168.2.0 netmask 255.255.255.0 gw 192.168.1.60

# End of rc.inet1

Great. We now have complete and permanent routing on our network. Did you notice how the syntax of the route command differs for the various operating systems we used? Also, we could of set up default gateways on machines B and C as we did on A. The way we proceeded above allowed us to see a different method (static routes).

configure the firewall

What is a firewall?

A firewall is a “system” (either a kind of black box, a dedicated computer, or more recently a software application that you install in Windows) that consists of rules that determine whether traffic will be allowed to pass through one (or more) network interface(s). There is a misconception that a firewall must also be a router but this is not technically true. You may have a firewall on an “end system” with only one network interface and still have it act as a firewall. It will look at the incoming packets and determine whether it should receive them, that’s all. Them same for outbound traffic -can it send certain types of traffic or not. In the large majority of cases, though, a firewall is also a router.

That said, a firewall’s rules are dependent on the network configuration as well as what sort of traffic we are expecting. Because of this, we will only look at “how we turn the firewall on” and not any specific rulesets. The next tutorial has this (a realistic firewall) as its subject matter.

The firewall system we will cover in this document is the excellent OpenBSD Packet Filter.

So we will now only use the minimum rule set required. You will see what files are involved and also become acquainted with some commands.

The Packet Filter configuration file is usually called /etc/pf.conf. We will call ours /etc/pf.conf.basic to emphasize that it is not a finished configuration. Make a backup of the default /etc/pf.conf (call it pf.conf.org).

Make the contents of pf.conf.basic:

pass in all
pass out all

This means that anything is passed in and passed out from (and to) any interface. We can say the same thing, by various degrees of explicitness, by doing any of the following:

pass in on rl0 all
pass out on rl0 all
pass in on ne3 all
pass out on ne3 all
pass in from any to any
pass out from any to any
pass in on rl0 from any to any
pass in on ne3 from any to any
pass out on rl0 from any to any
pass out on ne3 from any to any

Whatever form you use, at this point, effectively speaking, there is no firewall. But let’s “turn on” the firewall anyway by issuing the following command:

# pfctl -e -f /etc/pf.conf.basic

There, you now have a firewall. The “e” switch is for enabling PF and the “f” switch specifies what config file to use.

We could of also left the file completely empty and it would of given us the same effective configuration. That is because PF passes packets by default. This is a very important point to remember. The second most important point to keep in mind is that every line in the pf.conf file is evaluated for every packet that hits the firewall and it is the last matching line (or rule) that determines what should be done with the packet. There are some important exceptions to this point that we will cover in the full blown PF tutorial.

Notice how we used this pfctl command. This is the main control tool for PF.

To see the rules that are currently in effect do the following:

# pfctl -s rules {“s” is for show}

If PF is running (as it is now) and you change the ruleset (edit its config file) to have the new rules take effect, you would go:

# pfctl -Rf <config file>

To disable PF simply do this:

# pfctl -d

If we want to have PF started automatically upon boot we edit the appropriate line in /etc/rc.conf:

pf=YES

You may think that our ruleset is useless but it is good for debugging purposes. If we’re having trouble on our network (which would by then have a “real” firewall) then we can switch to this basic rule set to determine whether the firewall is to blame.

Here is a more standard looking file. It should be enough for common web browsing with the exception of allowing for FTP traffic. I have an Intel card (fxp0) as my internal adapter:

EXT = "tun0"
INT = "fxp0"

LAN_clients = "192.168.1.0/24"

LAN_to_INT_services = "{ www, https, ssh, smtp, pop3, nntp }"

nat on $EXT from $LAN_clients to any -> $EXT

pass in quick on lo0 all
pass out quick on lo0 all

block in on $EXT all
block out on $EXT all

pass out on $EXT \
        inet proto udp \
        from $EXT to any \
        port 53 \
        keep state

pass out on $EXT \
        inet proto tcp \
        from $EXT to any \
        port $LAN_to_INT_services \
        modulate state

It is now time for you to go through my Understanding Packet Filter tutorial.

About these ads

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

%d bloggers like this: