Because proxying interferes with communications between a client and a server, it has to be adapted separately to each service. Some things that are easy to do normally become much more difficult when a proxy is involved.
The ideal service for proxying makes a TCP connection in one direction; has only secure commands; has some piece of variable-length, user-specified data that's passed to the server; and is being used from an internal client to an external server. The following sections look at these ideal situations, and some that aren't so ideal.
Because TCP is a connection-oriented protocol, you only go through the overhead of setting up the proxy once, and then you continue to use that connection. UDP has no concept of connections; every packet is a separate transaction requiring a separate decision from the proxy server. TCP is therefore easier to proxy (although the UDP Packet Relayer package is a generic UDP proxy server). ICMP is so low-level, it's almost impossible to proxy.
It's easy for a proxy server to intercept the initial connection from a client to a server. It's harder for it to intercept a return connection. Either both ends of the conversation have to be aware of the existence of the proxy server, or the server needs to be able to interpret and modify the protcol to make certain the return connection is made correctly. For example, normal-mode FTP requires the proxy server to intercept the PORT command the client sends to the server, open a connection from the proxy to the client at that port, and send a different PORT command (for a port on the proxy) to the real server. It's not enough for the proxy server to simply read the PORT command on the way past, because that port may already be in use. Similar problems are going to arise in any protocol requiring a return connection.
Anything more complex than an outbound connection and a return is even worse. The talk service is an example; see the discussion in Chapter 8 for an example of a service with a tangled web of connections that's almost impossible to proxy. (It doesn't help any that talk is partly UDP-based, but even if it were all TCP, it would still be a proxy-writer's nightmare.)
For some services, proxying may be technically easy, but pointless from a security point of view. If a protocol is inherently unsafe, proxying it without doing anything else will not make it any safer. For example, X11 is mildly tricky to proxy, for reasons discussed at length in Chapter 8, but the real reason it's not widely proxied through firewalls has nothing to do with technical issues (proxy X servers are not uncommon as ways to extend X capabilities). The real reason is that X provides a number of highly insecure abilities to a client, and a proxy system for a firewall needs to catch unsafe operations and at least offer the user the ability to prevent them. This is reasonably possible with X (and the TIS FWTK provides a proxy called x-gw that does this), but it requires more application knowledge than would be necessary for a safer protocol.
If it's difficult to distinguish between safe and unsafe operations in a protocol or impossible to use the service at all if unsafe operations are prevented, proxying may not be a viable solution. In that case, there may be no good solution, and you may be reduced to using a victim host, as discussed in Chapter 5, Bastion Hosts. Some people consider HTTP to be such a protocol (because it may end up transferring programs that are executed transparently by the client).
If you're going to use modified-procedure proxying, you need a modifiable part of the procedure. Programs like FTP and HTTP clients in which the client passes a nice long user-specified string to the server, are perfect. (FTP clients pass a user name to the server; HTTP clients pass a URL.) A program like ping in which the client passes absolutely no data to the server is fundamentally impossible to proxy using an unmodified client.
 People have been known to claim that forcing users to log into a bastion host to use ping is an extreme version of modified-procedure proxying. It's clearly a modified procedure, but the "proxy" part is hard to detect.
Most proxy servers are designed for situations in which the client is on the inside and the server on the outside, of the firewall. This is because most proxy servers require some cooperation at the client's end, and the modifiable clients and the trainable users are probably both inside the firewall. Proxying for external clients works only in a few situations:
Using modified procedures to provide inbound services for your own users. (See Chapter 10, Authentication and Inbound Services for more information about this situation.)
Using something like plug-gw to redirect connections from the proxy server to an internal machine. A program of this kind will support any number of clients, as long as they all want to connect to the same internal server.
Providing a special service for which you distribute clients. If you write your own Internet service, you can easily design the clients to include proxy support.