Timing Out a Socket Connect

 < Day Day Up > 



Timing out a socket connect call can sometimes be useful, especially in systems that do not support blocking function semantics. Consider the problem of trying to connect to many nodes (or ports) at a given time. Either a large number of threads must be created for each connect request, or the connect call can be made nonblocking so that many connects can be performed simultaneously by a single thread.

One useful example of this technique is in the construction of a simple port scanning utility. Port scanning is the name given to applications that search a network for nodes that have applications sitting on ports of interest (a common hacking tool). In this example, we want to know for our given subnet, which nodes provide telnet servers. We know that telnet daemons commonly sit on port 23, so if we connect to port 23 on all available nodes, we should be able to identify the location of all telnet daemons (based upon successful completion of the connect call).

Consider the simple port scanner shown in Listing 6.9. We begin by setting up our timeout structure for five seconds (the maximum amount of time we’ll await the connect requests) and then set up our address structure with everything but the address to which we’ll connect. We then perform two loops. The first loop connects to each address and the second loop awaits responses.

In the first loop, we complete the address structure with the address to which we’ll connect, and then attempt a connect to that address. The socket is made nonblocking so that our connect does not block for each attempt, and the socket descriptor is added to our descriptor list that we’ll later pass to select. The connect function begins the TCP three-way handshake, so at the completion of the connect, we should have received a SYN-ACK from the peer, which lets us know that an application is actually sitting on the designated port. Otherwise, if no application sits on the port, a RST is returned, indicating that no server with that port designation is present.

All of our connect requests have now been made, and we enter the second loop that awaits the responses (the SYN-ACK). In this select example, we use the write descriptors to know when a socket has been connected (if the socket is writable, then the connect succeeded and a server sits on the port on the given node). When select returns in the loop, we check to see if a positive value was returned indicating that some file descriptors are writable. We then walk through the descriptor list looking for descriptors that were set and indicate to the user which IP addresses housed the telnet daemon. Note that we also clear the descriptor so that it won’t be shown as writable in our next iteration. If a nonpositive value was returned from select, then either an error occurred or the process has timed out and we exit. As a final cleanup step, we close all of our sockets at the end of the port scanner application.

Listing 6.9 Simple port scanner illustrating timing out the connect function (portscan.c).

start example
#include <sys/socket.h> #include <sys/types.h> #include <sys/time.h> #include <arpa/inet.h> #include <stdio.h> #include <unistd.h> #include <time.h> #include <fcntl.h> #include <unistd.h> #define SUBNET    "192.168.1.%d" #define MAX_HOSTS    254 int main ( ) {   int i, count, ret;   struct sockaddr_in servaddr;   int  socks[MAX_HOSTS], maxfd=0;   char buf[30+1];   fd_set fds;   struct timeval timeout;   /* Set up a timeout of 5 seconds */   timeout.tv_sec = 5;   timeout.tv_usec = 0;   /* Partially set up the address structure */   memset(&servaddr, 0, sizeof(servaddr));   servaddr.sin_family = AF_INET;   servaddr.sin_port = htons(23);   FD_ZERO( &fds );   /* Attempt to connect to all nodes on the subnet */   for (i = 1 ; i <= MAX_HOSTS ; i++) {     /* Complete the address structure */     sprintf(buf, SUBNET, i);     servaddr.sin_addr.s_addr = inet_addr(buf);     /* Create a new socket for this node */     socks[i] = socket(AF_INET, SOCK_STREAM, 0);     /* Add it to the socket descriptor list */     FD_SET( socks[i], &fds );     /* Make the socket nonblocking */     fcntl(socks[i], F_SETFL, O_NONBLOCK);     /* Attempt a connect (nonblocking) */     connect( socks[i], (struct sockaddr_in *)&servaddr,                sizeof(servaddr));     if (socks[i] > maxfd) maxfd = socks[i];   }   count = MAX_HOSTS;   while (1) {     /* Await connect responses (writable sockets) */     ret = select(maxfd, NULL, &fds, NULL, &timeout);     if (ret > 0) {       count -= ret;       /* Walk through the socket descriptor list */       for (i = 1 ; i <= MAX_HOSTS ; i++) {         if ( FD_ISSET( socks[i], &fds ) ) {           printf("Port open at 192.168.1.%d\n", i);           FD_CLR( socks[i], &fds );         }       }       /* If we've found everything, exit */       if (count == 0) break;     } else {       /* Timeout, exit */       break;     }   }   /* Cleanup, close all of the sockets */   for (i = 1 ; i < MAX_HOSTS ; i++) {     close(socks[i]);   }   return(0); }
end example



 < Day Day Up > 



BSD Sockets Programming from a Multi-Language Perspective
Network Programming for Microsoft Windows , Second Edition (Microsoft Programming Series)
ISBN: 1584502681
EAN: 2147483647
Year: 2003
Pages: 225
Authors: Jim Ohlund

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net