s6-networking: the s6-tcpserver-access program
Keywords: s6-networking s6-tcpserver-access tcp access control tcprules tcpwrappers libwrap

s6-networking
Software
skarnet.org

# The `s6-tcpserver-access` program

`s6-tcpserver-access` is a command-line TCP access control tool, and additionally performs some fine-tuning on a TCP socket. It is meant to be run after s6-tcpserver and before the application program on the s6-tcpserver command line, just like tcpwrappers' `tcpd` program.

## Interface

         s6-tcpserver-access [ -v verbosity ] [ -W | -w ] [ -D | -d ] [ -H ] [ -h ] [ -R | -r ] [ -P | -p ] [ -l localname ] [ -B banner ] [ -t timeout ] [ -i rulesdir | -x rulesfile ] prog...

- s6-tcpserver-access checks it is run under a UCSPI server tool such as s6-tcpserver or its stripped-down version s6-tcpserverd.
- It checks that the remote end of the connection fits the accepted criteria defined by the database contained in rulesdir or rulesfile. If the database tells it to reject the connection, the program exits 1.
- It sets up a few additional environment variables.
- It executes into prog..., unless the first matching rule in the rule database includes instructions to override prog....

## Environment variables

s6-tcpserver-access expects to inherit some environment variables from its parent:

- PROTO: normally TCP, but could be anything else.
- ${PROTO}LOCALIP: the local address of the socket.
- ${PROTO}LOCALPORT: the local port of the socket.
- ${PROTO}REMOTEIP: the remote address of the socket, i.e. the client's IP address.
- ${PROTO}REMOTEPORT: the remote port of the socket.

Additionally, it exports the following variables before executing into prog...:

- ${PROTO}REMOTEHOST: set to the remote host name obtained from a DNS lookup. Unset if the `-H` option has been given.
- ${PROTO}LOCALHOST: set to the local host name obtained from a DNS lookup. If the `-l` option has been given, set to localname instead.
- ${PROTO}REMOTEINFO: normally unset, but set to the information retrieved from ${PROTO}REMOTEIP via the IDENT protocol if the `-r` option has been given.

Also, the access rules database can instruct s6-tcpserver-access to set up, or unset, more environment variables, depending on the client address.

## Options

- `-v verbosity` : be more or less verbose, i.e. print more or less information to stderr:
  - 0: only log error messages.
  - 1: only log error and warning messages, and accepted connections. This is the default.
  - 2: also log rejected connections and more warning messages.
  - 3: also log detailed warning messages from DNS and IDENT resolution.
- `-W` : non-fatal. If errors happen during DNS or IDENT resolution, the connection process is not aborted. However, incorrect or incomplete results might still prevent a legitimate connection from being authenticated against a DNS name. This is the default.
- `-w` : fatal. Errors during DNS or IDENT resolution will drop the connection.
- `-D` : disable Nagle's algorithm. Sets the TCP_NODELAY flag on the network socket.
- `-d` : enable Nagle's algorithm. This is the default.
- `-H` : disable DNS lookups for the ${PROTO}LOCALHOST and ${PROTO}REMOTEHOST environment variables. The default, when this option is not given, is to try and read them from DNS.
- `-h` : consult `/etc/hosts` before DNS. The default, when this option is not given, is to ignore `/etc/hosts`. Note 1: the `-H` option overrides this one, no DNS lookups means that the hosts database won't be consulted either. Note 2: if a name is obtained via the hosts database instead of DNS, any `-p` checks will be disabled for it.
- `-R` : disable IDENT lookups for the ${PROTO}REMOTEINFO environment variable. This is the default.
- `-r` : enable IDENT lookups. This should only be done for legacy programs that need it.
- `-P` : no paranoid DNS lookups. This is the default.
- `-p` : paranoid. After looking up a name for the remote host, s6-tcpserver-access will lookup IP addresses for this name, and drop the connection if none of the results matches the address the connection is originating from. Note that this still does not replace real authentication via a cryptographic protocol.
- `-l localname` : use localname as the value for the ${PROTO}LOCALHOST environment variable, instead of looking it up in the DNS.
- `-B banner` : print banner to the network as soon as the connection is attempted, even before checking client credentials. The point is to speed up network protocols that start with a server-side message.
- `-t timeout` : set a timeout on all the operations performed by s6-tcpserver-access. If it is not able to do its job in timeout milliseconds, it will instantly exit 99. The default is 0, meaning no such timeout.
- `-i rulesdir` : check client credentials against a filesystem-based database in the rulesdir directory.
- `-x rulesfile` : check client credentials against a cdb database in the rulesfile file. `-i` and `-x` are mutually exclusive. If none of those options is given, no credential checking will be performed.

## Access rule checking

s6-tcpserver-access checks its client connection against a ruleset. This ruleset can be implemented:

- either in the filesystem as an arborescence of directories and files, if the `-i` option has been given. This option is the most flexible one: the directory format is simple enough for scripts to understand and modify it, and the ruleset can be changed dynamically. This is practical, for instance, for roaming users.
- or in a CDB file, if the `-x` option has been given. This option is the most efficient one if the ruleset is static enough: a lot less system calls are needed to perform searches in a CDB than in the filesystem.

The exact format of the ruleset is described on the s6-accessrules-cdb-from-fs page.

s6-tcpserver-access first gets the remote address ip of the client and converts it to canonical form. Then it checks it with the s6_accessrules_keycheck_ip46() function. In other words, it tries to match broader and broader network prefixes of ip, from `ip4/`ip`_32` to `ip4/0.0.0.0_0` if ip is v4, or from `ip6/`ip`_128` to `ip6/::_0` if ip is v6. If the result is:

- S6_ACCESSRULES_ERROR: it immediately exits 111.
- S6_ACCESSRULES_DENY: it immediately exits 1.
- S6_ACCESSRULES_ALLOW: it grants access.
- S6_ACCESSRULES_NOTFOUND: more information is needed.

In the last case, if DNS lookups have been deactivated (`-H`) then access is denied. But if s6-tcpserver-access is authorized to perform DNS lookups, then it gets the remote name of the client, remotehost, and checks it with the s6_accessrules_keycheck_reversedns() function. In other words, it tries to match shorter and shorter suffixes of remotehost, from `reversedns/`remotehost to `reversedns/@`. This time, the connection is denied is the result is anything else than S6_ACCESSRULES_ALLOW.

Note that even if the access check succeeds, the connection can still be denied if paranoid mode has been requested (`-p`) and a forward DNS query on remotehost does not match ip.

## Environment and executable modifications

s6-tcpserver-access interprets non-empty `env` subdirectories and `exec` files it finds in the matching rule of the ruleset, as explained in the s6-accessrules-cdb-from-fs page.

- An `env` subdirectory is interpreted as if the s6-envdir command had been called before executing prog: the environment is modified according to the contents of `env`.
- An `exec` file containing newprog completely bypasses the rest of s6-tcpserver-access' command line. After environment modifications, if any, s6-tcpserver-access execs into `execlineb -c newprog`.

## Notes

- s6-tcpserver-access may perform several DNS queries. For efficiency purposes, it does as many of them as possible in parallel. However, if asked to do an IDENT query, it does not parallelize it with DNS queries. Take that into account when estimating a proper timeout value.