Fact-checked by Grok 2 weeks ago

Unix domain socket

A Unix domain socket, also known as a local socket or socket, is a communications for exchanging between processes executing on the same host machine, utilizing the AF_UNIX (or AF_LOCAL) address family defined in the standard. Introduced in the 4.2BSD release of the Unix operating system in 1983, these sockets provide an efficient mechanism for local () that leverages the filesystem namespace for addressing via the sockaddr_un structure. Unix domain sockets support three primary types: SOCK_STREAM for reliable, connection-oriented communication; SOCK_DGRAM for connectionless, reliable datagram exchange; and SOCK_SEQPACKET for sequenced, reliable packet transmission (the latter available since Linux 2.6.4). They can operate in unnamed mode for simple connections, be bound to a filesystem pathname (where the socket appears as a special file type), or use -specific abstract namespaces that do not create visible filesystem entries. The address structure includes a family field set to AF_UNIX and a pathname component of variable length, typically up to 108 bytes on systems, though does not mandate a fixed size. Key features distinguish Unix domain sockets from network sockets, including the ability to pass file descriptors, process credentials, and security contexts via ancillary data mechanisms like SCM_CREDENTIALS (introduced in 2.2). Socket options such as SO_PASSCRED, SO_PEERCRED, and SO_PASSSEC enable authentication and access control based on filesystem permissions for pathname-bound sockets. While standardizes the core interface, implementations like extend functionality with non-portable features, making Unix domain sockets a foundational tool in systems for applications requiring low-overhead, secure local data exchange.

Introduction

Definition and Purpose

Unix domain sockets, also known as AF_UNIX or AF_LOCAL sockets, are a form of (IPC) in operating systems that enables processes executing on the same host to exchange by leveraging the file system namespace for addressing, thereby avoiding involvement of the network protocol stack. This mechanism treats sockets as special files within the filesystem, allowing communication endpoints to be identified via pathnames or abstract , which facilitates , kernel-mediated between processes. The primary purpose of Unix domain sockets is to support efficient, low-overhead communication for applications requiring local , such as client-server architectures confined to a single machine, where the absence of network layering reduces latency and resource usage compared to TCP/IP sockets over interfaces. By operating entirely within the kernel's local domain, they minimize switches and data copying, making them suitable for high-performance scenarios on shared-host environments. Key characteristics of Unix domain sockets include bidirectional data flow, support for both stream-oriented semantics (reliable, ordered byte streams) and datagram-based semantics (unordered, message-preserving packets), and seamless integration with the socket application programming interface for portability across compliant systems. These features enable reliable local messaging without the complexities of network addressing or routing. Common use cases encompass database servers like or interacting with local clients via socket paths such as /tmp/.s.PGSQL.5432, as well as inter-daemon communication in systems for tasks like service coordination and event notification.

Historical Development

Unix domain sockets originated in the Berkeley Software Distribution (BSD) Unix variants, specifically introduced in 4.2BSD released in August 1983 by the Computer Systems Research Group (CSRG) at the . Developed as an extension to the Berkeley sockets API, they were designed to facilitate efficient (IPC) on the same host, addressing the limitations of traditional Unix , which were unidirectional and required a common ancestor process for related processes. In 4.2BSD, themselves were reimplemented using pairs of connected Unix domain stream sockets, enhancing the overall IPC framework with bidirectional, reliable communication channels. The CSRG team, funded in part by for networking research, drove this innovation to unify local and network under a single paradigm, with key contributions from developers like and the broader networking group. Adoption extended beyond BSD when incorporated the socket interface into Release 4 (SVR4) in 1988, allowing portability of BSD socket-based applications to System V derivatives and promoting wider use in commercial Unix systems. Standardization followed in the inaugural POSIX.1 specification (IEEE Std 1003.1-1988), which defined the AF_UNIX address family for Unix domain sockets, ensuring cross-platform compatibility in POSIX-compliant systems. Subsequent enhancements included Linux-specific features like abstract sockets, introduced in kernel version 2.2 in January 1999, which allow unnamed sockets without filesystem entries for improved performance and cleanup. In 4.2BSD, Unix domain sockets initially supported SOCK_STREAM for stream-oriented communication and SOCK_DGRAM for connectionless, message-preserving transfers. SOCK_SEQPACKET, providing reliable, ordered delivery with boundary preservation, was added in subsequent BSD releases and POSIX standards. These developments solidified Unix domain sockets as a core IPC mechanism in Unix-like operating systems.

Core Concepts

Socket Types and Semantics

Unix domain sockets support three main socket types, each defining distinct communication semantics within the local framework. The SOCK_STREAM type establishes a reliable, bidirectional, connection-oriented byte , ensuring ordered delivery without message boundaries, akin to a virtual pipe between processes on the same host. This type requires explicit connection setup via system calls like connect(), providing flow control and error handling to prevent data loss or duplication. In contrast, the SOCK_DGRAM type enables connectionless, datagram-oriented communication, where each message is treated as an atomic unit with preserved boundaries but without guaranteed ordering or reliability in the specification; however, many implementations, including , ensure reliable delivery since operations occur entirely within the , eliminating network-related losses. Datagrams in this type undergo no fragmentation, as the entire message is delivered atomically if the receiving can accommodate it, and no establishment is needed for send or receive operations. The SOCK_SEQPACKET type combines aspects of the previous two, offering reliable, connection-oriented, sequenced packet that maintain message boundaries and deliver data in the exact order sent, using flags like MSG_EOR to delineate records. A key feature across these types is support for ancillary data, which allows transmission of metadata beyond the primary ; notably, SCM_RIGHTS enables the passing of open file descriptors between processes over the socket, facilitating resource sharing without . Unlike IP-based sockets, Unix domain sockets operate exclusively on the local machine, bypassing the network stack entirely, which obviates the need for routing, address resolution, or checksum computations, resulting in lower overhead and higher performance for intra-host communication. This local scope ensures all semantics are enforced by the without external layers.

Addressing Mechanism

Unix domain sockets operate within the AF_UNIX address family, also known as AF_LOCAL in POSIX standards, which enables local interprocess communication without relying on network protocols. Addresses in this family are identified using the filesystem namespace or, on Linux, an abstract namespace, distinguishing them from network sockets that use IP addresses and ports. Unlike Internet domain sockets, Unix domain addressing does not involve port numbers; instead, endpoints are referenced by pathnames or abstract identifiers that must remain unique within their respective namespace to ensure proper connection resolution. The core address structure is defined as struct sockaddr_un, which includes a family field and a component. Specifically, it consists of sa_family_t sun_family, set to AF_UNIX or AF_LOCAL, followed by char sun_path[], an array for storing the identifier. In POSIX implementations, the size of sun_path varies but is typically sufficient for paths up to 92–108 characters; defines a maximum of 108 bytes via UNIX_PATH_MAX. For pathname-based addressing, sun_path holds a representing a filesystem , and the full length is calculated as offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1. Pathname sockets bind to actual filesystem entries, which appear as special files (type S_IFSOCK) and persist until explicitly removed, allowing resolution through standard directory lookups. This ties the socket's visibility to the file system's structure and permissions, enabling processes to locate endpoints via path traversal. In contrast, Linux's abstract namespace provides a non-persistent alternative where the address begins with a null byte (\0) in the first position of sun_path, followed by an arbitrary sequence of bytes that do not create or rely on filesystem objects. These abstract addresses exist solely in memory, vanishing when all references to the socket are closed, and their length excludes the leading null byte in binding operations. During , the ensures uniqueness within the chosen to prevent conflicts, rejecting attempts to bind duplicate pathnames or abstract identifiers. Pathnames must be encoded as null-terminated strings, while abstract names use raw bytes without termination, allowing flexible but namespace-specific identification. This mechanism supports efficient local routing, as the directly maps to process descriptors without intermediate network layers.

Implementation Details

System Calls for Creation and Management

Unix domain sockets are created using the socket() with the address family AF_UNIX (also known as AF_LOCAL), specifying a socket type such as SOCK_STREAM for reliable, connection-oriented communication, SOCK_DGRAM for reliable service, or SOCK_SEQPACKET for sequenced packet transmission, and a protocol value of 0 to select the default protocol. The call returns a on success or -1 on failure, with common errors including EAFNOSUPPORT if the address family is unsupported, EMFILE or ENFILE if file descriptor limits are reached, and EPROTONOSUPPORT if the specified protocol is invalid for the family. To assign a local to the , the bind() is used, taking the , a pointer to a sockaddr_un containing the AF_UNIX family and the (such as a pathname or abstract identifier, as detailed in the Addressing ), and the length of the . On failure, it returns -1 and sets errno to values like EADDRINUSE if the is already in use, ENOENT if a pathname component does not exist, or EACCES if permissions are insufficient for the filesystem path. For server-side operations, after binding, the listen() call marks the socket as passive, specifying a parameter to limit the queue of incoming connections, typically up to the system-defined SOMAXCONN limit. It returns 0 on success or -1 with errors such as EINVAL for an invalid backlog or ENOTSOCK if the descriptor is not a socket. The accept() call then extracts the next pending connection from the queue, creating a new connected descriptor while optionally retrieving the peer's address; it blocks until a connection arrives unless the socket is in non-blocking mode, in which case it returns EAGAIN or EWOULDBLOCK if the queue is empty. Common errors include EMFILE for process exhaustion and ECONNABORTED if the connection attempt was aborted. Client-side connection establishment uses the connect() on an unbound , providing the server's sockaddr_un and length to link the two endpoints. It returns 0 on success for connection-mode sockets or -1 with errno set to ECONNREFUSED if the server rejects the connection, ENOENT if the server's pathname does not exist, or EISCONN if already connected. Data transfer on connected Unix domain sockets can employ send() and recv() for message-oriented operations or the generic read() and write() system calls on the socket descriptor, with send() transmitting up to the specified and returning the number of bytes sent or -1 on errors like ENOTCONN if unconnected or EPIPE if the peer has closed the connection. Similarly, recv() receives data into a , returning the byte count, 0 on orderly shutdown, or -1 with errors such as ECONNRESET if the connection is reset. For sockets, these calls handle individual messages, while sockets treat data as a continuous byte . To manage connection lifecycle, shutdown() disables send, receive, or both directions on a connected via the how (SHUT_RD, SHUT_WR, or SHUT_RDWR), returning 0 on success or -1 with ENOTCONN if unconnected. Finally, close() deallocates the descriptor, potentially blocking briefly if the SO_LINGER option is set to ensure data transmission, and returns 0 on success or -1 with EBADF for an invalid descriptor. An important ancillary feature of Unix domain sockets is the ability to pass file descriptors between processes using control messages with sendmsg() and recvmsg(), where the msghdr structure's msg_control carries via level SCM_RIGHTS and type SCM_RIGHTS for file descriptors, limited typically to 253 per message to avoid issues. These calls return the number of bytes sent or received on success, or -1 with errors like ETOOMANYREFS if too many descriptors are passed or EBADF for invalid ones; credentials can also be passed using SCM_CREDENTIALS if the SO_PASSCRED socket option is enabled.

Kernel-Level Handling

In the , Unix domain sockets are managed through specialized data structures that extend the generic framework. The core structure is struct sock, which provides common functionality including receive and send queues, such as sk_receive_queue for buffering incoming in the form of sk_buff objects. This is extended by struct unix_sock, embedded within struct sock, which includes members like addr for the socket address, path for filesystem associations, peer for the connected counterpart, and inq_len to track input queue length. These structures enable efficient local communication without the overhead of network protocols. Data flow in Unix domain sockets relies on kernel-managed buffers to handle transmission between processes. Incoming data is queued in the sender's output buffer and then moved to the receiver's sk_receive_queue, where it awaits user-space retrieval via system calls like recvmsg. Due to the local nature of these sockets, zero-copy optimizations are feasible; for instance, file descriptors passed via ancillary data (SCM_RIGHTS) reference shared kernel file descriptions without duplicating content, and direct memory transfers between process address spaces minimize copying. Pathname-based sockets associate with filesystem inodes via the sockfs pseudo-filesystem, allowing the kernel to enforce access through inode permissions during binding and connection. Protocol handling for Unix domain sockets bypasses traditional transport layers, enabling direct process-to-process routing. Connections are established via file descriptors or process IDs embedded in control messages (e.g., SCM_CREDENTIALS for , , and GID), with the kernel using the peer pointer in struct unix_sock to link sockets without address resolution overhead. Supported types include (SOCK_STREAM), (SOCK_DGRAM), and sequential packet (SOCK_SEQPACKET), with queued per-message for datagrams to preserve boundaries. Cleanup occurs automatically: abstract sockets (those without a filesystem path) are removed from the 's upon the last close of all references, while pathname sockets require explicit unlinking from the filesystem to remove their inode association, preventing lingering entries.

Practical Usage

Pathname vs. Abstract Sockets

Unix domain sockets support two primary addressing modes: pathname-based and abstract. Pathname sockets bind to a filesystem path, creating a visible socket file that persists until explicitly unlinked, while abstract sockets use a namespace independent of the filesystem, remaining invisible and automatically cleaned up upon process termination. Pathname sockets require specifying a filesystem path during the bind operation, such as /tmp/mysock, which results in the creation of a special socket file in the directory. This file is marked with socket type permissions and requires the process to have write access to the parent directory. The socket remains active even after the creating process exits, as long as it is not removed via unlink, allowing for persistent interprocess communication across process lifecycles. For creation, a process typically creates a temporary directory if needed (e.g., using mkdir), binds the socket to the path with the bind system call, and ensures cleanup by unlinking the path after use to avoid leaving orphaned files. Abstract sockets, a Linux-specific extension not available in standard BSD implementations, are addressed by a path prefixed with a null byte (e.g., \0mysock), preventing any filesystem interaction or visibility. These sockets do not create files, bypassing filesystem overhead and permissions like umask, and are automatically removed when all file descriptors referencing them are closed, eliminating manual cleanup needs. To create one, the address structure for bind includes the null-prefixed string without a terminating null, limiting the effective path length to the socket address size minus the family field (typically up to 108 bytes on Linux). The choice between modes involves trade-offs in visibility, security, and performance. Pathname sockets offer discoverability, as they appear in directory listings (e.g., via ) and leverage for , making them suitable for scenarios requiring explicit identification. In contrast, abstract sockets provide enhanced by avoiding filesystem exposure and slightly faster binding due to no disk I/O, but they lack discoverability and rely on out-of-band coordination for endpoint sharing, which can complicate multi-process setups.

Security and Permissions

Unix domain sockets are treated as special files in the filesystem when bound to a pathname, inheriting the standard Unix permission model where access is controlled by mode bits such as those set via chmod(2). For instance, connecting to a stream socket or sending datagrams requires write permission on the socket file itself, while search (execute) permission is needed on all directories in the path prefix. These permissions default to all bits enabled except those masked by the process's and can be modified using chmod(2) to restrict access, such as setting mode 0777 for broad readability or more restrictive values for security. Ownership of pathname-bound sockets follows the creator's user ID (UID) and group ID (GID), which can be altered with chown(2). During connection attempts via connect(2), the kernel verifies that the connecting process has the necessary permissions against the socket's ownership and mode bits, denying access with EACCES if write permission on the socket or search permission on the path components is lacking. This model ensures that only authorized processes can establish communication, with the superuser able to bypass certain restrictions. Advanced security features allow explicit credential passing to enhance authentication. Setting the SO_PASSCRED socket option enables the receiver to obtain the sender's process ID (PID), UID, and GID through an SCM_CREDENTIALS ancillary data message attached to messages via sendmsg(2). This mechanism, which requires kernel verification of the sender's credentials, permits fine-grained access control based on the peer's identity, though privileged processes can forge credentials. Additionally, SO_PEERCRED retrieves the peer's credentials for connected stream sockets. Abstract sockets, lacking filesystem ties, ignore these ownership and permission changes, relying instead on other mechanisms like network namespaces. Pathname-bound sockets are susceptible to race conditions during creation and binding, where an attacker might exploit timing gaps in filesystem operations to access or hijack the socket path. To mitigate such races when creating intermediate directories, use mkdir(2) with the O_EXCL to ensure atomic existence checks and creation. Abstract sockets circumvent filesystem-based attacks entirely by not creating persistent files, thus avoiding permission-related vulnerabilities tied to the directory structure.

Comparisons and Alternatives

With Other Local IPC Methods

Unix domain sockets provide a versatile mechanism for local () on systems, supporting both stream-oriented and datagram modes that enable bidirectional data exchange between unrelated processes through named endpoints in the filesystem or abstract namespaces. In contrast, offer a simpler, unidirectional channel primarily for related processes, such as parent-child pairs, where data flows in a first-in-first-out manner without a name in the filesystem unless using named (FIFOs), which still limit communication to one direction and require filesystem involvement for unrelated processes. This makes Unix domain sockets preferable for scenarios requiring full-duplex, named interactions, while or FIFOs suffice for basic, one-way data streaming between closely related or loosely coupled processes. Compared to , which allows multiple processes to map a common region directly into their address spaces for high-speed data access without mediation, Unix domain sockets facilitate mediated transfers where the handles copying and provides built-in through semantics, avoiding the need for explicit mechanisms like semaphores to manage concurrent access. excels in raw throughput for large data sets but demands manual coordination to prevent race conditions, whereas sockets ensure ordered, reliable delivery with less programmer overhead for . Message queues, as defined in , enable asynchronous, persistent storage of messages in a kernel-managed structure with or priority-based ordering, senders and receivers without requiring direct connections. support connectionless mode for point-to-point communication but lack native or fanout capabilities; one-to-many distribution requires application-level mechanisms, distinguishing them from message queues which provide queuing without connections but with persistence and strict ordering. The choice among these methods depends on application needs: Unix domain sockets are ideal for local applications leveraging familiar socket APIs for flexible, connection-based or , while pipes suit simple unidirectional flows, targets performance-critical direct access with added synchronization, and message queues fit decoupled, ordered messaging scenarios.

With Network Sockets

Unix domain sockets operate within the AF_UNIX address family, in contrast to network sockets which use the AF_INET family for or AF_INET6 for communications. This distinction fundamentally affects addressing: Unix domain sockets employ filesystem paths or abstract namespaces as identifiers, enabling local without requiring or numbers, whereas network sockets rely on and tuples to facilitate across hosts. Unlike network sockets, which traverse the full or —including packet headers, checksums, and potential routing—Unix domain sockets bypass these network layers entirely, performing all data transfer within the for reduced overhead and higher efficiency on the same host. This local-only mechanism eliminates the need for network protocol processing, such as fragmentation or reassembly, making Unix domain sockets particularly suitable for high-performance local . Unix domain sockets offer unique features not available in network sockets, such as the ability to pass open file descriptors between processes using ancillary data mechanisms like SCM_RIGHTS, which supports advanced local semantics like process credential exchange (e.g., PID, UID, GID via SCM_CREDENTIALS). However, they lack support for multicast or broadcast transmissions, which are inherent to IP-based network sockets for group communications. Additionally, while both socket types can use stream (SOCK_STREAM) or datagram (SOCK_DGRAM) semantics, Unix domain sockets enforce stricter local scoping, preventing cross-host connectivity. In terms of portability, Unix domain sockets are defined in the standard and widely implemented on systems, but their filesystem-based addressing limits interoperability compared to the universally adopted sockets, which function across diverse operating systems including non- environments. Although sockets provide broader reach, they incur performance penalties for local use due to unnecessary network stack involvement, often resulting in lower throughput than Unix domain sockets on the same machine.

Advantages and Limitations

Unix domain sockets offer several advantages for (IPC) on the same host. They provide higher performance than /IP loopback connections by bypassing the network stack, resulting in lower and reduced overhead—typically 20-40% faster in benchmarks for local data transfer. This efficiency makes them suitable for high-throughput applications like database clients or service proxies. Additionally, they support passing open file descriptors and process credentials via (e.g., SCM_RIGHTS and SCM_CREDENTIALS), enabling secure transfer of resources without . Filesystem permissions on pathname-bound sockets provide built-in , enhancing in multi-user environments. However, Unix domain sockets have notable limitations. They are restricted to communication within the same machine, lacking support for network-wide . Pathname lengths are capped, typically at 108 bytes on systems, which can constrain addressing in complex directory structures; other implementations may limit to 92 bytes or less. Portability is an issue, as features like abstract namespaces and credential passing are -specific and not part of the standard, potentially causing incompatibility across systems. Pathname-bound sockets require manual cleanup with unlink(2) to avoid lingering filesystem entries, and options like SO_RCVBUF may not function as expected. They also lack support for , limiting use in certain legacy protocols.

References

  1. [1]
    socket
    DESCRIPTION ; domain: Specifies the communications domain in which a socket is to be created. ; type: Specifies the type of socket to be created. ; protocol ...
  2. [2]
  3. [3]
    <sys/un.h>
    The sockaddr_un structure is used to store addresses for UNIX domain sockets. Values of this type shall be cast by applications to struct sockaddr for use with ...
  4. [4]
    unix(7) - Linux manual page
    ### Summary of Unix Domain Sockets (unix.7)
  5. [5]
    System Interfaces Chapter 2
    UNIX domain sockets provide process-to-process communication in a single system. Headers. The symbolic constant AF_UNIX defined in the <sys/socket.h> header ...
  6. [6]
    UNIX Domain Sockets - Oracle Help Center
    UNIX domain sockets communicate only between processes on a single host. Sockets in the UNIX domain are not considered part of the network protocols.
  7. [7]
    18: 19.3. Connections and Authentication - PostgreSQL
    Sets the access permissions of the Unix-domain socket(s). Unix-domain sockets use the usual Unix file system permission set. The parameter value is expected ...
  8. [8]
    An Advanced 4.4BSD Interprocess Communication Tutorial
    This document provides an introduction to the interprocess communication facilities included in the 4.4BSD release of the UNIX system.
  9. [9]
    7. Sockets - UNIX® System V Network Programming [Book]
    The socket interface that originated in the BSD UNIX operating system is also provided in System V Release 4. This allows the many applications written to the ...
  10. [10]
    [PDF] man Pages(5): Headers, Tables and Macros
    POSIX.1-1988 update. Solaris 2.0. POSIX.1b-1993. Solaris 2.4 realtime ... The sockaddr_un structure is used to store addresses for UNIX domain sockets.
  11. [11]
    socket
    The type argument specifies the socket type, which determines the semantics of communication over the socket. The following socket types are defined; ...
  12. [12]
    <sys/socket.h>
    The sockaddr structure is used to define a socket address which is used in the bind(), connect(), getpeername(), getsockname(), recvfrom(), and sendto() ...
  13. [13]
  14. [14]
    bind
    ### POSIX Description of bind() for Unix Domain Sockets (AF_UNIX)
  15. [15]
    listen
    ### Summary of POSIX Description of listen() for Sockets
  16. [16]
    accept
    ### Summary of POSIX Description of accept() for Sockets
  17. [17]
    connect
    ### Summary of POSIX Description of connect() for Unix Domain Sockets
  18. [18]
    send
    ### Summary of POSIX Description of send() for Connected Sockets (e.g., Unix Domain)
  19. [19]
    recv
    ### POSIX Description of recv()
  20. [20]
    shutdown
    ### POSIX Description of shutdown()
  21. [21]
    close
    ### POSIX Description of close() for Sockets
  22. [22]
    sendmsg
    ### Summary of POSIX Description for sendmsg() and recvmsg() with Ancillary Data (Unix Sockets)
  23. [23]
  24. [24]
    How Linux creates sockets and counts them | ops.tips
    Oct 16, 2018 · How Linux creates sockets and counts them. A deep dive into what goes under the hood in the Linux kernel when you can the socket system call.
  25. [25]
    mschwager/socket-speed: Comparing IPC methods on Linux. - GitHub
    The so-called abstract namespace is a Linux-specific feature that allows us to bind a UNIX domain socket to a name without that name being created in the file ...Missing: addressing | Show results with:addressing
  26. [26]
  27. [27]
    umask(2) - Linux manual page - man7.org
    The umask setting also affects the permissions assigned to POSIX IPC objects (mq_open(3), sem_open(3), shm_open(3)), FIFOs (mkfifo(3)), and UNIX domain sockets ...<|control11|><|separator|>
  28. [28]
  29. [29]
    connect(2) - Linux manual page - man7.org
    EACCES For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket file, or search permission is denied for one of the ...
  30. [30]
  31. [31]
    bind(2) - Linux manual page - man7.org
    An example of the use of bind() with Internet domain sockets can be found in getaddrinfo(3). The following example shows how to bind a stream socket in the UNIX ...
  32. [32]
  33. [33]
  34. [34]
  35. [35]
  36. [36]
  37. [37]
    Definitions
    Summary of each segment:
  38. [38]
    socket(7) - Linux manual page
    ### Summary of Socket Domains: AF_UNIX vs AF_INET