Simple Security: Building a SOCKS Proxy Server
Building your own IP firewall might seem like a scary prospect at first, but like any other technology in the TCP/IP arena, once you do your homework, plan a bit, test, and then cautiously roll it out, the results can be very satisfactory.
Some sites have a need for an outgoing-only firewall, that is, a firewall that allows certain folks inside to initiate connections to the outside world, but allows no Internet-initiated traffic in. Some sites also need to use bogus, private, or non-registered IP addresses, either as an "information hiding" technique or as a pragmatic concern. For example, although legal IP addresses have been available for decades, many shops are still using an unregistered IP address superstructure, designed back when nobody anticipated connecting their private IP network to the Internet. Thus, it is desirable for such shops to use a firewall that can handle "bogus" IP numbers. After all, renumbering 80 subnets with 3000 nodes could be an expensive overtime nightmare. A firewall that doesn't care about internal IP addresses is also great for folks with real IP addresses who want to switch ISPs - after all, the advent of Classless InterDomain Routing (CIDR) implies that "you can't take it with you!" With CIDR, each ISP is allocated a specific block of network numbers, which are not routable through another ISP. Changing ISPs thus means that all networks within the Internet routing domain must be renumbered.
SOCKS is a freeware firewalling package that caters to these needs very nicely. Two major versions of SOCKS are available, version 4 and 5; version 5 is available from NEC at http://www.socks.nec.com. Version 5 has some bells and whistles that version 4 does not (i.e., the ability to handle UDP connections).
Sock Matching: SOCKS Theory
If you're looking for a "router-on-steroids," that is, a packet-filtering router, stop reading now. SOCKS is not a packet-filtering router; it is not a router at all, at least on the network level. A packet-filtering firewall still has the inside workstation doing outside network connection via routers. The router, aka the packet-filtering firewall, tries to keep track of what it routes and disallow certain types of connections. In contrast, SOCKS is a circuit-level proxy, or generally, a "proxy server" in the Microsoft parlance. This means that each connection made from the inside actually appears on the outside as if it is originating from the SOCKS server, not from the real originating workstation. Conversely, the end-station's TCP stack only talks back to the SOCKS server. This has the effect of "hiding" the IP addresses from each other and localizing the routing domains, as in Figure 1. The SOCKS server is told to route all local addresses (no matter how bogus) through its internal interface and all other addresses through its outside interface.
We really like this, because a proxy abstracts the network layer down to a very simple and manageable concept. A proxy will accept packets from authorized workstations coming in on an authorized interface, then mimic these connections to the outside world. SOCKS is sort of like giving your lunch money to a friendly kid who knows karate. The friendly kid goes and buys your lunch, and brings it back to you, which lets you avoid bullies who might be able to shake you down. The same thing happens with a circuit proxy like SOCKS. You give the SOCKS server your request, and it goes and gets what you want, then brings it back to you. Since the server must inspect each request anyway, logging is a snap.
Certain shops need a greater level of scrutiny, such as that of an application-level proxy. This is like asking the friendly karate kid to taste your lunch before giving it to you - after all, the bullies may have poisoned it! For example, an http proxy might scrutinize incoming replies to requests, and remove any Java code in accordance with a shop's Internet policy. However, each application proxy is a separate server to configure (gopher, ftp, http, etc). As your number of proxies grows, so do your chances of misconfiguration and potential security hazard. So, some shops opt for a generic circuit-level proxy like SOCKS. Content is not checked, but SOCKS does check who is connecting to what.
Some shops have a hybrid approach; they either allow or are forced to use specialized gateways for certain applications (e.g., SMTP or http) and use a circuit-level proxy like SOCKS for others. Gateways that act as their own application-level proxies and do not allow general network traffic can safely work in concert with SOCKS. See the February 1996 Sys Admin, "Simple Security: A GroupWise/SMTP Connection" for an example of such a gateway.
From a network level, here's how a simple SOCKS configuration works. The end-station is configured with SOCKS client software, or a SOCKS-aware ("Socksified") version of a network client. A Socksified network client is written to use SOCKS calls that are named similarly to regular socket calls, however, this has the negative effect of forcing a recompile to take advantage of SOCKS. A better way is to use generic SOCKS client software. This acts to override standard network calls to your shared libraries or uses the SOCKS subroutines as a replacement or a supplement to the "real" socket call library (WINSOCK.DLL or WSOCK32.DLL on Windows 95 workstations; or via shared libraries under UNIX). The client software, whether compiled into a program or accessed through a shared library, is configured beforehand with the host on the inside network that is going to act as the SOCKS server and with local addresses. In any event, all traffic between the client and the server is handled in normal TCP/IP fashion; no special routing setup is required.
When the client wants to get to an Internet host, the client performs DNS resolution either normally (via the TCP/IP stack) or via the SOCKS client software. SOCKS5 supports client lookup, which means you don't have to configure your internal DNS servers to look up hosts from the Internet, thus plugging another potential security hole.
The connection request is sent by default to port 1080 of the server, which then checks the request against its configuration. If the client is authorized and if the request has come via the authorized interface (inside), the request is processed. Because the interface-of-entry is checked, the risk of spoofing is minimized. Requests that appear to come from an authorized client, but have actually entered from the wrong interface, are dropped.
After authorization, the server itself, using normal TCP/IP routing, sets up a connection to the requested destination port and address. The routing is "normal yet different" because the outside world has no business knowing about or playing with your internal routes. Again, this is why private or bogus addresses can be used. Routing protocols are typically not used, as that could defeat the security.
Data generated by the destination is passed through the server to the client, and vice versa. The connection is now up and passing data, even though the client and destination never really "see" each other on a network level. A ping from the destination machine would never get through, even if a person at the destination somehow found out (through Java, perhaps) the real originating address, because there simply isn't any tied-together routing in the picture.
Putting on Your SOCKS
To get SOCKS running at your shop, first you'll want to lobotomize an otherwise perfectly good UNIX server. That is to say, you'll want to use a fresh OS install, then disable all networking services, as they pose a hazard to your yet-to-be-born SOCKS server. We use Linux, but any other UNIX would work, too. Make sure you turn off IP forwarding in the kernel. Even though you're going to set up some very specific IP routes, you need to make extra sure that no raw IP traffic gets into your network from the outside. Under Linux, this typically requires a recompile of the kernel. In AIX, use the no (Network Options) command.
Specifically remove things like inetd, thereby implicitly removing all sorts of potentially dangerous daemons such as telnetd and ftpd, and sendmail from your startup scripts. Make sure you haven't missed anything by doing a netstat -a immediately after rebooting. You shouldn't see anything in a "LISTENING" state. Check your startup scripts again if you do. Put the /usr/local/bin/socks5 daemon into your startup scripts after you're done testing.
Get the SOCKS5 package from http://www.socks.nec.com. It's simple to compile, consisting of a ./configure and a make. If you have any problems using your native compiler, get gcc (the Gnu C Compiler) from ftp://prep.ai.mit.edu and try it again. (A binary distribution of SOCKS5 for NT is available from NEC.) While it's compiling or downloading, spend some time planning your /etc/socks5.conf file.
Listing 1 shows a socks5.conf file for the network shown in Figure 1. I personally find it a little tedious to create a large socks5.conf file, but once you read the man page and get the basics down, it really isn't difficult. Just make sure that you have a bit of time in a quiet room to plan this out, because it is very important to get it right.
Basically, the socks5.conf file is reasonably self-documenting, if you have an example to look at. The distribution that we used was a bit weak on this, but a little trial-and-error in a test environment straightened us out.
The rule for setting up your TCP/IP routing (different from the "route" line in the socks5.conf; you need both) on the SOCKS server is fairly simple. Route your internal addresses to go out to a router on the same subnet as the internal interface, and point your default "everything-else" route to your internet router. (See Listing 2.)
Note that the socks5.conf is the server configuration file, and has nothing to do with the client. The SOCKS5 distribution comes with both client and server software, and each uses a different configuration file. The clients use /etc/libsocks5.conf - the server doesn't look at this file at all. In practice, a SOCKS server doesn't have much use for the client except for testing. The server uses straight networking to hit anything it wants. However, your internal UNIX machines will have plenty of use for these clients and for the libsocks5.conf file. An example libsocks5.conf should simply be:
# type cmd dhost dport usrlist proxylist
socks5 - - - - socks
which is gobbledegook for "use the internal DNS host named 'socks' for all SOCKS operations; it is a SOCKS5 server."
There are several options for configuring your Windows clients. You can choose to use the client software provided by NEC, "sockscap," to Socksify non-SOCKS aware applications. (See Figure 2.) Or you can simply rely on the built-in SOCKS client software in applications like Internet Explorer, Netscape, and NetTerm. These are all very easy to configure. Make sure that you do not Socksify a client that already does its own SOCKS.
When configuring any of your client software, you probably will want to specify a symbolic name rather than an IP address when configuring the SOCKS software to point to a SOCKS server. (Remember, this is a server, not a router or DNS server; you can assume that your internal name resolution ought to be working.) Later, when you outgrow your initial SOCKS server, you can add more SOCKS servers and have your internal DNS issue round-robin SOCKS server addresses as a primitive form of load balancing.
If you do anything important with your network, you will want to test, test, and test some more before rolling out any type of firewall. For example, we tested our configuration using disconnected hubs and Linux routers to simulate Internet conditions. We specifically created one of our internal networks on the outside of the firewall to make sure that we could not spoof the server, and to make sure that the route lines worked correctly.
We've been at sites where folks haven't tested their firewalls at all, or haven't tested them after a reconfiguration, and we've been able to telnet from the Internet into their inside hosts. Scary. The moral of the story is to re-test the server whenever you do any significant modifications to the configuration. Better yet, test a server off-line thoroughly, then do a forklift upgrade when it's time to roll it out.
Because all connections are logged, you will quickly have large log files. For example, one SOCKS server that I know of logs 15,000 hits a day. (Remember, each http page and each GIF, etc. represent separate connections.)
One good way to deal with this is to "push" the log file (which is, by default, /var/adm/messages) via ftp from the SOCKS server to an internal machine and clear the server log every night. (Running an ftp client from the SOCKS server to an internal machine is not a big deal. Remember that you choose who the ftp client talks to, and you're not running an ftp server on the SOCKS server. That would be dangerous.) Cron does a nice job handling the ftps, and this way, your internal machine has backups of the log files and problem tracking gets a bit easier.
You may also want an executive summary of what's going on with the server. SOCKS5Tools includes a conversion program for those of you converting from SOCKS4 configuration files along with a useful statistics program, written in Perl, that you can modify to your heart's delight.
With a small Internet rollout team and a small budget, we've been very happy with SOCKS; it has helped us provide Internet services to our users in a reasonably secure and centralized manner, without a lot of messy renumbering or router changes. We're grateful to the City of Savannah, Ed Rabhan in particular, for working with us to cooperatively implement our SOCKS environment.
About the Author
Jonathan Feldman works with a couple of flavors of UNIX, NetWare, and NT in his role as Technical Systems Manager at the Chatham County Government in Savannah, Georgia. He can be reached at firstname.lastname@example.org. In his spare time he likes to play the guitar with his feet and write silly haikus about his ever-expanding family, much to their chagrin. His 10-month-old son, Moshe, is his latest target.