KVM bridge for promisc interface IDS

batflaps asked:

I have a KVM virtualization server which serves up a br0 bridge, mapped to eth0. I want to add eth2 as a bridge to br2 for a IDS virtual machine I’m testing, but the guest OS doesn’t see either br2 or eth2 as a valid interface. I ran tcpdump on eth2 and can verify it’s seeing packets, so I know I have a valid source and that interface has the PROMISC option using ifconfig eth2 promisc up. Here’s my /etc/network/interfaces file:

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet manual

auto br0
iface br0 inet static
    address 1.2.3.4
    netmask 255.255.255.0
    gateway 1.2.3.1
    bridge_ports eth0
    bridge_fd 9
    bridge_hello 2
    bridge_maxage 12
    bridge_stp off

auto eth2
iface eth2 inet manual

auto br2
iface br2 inet static
    up ifconfig br2 promisc up
    down ifconfig br2 promisc down
    bridge_ports eth2
    bridge_fd 9
    bridge_hello 2
    bridge_maxage 12
    bridge_stp off

What am I missing?

My answer:


The Linux bridge is a basic layer 2 switch. In order for it to send traffic to an interface connected to it, the traffic must be appropriate for that interface (i.e. the destination MAC address is reachable via that port).

While layer 2 switches often have a port mirroring feature which forwards all traffic crossing the switch to a designated port, the Linux bridge has no such functionality.

However, you can fake it with Linux’s traffic control (tc). I do this to forward traffic to a KVM virtual machine running suricata. The limitation of this method is that you can only mirror traffic on a single physical port.

In this script, the MONITOR_PORT is the port to be monitored, which must be a physical port, and MIRROR_PORT is the interface to which the traffic will be sent (which can be a virtual port or a bridge). The monitored port does not need to be in promiscuous mode with this method. And the mirror port does not need to be bridged to the monitored port.

In my case, the host has a bridge br0, bridged to eno1 and to which all the virtual machines have a virtual NIC. I have created a host-only virtual network (as virbr2) for this VM and added a second NIC in the suricata VM on this network in addition to its regular NIC, and directed the traffic to it.

[error@hypervisor ~]$ cat /etc/rc.d/rc.local
#!/bin/bash

# Mirror all packets from one port to another (for suricata)

MONITOR_PORT=eno1
MIRROR_PORT=virbr2

# Ingress
tc qdisc add dev $MONITOR_PORT ingress
tc filter add dev $MONITOR_PORT parent ffff: protocol all u32 match u8 0 0 action mirred egress mirror dev $MIRROR_PORT
# Egress
tc qdisc add dev $MONITOR_PORT handle 1: root prio
tc filter add dev $MONITOR_PORT parent 1: protocol all u32 match u8 0 0 action mirred egress mirror dev $MIRROR_PORT

Note that I didn’t create this myself; I shamelessly ripped it off from Port mirroring with Linux bridges, which has a detailed explanation of how it works and an alternative using Open vSwitch which is a lot more flexible (and a lot more complex).


View the full question and answer on Server Fault.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.