Home / Alt manpages / proc_net(5)

  • proc_net(5)
  • File format
  • linux

Read Linux Network State Safely from /proc/net

You will finish with a small, repeatable workflow for reading interface counters, socket tables and namespace-specific network state from /proc/net. The files are live kernel views, so this is an inspection guide: it does not change routes, interfaces, firewall rules or services. Allow about fifteen minutes. You need a shell and a Linux system with procfs mounted; the examples normally run as an ordinary user.

The examples below were checked against Linux man-pages 6.7, from Debian package manpages 6.7-2. The contents of these files depend on the running kernel, loaded protocols, active sockets and your network namespace. Treat sample values as shapes to recognise, not values to copy.

1. Check what /proc/net means on this host

Start by checking the path and its target. This is a read-only command and needs no elevated privileges:

$ ls -ld /proc/net /proc/self/net
lrwxrwxrwx 1 root root 8 ... /proc/net -> self/net
dr-xr-xr-x ... /proc/self/net
$ readlink /proc/net
self/net

Since Linux 2.6.25, /proc/net is a symbolic link to /proc/self/net. That detail is the main source of confusing results: the directory exposes the network namespace of the process reading it. A process in another namespace can see a different set of interfaces, routes and sockets even when both processes use the path /proc/net.

Checkpoint: verify that procfs is available and that the link resolves before diagnosing an empty or unexpected table:

$ test -r /proc/self/net/dev && echo 'network procfs is readable'
network procfs is readable

2. Read interface counters without changing anything

Read /proc/net/dev to see per-interface receive and transmit counters. The first two lines describe the columns. Each later line starts with an interface name and contains receive fields, then transmit fields:

$ cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo: 43922714770 48753419    0    0 ...
enp0s31f6: 138237730712 222401549    0    0 ...

For each direction, the useful first counters are bytes and packets. Errors and drops are separate columns, not a single health score. A growing counter is normal on a busy link, and a zero value does not prove that every packet path is healthy. Save two readings a few seconds apart if you need a rate:

$ awk -F: 'NR > 2 {gsub(/^ +| +$/, "", $1); print $1, $2}' /proc/net/dev
lo 43922714770 48753419 ...
enp0s31f6 138237730712 222401549 ...

Do not parse column positions by splitting only on spaces without handling the colon and repeated whitespace. Interface names and counter widths make that approach fragile.

3. Inspect TCP, UDP and UNIX socket tables

The socket files are ASCII dumps intended for inspection and debugging. Read them as snapshots. A row can disappear between two commands because the owning process closed the socket.

$ head -3 /proc/net/tcp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
   0: 0100007F:734A 00000000:0000 0A 00000000:00000000 00:00000000 ...
$ head -4 /proc/net/unix
Num       RefCount Protocol Flags    Type St Inode Path
0000000000000000: 00000003 00000000 00000000 0001 03 283705574
...

In the TCP and UDP tables, local_address and rem_address contain hexadecimal address and port pairs. st is the kernel socket state, while the queue fields describe kernel memory queued for the socket. The man page labels several other fields as internal and mainly useful for debugging. Avoid treating an undocumented numeric field as a stable application interface.

The UNIX table includes local sockets and can include abstract sockets. A path beginning with @ is not an ordinary filesystem pathname. The inode and path can help you connect a socket to a process, but they do not by themselves identify whether a service is trusted.

For a quick count of TCP rows, keep the header out of the count:

$ awk 'NR > 1 {n++} END {print n, "TCP rows"}' /proc/net/tcp
2 TCP rows

Your number will differ. If the file is absent or unexpectedly sparse, check the kernel and namespace context before assuming that networking is broken.

4. Compare a process network namespace

Use /proc/PID/net when you need the view belonging to a particular process. The PID is a placeholder, so replace it with a real process ID. This command only reads state:

$ PID=1234
$ test -r "/proc/$PID/net/dev" && head -3 "/proc/$PID/net/dev"
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
 ...

Compare the interface names in /proc/self/net/dev and /proc/$PID/net/dev. Different names can be expected when the process is in a container or another network namespace. A process can also exit while you inspect it, producing a missing path or a failed read.

Checkpoint: record the process and namespace context with the data you collect:

$ printf 'reader pid: '; printf '%s\n' "$$"
reader pid: 12345
$ readlink /proc/self/ns/net
net:[4026531993]
$ readlink "/proc/$PID/ns/net"
net:[4026531993]

Matching namespace identifiers support a comparison; they are not a security decision. Reading another process's proc entries can also be restricted by mount options, permissions or process visibility. Use elevated privileges only when your system's access policy requires it, and do not add sudo merely because a table is interesting.

5. Check supporting files only when the question needs them

/proc/net/arp shows the kernel ARP table, including learned and preconfigured entries. /proc/net/snmp contains ASCII management counters for IP, ICMP, TCP and UDP. /proc/net/raw contains the raw socket table. /proc/net/igmp describes Internet Group Management Protocol state. These are diagnostic views, not configuration files.

Some entries are conditional. The man page says /proc/net/rarp is absent when RARP is not configured into the kernel. Netfilter queue information appears at /proc/net/netfilter/nfnetlink_queue only when user-space queueing is in use. Check before reading:

$ for path in /proc/net/arp /proc/net/snmp /proc/net/rarp /proc/net/netfilter/nfnetlink_queue; do
>   if test -r "$path"; then
>     printf '\n%s\n' "$path"
>     head -4 "$path"
>   else
>     printf '%s: not present or not readable\n' "$path"
>   fi
> done

Do not create a missing file or redirect output back into /proc/net. These paths are kernel interfaces, and the documented operation here is reading them with tools such as cat.

6. Avoid the common interpretation traps

First, these are snapshots, not transactionally consistent reports. A process can open or close a socket while you parse the output. Second, the address and port fields in the legacy TCP and UDP dumps are hexadecimal and encoded for kernel display, so do not read them as dotted-decimal text. Third, the same path can describe different data in different network namespaces. Finally, the man page describes netstat as a cleaner interface, but many modern systems do not install it; use an installed, documented tool such as ss when you need a human-facing socket view, and compare its namespace context with your proc read.

Nothing in this guide changes state, so there is no rollback step. If you redirected a proc file into a regular output file for later analysis, remove that copy only after checking that it is no longer needed. The proc entries themselves remain managed by the kernel.

Done means

  • /proc/net resolves to the reader's network namespace and is readable.
  • /proc/net/dev was read with its receive and transmit columns kept distinct.
  • TCP, UDP or UNIX socket rows were treated as live diagnostic snapshots.
  • Any per-process comparison used /proc/PID/net and recorded namespace context.
  • Optional files were tested for presence, and no proc entry was modified.