Packet Capture From Inside Docker
Tags: docker, nsntrace, pcap, wireshark
Published: 2024-03-10 19:26:42

---
title: Packet Capture From Inside Docker
published: true
description: Capturing a processes' network traffic from inside a Docker container.
tags: docker, nsntrace, pcap, wireshark
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cqqtrvhnkgpqh4ly68s2.png
# Use a ratio of 100:42 for best results.
# published_at: current
---

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](https://askubuntu.com/questions/11709/how-can-i-capture-network-traffic-of-a-single-process). 

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](https://askubuntu.com/questions/11709/how-can-i-capture-network-traffic-of-a-single-process/499850#499850) 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](https://askubuntu.com/a/798919) with a Github project for the tool [nsntrace](https://github.com/nsntrace/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
```

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 .

## Running

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

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.
    $

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

![pcap](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p2xj35kyhzxqqun4pbrx.png)
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.