Cover V13, i12

Article
Figure 1
Figure 2

dec2004.tar

Building a Bridge-Based Firewall

Gleicon S. Moraes

Bridges are network devices that were widely used in older network setups (like Novell's NetWare) and are still in use in some equipment, such as xDSL modems. In a simple way, they just copy the network packet from one interface to another, making it possible to deal with two different network buses (or types), as is the case of DSL bridges.

In this article, I will introduce building firewalls with bridges, suggest setups for GNU/Linux, and provide a general BSD outline to build an invisible firewall (i.e., a firewall that is not detectable by common methods because it has no IP address in its interfaces). Of course, for a skilled network hacker, it would not be impossible to tell that there is "something" different in the wire, but usually this setup will pass unnoticed.

Bridges were a must for IPX/SPX-based networks, since these protocols had no form of easy routing. After some hardware implementations came some nice software bridges, ranging from a simple packet copy between interfaces (as in GNU/Linux) to more complex ones (e.g., xDSL modems and routers with more resources than just a packet copy).

Network Packets and Firewalls

Before going further, I should provide some basic information about network packets and firewalls. The basic network data units -- network packets -- and the concept of handling them comprise the heart of a router and a firewall. It's all about packets at the lowest level. Routers usually have some firewall capabilities, and firewalls have some router capabilities.

A router is a device that routes or directs network traffic, which is composed of network packets. Of course, there is much more inside modern, tiny routers than this, including filtering capability or VPNs (virtual private networks).

A firewall, on the other hand, is a device or a program installed on a server that implements and enforces an organization's security rules by filtering network packets. Again, many firewalls have routing capabilities, as implemented by DMZs (DeMilitarized Zones) where packets are routed to another interface and subject to a different ruleset. Also, VPNs are one of a modern firewall's most-used resources.

In short, we are dealing with networks packets and three conditions: FROM, TO, and WHAT (i.e., where is the packet FROM, where is it meant TO go, and WHAT to do with it).

Architectures and Networks

Most open source operating systems now have built-in packet filtering and routing capabilities. In a basic setup, a machine acts as a gateway for the network, with all the routes and rules defined by the systems administrator, and sometimes acts as the HTTP and SMTP proxy/controller. This setup can range from a single machine to a multi-processor server or a cluster to provide users with services and an interface between systems and companies.

Another way to implement a firewall is to use a bridge to copy packets between interfaces and use the operating system's resources and network stack to filter and route these packets. This is not a typical solution; however, it would result in an interesting setup where the firewall would be an "intelligent wire" without an IP address sitting between your network and Internet connection.

The Bridge

You can have IP addresses in the bridge's interfaces, but it's not necessary and not having them will keep your firewall from being a target for script kiddies. Another reason for this setup is when you don't have many IP addresses. Usually, for small links, you are charged by network classes, and getting a full C class is pretty hard these days.

The downside is that you will have to maintain it with a local console, serial console, another network card, or by setting up a reserved IP address in the internal network card. However, once it's set up and working, there is little -- if any -- maintenance. My setup has another network card in a reserved network to perform general management, but that is not mandatory. You could set up an IP address in the bridge interface to do that, too.

Figure 1 shows a sample network setup. This is by no means the only way you could implement it, but it's a good example because of its simplicity and lack of external constraint, such as VPNs and DMZ. (Later, it will be easy to figure out how to add these capabilities.)

This is basically a network with no protection from outsiders. Some rules could be enforced in the router, but routers usually don't have the horsepower to deal with high-traffic rates and long rulesets at the same time. A firewall machine usually would be located in an intersection between the router and the switch. Keep in mind that the logical diagram is not a direct reflection of the physical layout. The firewall actually would be connected in a switch port as the router, and the proper setup would be ensured to make the ends meet.

To connect a bridge in this setup is a matter of using a crossover cable, literally inserting the bridge between the router and the LAN as shown in Figure 2. This way, each packet present in the router's interface would be present at our machine's input and would be replicated (after proper filtering) to the output interface, making its way through the switch to the network.

The sample bridge will use GNU/Linux, but I will show some pointers for FreeBSD later in the article. This article may also help you implement this setup using any other OS offering this capability.

The original bridge code would be like an infinite loop, just reading packets from one interface and writing to another. It was advertised originally as helping games -- like Doom and Quake -- in an IPX network, but since its first release has evolved and been incorporated into the Linux kernel.

Behind the operating system and the necessary code, the concept is simple. To ensure the network cards will receive all the packets presented, set them to promiscuous mode, which is one of the three possible modes. The other two modes are unicast (the default) and multicast. Being in promiscuous mode will set the traffic at the same rate as the total network bus traffic. With both interfaces in promiscuous mode, you will join them in a pseudo-interface, called br0, and enable it. Activating packet forwarding will ensure the setup will start passing packets to both sides. These packets are subject to the netfilter layer, managed by iptables, and from that you can use other utilities and resources (such as the iproute2 package) to customize your firewall. For the sake of brevity, complex firewall rules will not be covered in this article.

Building the Bridge

For this setup, you need a machine with enough processing power to handle this job. A Pentium II or AMD 450 will suffice, but keep in mind that the more complex you want your bridge/firewall, the more muscle you will need. Both interfaces will be in promiscuous mode, so heavy traffic can really hog resources. Also, applying traffic filter rules can be time-consuming from both a memory and CPU perspective. The kernel must set up lists and data structures to do ordering and filtering to the incoming flow, so if you don't provide enough memory, it can start using swap space and increase the network latency and response time.

With the latest 2.4 kernel (latest is 2.4.27, which I will use as an example, and the latest stable kernel is 2.6.9), it's not necessary to apply patches to enable bridging. For other kernel releases, check: http://bridge.sf.net for instructions on how to enable it. The only patch you will need is the one from ebtables (http://ebtables.sf.net) for your kernel version, to enable the hooks between netfilter and your bridge. Download it and apply to your kernel source as instructed (patch -p1 < ebtables-brnf-xxx.diff from inside your source directory).

You'll also need to know how to compile a Linux kernel. For that, there is plenty of documentation available online. After you configure it with make menuconfig or make xconfig (or make config), enable the following options (in addition to your hardware and software needs):

    Code Maturity Level:

  • Prompt for development and/or incomplete code/drivers.

    Loadable Module Support:

  • Enable loadable module support (in case you prefer the bridge code as module).
  • Set version information on all module symbols.
  • Kernel module loader.

    Networking Options:

  • Set up your needs, including netfilter, which is necessary for iptables.
  • Or [M] 802.1d Ethernet Bridging.
  • Or [M] Bridge: ebtables.
  • Set up the options that will appear below as module, until you learn what you need.

    Network Device Support:

  • Set up your Ethernet boards drivers.

Compile, install, and test as soon as the new kernel is working. Connect it using a cross cable if you are connecting one of the Ethernet ports directly to the router. If you are using a DSL setup just to test it, use two cross cables -- one from the DSL router to the bridge and another from the bridge to your machine. It's helpful to test the setup before applying it to a real network. You can plug it straight to your switch or hub with a regular cable. The cross cables are useful for testing and for point-to-point setups, where you don't need a hub, switch, or VPN to connect two interfaces.

You also will need to install the bridge tools. Check whether your distribution has some binary package, or if you prefer, download it, and compile from http://bridge.sf.net. My distribution is Slackware 9.1 with all current updates, but I chose to download and compile "bridge-utils". It's not that hard -- download, unpack, and just follow the install guide. Mostly, it is the usual ./configure, make, make install. Check the install place and permissions to see whether they suit your system's needs.

There are small programs to create, enable, and manage your bridge. To test your installation, load the bridge.o module (if you have compiled it as a module), and run brctl. If you get some error, such as "Package not installed", check whether your kernel is compiled correctly and that bridge-utils has proper rights to execute, is in the PATH, and is the latest release. Next, load your network cards modules, if they aren't loaded already, and type the following commands (as root):

brctl addbr br0
brctl addif br0 eth0
brctl addif br0 eth1
ifconfig eth0 0.0.0.0 promisc
ifconfig eth1 0.0.0.0 promisc
ifconfig br0 up
If none of these commands gave you error messages, your bridge is up and running. Issue an ifconfig command and check your new interface, called br0. It could have another name, but this is the standard you'll find in the documentation. The first command creates the br0 interface; the second and third add eth0 and eth1 to your bridge (in essence, gluing them). The following two ifconfig commands wipe any IP addresses that might be there (since they will be part of another interface) and set them in promiscuous mode to receive and pass any packet to the kernel's network stack.

Your interface is eth0 and eth1, due to the irq or precedence in the PCI slots. However, it doesn't matter now because your rules will work over the br0 interface. If you want it to have a real/internal IP address, you should change the last line to ifconfig br0 ip-addr.

Plug it into your network and, from a workstation, run some commands (such as ping) to external hosts or do some Web browsing -- it should work transparently. The speed shouldn't be a concern, since you know your machine's limitations. If it has good CPU and memory, everything should be smooth. As for the bridge administration, either you could have another Ethernet board or you could set up the bridge interface (br0, in our case) with an IP address. An even better idea would be to set up a so-called invalid IP address from the reserved network block (or a different block from what you use for your internal machines) and set up an interface alias using the same network in a gateway or server. You have many options.

The first step is up and running; now let's set up some rules to make it a firewall and introduce some ideas to make it highly available.

Firewall Rules

The first concept is that you can use any rule you would use to filter packets from and to your network. After applying the kernel patch, the netfilter subsystem is hooked to the bridge subsystem and knows the interface and data flow.

Let's focus on filtering rules; this one will clarify everything:

iptables -A FORWARD -p tcp -s 0/0 -d xxx.xxx.xxx.xxx/yy --dport 22 -j DROP
This rule drops all packets from everywhere to the xxx.xxx.xxx.xxx/yy machine/network. The main point is that we've used the FORWARD chain. The INPUT and OUTPUT chains, used to control the flow from and to the bridge machine, could be used if you have set up an IP address-based bridge.

All iptables resources can be used -- even some experimental patches like this rule:

iptables -A  FORWARD  -p tcp -s 0.0.0.0/0 -m string --string "cmd.exe" -j DROP
Using the experimental module string, this rule filters and drops all packets containing cmd.exe, which usually are used by worms to scan several network blocks for buggy machines.

That said, there are plenty of Linux firewall scripts and helper applications on the Web. I encourage you to test them and find your own setup. Just remember the FORWARD chain is the place to work these packets, but you can create your own chain and combine other ones.

At the lowest network level, there are two other applications: ebtables and arptables. These are found at the ebtables Web site and must be installed according to your Linux distribution, to route packets, alter MAC addresses, and some advanced features. Most important is the bridge's basic concept, which can be extended to do almost anything you want. Check out the FAQ for some ideas.

Other programs can run on your bridge; you might try tcptrack or ntop. Both of these monitor network traffic and, in promiscuous mode, count, classify, and show a lot of statistics -- ntop even shows graphics. With both your interfaces in promiscuous mode, you can choose one and use it as your favorite, because you will already be receiving all packets and the overhead will be minimal. Note that you will either need to have physical access or set up an IP address to check them via ssh or http.

High Availability

The bridge is up, working full-time filtering and routing traffic, giving statistics, and is part of your network culture -- everyone relies on it. Now it's time to think about what will happen if your bridge, for any reason, suddenly goes out.

From a hardware point of view, it would be enough to wire your bridges to the network, set one as standby, and use something like heartbeat or other monitoring software, to check via serial or even Ethernet link if a machine is down, and take the right measures.

The Spanning-Tree Protocol (STP) is part of the bridge specs and works nicely for this purpose. STP will broadcast notification of a change in network topology, such as a bridge cable out. If the bridges are wired appropriately and assigned priorities, an STP notification will alert the standby bridge to awaken and begin fielding all traffic.

In any setup, you need to ensure that your bridges see the same network traffic flow. This means they must be wired in parallel, or otherwise connected to the same network elements, such as hubs and switches. Use brctl and the setbridgeprio to set the bridge priorities (the lowest value is the root or main bridge). Use stp to turn STP on or off; it is on by default. With both bridges wired and assigned priorities, test by disconnecting one of the cables. The network traffic should pass automatically from one to the other, maintaining full logical connectivity and with the topology change event noted in the syslog.

Other Operating Systems

One of many OS you can set up a bridge is FreeBSD. It's easy; the FreeBSD handbook says that you should:

  • Compile the kernel with the BRIDGE option ON (options BRIDGE);
  • # sysctl -w net.link.ether.bridge=1
  • # sysctl -w net.link.ether.bridge_cfg=if1,if2
  • # sysctl net.link.ether.bridge_ipfw=1
  • Use ipfw to set up your rules.

Once the basic concepts have been grasped, it isn't hard to port to another operating system/architecture.

FreeBSD was chosen by the easy online documentation, but if you have information in your OS's documentation, just apply the whole idea. Perhaps one resource will not be fully functional, but it can open the field to discussion or even contribution in form of testing, documentation, and code.

Conclusion

This is not, by any means, the definitive bridge, firewall, or security document. But, it's a simple idea that can really make the difference within an organization in a given situation.

Just give it a try -- after all, it's free -- and invisible too! Be sure to respect the basic security rules, check the code updates, and test it before applying to a production environment.

Gleicon S. Moraes has used Linux since 1996; he works as consultant and is pursuing a Master's degree. His Web site, http://videodog.cjb.net, holds some projects and information. When he isn't in front of a computer, he is playing guitar or doing some judo -- always with biolinha and lots of cats.