As I mentioned in my previous post on security, it’s much better if you can confine your connections to clients on the current machine and completely block external attackers. Since my service is going to fit in the same slot as MySQL in the LAMP ecology, confining it to the local machine and having an external interface provided through PHP is reasonable for my purposes. A bonus is that I should get better performance thanks to skipping several layers of network code.
To restrict connections, you need to use a different family of sockets based on the file system rather than TCP/IP network connections. Instead of a port number, the client and server collaborate by agreeing on a file name they’ll use to contact each other. There are potential security issues involved in choosing the location of the file, but if you trust all processes on the local machine then using something like /tmp/myservicesocket should be fine.
The code itself looks pretty similar to the internet socket example, with the main change being that we use a sockaddr_un structure to specify the file name of the socket rather than a sockaddr_in to define the IP address and port number. Here’s the new source, and I’ll describe the server changes below.
struct sockaddr_un listenAddress;
if (listenFileNameLength>=sizeof(listenAddress.sun_path))
error("ERROR, the filename must be shorter
than the maximum path length (normally around a hundred chararacters)\n");
const int listenSocketFile = socket(AF_UNIX,
SOCK_STREAM, 0);
if (listenSocketFile < 0)
error("ERROR opening server socket");
bzero((char *) &listenAddress, sizeof(listenAddress));
listenAddress.sun_family = AF_UNIX;
strncpy(listenAddress.sun_path, listenFileName,
sizeof(listenAddress.sun_path));
const int connectResult = connect(transferSocketFile,
(struct sockaddr*)&serverAddress,
sizeof(serverAddress));
We’re taking a single filename as an argument to both the client and server now, so you’ll need to run them as "./wcserver /tmp/yourfilename" and "./wcclient /tmp/yourfilename" . The structure the filename is stored is an odd one, it’s basically a char to specify the family, sometimes preceded by another byte for a string length on some systems, immediately followed in memory by a stream of bytes representing the string for the file name, eg:
|sun_family byte|p|a|t|h|b|y|t|e|s|…
There’s a lot of confusion about this structure, whether it’s NULL terminated, if you can dynamically allocate a large than provided path string, and lots of other behavior that seems to vary between the *nixes.
You specify it’s total size as arguments to bind() or connect(). So, in theory you can duplicate this layout with a string of any length. In practice the default sockaddr_un structure defines a fixed-length array of chars after the family, and in most implementations this is at least 100 (104 on OS X, 108 on Red Hat). In practice, I experimented with dynamic sizing and found myself in a scary wood full of underdocumented questions, so I decided to go with using the default structure layout. This limits me to file names less than 100 characters, but it also means I’m using the same code as 99% of the other local socket programs out there. This should make it a lot more portable and less prone to strange OS bugs.