tcpserver: Secure, Flexible Daemon Management

If you’re still running inetd, it’s time to move on. Either xinetd or tcpserver offer superior security and control. We’re going to look at tcpserver. Note that there is one limitation: it manages only tcp. If you’re using UDP or rpc services, tcpserver alone will not do the job. In that case, xinetd is the way to go.

The (in)Famous DJB
tcpserver is part of the ucspi-tcp suite of tools by none other than the famous, and infamous, Daniel J. Bernstein. Professor Bernstein seems to inspire strong passions in the tech community; some refuse to use his software because they do not like the author. Other objections are that his programs install themselves in non-standard file locations, and that he keeps too tight a grip on the code. Personality issues aside, I find that his programs are lean, fast, secure, and worthy on their own merits. A special item of note is Professor Bernstein led the suit against the United States Government against export controls on encryption software, and won.

DJB’s security model is based on a zero-trust premise. His programs don’t even trust themselves- each function is isolated from other parts of the program. They run in user accounts with restricted rights; services that require root access are as restricted and limited as possible. Any successful intrusion will be severely limited, if an intruder can get in at all.

Put It To Work
tcpserver listens for connections from tcpclient, which is also part of ucspi-tcp. Then it runs programs as defined by command-line variables, or by rulesets stored in the cdb, constant database. This is created with the tcprules program.

For this article, let’s assume an average network running various private and public services, set up with proper firewalls and gateways. tcpserver is so flexible it enables the user to run any program as a service. Like this:

tcpserver 0 21 /path/to/ftpd

The 0 means bind to all available IP addresses. 21, of course, is the listening port for FTP. (If the port number were set to 0 tcpserver would assign it any available port. Which makes no sense for an FTP server, but it might be useful for other applications.) So the output from netstat looks like this:

$ netstat -an –inet
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0* LISTEN

This is how inetd runs the show, which isn’t a desirable condition. It leaves too many holes for an attacker to exploit. One of tcpserver’s nicest features is the fine-grained port management. inetd does not let you specify which port 21. Let’s say our server is assigned the public IP It also has, localhost, and the private, non-routable IP of So let’s tie this down more tightly. We have both an internal and external FTP repository:

#public FTP server
tcpserver 21 /path/to/ftpd
#private FTP server
tcpserver 21 /path/to/ftpd

$ netstat -an –inet
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0* LISTEN
tcp 0 0* LISTEN

Pretty slick, eh? No sign of localhost, and the private server will not receive requests from the big bad outside world. This is most useful for separating public and private services. Even with a good strong firewall/gateway, additional layers of protection are vital. Relying on a single defense is unwise, as all good admins know. I know, this is preaching to the choir; perhaps it will be useful to show your boss, should he or she need some persuading.

The syntax is:

tcpserver options host port program

It does not use a configuration file, but rather command line options, and environment variables set by envuidgid, or setuidgid. The command-line switches are -g and -u, to set GID and UID.

envuidgid is a handy little time-saver. Create a pool of user accounts specifically for running services, user1, user2, etc. Assign GID, UID, and set permissions. Use envuidgid to select the appropriate one:

envuidgid user2 tcpserver -RH 21 /path/to/ftpd

Options and program may have more than one value. Some commonly used options:
-c n
Concurrent connections are limited, the default is 40. New connections are deferred until old ones terminate.
-x cdb
This tells it to use rules that have been compiled into the binary constant database. cdb by itself is fascinating, it is the core of several of djb’s programs. It is lightning fast, enabling large-scale operations on relatively modest hardware. cdb can be edited and restarted on the fly, without interrupting tcpserver. It handles databases up to 4 gigabytes.
Do not attempt to obtain $TCPREMOTEINFO from the remote host
Do not perform a reverse lookup. Many hosts do not provide reverse-lookup information in any case. Using -R and -H will speed things along considerably. You MUST use these options when running a DNS server, port 53, and also auth/ident, port 113. Otherwise they’ll get stuck in a loop.
-t n
will set a time limit on attempting to get $TCPREMOTEINFO, the default is 26 seconds.

We all know allow/deny rules for access control, easy as pie. Use tcprules if you have a need to deny. First create a plain text rules file, let’s narcissistically call it myrules:


Now convert this to cdb format:

tcprules /myrules.cdb /myrules.tmp < /myrules

Tell tcpserver to use this cdb file:

envuidgid user2 tcpserver -RHx /myrules.cdb 21 /path/to/ftpd

tcprules is also used to define environment variables. Pile on the variables, as many as you like. Use tcprulescheck to see how your rules will be interpreted.

Rather than rassling with inittab, init.d and rc files, use DJB’s daemontools package to control tcpserver. It’s easier, and more versatile. You might even like it for managing all services.

Many thanks to Kai MacTane for invaluable assistance with this article.

DJ Bernstein home
Software User’s Rights
man pages for DJB software
Bernstein v. US Dept. of State


See All Articles by Columnist
Carla Shroder

Latest Articles

Follow Us On Social Media

Explore More