In Windows NT, the system typically assigns network-based TCP/IP services to a well-known port, in accordance with Request for Comments (RFC) 1700. POP3 servers, the topic of this continuing series of articles, run on TCP port 110. The first step in getting your mail server to answer requests on that port is to bind the socket.
To understand how to bind a TCP socket to a port, you need to look at the arguments for the bind() function. One of these arguments (the second) is a pointer to a sockaddr structure. For IP applications, that pointer is typically a sockaddr_in structure that contains the numeric IP address and port that you want to bind to locally. If you can't easily identify what interfaces are available, you can simply bind to all available local interfaces by specifying INADDR_ANY as the address.
One security risk that you need to be aware of is that users can bind two sockets to the same port using a socket option known as SO_REUSEADDR. In other words, two different applications can answer connections on the same port. So, in the case of a POP3 server, one application might be delivering mail, while another is stealing passwords. Working with NT 4.0 and earlier requires a lot of Registry reads to determine which IP addresses are available. As a result, many programmers simply specify INADDR_ANY to get all the interfaces. Under Windows 2000, you can have new interfaces popping up and down on the fly. Unless you’re prepared to write code to detect these changes, your service might not behave properly if you don’t bind to all the interfaces.
You're probably thinking, "Why not just specify INADDR_ANY all the time and avoid these problems?" Here's the catch: If someone does bind to a specific IP address, the OS prefers the specifically bound socket to one that binds to all available interfaces. To handle this problem, Microsoft implemented the SO_EXCLUSIVEADDRUSE socket option in NT 4.0 Service Pack 4 (SP4) and Win2K.
The code in Listing 1 demonstrates how you use this option and contains a function you can use in your code to make binding sockets easier. The first function in the code, InitWinsock(), is a requirement for all Winsock applications. However, before you paste this function into your code, take heed of the comments—this version works only with Winsock 2.0 and higher.
The second function, BindSocket(), does a lot of work, so let’s look at it in detail. To begin, we want to check for errors in the inputs—note from the sample code that I’m not concerned about a null pointer for the IP address. Next, the code initializes the sockaddr_in structure (line 57). The sin_family member is always set to AF_INET. The sin_addr member is actually an inet_addr structure that contains the IP address of the interface we want to bind our socket to. If the user doesn’t specify an address by passing a null pointer, we’ll use the specially defined value of INADDR_ANY. If we look in your winsock2.h file, we see that this value is defined to be 0.
If the user passes the BindSocket() function an IP address represented as a string, we use the inet_addr() function to convert that string to an unsigned long value—inet_addr() will return INADDR_NONE (0xffffffff or ~0) if inet_addr() fails. Note that the code also checks for a 0 return by this function, which the software development kit (SDK) doesn't document as a possible error value but can occur. If an error occurs at this stage, the function can't know what interface to bind, and the function returns an error.
If we look at main(), the code initializes Winsock and creates the two sockets. The next step is to test to see whether SO_EXCLUSIVEADDRUSE is available. The testport variable, which the code defines as a const at the top of the file, specifies the port that the first socket binds to. This port is typically not in use. However, if this port is in use, change testport to a port number that is not in use. Next, the code sets SO_REUSEADDR on sock2, which is required to reuse a port, and tests whether the bind succeeds.
The sample code in Listing 1 shows you the best way to avoid security problems with reused ports, and contains some functions that can help you build your applications more easily. Next time, I’ll explain the ins and outs of service user contexts.