Cover V04, I03
Article
Figure 1
Figure 2
Figure 3
Figure 4
Figure 5
Figure 6

may95.tar


Implementing SOCKS

Matt Ganis

Depending on your perspective (system administrator, programmer, end user), firewalls can be either a blessing or a curse: usually what you buy in security, you often pay for in convenience and/or ease of use.

For some years I ran a traditional dual-homed gateway, where users logged in, did their work using vt100 emulation, and logged out. This worked well for applications like telnet, gopher, and archie, but the picture changed dramatically when Mosaic and the World Wide Web (WWW) came to town. Was it possible to allow all 50 or 60 concurrent users to run this behemoth of a program (on the same machine!) and not put the system performance in the dumpster? Along came SOCKS.

How SOCKS Works

SOCKS is officially classified as an Authenticated Firewall Traversal protocol (that's the name of the working group in the IETF furthering the protocol). With SOCKS I could allow users to run TCP-based applications on their workstations and tunnel the traffic to and from the Internet through my firewall. The SOCKS protocol, as discussed in this article, was developed by David and Michelle Kolbas (see References). The current implementation is maintained by Ying-Da Lee of NEC corporation and can be obtained by anonymous ftp from ftp.nec.com (143.101.113.3) in /pub/security/socks. The current version (as of this writing) is version 4.2 pre-release number 3. It's been built and tested on many platforms, including SunOS, HP-UX, AIX, and others (see the README for specifics).

To understand how SOCKS works, it's useful first to look at a traditional TCP-based client/server model. Figure 1 diagrams the networking calls for such a model. The client first sets up for socket-level communication by issuing a socket() call, which returns a socket descriptor -- typically an integer value. The connect() call then initiates the TCP session to the server on a given port. The server traditionally listens on that port for incoming data, while the client writes the data to the port (perhaps with a write() call) and listens with a read(). In general, in an open environment, each client connects directly with and establishes its own TCP connection to a server, as in Figure 2.

SOCKS is like a relay between the client and the server. Using the same example, the networking flow would look like that shown in Figure 3. So in essence, the SOCKS server is really a funnel. All of the internal clients connect to the firewall, and the firewall makes all of the connections to the Internet on behalf of the clients, as in Figure 4.

Building SOCKS

SOCKS has two components: the server (sockd) and the clients that connect to the server. When you build the package, you actually build the two parts: the server (sockd) and the SOCKS library (libsocks.a). The SOCKS library consists of replacements for the traditional TCP/IP networking calls connect, bind, listen, accept and getsockname. The replacement calls just prepend an "r" to the standard call (e.g., the replacement for connect() is rconnect()).

Building the package is relatively straightforward. Once you have unpacked the archive, issue a make all to build the server (sockd), the sample clients (telnet, ftp, and finger) and the SOCKS library (libsocks.a). You'll need to make a few decisions and set some variables in the main Makefile based on your platform, but the documentation makes these steps clear and easy to manage.

One option that is not in the Makefile is

#define NOT_THROUGH_INETD.

If you #define this, you're indicating that you want to start the SOCKS server from the command line rather than run it from the inetd process. I prefer to run it through inetd, but if you have a large /etc/sockd.conf file (explained below), you may want to consider this option for performance reasons. Basically, for every connection to the SOCKS server, the file /etc/sockd.conf must be consulted to determine if the connection is valid or not. If you run from the command line, this configuration file is read once and stored in memory, thus speeding up the performance a bit.

Implementing SOCKS

The process of modifying your clients to use a SOCKS gateway is called "socks-ification" (see the file called How_to_SOCKSIFY, included in the package). Over the releases of SOCKS, socksification has become much easier. With the library, libsocks.a, built, you need only replace the basic networking calls (connect, accept, bind, etc.) with their SOCKS counterparts (rconnect, raccept, rbind). To make life even easier, copy from the Makefile the #define line that defines connect as Rconnect and accept as Raccept, then just build your application (it's not necessary to modify the source, just recompile and link with the SOCKS library).

Assume, for the sake of this article, a network that looks like one in Figure 5. The host that will run the socksified clients must have a control file, /etc/socks.conf, on it. This file looks something like:

direct  127.0.0.1    255.255.255.255
direct  198.15.15.0  255.255.255.0
direct  198.15.14.0  255.255.255.0

sockd  @=198.15.15.3 0.0.0.0  0.0.0.0

When a client application (like a Web browser or telnet) attempts to make a connection, it consults the /etc/socks.conf file on the host. Once the name of the far end client has been resolved to an IP address, the address is compared with those listed in this file to determine whether the client should make the connection through the SOCKS gateway, or go directly to the server. The example above tells this client to connect directly (i.e., don't use the gateway) for all internal hosts, and to use the gateway at address 198.15.15.3 for everything else (0.0.0.0).

If you don't have access to the external namespace on your local nameserver, you may want to define the environment variable SOCKS_NS to point to a nameserver that can resolve names in the external namespace. I run a caching-only nameserver on the same machine where I run my SOCKS server. You can also define SOCKS_SERVER to point at a different server than that defined in /etc/socks.conf.

Setting up and running the SOCKS server isn't difficult: what you must remember is that you don't "create" a firewall merely by running SOCKS on a machine. SOCKS is a "tunnel" or small hole (a diode -- or one-way hole) that you open in your firewall. For details on firewalling beyond the scope of this article, see Cheswick and Belovin, Firewalls and Internet Security. If you are running out of inetd, move the binary to your firewall and edit /etc/services to add the following line:

socks   1080/tcp  # socks service on port 1080

then edit /etc/inetd.conf to include:

socks  stream  tcp  nowait   nobody /usr/local/sockd sockd

You must maintain two configuration files to run SOCKS. The first is /etc/sockd.route. This file was put into place for dual-homed hosts to enable the system administrator to point (or route) networks out through a pre-defined interface. Here's an example of an /etc/sockd.route file:

198.15.15.1  198.15.15.0  255.255.255.0
198.15.15.1  198.15.14.0  255.255.255.0
198.15.2.1   0.0.0.0      0.0.0.0

Figure 5 shows the firewall, with network 198.15.2.0 being the Internet (or un-secure) side, and 198.15.15.0 being the secure side (Note: I made up these network addresses; they are not meant to represent actual networks. The /etc/sockd.route example above specifies that anything in networks 198.15.15.0 and 198.15.14.0 (both with a mask of 255.255.255.0) should be routed out via interface 198.15.15.1 and that everything else should be routed to the 198.15.2.1 interface (or the un-secure, Internet side).

The second key configuration file is /etc/sockd.conf. This file defines which IP addresses can pass through the box and which addresses it can "talk" to. Figure 6 shows an example of the /etc/sockd.conf file. These are basic source/destination filters. The first rule that matches a particular pattern is the rule applied to the packets. For example, according to the first rule, any packet with no masking -- i.e., 0.0.0.0 -- that is destined for the internal network (198.15.14.0) will be denied -- packets should only be destined for the un-secure network adapter.

The same is true for rule number 2 -- anything destined for the internal network should be denied.

Rule 3 permits any machine in the 198.15.14.0 network (applying the mask 255.255.255.0) access to any machine (0.0.0.0) on the Internet.

Rule 4 will allow only the machine at 198.15.13.1 (note the full host mask) to communicate with any machine on the Internet.

Rule 5 a catchall: deny all access.

Nameservice and Protocol Requirements

There are two important things to remember regarding a SOCKS setup: the nameservice and the protocol used by the client applications. SOCKS is a TCP relaying protocol. This means that the only applications that can use SOCKS are those based on TCP connections (telnet, ftp, and WWW are examples; archie, though, uses UDP and thus cannot use SOCKS). Clients must have full access to the Internet DNS tree. I accomplish this by running bind (or named) on the firewall as a caching-only nameserver. The named.boot file is relatively simple:

cache   .   /etc/named.ca

The /etc/named.ca file contains entries for the Internet root nameservers, which can be obtained from the NIC via anonymous ftp from rs.internic.net, in the file domain/named.root. Here's a sample:

;    last update:  Oct 5, 1994
;    related version of root zone:  1994100500
;
.                99999999 IN NS  NS.INTERNIC.NET.
NS.INTERNIC.NET.     99999999   A   198.41.0.4
.                99999999   NS  NS1.ISI.EDU.
NS1.ISI.EDU.         99999999   A   128.9.0.107
.                99999999   NS  C.PSI.NET.
C.PSI.NET.           99999999   A   192.33.4.12
.                99999999   NS  TERP.UMD.EDU.

Despite these caveats, I think you'll find SOCKS a handy solution for your firewalls. If your users are looking for WWW access, I think they'll thank you as well.

References

Cheswick, William R., and Steven M. Bellovin. Firewalls and Internet Security: Repelling the Wily Hacker. Reading, MA: Addison-Wesley, 1994. ISBN-0-201-63357-4.

Kolbas, David, and Michelle Kolbas. SOCKS. Available for anonymous ftp: ftp.ibm.net (/pub/socks/socks.ps).

About the Author

Matt Ganis is currently manager of Internet Server Design and Integration group for the IBM Global Network in White Plains, NY. In his spare time he teaches Astronomy at Pace University in Pleasantville, NY. He can be reached at 14 Udell Ct, Cortlandt Manor, NY 10566 or mganis@ibm.net.