Skip to content
FreeBSDDeep Dive Published Updated 8 min readViews unavailable

FreeBSD sockstat Operations: Attribute Listeners, Connections, and Unix Sockets

Use FreeBSD sockstat to identify socket owners, separate listeners from sessions, inspect jail scope, and verify network changes without guessing.

When a service appears reachable but clients cannot connect, or a port remains busy after a configuration change, inspect the kernel’s socket table before restarting processes. FreeBSD’s sockstat(1) lists open Internet and Unix-domain sockets and associates many of them with a user, command, process identifier, and descriptor. It gives an operational snapshot, not a complete history and not a packet trace: it can show which endpoint exists now, but it cannot prove that a firewall, route, or remote peer will permit a new exchange.

The most useful diagnostic distinction is between a listener and a connected endpoint. A listening TCP socket has no remote peer and waits for new connections. An established TCP socket has both local and foreign endpoints. UDP does not have TCP’s connection-state handshake; a UDP socket may be bound, connected to a peer, or unbound. A Unix-domain socket has a pathname or another local address representation rather than an IP address. Treat those forms separately instead of searching the output for a port number alone.

Capture a reproducible socket snapshot

Start with the host identity and a broad inventory. Use the same privileges and time window for before-and-after comparisons, because short-lived clients can disappear between commands:

freebsd-version -kru
date -u
sockstat

For a compact IPv4 listener check on a known TCP port, narrow the output:

sockstat -4 -l -P tcp -p 8080

The manual’s example uses the same option combination for TCP port 22. Replace the example port with the service’s configured port. -4 selects IPv4, -l selects listening sockets, -P tcp filters the protocol, and -p takes a port list. These filters help answer a particular question but can hide a dual-stack listener, UDP socket, or Unix-domain endpoint. If a connection still fails, run an unfiltered snapshot before concluding that the process has no socket.

For a service expected to have active clients, compare listening and connected results:

sockstat -4 -P tcp -p 8080
sockstat -6 -P tcp -p 8080
sockstat -4 -c -P tcp -p 8080

When neither -c nor -l is specified, the utility lists both connected and listening sockets. -c requests connected sockets and -l requests listeners. A service can listen only on a specific local address, on a wildcard address, or on one protocol family. A listener shown for IPv4 does not establish that IPv6 clients can connect, and an IPv6 wildcard does not automatically prove the expected IPv4 behavior. Verify the actual local address shown by the command and then test from the relevant network path.

Read ownership and endpoint columns carefully

The standard output columns include user, command, PID, file descriptor, protocol, local address, and foreign address. The row answers “which process currently holds this socket?” only to the extent that the kernel can associate a file descriptor with the socket and the caller can see the process. A process name is not a service identity: multiple workers may have the same command, a supervisor may differ from the socket-owning worker, and a socket may be inherited across fork(2).

Do not infer that the first row is the only owner. A listening socket can be shared among worker processes, depending on how the service was started. sockstat may show repeated rows when multiple descriptors or processes refer to the endpoint. The -v option increases verbosity, while -q suppresses only the header. Neither option changes the socket’s state.

If a row identifies a PID but the process lifecycle is unclear, correlate rather than signal immediately:

ps -p 1234 -o pid,ppid,user,state,command
procstat -f 1234
fstat -p 1234

Substitute the PID from the live output. procstat -f and fstat inspect process descriptors and can confirm whether a descriptor corresponds to the socket. A PID can exit and be reused between commands, so compare command, start time, parent, and descriptor data in a short interval. Do not kill a process merely because it owns a port; first determine whether it is the expected service, a managed worker, or an unrelated process.

Scope the query by address family, protocol, jail, and address

The default report includes IPv4, IPv6, and Unix-domain sockets. Use -u when investigating local IPC, such as a daemon control socket or application socket file:

sockstat -u -l
sockstat -u -c

A pathname may persist on disk after a process exits, but a stale socket file is not itself evidence that a live listener remains. Check whether sockstat reports an owning process and inspect the application’s cleanup behavior before removing the path. Deleting a socket pathname while a service is live can break clients or cause the service to recreate a separate endpoint at the same name.

FreeBSD jails create an important namespace boundary. Use the -j option with a jail name or jail ID when the question concerns a specific jail:

jls -n
sockstat -j web01 -l

Confirm the jail identifier and host-side interface mapping separately. Host output, jail output, and a VNET jail’s network stack answer different questions. A process in a jail may bind an address that is not configured on the host’s ordinary interface list, and a host-level route check does not establish the jail’s route. Avoid mixing socket evidence from different jail contexts into one conclusion.

For protocol filters, -P accepts a comma-separated list such as tcp,udp; use names from protocols(5). The -L option selects sockets whose local and foreign addresses are not both loopback, which can reduce noise during a remote-traffic investigation. It is a display filter, not an access-control rule and not proof that the socket is externally reachable.

Explain common port-conflict reports without overclaiming

If a service reports “address already in use,” first identify the exact address family, local address, port, and protocol in its error or configuration. A wildcard bind may conflict with a more specific bind depending on socket options and platform behavior. Separate TCP from UDP; the same numeric port can be used independently by different transport protocols. Also distinguish a listening endpoint from a recently closed connection: a row with a foreign address is not equivalent to a listener. Use the service’s own logs and a narrow sockstat query to correlate the failure time.

If the expected listener is absent, check whether the service is running in another jail, bound to a different address, configured for a Unix socket, or started only on demand by inetd(8). A socket activated by inetd can be owned by the activation daemon until a request launches the child. A short-lived listener can also vanish between observations. Inspect service, the rc.d configuration, and the service log; do not edit firewall rules to fix a local bind failure.

If the listener exists but clients fail, move outward in layers. Confirm local address assignment with ifconfig, route selection with route -n get, and firewall state/rules with the configured firewall’s documented status commands. From a separate client, test the destination address and protocol. sockstat is local endpoint evidence only; it does not show packet loss, remote ACLs, name resolution, or TLS/application readiness.

Use machine-readable output deliberately

--libxo enables libxo output modes. For example:

sockstat --libxo json,pretty

Use JSON mode for a local diagnostic script only after checking the output schema on the installed FreeBSD release. Do not parse the default aligned table with awk when a structured format is available: command names, addresses, and optional columns can make whitespace-based assumptions brittle. Also avoid assuming that every row has a meaningful PID or descriptor; the manual notes that when a socket is not associated with a file descriptor, the first columns do not convey ordinary process ownership.

For a time-series capture, keep the collector non-invasive and bound its output:

for sample in 1 2 3 4 5; do
    date -u
    sockstat -4 -P tcp -p 8080
    sleep 1
done

This demonstrates repeated snapshots rather than a continuous event stream. It can miss a connection that opens and closes between samples. For high-churn incidents, use application metrics, packet capture with an explicit filter, or supported tracing after assessing overhead and privacy. Do not log full endpoint data indefinitely when it may disclose user activity or internal topology.

Acceptance criteria for a socket investigation

Record the service, jail, transport, expected bind address, expected port, query flags, timestamp, and the relevant output. A listener investigation is complete when the intended process and endpoint are present in the correct network context, the address family matches the clients, and a separate end-to-end test succeeds. A port-conflict investigation is complete when the actual owner is identified and the service’s bind configuration is reconciled with that endpoint. If the service is intentionally socket-activated or shares a listener, document that ownership model instead of treating multiple rows as a leak.

After a configuration change, repeat the same query and client test. Preserve the original output before changing processes or firewall state. The disciplined sequence is observation, correlation, one bounded change, and verification. That keeps sockstat useful as evidence instead of turning it into a trigger for speculative restarts.

Related:

Sources:

Comments