Networking in C · intermediate · ~20 min

Unix domain sockets — local IPC

Communicate between processes on the same machine via AF_UNIX sockets.

Overview

AF_UNIX sockets give you the standard Berkeley sockets API for local inter-process communication (IPC) — that is, communication between processes on the same machine.

You use the same calls as with network sockets: socket, bind, listen, accept, connect, read, and write. The only real difference is the address. Instead of an IP and port, the endpoint is a filesystem path.

Two benefits follow:

  • They are faster than talking to localhost over TCP, because there is no network stack to traverse.
  • The operating system can tell you which process is on the other end.

Why it matters

Unix sockets are everywhere on Linux:

  • Every init system uses them.
  • Every container runtime uses them.
  • Every database that exposes a local-only protocol uses them.

One practical consequence: the file permissions on the socket path become your access control. Whoever can open the path can connect.

Core concepts

Stream vs. datagram

  • SOCK_STREAM behaves like TCP: an ordered, reliable byte stream.
  • SOCK_DGRAM behaves like UDP: individual messages.

Stream is almost always what you want.

Path-based address

The address lives in sun_path, a fixed 108-byte buffer. The socket shows up as a file on disk, so chmod and chown apply to it like any other file.

Abstract namespace (Linux-only)

If you start sun_path with a NUL byte (\0), you create an abstract socket. It lives in kernel space, not on disk. There is no file to clean up afterward.

Peer credentials

Call getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) to learn the peer's uid, gid, and pid. Use this for access control inside your own protocol.

SCM_RIGHTS

You can pass file descriptors between processes by sending them as ancillary data (extra control data attached to a message) in sendmsg/recvmsg. This is the mechanism behind the systemd socket-activation pattern.

Pentester mindset

  • Permissions on the socket path control who can connect.
  • A world-writable Unix socket means anyone on the box can connect.
  • SO_PEERCRED is your authentication knob inside the protocol.

Defensive coding habits

  • Chmod the socket file to 0660 (or 0600).
  • Unlink the path before bind, or use the abstract namespace.
  • Validate SO_PEERCRED on every accept.

Syntax notes

The address structure for AF_UNIX sockets:

#include <sys/un.h>

struct sockaddr_un {
    sa_family_t sun_family;   /* always AF_UNIX */
    char        sun_path[108]; /* filesystem path */
};

Lesson

Unix domain sockets (AF_UNIX) speak the same API as TCP, but the endpoint is a filesystem path instead of an IP address.

This gives you three things:

  • Faster communication.
  • No network round-trip.
  • A way to identify the process on the other end, via SO_PEERCRED.

Code examples

int s = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr = { .sun_family = AF_UNIX };
strcpy(addr.sun_path, "/tmp/cplat.sock");
bind(s, (struct sockaddr *)&addr, sizeof addr);
listen(s, 4);

Line by line

int s = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr = { .sun_family = AF_UNIX };
strncpy(addr.sun_path, "/tmp/cplat.sock", sizeof addr.sun_path - 1);
unlink(addr.sun_path);                              /* stale from prior run */
bind(s, (struct sockaddr *)&addr, sizeof addr);
chmod(addr.sun_path, 0660);                         /* who can connect? */
listen(s, 4);

Common mistakes

  • Forgetting to unlink the path before bind. On the second run, the stale socket file is still there, and bind fails with EADDRINUSE.

Debugging tips

Two commands help you inspect Unix sockets:

  • ss -xnp lists Unix domain sockets and shows which process holds each end.
  • lsof /tmp/cplat.sock shows the owners of a specific socket file.

Memory safety

sun_path is a fixed 108-byte buffer.

Copy at most sizeof sun_path - 1 bytes into it, and make sure the result is NUL-terminated. This leaves room for the terminator and avoids overflowing the buffer.

Real-world uses

  • Docker daemon (/var/run/docker.sock)
  • systemd
  • MySQL
  • PostgreSQL (local connections)
  • nginx FastCGI

Practice tasks

  1. Build a Unix echo server bound to /tmp/echo.sock.
  2. Use SO_PEERCRED to print the uid of each connecting client.
  3. Reject any peer whose uid is not 1000.

Summary

  • Unix domain sockets use the Berkeley sockets API, but with a filesystem path as the address.
  • They are faster than localhost TCP and let you identify the peer process.
  • Set permissions on the socket path to control who can connect.
  • Use SO_PEERCRED for authentication inside your protocol.

Practice with these exercises