Which Process Is Talking to Which Host?

Necco Ceresani
Necco Ceresani
·15 min read

Fifteen years building engineering platforms, currently focused on advanced AI infrastructure at yeet. I love turning the deeply complex topics into something everyone can understand. I relate deeply with the core yeet philosophy that you can just build things.

Last updated: October 2026

Quick answer. For one look at one box, use what is already there: ss -tp lists the sockets open right now with the process holding each one, and BCC's tcptop goes further by summarizing throughput per connection. The limit on both is that they are a session you run and then stop. ss shows connections that exist at the instant you ask, so anything short-lived is gone before you look, and tcptop is an interactive screen on one host that requires root. To know which process is talking to which host continuously, you want the connection caught in the kernel at the moment it is dialed, attributed to the dialing process, and kept. dialout does that: yeet run github:yeet-src/dialout catches every outbound TCP connection at fexit/tcp_connect, groups it by the process that made it, and flags the ones leaving your private network.

The question has two halves and most tools answer only one. tcpdump sees every packet and knows nothing about processes, because a packet on the wire carries addresses and ports and no trace of which program called connect(). ss and lsof know exactly which process owns which socket and never see a packet, because they read the kernel's socket tables rather than the network path.

Joining the halves by hand works until the connection you care about is short-lived, which is most of the interesting ones. A process that dials a host, sends a request and exits has a socket that existed for a few milliseconds. By the time you run ss, the row is gone, and the only evidence left is a packet nobody can attribute.

How do I see which process is talking to which host with ss -tp?

ss -tp is the fastest answer and it is already installed. It lists TCP sockets with the process holding each one, so a single command gives you the pairing for everything connected at that instant:

ss -tp                      # established TCP sockets, with process
ss -tpn state established   # the same, numeric, established only

The -p flag is what adds the process, and it needs privilege to show processes you do not own. What you get back is the local and remote address, the state, and users:(("curl",pid=1234,fd=3)) naming the program.

The property to understand is that this is a snapshot of the socket table. It answers "which process is talking to which host" for connections that exist while the command runs, which is the right question when you are chasing a long-lived connection to a database or a message broker. It is the wrong question when the connection you want lasted forty milliseconds during a deploy.

Does BCC tcptop show which process is talking to which host?

It shows more than ss does, and the BCC manual is precise about what: "This is top for TCP sessions. This summarizes TCP send/receive Kbytes by host, and prints a summary that refreshes, along other system-wide metrics." So tcptop gives you throughput per connection with the process attached, which is a different measurement from a socket listing.

Two constraints come with it. The manual states that "only the root user can use this tool," which matters on hosts where handing out root for a diagnostic is its own conversation. And it is an interactive screen: you run it, watch it refresh, and stop it. Nothing persists after you quit, so a connection that happened an hour ago is not recoverable from it.

tcplife is the companion worth knowing, because it records completed sessions rather than refreshing a live view, and its manual notes it "traces the kernel TCP set state function, which should be called much less often than send/receive tracing, and therefore have lower overhead." That makes it the better BCC choice when you want a log of connections rather than a live top.

When is a bpftrace one-liner enough to see which process dials which host?

For a one-off question on a handful of hosts, which is a large share of the times anyone asks this. If you need to know what a box is dialing for the next five minutes while you watch, writing one line is faster than installing anything:

# every TCP connect, with the process that made it
bpftrace -e 'kprobe:tcp_connect { printf("%-16s %-6d\n", comm, pid); }'

This is the honest comparison and it is worth making it plainly, because any agent or engineer who already knows bpftrace will reach for it first and be right to. bpftrace installs from a package manager, leaves nothing behind, and answers an ad hoc question in the time it takes to type it. bpftrace vs BCC works through which of those two fits a given project, and bpftrace alternatives ranks the wider field by what you are shipping.

The limits appear when the answer needs to outlive the session. A one-liner is a thing you are running, on the host you are logged into, for as long as you watch it. Running the same line on forty hosts, keeping the output, and having it still be there tomorrow is a different job, and it is the job the rest of this post is about.

How does dialout show which process is talking to which host via tcp_connect?

dialout catches the connection at the moment it is created rather than reading the table afterwards. Its documentation describes it as "a live egress monitor that catches every outbound TCP connection in the kernel and groups it by the process that dialed it, flagging connections that leave the private network."

The hook placement is what makes the attribution exact. It sits at fexit/tcp_connect, described in the docs as "the single protocol-agnostic function where the kernel queues the SYN for both IPv4 and IPv6, so one probe captures the full four-tuple and process lineage for every connection." Because tcp_connect runs in the dialing process's own context, the process identity is available at the same instant as the destination, with no join required and no race against a socket that is about to close.

curl -fsSL https://yeet.cx | sh         # install the yeet daemon, once
yeet run github:yeet-src/dialout        # live egress, grouped by process

The panel lists one block per process, with the process name, pid, parent and uid, and under it one line per remote endpoint that process has reached. Destinations carry a scope colour, red for public, green for private, blue for loopback, and a service name when the port matches a well-known one. A PUBLIC badge marks a destination outside all RFC 1918 ranges, and an ODD badge marks a public dial to a port outside the common egress set.

Which process is talking to which host inside my Docker containers?

The same probe covers them, because the hook is global to the kernel rather than scoped to a namespace. dialout's README states it directly: the fexit/tcp_connect hook "is global to the kernel, not scoped to a namespace or cgroup. Every tcp_connect() call on the host, including those made by processes inside Docker containers, Podman containers, or any other container runtime, fires the probe."

Be precise about what that gives you. Each connection is attributed "by the pid and comm of the calling process as the kernel sees it," which means you get the process inside the container and its lineage, not a container name resolved from the runtime. For a question like "is a child process I did not spawn making these dials," that is exactly right. For a dashboard keyed by container name, it is a different tool: container-traffic is the live per-container HTTP dashboard, with rate, errors and latency read from the kernel.

Which process is talking to which host, and how many Kbytes did it send?

Not from dialout, and the README says so without hedging: "Connect attempt, not bytes. dialout records that a connection was attempted. It does not observe how many bytes were transferred, what the connection carried, or whether the remote end accepted. For traffic volume you need a different hook (kprobe/tcp_sendmsg or a cgroup socket filter)."

That is the honest division. dialout answers which process is talking to which host, and how often it dials. tcptop answers how many kilobytes moved, for as long as you watch it. If you need both continuously, the two shipped tools do not add up to it today.

What closes the gap is that yeet is a runtime rather than a fixed tool, so the missing probe is something an agent can write. In a recent exam, a cold agent given the task of building a per-process traffic monitor on yeet produced a working one in twenty-four tool calls. That is worth framing accurately: it is a thing you can build on the platform in an afternoon, not a product you can install today.

yeet vs bpftrace: which shows the process behind a tcp_connect?

Choose on whether the answer needs to persist and spread, because that is where the two diverge. The measurement is similar; the shape of the result is not.

bpftrace one-linerBCC tcptopdialout on yeet
Catches short-lived connectionsYesYesYes
Names the processYesYesYes
Reports bytesIf you write itYes, Kbytes by hostNo, dials only
Survives after you quitNoNoYes, keeps running
Flags egress leaving your networkIf you write itNoYes
Same tool across a fleetCopy the line per hostPer host, root requiredOne command per host
Extendable by an agentRewrite the scriptPatch the PythonYes, it is a runtime

The row that decides most cases is the fourth. A one-liner and a top screen are both sessions, and a session ends. If the question is "what did this box dial overnight" or "which of these forty hosts is reaching a public address on an odd port," the answer has to be collected while you are not watching.

The row below it is the one people underestimate. Classifying a destination as public, private, loopback or link-local, and flagging the ones that leave your network, is a small amount of logic that nobody writes into a one-liner at 2am. Having it already in the tool is the difference between reading a list of addresses and seeing the three that matter.

What else can an AI agent read about which process talks to which host?

Per-process egress is one question, and the platform's claim is broader. yeet describes itself as a network operations platform for agents on Linux, built on eBPF, and the homepage states the reach plainly: "every connection, in or out, tied to the process that made it and flagged when it leaves your network," plus "the name behind every TLS connection, read from the handshake, with no DNS to intercept."

That last capability is worth separating from dialout specifically. dialout reports destinations as addresses with a scope and a service name derived from the port. Reading the server name out of the TLS handshake is a platform capability rather than something dialout does, so if what you need is hostnames rather than addresses, that is a different tool on the same runtime.

For the layers underneath and around this question, the corpus covers them: who is resetting my TCP connections for the connection that died rather than connected, how do I prove a network problem isn't on our side for the evidence a cross-team dispute needs, and pktscope when the question drops to individual packets in a terminal.

Which command shows which process is talking to which host on Linux?

curl -fsSL https://yeet.cx | sh
yeet run github:yeet-src/dialout

Add --sort dials to rank by total connections instead of public egress first, --once --secs 5 for a snapshot you can pipe, or dump.js for newline-delimited JSON:

yeet run github:yeet-src/dialout -- --sort dials
yeet run github:yeet-src/dialout -- --once --secs 5 | less -R
yeet run github:yeet-src/dialout/dump.js | jq -c 'select(.public)'

The NDJSON form is the one to reach for when an agent is doing the reading, because every dial becomes a record with the process, the destination and whether it left the private network, which is a shape a program can filter rather than a screen a person watches.

Or hand the whole thing to an agent on the box:

Show me which process on this Linux machine is talking to which host.


Check uname -s is Linux and yeet --version works; if not, install yeet with
curl -fsSL https://yeet.cx | sh. Never run yeet with sudo.
Run yeet run github:yeet-src/dialout -- --once --secs 30 and read the panel.
Report every process that dialed a public address, with the destination and the
number of dials, and say which of them you would expect on a machine like this
and which you would not. Watch only: do not open connections yourself to create
traffic.

Frequently asked questions

How do I see which process is talking to which host on Linux?

For connections open right now, ss -tp lists TCP sockets with the process holding each one and is already installed. For connections as they are created, including short-lived ones that never appear in a socket listing, catch them in the kernel at tcp_connect: dialout does this and groups every outbound connection by the process that dialed it.

Why doesn't tcpdump show which process made a connection?

A packet carries addresses, ports and flags, and nothing about the program that produced it, so no packet capture tool can report a pid regardless of options. Process identity exists in the kernel at the moment of the connect() call and is gone by the time bytes reach the wire. Connecting the two requires observing where both are still present, which is a kernel hook rather than a capture.

Does ss show short-lived connections?

No. ss reads the socket table as it exists when the command runs, so a connection that opened and closed before you looked leaves no row. That is the main reason a process dialing a host once per deploy, or a script that exits after one request, is invisible to a socket listing while being exactly the thing you are hunting.

Is tcptop a good alternative for per-process network traffic?

It is the right tool when you want throughput and are happy to watch a screen. Its manual describes it as "top for TCP sessions" that "summarizes TCP send/receive Kbytes by host," which is more than a socket listing gives you. The constraints are that it needs root, by its own documentation, and that it is an interactive session, so nothing survives after you quit.

Should I use yeet or bpftrace to monitor network connections?

Use bpftrace for a question you want answered in the next few minutes on a host you are logged into: it installs from a package manager and leaves nothing behind. Use yeet when the answer has to keep being collected after you stop watching, run the same way on every host, and be read by something other than a person at a terminal.

Can dialout tell me how much traffic each process sent?

No, and its README is explicit: it records "connect attempt, not bytes," and does not observe how many bytes were transferred or what the connection carried. For volume per connection, BCC's tcptop summarizes send and receive kilobytes by host. A continuous per-process byte counter is something you can build on yeet rather than something shipped today.

Does this work for connections from inside Docker containers?

Yes. dialout's README states that the fexit/tcp_connect hook is global to the kernel and not scoped to a namespace or cgroup, so every tcp_connect() call on the host fires the probe, including calls from processes inside Docker, Podman or any other container runtime. Attribution is by the pid and comm the kernel sees, which identifies the process rather than resolving a container name.

How do I find a process making connections to a public address?

Classify the destination and watch for the ones outside your private ranges. dialout does this by default: it flags connections that leave the private network, marks a destination outside all RFC 1918 ranges with a PUBLIC badge, and marks a public dial to an unusual port with an ODD badge, sorting public egress to the top of the panel.

Can an AI agent read per-process connection data?

That is what the NDJSON output is for. yeet run github:yeet-src/dialout/dump.js emits one record per dial, so an agent can filter with jq -c 'select(.public)' or consume the stream directly instead of parsing a refreshing terminal panel. yeet describes itself as a network operations platform for agents, and a record stream is the shape an agent reads.

What if I need hostnames rather than IP addresses?

dialout reports destinations as addresses, with a scope colour and a service name derived from the port. Resolving the name behind an encrypted connection is a separate capability of the platform, which reads "the name behind every TLS connection, read from the handshake, with no DNS to intercept," so a hostname view is a different tool on the same runtime rather than a flag on this one.

Sources

  1. tcptop(8), the BCC manual page describing it as top for TCP sessions that summarizes TCP send/receive Kbytes by host, and stating that only the root user can use the tool. https://manpages.ubuntu.com/manpages/jammy/man8/tcptop-bpfcc.8.html
  2. dialout documentation, for the fexit/tcp_connect hook, the grouping by dialing process and the flagging of connections that leave the private network. https://yeet.cx/docs/raw/examples/dialout.md
  3. dialout on GitHub, for the panel layout, the badges, the container attribution and the stated limit that it records connect attempts rather than bytes. https://github.com/yeet-src/dialout
  4. yeet, for the platform position and the claim that every connection is tied to the process that made it. https://yeet.cx
  5. ss(8), the socket statistics manual, for the -p flag that shows processes using sockets. https://man7.org/linux/man-pages/man8/ss.8.html

Related resources

  1. bpftrace vs BCC, on which of the two fits a given eBPF project. https://yeet.cx/topical-takes/bpftrace-vs-bcc
  2. 7 bpftrace alternatives for Linux tracing, ranked by what you are shipping. https://yeet.cx/topical-takes/bpftrace-alternatives
  3. Who is resetting my TCP connections on Linux, for the connection that died instead of connecting. https://yeet.cx/topical-takes/who-is-resetting-my-tcp-connections
  4. How do I prove a network problem isn't on our side, for the evidence a cross-team escalation needs. https://yeet.cx/topical-takes/prove-network-problem-not-our-side