The built-in wifi radio on a Raspberry Pi 4 is kind of sad, as it does not support monitor mode. Luckily the hackers at Seemo Labs have fixed this.
In this post we'll describe how to load Seemoo's Nexmon onto a pi4 running a modern kernel, and package it into a SPR Plugin named spr-nexmon. We'll demonstrate that packet capture and injection works.
First, we will copy the template plugin
$ cp -R super/api_sample_plugin/ spr-nexmon
Development
Prebuilt binaries
We'll use some prebuilt binaries that include
- the nexmon firmware build for the broadcom wifi radio
- the 6.2 kernel build
- the nexutil binary
These were built from the 6.1/6.2 support pull-request
$ cp -R ../nexmon/binaries spr-nexmon/binaries
Docker preparations
We'll update the Dockerfile to include some useful tools and build the project.
FROM ubuntu:23.04 as builder
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update
RUN apt-get install -y --no-install-recommends nano ca-certificates git curl
RUN mkdir /code
WORKDIR /code
ARG TARGETARCH
RUN curl -O https://dl.google.com/go/go1.20.linux-${TARGETARCH}.tar.gz
RUN rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.linux-${TARGETARCH}.tar.gz
ENV PATH="/usr/local/go/bin:$PATH"
COPY code/ /code/
ARG USE_TMPFS=true
RUN \
[ "$USE_TMPFS" = "true" ] && ln -s /tmpfs /root/go; \
go build -ldflags "-s -w" -o /nexmon_plugin /code/nexmon_plugin.go
FROM ghcr.io/spr-networks/container_template:latest
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends tcpdump kmod iw wireless-regdb && rm -rf /var/lib/apt/lists/*
COPY scripts /scripts/
COPY /nexmon_plugin /
COPY binaries/ nexmon/
ENTRYPOINT ["/scripts/startup.sh"]
We also want this container to use the host network and be privileged so it can load kernel modules. And we'll also set it to restart automatically
And heres the docker-compose.yml:
version: '3.4'
x-logging:
&default-logging
driver: journald
x-labels:
&default-labels
org.supernetworks.ci: ${CI:-false}
org.supernetworks.version: ${RELEASE_VERSION:-latest}${RELEASE_CHANNEL:-}
services:
nexmon:
container_name: supernexmon
build:
context: .
labels: *default-labels
logging: *default-logging
restart: always
network_mode: host
privileged: true
volumes:
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
- /lib/firmware/cypress/:/lib/firmware/cypress/
- "${SUPERDIR}./state/plugins/nexmon:/state/plugins/nexmon"
- "${SUPERDIR}./state/public/:/state/public/:ro"