I am trying to create IP-MAC pairing rules in ebtables. There are few tutorials and related questions [1] available but I have kind of specific setting.
ENVIRONMENT: I have many physical hosts. Each host has few ethernet cards, joined in bond and used as slave for bridge. There are many virtual machines on each host (kvm, qemu, libvirt). Each virtual machine is connected to a bridge of its physical host via new port called vnet[0-9]+. There is no NAT. Networking works fine, all the physical hosts can be pinged, all the virtual machines too. Each virtual machine has its own IP address and MAC address.
PROBLEM: Inside of a virtual machine, IP address can be changed to another one.
FOUND SOLUTION: There is known solution on the ebtables site [2], but this solution is aplicable when only one host is used. It allows all traffic and if there is a packet from IP with another MAC than allowed, packet is droped. If there are more than one host, it requires all existing IP-MAC pairs to be registered on all hosts. There is need for reverse policy solution.
CRAFTED SOLUTION: I have tried to use ebtables in inverted manner. Here is an example what I tried.
EXAMPLE 1
Bridge table: filter
Bridge chain: INPUT, entries: 2, policy: DROP
-i bond0 -j ACCEPT
-p IPv4 -s 54:52:0:98:d7:b6 --ip-src 192.168.11.122 -j ACCEPT
Bridge chain: FORWARD, entries: 0, policy: ACCEPT
Bridge chain: OUTPUT, entries: 0, policy: ACCEPT
EXAMPLE 2
Bridge table: filter
Bridge chain: INPUT, entries: 0, policy: ACCEPT
Bridge chain: FORWARD, entries: 1, policy: DROP
-p IPv4 -s 54:52:0:98:d7:b6 --ip-src 192.168.11.122 -j ACCEPT
Bridge chain: OUTPUT, entries: 0, policy: ACCEPT
The core of what I want is to have default policy DROP and only allow traffic from virtual machines with correct IP-MAC pair deployed on given host. However, those solutions do not work.
QUESTION: How to allow traffic on bridge only for specified IP-MAC pairs of running virtual machines and drop all unknown IP-MAC pairs comming from ports vnet[0-9]+?
Thank you very much for any answers.
I have finally managed to craft a working solution.
So, in the begining, there are no rules whatsoever and all policies are set up to ACCEPT. There are no user defined chains. Filter table looks like this:
A new chain is addded. This chain contains all the allowed IP-MAC pairs. It is called VMS.
Now, the important part. For every frame containing IP packet (or its parts) which is going thru bridge from port vnet[0-9]+, apply chain policy and rules of chain VMS. In other words, for every IP packet comming from any virtual machine, apply VMS chain.
The default policy of chain VMS has to be DROP. This way, every IP packet comming from any virtual machine is droped by default. Later, allowed IP-MAC pairs exceptions are added. The default policy DROP causes, that all traffic from any virtual machine with unknown IP-MAC pair is droped at once, making IP spoofing impossible.
The table filter looks now this way. Also, this way it looks when there are no virtual machines running (allowed).
Suppose, there are two running machines. If we try to ping to/from them, traffic is dropped and destination is unreachable. This is desired result, as of this traffic has not been allowed yet. Only one command is enough to allow every one virtual machine traffic.
Now, traffic from allowed virtual machines is flowing alright and IP spoofing is prevented.
This solution may be unperfect and if you have any comments or improvements, I will gladly hear them.