The "802.1d Ethernet Bridging" option in the kernel allows a Linux machine with more than one network interface to bridge those interfaces as an ethernet switch would. In addition, routing and firewall rules can be applied to traffic crossing the bridge. The 802.1d in the title refers to the Spanning Tree algorithm standard which allows multiple switches to operate together on a network without accidental network loops forming.
I started researching the Ethernet Bridging support in Linux in order to build a transparent firewall that would not occupy an IP address. I did this for my home network which had already used up all of the IP addresses available to me (without paying for more, or switching to IP Masquerading). Before continuing with these instructions, consider your own "why?", since the answers may change how you proceed. Much of this document has been gleaned from the Bridging Howto and the ebtables documentation hosted on the tools' respective sites on sourceforge.
The machine used will be referred to as the "bridge" machine. For the firewalling purpose of this document, I will call interface
eth1 the "inside" interface (towards the protected network) and interface
eth0 the "outside" interface, (towards the internet). There are a number of other terms which will be used that are specific to the ebtables process, such as "brouting" (the process of routing ethernet frames). Kernel CONFIG_ flags are based on the 2.6.10 kernel, and may be different for older kernels.
Before beginning this process, your kernel will need to be compiled with "802.1d Ethernet Bridging" enabled (CONFIG_BRIDGE under Networking Options. This will also unlock new entries under the "Network packet filtering" menus) (note, older kernels provided a "Fast Switching" option for some network cards. If you enable this option, you will not be able to use ebtables/iptables to control frames/packets, but you will get lower CPU utilization). You will also need the ebtables and brctl tools. Debian provides these in the ebtables and bridge-utils packages.
Configuring a Bridge
The first step is to make sure the network cards are working and configured without addresses. This can be done with
ifconfig ethX 0.0.0.0 (some drivers use
promisc instead of
The next step is to configure the network bridge itself. This is done through the
brctl program. There are two parts to creating the bridge: first, create the bridge using
brctl addbr brname. Second, add interfaces to the bridge using
brctl addif brname ethX. Use ebtables to set the default policy for the BROUTING chain in the broute table to ACCEPT (with
ebtables -t broute -P BROUTING ACCEPT) if it isn't already. Finally, use
ifconfig brname up to enable the bridge, and after a brief period of learning MAC addresses, traffic will begin flowing through your new switch.
If this is a large network with multiple switches in different locations or if you use redundant switches, the next step is to turn on the 802.1d Spanning Tree Protocol. This allows the bridge to participate in the loop-detection routines in place on the network. This is done with
brctl stp brname on. If this is a small network that you are certain has no loops, you can leave this off.
Bridging and Firewalling
Firewalling on a bridge can be done at two levels. First, ebtables can perform some filtering by itself, if you enable "ebt: filter table support" (CONFIG_BRIDGE_EBT_T_FILTER under Bridge netfilter Configuration). This will allow you to use
ebtables --t filter -A FORWARD .... to create rules allowing certain MAC addresses through the firewall. With additional ebt modules, you can also match based on IP address, packet marking, or other criteria.
Second, bridged IP traffic can be configured to pass through iptables. This is set using
echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables. After that, all bridged IPv4 traffic will flow through the iptables
FORWARD chain. However, on 2.6 kernels, iptables cannot tell on its own which direction the traffic is flowing through the bridge.
Most users using the bridge as a firewall will want to define an "incoming" side and an "outgoing" side, and treat them differently. To do this, you will need the "Physdev match support" (IP_NF_MATCH_PHYSDEV Under netfilter IPv4 configuration, only after you have enabled bridging). Now, with
iptables -t filter -m physdev you have new options:
--physdev-in ethX and
--physdev-out ethX (among others, use
iptables -m physdev -h to see the complete list). These options allow you to specifically block traffic from one interface of a bridge. Thus, you can block incoming connections to port 80 using
iptables -t filter -m physdev -A FORWARD --destination-port 80 --physdev-in eth0 -j DROP.
The next step: Brouting
Note: the iptables save and restore scripts many distributions provide do not operate on ebtables. You will need to provide your own startup script to establish the bridge and any ebtables rules for bridging. ebtables provides its own features for atomically loading all of its rules in a single operation, read its manpage for an explanation.
By default, all traffic simply passes through your bridge and the firewall, without any further processing. Brouting (Bridge-Routing) changes this by allowing you to select frames to undergo further processing based on certain aspects of the frame at the network level (most notably, the MAC address and the protocol type, though there are more options for some protocols, such as IPv4). This allows your bridge to perform more complex operations or send and receive network traffic directly. Before you begin, you will need to assign IP addresses to your machine's network interfaces and establish at least routes to the network (if not a default route to the internet). You will also need "ebt: broute table support" (CONFIG_BRIDGE_EBT_BROUTE under Bridge netfilter) in your kernel.
There are two kinds of brouting: the first (and simplest) allows the kernel to "catch" the packets that are addressed to itself. This consists of an
ebtables -t broute -A BROUTING -p arp -i ethX -d ethX:MAC:Addr:ess -j DROP and an
ebtables -t broute -A BROUTING -p ipv4 -i ethX --ip-dst ethX.ip.addr.ess -j DROP for each interface on your bridge with an address. This will "DROP" the traffic into the kernel's normal processing in order to accept and respond to ARP replies, as well as accept IPv4 traffic destined for the bridge machine.
The second is slightly more complex, and is used to capture frames that were not addressed to the machine, in order to pass them to Linux's routing system. if we attempt to DROP the packets as above, Linux will ignore them, since the MAC address does not match the address of the network interface. We will have to redirect these packets first to update the MAC address, then DROP them:
ebtables -t broute -A BROUTING -p ipv4 -i eth0 -j redirect --redirect-to DROP (a very basic example). The "ebt: IP filter support" (CONFIG_BRIDGE_EBT_IP under Bridge netfilter) provides better rules for matching TCP and UDP traffic. See ebtables's manpage for details. For real world examples of ebrouting in action, I suggest you read the ebtables examples guide
This guide heavily draws from several sources: The BRIDGE-STP-HOWTO, the ebtables website, and the ethernet bridging website.
This document was last updated 2005-02-19