Socketbox-inetd compatibility

Due to the nature of inetd, most programs should work without any modifications.

Name Works? Notes
OpenSSH yes Run with sshd -i. Tested with version 8.2p1.
Busybox httpd yes Run with httpd -i. Tested with versions 1.31.1 and 1.32.0.
Exim yes Run with exim4 -bs. Tested with version 4.93.

Socketbox-preload compatibility

Name Works? Notes
Apache2 yes Tested with version 2.4.41. Be sure to use a "Listen" statement that specifies a fe8f::/96 address to actually create a new socket. You can ignore the "Failed to enable APR_TCP_DEFER_ACCEPT" error message.
Nginx yes, with limitations Tested with version 1.18.0. Use listen [fe8f::(address)]:80 in your server block. Retrieval of $server_addr does not work (it returns the fe8f:: address instead of the real server IP address). $remote_addr works. Patch WIP. Please use HAProxy instead.
Postfix yes, with hacks Tested with version 3.4.13. Set inet_interfaces to [fe8f::(address)]. The fe8f::/96 address actually has to exist as an interface address in the network namespace that Postfix is running in; use ip addr add fe8f::1 dev eth0 preferred_lft 0. You will need to move /usr/lib/postfix/sbin/master to /usr/lib/postfix/sbin/master.distrib (with dpkg-divert, if using Debian/Ubuntu). Replace /usr/lib/postfix/sbin/master with a shell script:
exec env SKBOX_DIRECTORY_ROOT=/run/socketbox-conf LD_PRELOAD=/path/to/ /usr/lib/postfix/sbin/master.distrib "$@"

Upon further testing, it appears that you might also need to do this on /usr/lib/postfix/sbin/smtpd.

Reverse DNS lookups on incoming connections might not work, though I don't know whether this is a Postfix bug or if my mail server container is configured incorrectly. Needs further internal testing.

Not yet tested:

  • Ports 465 or 587 Works.
  • Actually trying to send an email (only tested EHLO/MAIL FROM/RCPT TO) Works on port 25 (MTA->MTA) and port 465 (implicit TLS submission). Port 587 (STARTTLS submission) not tested, though the result might be similar to the port 25 case.
  • chroot=y in
Python yes Tested with version 3.8.5. Use code like the following:
import socket
my_socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
while True:
    a, addr = my_socket.accept()
    # do something with (a, addr)

(Note that this normally fails with OSError if socketbox-preload is not used.)

Also tested to work (using fe8f::x:y:y) with whatever web server Synapse (the Matrix homeserver) is using, though it seems to throw an exception if you attempt to send a Unix domain socket as a connection; set environment variable SKBOX_STEALTH_MODE=1 as a workaround.

Not yet tested:

  • socket.create_server(('fe8f::x:y:y', ...), ...)
Node.js yes, with hacks and limitations Tested with version 12.22.5 on Debian 11. host: 'fe8f::x:y:y' in net.createServer(...).listen(options) works. fd: not yet tested, based on the previous observation with 12.19.0, it might not work. May require a relatively recent version of libuv. Returns a bogus EADDRINUSE error if the socket under $SKBOX_DIRECTORY_ROOT2 already exists. The technique described below is still applicable here (characterized but untested).

Tested with version 12.19.0 with server.listen({fd: +process.env.WHATEVER}), which did not work. As an alternative, the core functionality of socketbox can be implemented in Node.js directly:

const net = require('net');
const http = require('http');
var appOne = http.createServer(/* (req, res) => ... */);
var appTwo = http.createServer(/* (req, res) => ... */);
var appDefault = http.createServer(/* (req, res) => ... */);

var mapping = {
    "@2001:db8::1": appOne,
    "@2001:db8::2": appTwo

var masterServer = net.createServer(s => {
    let key = "@" + s.localAddress;
    if (mapping.hasOwnProperty(key)) {
        mapping[key].emit("connection", s);
    } else {
        appDefault.emit("connection", s);

masterServer.listen({host: "::", port: 80}); /* Alternatively call Node.js from Python using an inherited AF_INET[6] listening socket, perhaps using the IPV6_TRANSPARENT + TPROXY trick to arbitrarily select IPs and port numbers. */

See TCP Battleships.

TCP listening sockets created with ctrtool ns_open_file also work with fd:, regardless of network namespace; see Universal Relay.

Apache Tomcat yes
Dovecot yes Tested with version Only imap module currently tested. Set listen = fe8f::(address) in dovecot.conf. Needs the same hack described above with postfix for both the main binary and imap-login (or possibly pop3-login [untested]).


Name Works? Notes
HAProxy yes, with source code modifications Tested with version 2.4.0. I maintain my own private fork of HAProxy which relaxes the sockpair address mode, such that it will be fully compatible with the "A" protocol without requiring socketbox-preload or socketbox-inetd.

Run this modified version of HAProxy with the following Python script:

import socket, os

s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)

# os.chown("/run/socketbox/haproxy_dgram.sock.tmp", 0, [gid of socketbox group]) # only if /run/socketbox is not set-gid
os.chmod("/run/socketbox/haproxy_dgram.sock.tmp", 0o660)
os.rename("/run/socketbox/haproxy_dgram.sock.tmp", "/run/socketbox/haproxy_dgram.sock")

os.environ["SKBOX_HAPROXY_DGRAM_SOCK"] = str(s.fileno())

os.execv("/usr/local/bin/haproxy", ["haproxy", "--", "/etc/haproxy/haproxy.conf"])

and use bind sockpair@${SKBOX_HAPROXY_DGRAM_SOCK} in haproxy.conf.

Now that ctrtool ns_open_file can open Unix dgram sockets (requires experimental nsof_special branch), you could use that instead of the above script, using bind sockpair@${CTRTOOL_NS_OPEN_FILE_FD_0}. This still requires the custom version of HAProxy that I maintain as above.

Stuff that will likely work and not work

  • UDP servers will not work.
  • FTP servers will likely not work, because FTP requires an extra socket connection to be made when transferring data.
  • Servers written in Go(lang) will likely not work because of the effectively static linking.

Servers to test

  • Squid
  • Traefik
  • Caddy
  • systemd-socket-proxyd