howdydaemon, part 2
Hi there! Welcome back.
Let's recap part 1 and the pieces that went into making a TCP/IP service with daemontools and ucspi-tcp:
a server, in this case howdyd.sh, that simply reads from the network via stdin (file descriptor 0), and writes to the network via stdout (file descriptor 1)
a daemontools run script for the server, in this case howdyd/run, that invokes the server through tcpserver
(optionally) a daemontools run script for the logger, in this case howdyd/log/run, that uses daemontools multilog to read input from stdin, and maintains a set of rotated log files within a subdirectory of /var/multilog
(optionally) a set of tcprules access rules, maintained in /etc/tcprules, used by tcpserver to control and parameterize remote clients' usage of the server
The howdy
daemon demonstrated all of these components,
as well as other standard practices used in putting up a secure service
with daemontools:
use of the daemontools setuidgid (or envuidgid) utility, to run services with unpriveleged system accounts, in this case "howdyd" and "multilog", rather than root
use of the daemontools softlimit utility, to place upper bounds on the use of system resources
use of the -c option to tcpserver, to control the maximum number of concurrent connections to the service, parameterized in the example with the variable $CONLIMIT
But while our first cut at the howdy
daemon may have
used these features
--and while it was certainly friendly enough--
the howdyd server we have seen so far isn't especially useful.
In fact, though,
a howdy
server can actually be nice to have around.
Think of the applications where you might want a quick way to get a
status check on a remote system without having to log in.
The howdyd framework also provides a great way
to thoroughly explore all the details and options
of setting up a server with daemontools and ucspi-tcp.
To see some possibilities, install this slightly enhanced version of howdyd.sh in /var/svc.d/howdyd/howdyd.sh:
#!/bin/sh # howdyd.sh # a howdy daemon # === echo "*** A visitor from ${TCPREMOTEIP}!" >&2 echo "Hi there! Welcome to `hostname`!" echo "The time here: `date`" echo "Our uptime is: `uptime`" echo echo "The howdyd environment:" printenv | sort echo echo "The howdyd user:" who -Hm echo echo "Our users:" w -h echo /usr/games/fortune echo "Bye!" echo "*** The visitor from ${TCPREMOTEIP} departs!" >&2 exit 0 ### that's all, folks!
Now open three other terminals. Use one of these to control the service, restarting it every time you modify the settings:
# svc -t /service/howdyd
Use another to follow the log (use -f for OpenBSD):
$ tail -F /var/multilog/howdyd/current | tai64nlocal 2004-01-06 16:09:25.408525500 *** Starting howdyd service... 2004-01-06 16:09:25.415041500 tcpserver: status: 0/13
And use another to contact the server with your "client":
$ tcpcat 10.0.1.16 1789 Hi there! Welcome to slate.copperisle.com! The time here: Tue Jan 6 16:13:19 EAT 2004 Our uptime is: 4:13PM up 7:23, 5 users, load averages: 0.11, 0.10, 0.08 The howdyd environment: PATH=/command:/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin PROTO=TCP SOMEVAR=somevalue TCPLOCALHOST=0 TCPLOCALIP=10.0.1.16 TCPLOCALPORT=1789 TCPREMOTEHOST=alloy.copperisle.com TCPREMOTEIP=10.0.1.10 TCPREMOTEPORT=49158 The howdyd user: USER LINE WHEN FROM howdyd tty?? Jan 6 16:13 Our users: USER TTY FROM LOGIN@ IDLE WHAT wcm C0 - 8:53AM 7:20 xinit /home/wcm//.xinitrc -- wcm p0 :0.0 8:53AM 4 tail -f /var/multilog/howdyd/current wcm p1 :0.0 8:54AM 7:18 tail -f /var/multilog/fetchmail/curr wcm p2 :0.0 8:56AM 4:42 -bash wcm p3 :0.0 11:58AM 0 bash -l What's another word for "thesaurus"? -- Steven Wright Bye!
This shows the environment that tcpserver sets up for the howdyd server. Note the $SOMEVAR variable, set as we specified in the howdy.rules configured for this service.
The message is also sprinkled with a few other system info commands, as well as a fortune, before a cheerful farewell.
Now switch back to the log to see what was recorded for this connection:
2004-01-06 16:09:25.408525500 *** Starting howdyd service... 2004-01-06 16:09:25.415041500 tcpserver: status: 0/13 2004-01-06 16:13:00.490932500 tcpserver: status: 1/13 2004-01-06 16:13:00.491776500 tcpserver: pid 10390 from 10.0.1.10 2004-01-06 16:13:00.500501500 tcpserver: ok 10390 0:10.0.1.16:1789 alloy.copperisle.com:10.0.1.10::49157 2004-01-06 16:13:00.503919500 *** A visitor from 10.0.1.10! 2004-01-06 16:13:00.532722500 *** The visitor from 10.0.1.10 departs! 2004-01-06 16:13:00.533943500 tcpserver: end 10390 status 0 2004-01-06 16:13:00.533959500 tcpserver: status: 0/13
Most of the lines are tcpserver status messages. These show the current connection number (slash) maximum connections, such as 1/13. In this case, the 13 comes from the $CONLIMIT parameter in the run script.
The log also shows a few lines generated by the howdyd.sh script itself. Your server only needs to write to stderr, and multilog will pick it up for the log.
The other lines in the log pull data from the $TCP* variables.
The completeness of these variables depend on DNS records for
the clients, and the data gathering
options used with tcpserver:
So now what to do is just mess around, changing things and remembering to restart the server each time with svc -t, studying the results:
Change setuidgid to envuidgid in the run script. What happens differently?
Set up the server to run on a port number less than 1024, say 981. Leaving the setuidgid invocation in the run script, what happens? Then change setuidgid to envuidgid. Now what happens? Why does the port number matter?
How can you arrange to run this service as a non-priveleged user even when using a priveleged port?
Decrease the softlimit parameters until the run script croaks. What messages appear in the log?
Remove the execute bits on the run script, with chmod 644 run. What happens in the log? What happens when you fix the problem, with chmod 755 run?
Experiment with the data gathering options to tcpserver. How do these affect the $TCP* environmental variables and the log output? How do these affect the latency (that is, the time required) to service remote connections?
Play with different access rules in /etc/tcprules/howdy.rules. Are there funner things you can make the script do, setting up different environmental variables depending on the client?
Of course, howdyd.sh doesn't have to be a shell script, either. Use your favorite language, Perl, Python, Ruby. Why, you could write your server using C!
The more time you spend playing around with this framework, the more you will understand the use of daemontools services.
Copyright © 2003, 2004, Wayne Marshall.
All rights reserved.
Last edit 2004.03.08, wcm.