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. |