SATAN(tcp_scan.c) patches for Linux

SATAN(tcp_scan.c) patches for Linux

Post by Larry Doolitt » Tue, 11 Apr 1995 04:00:00



I made some changes to tcp_scan.c for proper (I hope) operation
under Linux 1.2.0.  The "problem" seems to be that Wietse is
expecting "Connection Refused" messages to trigger action by
select() when it has the write mask set, but Linux select() only
triggers in this situation when the except mask is set.  I have
also e-mailed this patch to Wietse.  To my amateur eye, this
doesn't look like it would break tcp_scan on "normal" systems ;^)
I will happily listen to anybody who can tell me a better way
to make it work.

In case anybody hasn't heard, don't trust ready-made Linux SATAN
binaries.  A trojan was found in one set, who knows how far it
has propogated.  Besides, they don't have this fix in them ;-).


--- tcp_scan.c.orig     Tue Apr  4 09:33:08 1995

 struct timeval now;                    /* banner_info last update time */
 fd_set  write_socket_mask;             /* sockets with connect() in progress */
 fd_set  read_socket_mask;              /* sockets with connect() finished */
+fd_set  except_socket_mask;            /* sockets with either of above */
 int     ports_busy;                    /* number of open sockets */
 int     ports_done;                    /* number of finished sockets */

     FD_ZERO(&write_socket_mask);
     FD_ZERO(&read_socket_mask);
+    FD_ZERO(&except_socket_mask);
     ports_busy = 0;


 {
     fd_set  read_mask;
     fd_set  write_mask;
+    fd_set  except_mask;
     static struct timeval waitsome = {1, 1,};
     static struct timeval waitnot = {0, 0,};

        /*
         * When a connect() completes, report the socket and get rid of it.
         */
-       write_mask = write_socket_mask;
-       read_mask = read_socket_mask;
-       if (select(max_sock + 1, &read_mask, &write_mask, (fd_set *) 0,
+       write_mask  = write_socket_mask;
+       read_mask   = read_socket_mask;
+       except_mask = except_socket_mask;
+       if (select(max_sock + 1, &read_mask, &write_mask, &except_mask,
                   wait ? (struct timeval *) 0 : &waitnot) < 0)
            error("select: %m");
        if (FD_ISSET(icmp_sock, &read_mask))
            receive_icmp(icmp_sock);
        for (sock = 0; ports_busy > 0 && sock <= max_sock; sock++) {
-           if (FD_ISSET(sock, &write_mask)) {
+           if (FD_ISSET(sock, &write_mask) || FD_ISSET(sock,&except_mask)) {
                if (read(sock, &ch, 1) < 0 && errno != EWOULDBLOCK && errno != EAGAIN) {
                    report_and_drop_socket(sock, errno);

         * banner_time seconds. Assume we have received all banner data when
         * a socket stops sending for BANNER_IDLE seconds.
         */
-       write_mask = write_socket_mask;
-       read_mask = read_socket_mask;
-       if (select(max_sock + 1, &read_mask, &write_mask, (fd_set *) 0,
+       write_mask  = write_socket_mask;
+       read_mask   = read_socket_mask;
+       except_mask = except_socket_mask;
+       if (select(max_sock + 1, &read_mask, &write_mask, &except_mask,
                   wait ? &waitsome : &waitnot) < 0)
            error("select: %m");

                    report_and_drop_socket(sock, 0);
                    break;
                }
+           } else if (FD_ISSET(sock, &except_mask)) {
+               if (read(sock, &ch, 1) < 0 && errno != EWOULDBLOCK && errno != EAGAIN) {
+                   report_and_drop_socket(sock, errno);
+               } else {
+                   report_and_drop_socket(sock, 0);
+               }
            } else if (FD_ISSET(sock, &read_socket_mask)) {
                if (time_since_connect(sock) > banner_time

        bp->flags = 0;
     }
     FD_SET(sock, &write_socket_mask);
+    FD_SET(sock, &except_socket_mask);
     if (sock > max_sock)
        max_sock = sock;

     close(sock);
     FD_CLR(sock, &read_socket_mask);
     FD_CLR(sock, &write_socket_mask);
+    FD_CLR(sock, &except_socket_mask);
     ports_busy--;
     ports_done++;
 }

-----end of patch----