ARP Cache can not be flushed within docker containers

I am trying to create a group of docker containers that communicate with one another and regularly flush their ARP cache. The goal is for the application to serve as an interactive demonstration of ARP cache poisoning. However, my attempts to flush the ARP cache within the docker containers have been unsuccessful. All attempts have been made with Docker 27.3.1 for Arch Linux (Kernel 6.11.5).

Two containers suffice to show this problem. See here two Dockerfiles and a docker-compose.yml:

# A/Dockerfile
FROM ubuntu:22.04

RUN apt-get update -y && \
	apt-get install -y netcat iputils-ping iproute2 net-tools && \
	apt-get clean

WORKDIR /root

ENTRYPOINT ["bash", "-c", "ping -i 3 10.10.8.3"]
# B/Dockerfile
FROM ubuntu:22.04

RUN apt-get update -y && \
	apt-get install -y netcat iputils-ping iproute2 net-tools && \
	apt-get clean

WORKDIR /root

ENTRYPOINT ["bash", "-c", "ping -i 3 10.10.8.2"]
# docker-compose.yml
services:
  alice:
    build:
      context: ./A
    networks:
      attacknet:
        ipv4_address: 10.10.8.2
    restart: on-failure:3
  bob:
    build:
      context: ./B
    networks:
      attacknet:
        ipv4_address: 10.10.8.3
    restart: on-failure:3

networks:
  attacknet:
    driver: bridge
    internal: true
    ipam:
      config:
        - subnet: 10.10.8.0/24

When running these containers and logging into Alice with sudo docker exec -it mwe-alice-1 "bash", the following commands all fail:

root@7a8941bb0171:~# ip neigh flush all dev eth0
Failed to send flush request: Operation not permitted
root@7a8941bb0171:~# arp -d 10.10.8.3
SIOCDARP(dontpub): Operation not permitted
root@7a8941bb0171:~# ip link set arp off dev eth0
RTNETLINK answers: Operation not permitted

Maybe it should be noted: When testing with just one container, being assigned a network with external access (eth0) and the attacknet (eth1), the commands fail on eth0 but do not report an error on eth1.

So… what does this mean? The error messages are definitely confusing to me, since I would expect to have the necessary permissions with root privileges. But it seems clear that the docker networking drivers have something to do with it.
Do you have any ideas what causes this issue? Is there something about docker’s inner working that makes flushing (and more importantly, poisoning) the containers’ ARP cache impossible, or is there still hope for my project in some way?

When a container is started, capabilities are dropped as part of the isolation. The error message indicates that the binary requires capabilities the container lacks.

Capabilities can be added when the container is created, see: https://docs.docker.com/engine/containers/run/#runtime-privilege-and-linux-capabilities and https://docs.docker.com/reference/compose-file/services/#cap_add

You will need at least the capability NET_ADMIN, maybe NET_RAW and other capabilities as well. You need to find out which capabilities are need.

2 Likes

Thank you very much! Capabilities were indeed the missing piece of the puzzle.

For reference, this page here specifies which capabilities are granted by default, and
what other capabilities are available: Running containers | Docker Docs

While this man page specifies what each capability entails: capabilities(7) - Linux manual page

I find that adding the NET_ADMIN capability solves my problems:

# docker-compose.yml
services:
  alice:
    build:
      context: ./A
    networks:
      attacknet:
        ipv4_address: 10.10.8.2
    cap_add:
      - NET_ADMIN
    restart: on-failure:3
  bob:
    build:
      context: ./B
    networks:
      attacknet:
        ipv4_address: 10.10.8.3
    restart: on-failure:3

networks:
  attacknet:
    driver: bridge
    internal: true
    ipam:
      config:
        - subnet: 10.10.8.0/24

Within my actual container setup, I have also been able to verify that ARP cache poisoning works as desired! Issue solved.