Skip to content

Application Network Auditing

I see that many people carelessly express their opinions about how private and privacy oriented some applications are, especially in the browsers landscape, but, so far, all failed to report a strict analysis with real world data or numbers.

Here you can find some of the possible ways of auditing a web browser for background network connections. Specifically to see if it phones home, if it bypasses the system dns, if it contacts third parties.

While this type of auditing requires some experience in networking, it is also meant to be naive and superficial by showing only connections and not their content, to show what actually happens behind the scenes and finally have some actual real world data and visuals on this.

There are easier or quicker ways of doing this kind of test, for these, check the last part of this article where I propose some alternative methods.


  • The Application, in this case:
chromium | 120.0.6099.129-1 | testing/main amd64 Packages
  • Wireshark
  • A GNU/Linux distribution


For this task we have two options,

  • Option 1: to monitor network activity at the first run, we can run a freshly installed Virtual Machine snapshot so we can roll back to a pristine state before each test every time.

  • Option 2: we do not care about the first run, we can proceed with no need for virtual machine, saving time and disk space.

Regardless of the option chosen, the following steps apply.

Network setup

In order to perform a clean analysis of the network activity, we need to confine the application we want to audit in an ad-hoc Network Namespace. This way we will be able to inspect only the application traffic, without interferences and other possible sources of traffic (automatic updates, Ntp, etc), so to make sure that everything we see in Wireshark can only originate from the application of which we want to inspect the traffic.

SSL Encryption

Since all the transmissions are encrypted, we will not be able to inspect the content of these transmissions. We will be able to see the endpoints of these transmissions.

It would be interesting though, to see if there is a way to tap into these data before they are encrypted so to check the content. In the end they are originated in the browser and must be unencrypet at a certain point. Mitm proxy can be the solution to this, as not only will proxy the requests but it will also provide a dummy certificate (needs installing in the client) in order to inspect the content of the encrypted traffic. This is not covered in this article.

Network Namespace

In order to create and use a Network Namespace we are going to use Gnu/Linux Debian Testing as Operating System of choice, with only the default apt repositories enabled.

The following command will show existing user generated network namespaces

ip netns

The following script, will create a network namespace called "regular-dns" using the network interface called "wlp0s20f3".

In order to run this script the user needs to configure at the very least the interface(s) name.

The name "regular-dns" is arbitrary and it is used because this particular namespace will use regular public dns servers.

The following script needs to be ran with sudo and prior knowledge on these commands is advised.

These commands can also be ran by hand, one by one, to see the result of each one.

set -x
NS=regular-dns # arbitrary name for the network namespace
IF=eth0 # name of the network interface

# I usually run my own resolver + dnsbl but in this case I want all the dns requests to pass, so
# I assign to the network namespace an ad-hoc resolv.conf

mkdir -p /etc/netns/${NS}
echo "nameserver" > /etc/netns/${NS}/resolv.conf
echo "nameserver" >> /etc/netns/${NS}/resolv.conf

# just delete possible leftovers
ip netns del ${NS}
ip link delete ${VIF}

ip netns add ${NS}
ip link add ${VIF} type veth peer name ${VPF}
ip link set ${VPF} netns ${NS}
ip addr add dev ${VIF}
ip link set ${VIF} up
ip netns exec ${NS} ip addr add dev ${VPF}
ip netns exec ${NS} ip link set ${VPF} up
ip netns exec ${NS} ip link set lo up
ip netns exec ${NS} ip route add default via

# Watch out you might already have iptables or UFW configured so better to check the next commands not to break your setup
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -P FORWARD DROP
iptables -F FORWARD
iptables -A FORWARD -i ${IF} -o ${VIF} -j ACCEPT
iptables -A FORWARD -i ${VIF} -o ${IF} -j ACCEPT
iptables -t nat -A POSTROUTING -s -o ${IF} -j MASQUERADE

When creating a new network namespace we can set specific settings like, as you can see here, the dns servers. I personally have to do this because I use TOR as resolver for anonymity and on top of that Pi-hole to filter traffic to known trackers and stalkers.

In this case, in order to use an ad-hoc resolv.conf we need to create a folder in /etc/netns with the same name as the network namespace and put our resolv.conf in said folder.

Test the network namespace

The first test is to check that the new network namespace has been created. For this we can simply run:

➜  ~ sudo ip netns 

This will return the network namespaces created by users

Next we can see the ip address of the interface assigned with sudo ip netns exec regular-dns ip a

➜  ~ sudo ip netns exec regular-dns ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host proto kernel_lo 
       valid_lft forever preferred_lft forever
8: vpeer1@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether da:b2:c6:e6:d6:3d brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet scope global vpeer1
       valid_lft forever preferred_lft forever
    inet6 fe80::d8b2:c6ff:fee6:d63d/64 scope link proto kernel_ll 
       valid_lft forever preferred_lft forever

Next we can run some dig commands the same way we ran the previous command, to verify that dig is indeed using the dns listed in /etc/netns/regular-dns/resolv.conf.

In fact we can see here dig using as dns server:

➜  ~ sudo ip netns exec regular-dns dig

; <<>> DiG 9.19.17-1-Debian <<>>
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33997
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

; EDNS: version: 0, flags:; udp: 512
;            IN  A

;; ANSWER SECTION:     300 IN  A

;; Query time: 56 msec
;; WHEN: Thu Dec 21 17:13:22 CET 2023
;; MSG SIZE  rcvd: 55

And we can even run a bash shell

sudo ip netns exec regular-dns bash


In this case we need to run programs with a graphical UI: Wireshark and the browser, so we also need to export the DISPLAY

In my case I do:

export DISPLAY=:1

It might be different in your case, you will have to figure this out. I obtained this information using:

xdpyinfo | grep -i display

First Run

First thing let's run bash on the network namespace and drop root privileges

sudo ip netns exec regular-dns bash
[sudo] password for frank:
root@host:/home/frank# su frank -

Sudo is required and without an open sudo session it will ask for a password, preventing Wireshark from opening the GUI. In order to avoid this we first run a simple (any) command using sudo, so it will ask for a password and establish a sudo session in the terminal used so subsequent commnands won't need a password for sudo.

sudo ls
[sudo] password for frank:

Now let's run Wireshark

sudo wireshark &

Here we select the interface we created before, vpeer1 and start listening for network traffic:

Wireshark image of detail

Now, in the same shell (if there is output from wireshark, just hit enter to get the prompt back) let's run our application ...say chromium


We will see that immediately, without any interaction with the browser, several connections will start populating the capture window of Wireshark

Wireshark image of detail

Let's not touch the browser so we can be 100% sure that these connections are not generated by our interactions. Let this go for some minutes, then we can stop the browser, stop the packet capture and check some data.

First thing to check is the Statistics->Endpoints menu item. It will open a windows with several tabs and a list of all the endpoint of the connections made. We should flag the checkbox "Name resolution" for an easier reading. Also we don't need the Ethernet protocol to be flagged, as Ethernet refers to a lower network layer not interesting for our investigation, or at least not at this point.

Wireshark image of detail

Here you will find all the endpoints that the browser contacted while idle.

Besides seeing that Chromium (this is the version in the Debian repositories) is making a lot of different connections, it is even more interesting to notice that in the UDP tab we can easily see that it bypassed the system dns with what seems to be DoH. This pictures were taken as example and were taken from my laptop where i already used and reconfigured chromium, so it is NOT a real audit, but just an example of it.


This method can be used to monitor the network activity of any software: from the web browser to the email client (I invite you to run this audit on Mozilla Thunderbird and I can guarentee you that you will shower in a fetal position after seeing the results).

Being Open Source or Free Software does not mean that it is necessarily going to respect your privacy and/or dignity, especially if noone looks into it.

A software can very well be Free Software and contain a piece of code that connects to a server revealing that the user just open the browser, or even worse, identify the user, and have some unknown company building a user profile without permission (IMHO =ILLEGAL).

Other ways


When I want to quickly check a software for background network connections or see if it phones home, without setting up network namespaces, I use proxychains. It is not accurate but it gives an idea on connections generated by the software tested.

To accomplish this the user will have to install Tor and Proxychains because Proxychains will use tor if not differently configured.

apt install tor proxychains

Then run the binary via terminal ths following way:

➜  ~ proxychains chromium 
ProxyChains-3.1 (
[323370:323370:1222/] :components/enterprise/browser/controller/ Cloud management controller initialization aborted as CBCM is not enabled. Please use the `--enable-chrome-browser-cloud-management` command line flag to enable it if you are not using the official Google Chrome build.
|S-chain|-<>-<><>-[323370:323398:1222/] After loading Root Certs, loaded==false: NSS error code: -8018


It is possible to use strace to inspect the network activity of a command, although it is quiet verbose, and the output of strace cannot be used in wireshark to get statistical data or quick list of endpoints.

strace -f -e trace=network chromium 2>&1

As advised here on stackexchange, using grep might be a good idea to reduce the amount of output and make it more readable:

 strace -f -e trace=network chromium 2>&1 | grep sin_addr


Decript QUIC/TLS payload to inspect the content. According to this it is indeed possible to do so in the latest version of Wireshark, but I did not test this yet.


Please share your thoughts about this document. The message will be encrypted with my public key and sent by email.