Local services

A local service is a daemon that listens to incoming connections on a Unix domain socket. Clients of the service are programs connecting to this socket: the daemon performs operations on their behalf.

The service is called local because it is not accessible to clients from the network.

A widely known example of a local service is the syslogd daemon. On most implementations, it listens to the /dev/log socket. Its clients connect to it and send their logs via the socket. The openlog() function is just a wrapper arround the connect() system call, the syslog() function a wrapper around write(), and so on.



The most important benefit of a local service is that it permits controlled privilege gains without using setuid programs. The daemon is run as user S; a client running as user C and connecting to the daemon asks it to perform operations: those will be done as user S.

Standard Unix permissions on the listening socket can be used to implement some basic access control: to restrict access to clients belonging to group G, change the socket to user S and group G, and give it 0420 permissions. This is functionally equivalent to the basic access control for setuid programs: a program having user S, group G and permissions 4750 will be executable by group G and run with S rights.

But modern systems implement the getpeereid() system call or library function. This function allows the server to know the client's credentials: so fine-grained access control is possible. On those systems, local services can do as much authentication as setuid programs, in a much more controlled environment.


The most obvious difference between a local service and a network service is that a local service does not serve network clients. But local services have another nice perk: while network services usually only provide you with a single channel (a TCP or UDP socket) of communication between the client and the server, forcing you to multiplex your data into that channel, local services allow you to have as many communication channels as you want.

(The SCTP transport layer provides a way for network services to use several communication channels. Unfortunately, it is not widely deployed yet, and a lot of network services still depend on TCP.)

The fd-passing mechanism is Unix domain socket black magic that allows one peer of the socket to send open file descriptors to the other peer. So, if the server opens a pipe and sends one end of this pipe to a client via this mechanism, there is effectively a socket and a pipe between the client and the server.


The UCSPI protocol is an easy way of abstracting clients and servers from the network. A server written as a UCSPI server, just as it can be run under inetd or s6-tcpserver, can be run under s6-ipcserver: choose a socket location and you have a local service.

Fine-grained access control can be added by inserting s6-ipcserver-access in your server command line after s6-ipcserver.

A client written as an UCSPI client, i.e. assuming it has descriptor 6 (resp. 7) open and reading from (resp. writing to) the server socket, can be run under s6-ipcclient.

Use in skarnet.org software

skarnet.org libraries often use a separate process to handle asynchronicity and background work in a way that's invisible to the user. Among them are:

Those processes are usually spawned from a client, via the corresponding *_startf*() library call. But they can also be spawned from a s6-ipcserver program in a local service configuration. In both cases, they need an additional control channel to be passed from the server to the client: the main socket is used for synchronous commands from the client to the server and their answers, whereas the additional channel, which is now implemented as a socket as well (but created by the server on-demand and not bound to a local path), is used for asynchronous notifications from the server to the client. The fd-passing mechanism is used to transfer the additional channel from the server to the client.