Pro-Tip: Port Mirroring In Linux

Sometimes a span/mirror port isn’t available on a switch when you need one. However, if you just need to monitor traffic from/to a Linux server, you can have the Linux server mirror it’s own traffic toward a collector. You just need a spare NIC on the Linux system.

For example, if you want to mirror all traffic going in/out of eth0, and send it out eth1 toward a collector, you can do that with the ‘tc’ subsystem. Some examples of this exist online. However, what they don’t tell you is that if eth1 goes down (unplugged, etc), that results in eth0 blocking all traffic — not good! I came up with a workaround for that problem using bridge and dummy interfaces. It’s kludgy, but it works!

See below for all the required config files / scripts. (don’t forget to chmod the scripts so root can run them!)

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto eth0
iface eth0 inet static
address 192.168.1.123
netmask 255.255.255.20
gateway 192.168.1.254
dns-nameservers 8.8.8.8

# physical mirror port toward collector
auto eth1
iface eth1 inet static
address 127.1.1.1
netmask 255.255.255.255
up ip addr del 127.1.1.1/32 dev eth1;:

# always-up mirror port toward dev null
auto dummy0
iface dummy0 inet static
address 127.4.4.4
netmask 255.255.255.255
pre-up modprobe dummy;:
up ip addr del 127.4.4.4/32 dev dummy0;:

# bridge of eth1 and dummy0
# this is so that it always stays up, even if eth1 is down
auto br0
iface br0 inet static
bridge_ports eth1 dummy0
address 127.5.5.5
netmask 255.255.255.255
up ip addr del 127.5.5.5/32 dev br0;:
post-up /etc/network/mirror-up.sh;:
pre-down /etc/network/mirror-down.sh;:
#!/bin/sh

# ALK 2014-10-23
# Send all 'source_if' traffic (ingress & egress) to collector box on 'dest_if'

# Normally called by boot process or ifup. i.e.
# --/etc/network/interfaces--
#   iface eth0 inet static
#     address X.X.X.X
#     netmask Y.Y.Y.Y
#     post-up /etc/network/mirror-up.sh;:

source_if=eth0
dest_if=br0

# enable the destination port
ifconfig $dest_if up;:

# mirror ingress traffic
tc qdisc add dev $source_if ingress;:
tc filter add dev $source_if parent ffff: \
protocol all \
u32 match u8 0 0 \
action mirred egress mirror dev $dest_if;:

# mirror egress traffic
tc qdisc add dev $source_if handle 1: root prio;:
tc filter add dev $source_if parent 1: \
protocol all \
u32 match u8 0 0 \
action mirred egress mirror dev $dest_if;:
#!/bin/sh

# ALK 2014-10-23
# De-provision mirroring config (See mirror-up.sh for provisioning)

# Normally called by boot process or ifdown. i.e.
# --/etc/network/interfaces--
#   iface eth0 inet static
#     address X.X.X.X
#     netmask Y.Y.Y.Y
#     pre-down /etc/network/mirror-down.sh;:

source_if=eth0

# de-provision ingress mirroring
tc qdisc del dev $source_if ingress;:

# de-provisoin egress mirroring
tc qdisc del dev $source_if root;: