DEV Community

Cover image for Packet Capture From Inside Docker
Kirby Angell
Kirby Angell

Posted on

Packet Capture From Inside Docker

For an existing project I needed a better way of capturing network traffic than what I had been using. Before, I used Python to setup a capture using Impacket. I would have to keep track of the ports the process used and then filter the pcap data based on those ports to get just the process I was interested in. That method had a big problem though. The port data had to be collected from the connections themselves which meant until the connection was setup, I wouldn't see any of the traffic.

Overview

Looking for a new solution what I wanted was something like strace but instead of recording library function calls I want the network packets being sent and in pcap format. I found what I was looking for in an AskUbuntu post.

A lot has changed in 13 years since that post was written, but how Linux does networking, at least from the administrators side is still valid. A response to the question has the answer which is to use some iptables magic to create an isolated network namespace. That author points out that it is fairly complicated though. It might also be hard to "wrap up" into a usable tool.

But it wasn't! At least not for Jonas Danielsson who followed up with a Github project for the tool nsntrace. So that's what I'm going to use in this article where I'll show you how to capture all of the network traffic into a pcap file for a process spawned inside of a Docker container.

Docker Configuration

Here is the basic Dockerfile configuration we will be using for this project:

# Use Debian as the base image
FROM debian:buster

# Update package lists and install necessary packages
RUN apt-get update && apt-get install -y \
    curl \
    build-essential \
    git \
    automake \
    docbook-xml  \
    docbook-xsl \
    iptables \
    libnl-route-3-dev \
    libpcap-dev \
    pkg-config \
    xsltproc \
    && rm -rf /var/lib/apt/lists/*

RUN update-alternatives --set iptables /usr/sbin/iptables-legacy
RUN update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy

WORKDIR /
RUN git clone https://github.com/nsntrace/nsntrace.git
WORKDIR /nsntrace
RUN ./autogen.sh
RUN ./configure
RUN make install
Enter fullscreen mode Exit fullscreen mode

The actual one for my project involves quite a bit more, but this has the essentials we'll need to get nsntrace working. The package list comes from the nstrace build instructions plus a few extras to facilitate the build and testing. Debian as of the Buster release started using nftables instead of iptables. Luckily Debian provides an easy way to switch back to iptables using the update-alternatives command in the Dockerfile.

We build the container using this command:

docker build -t test .
Enter fullscreen mode Exit fullscreen mode

Running

sudo docker run \
    --privileged \
    -v /tmp:/tmp -it test nsntrace \
    <process to run> 
Enter fullscreen mode Exit fullscreen mode

For nstrace to do the things it needs to capture the traffic, such as adding network interfaces and manipulating the firewall rules it needs the "--privileged" flag. I'm not a big fan of giving the container these capabilities and would like to narrow it down. With SYS_ADMIN and NET_ADMIN nstrace works, but displays an error message "failed to set namespace name". As of the time of this publiciation I haven't found a Docker run flag that will give it just the ability to control network namespaces.

I've chosen to map the host's /tmp directory to the container's /tmp directory so we can get the packet captures back out of the container to examine. Here I use the new container to capture the traffic curl generates accessing my company website:

$ sudo docker run --privileged -v /tmp:/tmp -it test nsntrace -o /tmp/test.cap curl https://alertra.com
Starting network trace of 'curl' on interface eth0.
Your IP address in this trace is 172.19.179.255.
Use ctrl-c to end at any time.

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="https://www.alertra.com/">here</a>.</p>
</body></html>
Finished capturing 33 packets.
$
Enter fullscreen mode Exit fullscreen mode

The pcap file is placed in /tmp/test.cap which we can examine with Wireshark:

pcap
Here we see everything the process did on the network. The DNS queries, the setup and teardown of the TCP connection, and the TLS negotiation. We even see the local network ARP packets!

Conclusion

Obviously this is a simple example and if you just want to capture packets coming or going on a port then there are easier ways to do it like tcpdump and Wireshark. But if you really need to see all the network traffic at a process level, then nsntrace works great and can be run from within a Docker container if need be.

Top comments (0)