Paranoid Penguin - Rehabilitating Clear-Text Network Applications with Stunnel
Listing 3. Service Definition on nearclient
[telnets] accept = 23 connect = farserver.wiremonkeys.org:992
Listing 4. Service Definition on farserver
[telnets] accept = 992 connect = 23
As you can see, a service definition can be as simple as a pair of lines, an accept line to designate a listening port and a connect line to designate a destination port. Precisely what this means depends on whether a given system is a Stunnel client or a Stunnel server. On a client system, client = yes, Stunnel expects clear-text packets on its accept port and sends encrypted packets to the connect port. On a server system, client = no, Stunnel listens for SSL connections (encrypted packets) on its accept port and sends decrypted packets to the connect port.
Also notice that on a client, in your connect statement you probably need to specify not only a port but also a remote hostname or IP address, as in Listing 3, connect = farserver.wiremonkeys.org:992.
According to the way we've configured things in Listings 3 and 4, any host can connect to TCP port 23 on nearserver and traverse nearserver's tunnel to farserver. We can restrict this in any number of ways, including by using iptables. We can tell Stunnel to accept only local connections to the Stunnel client process, however, by using accept = 127.0.0.1:23 on nearclient.
This technique would work on farserver as well. If farserver has multiple interfaces, eth0, wlan0, ppp0 and so on, you can write your accept statement to specify the IP address of the interface on which you want it to receive tunneled packets in the same way. On both Stunnel clients and servers, the default IP for accept statements is any (all local interfaces), and the default IP for connect statements is 127.0.0.1 (localhost).
What about the telnet server on farserver? After all, clear-text telnet sessions seldom are a good idea. Therefore, in practice you want to be sure to add the line bind = 127.0.0.1 to your /etc/xinetd/telnet script, so that only local processes can connect to TCP 23.
Once you've finished configuring Stunnel on client and server, start Stunnel simply by typing the command stunnel. You don't need to worry about starting it on the server before starting it on the client; the client doesn't initiate a tunnel until you try to use it, for example, by trying to start a telnet session. If either or both hosts are using a password-protected server certificate, you are prompted for it now. Keep this in mind if you set up a Stunnel startup script. Once you've entered the certificate, you should be up and running.
You now can check for successful startup by issuing a quick ps auxw and looking for a Stunnel process—Stunnel returns no output to the console whether or not it starts cleanly. It does, however, send messages to your system's syslog facility, including startup messages.
Once stunnel is running on both client and server, our users on nearclient can trigger a tunnel by connecting to nearclient's TCP port 23, for example, with the command telnet 127.0.0.1 (23 is telnet's default port). Listing 5 shows a sample encrypted-telnet session.
Listing 5. Sample Telnet Session
nearserver:/usr/local/etc/stunnel# telnet 127.0.0.1 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. Fedora Core release 1 (Yarrow) Kernel 2.4.22-1.2115.nptl on an i686 login: myfaraccount Password: ********** Last login: Sun Jun 13 21:39:17 from localhost.localdomain [myfaraccount@farserver myfaraccount]$
As you can see, from the end-user's perspective, connecting to farserver in this way is practically indistinguishable from any other telnet session. The bash prompt at the end of the listing, however, confirms that we have in fact connected to farserver.
Stunnel and inetd/xinetd
I have a confession. The examples in this article do not show the most efficient way to use Stunnel to encrypt telnet, although I assure you I've tested these examples, and they do work.
My justification is I wanted to illustrate the concept of tunneling generic TCP services quickly, using a technique that works for practically any single-TCP-port service. But telnet, pop3 and other services typically started by a super-server, such as inetd or xinetd, are supported through several different Stunnel features that are beyond the scope of this article.
For example, a Stunnel server can, rather than forward packets with a connect statement, pass them to a process that Stunnel invokes itself with the exec parameter in stunnel.conf. Alternatively, you can configure Stunnel itself to be invoked dynamically by inetd or xinetd.
For more information on using Stunnel with dynamically started dæmons or in conjunction with inetd or xinetd, see the stunnel(8) man page and the Stunnel FAQ.