Linux - Create a Linux Bridge Hub

 

How do Linux Bridge Hubs Work?

Linux bridges have been around since ancient times and are a simple, easy way to attach multiple physical and virtual ports in a Linux system. Layer-2 bridging (or switching) takes place in the Linux kernel, so network frame transfer is quick with minimal latency. For all intents and purposes, the Linux bridge serves the majority of situations that involve traffic going from one port to another efficiently, much like dedicated hardware network switch. 

Bridges and switches learn where devices reside by making a table of MAC addresses associated with ports. For example, when a frame is received on a physical or virtual port from system A, the source MAC address and the incoming port of system A is added to the table. Then the frame is broadcast out all other ports since the destination port for the MAC address of system B is not yet known. When system B responds, the same thing happens but in the opposite direction. The source MAC address and incoming port association for system B are placed in the table. Now the bridge/switch knows which ports both systems are connected and can direct network frames only between these two ports, using the most efficient path. The Linux kernel maintains a timer for each table entry to prevent table fill up. When a system stops sending frames, like when it is shut down, the kernel waits 300 seconds by default and then removes that entry from the table.

There are occasions where we need to have certain devices see all the traffic going across the bridge, not just from one port to another. For instance, we may have Intrusion Detection System (IDS) or packet sniffing virtual machines that need to see all traffic for analysis and anomaly alerting. In this case, we need the Linux bridge to act like an Ethernet hub. Hubs are legacy devices that repeat all frames out every port so all devices see all traffic in contrast to the one-to-one mechanism that Linux bridges natively use. 

To allow all devices to see all frames, the timer (also called ageing value) is set to zero. In essence, the table is essentially disabled and source MAC address to port mappings aren't recorded. Each frame received is then sent out all ports all the time because there the destination is always unknown (no entry in the table). The drawback is that every system has to process each frame to determine if it's for itself, taking up processing time versus having directed frames sent to it. Modern systems and VMs have plenty of computing power, so this has a minimal impact in today's environments. This is an interesting way to manipulate the Linux bridge to get the results we need.  

Configuration

There are two ways to change the ageing timer to get this hub affect, dynamically and statically. We'll cover both below. 

bridge-utils

The bridge-utils package has a program that allow you to change the ageing value on the fly. The brctl command (stands for "bridge control") has been around for a long time, but is a great tool for Linux bridge manipulation. 

Install:

root@prxmx1:~# apt-get -y install bridge-utils

Show brctl command options:

root@prxmx1:~# brctl --help
Usage: brctl [commands]
commands:
    addbr         <bridge> add bridge
    delbr         <bridge> delete bridge
    addif         <bridge> <device> add int to bridge
    delif         <bridge> <device> delete int from bridge
    hairpin       <bridge> <port> {on|off}turn hairpin on/off
    setageing     <bridge> <time>  set ageing time
    setbridgeprio <bridge> <prio>  set bridge priority
    setfd         <bridge> <time>  set bridge forward delay
    sethello      <bridge> <time>  set hello time
    setmaxage     <bridge> <time>  set max message age
    setpathcost   <bridge> <port> <cost> set path cost
    setportprio   <bridge> <port> <prio> set port priority
    show          [ <bridge> ] show a list of bridges
    showmacs      <bridge> show a list of mac addrs
    showstp       <bridge> show bridge stp info
    stp           <bridge> {on|off} turn stp on/off
root@prxmx1:~#

Let's create a temporary bridge which we will use to create our bridge hub.

root@prxmx1:~# brctl addbr br0
root@prxmx1:~# brctl addif br0 eth1
root@prxmx1:~# brctl addif br0 eth2
root@prxmx1:~# brctl show
bridge name    bridge id            STP enabled    interfaces
br0            8000.000c297a82bc    no             eth1
                                                   eth2
root@prxmx1:~#
Commands explanation:

  • brctl addbr br0 - creates the linux bridge in the linux kernel
  • brctl addif eth1 - adds the eth1 interface to the bridge br0
  • brctl addif eth2 - adds the eth2 interface to the bridge br0
  • brctl show - shows all the configured linux bridge info

As you can see from the previous --help output, one of the options for brctl is setageing. If we set the setageing parameter to zero, then all interfaces attached to the bridge will receive all network frames regardless of the destination. This is what we want so our IDS device will see all the network traffic. The bridge will essentially time out every entry in the kernel MAC address table immediately as each frame is received and not keep the port association information.

To do this, we use the following command:

root@prxmx1:~# brctl setageing br0 0

This takes affect immediately, you can verify this by issuing:

root@prxmx1:~# brctl showstp br0
br0
 bridge id       8000.000c297a82bc
 designated root 8000.000c297a82bc
 root port       0            path cost            0
 max age         20.00        bridge max age       20.00
 hello time      2.00         bridge hello time    2.00
 forward delay   15.00        bridge forward delay 15.00

 ageing time     0.00
 hello timer     0.00         tcn timer            0.00
 topology change timer  0.00  gc timer             0.00
 ...

root@prxmx1:~#

As you can see, the ageing time is now at zero and all ports will receive all traffic.

Keep in mind that the above configuration is in effect only until the system is rebooted. To make the configurstion permenent and effective after a reboot, edit your networking file as follows. I'm using debian Linux in this example, so use your Google-fu for the Linux distro you're using.

    root@prxmx1:~# cat /etc/network/interfaces
    auto lo
    iface lo inet loopback

    auto eth0
    iface eth0 inet static
        address x.x.x.x
        netmask 255.255.255.0
        network x.x.x.0
        broadcast x.x.x.255

    auto br0
    iface br0 inet static
        address x.x.x.x.x
        netmask 255.0.0.0
        network x.x.x.0
        broadcast x.x.x.255
        bridge_ports eth1 eth2
        bridge_stp off
        bridge_fd 0

        bridge_ageing 0
        bridge_maxwait 0

    auto eth1
    iface eth1 inet manual

    auto eth2
    iface eth2 inet manual
    root@prxmx1:~#

Notice the bridge ports (eth1, eth2) are set to manual mode on boot. This way they can be added to the bridge without unnecessary and conflicting configurations.

Verification:

You can now verify that your bridge hub is working by running a tool called tcpdump. tcpdump captures network frames on an interface, shows them on the command line or records them to a file to view in tcpdump or Wireshark later. Wireshark is a GUI application that allows you to graphically analyze network packets (a very cool and recommended tool! Look it up). 

To see if a port is receiving all network traffic, run tcpdump on the interface attached to our IDS system, recording to a packet capture file (.pcap format).

root@prxmx1:~# tcpdump -i eth1 -w traffic-file.pcap 

10456 packets captured
10456 packets received by filter
0 packets dropped by kernel

root@ubuntu-2004-1-texting:~# ^C

Command explanation: 

  • tcpdump - base command
  • -i eth1 - identifies the interface to capture traffic from
  • -w traffic-file.pcap - tells tcpdump to write the captured packets to a file 
  • ^C [ctrl-c] - tells tcpdump to quite capturing traffic

Now, when we look at the traffic file tcpdump created, we see traffic from all the ports. When looking at the layer-3 information, we should see traffic to and from IP addresses not assigned to the port being captured on.

root@prxmx1:~# tcpdump -r dumpfile.pcap
reading from file dumpfile.pcap, link-type EN10MB (Ethernet)
19:33:37.432852 IP 192.168.209.100.ssh > 192.168.209.1.51296: Flags [P.], seq 1748148483:1748148607, ack 4192579883, win 501, options [nop,nop,TS val 3185763333 ecr 608909605], length 124
19:33:37.432967 IP 192.168.209.1.51296 > 192.168.209.100.ssh: Flags [.], ack 124, win 2046, options [nop,nop,TS val 608909660 ecr 3185763333], length 0

...
root@prxmx1:~#

Command explanation:

  • tcpdump - base command
  • -r dumpfile.pcap - reads the .pcap file and shows the network traffic to the screen

Now, your IDS can have full view of all traffic that transverses the bridge hub and is looking for suspect and malicious communications between the virtual machines and the outside networks. This is great for virtualized environment and especially when doing hacking / security scenarios in a testing or home lab. 

When labbing up a scenario up for testing or learning, run an IDS, such as Security Onion, attached the bridge hub to see what your attacks look like on the network. Look at your IDS tools and see if the attack traffic has fired off alerts and if not, learn to write signatures that will do so. This is an awesome purple team exercise to see what attacks and breaches look like from both sides of the security table!