package netdiag
severity 613557 important
tags 613557 + patch
thanks

After a very laborious investigation, the source of the malfunction
has been located. The problem lies in gather() where the present code
sets the local variable LAST incorrectly. This leads to the removal of
the file descriptor corresponding to attempt[a_sock_max - 1], inspite
of it containing a live socket. Thus the file descriptor set begins
to grow steadily until it reaches the limit FS_SETSIZE, and other
corruptions come into play.

The included patch resolves the above calamity and also introduces
minor alterations to the code and to the manual page, in order that
either reflect what the other claims. The option "-S", which has been
unintentionally removed by the maintainer, is now correctly implemented.
The patch is calculated against netdiag_1.0-14.

It was deemed sensible and well-motivated to lower the connect timeout
as well as the capture timeout to two seconds each. The original values
lead to ridiculously long delays.

The weak computing power available to the original author were clearly
not enough to uncover the delicacy of the implementation automata.
The machines of today are sensitive to this, and so is also the 800 MHz
system used for most of this investigation.

Let me remark, that the use of the present patch, allows me to produce
a functional binary for FreeBSD for the first time ever. All three systems,
GNU/Linux, OpenBSD, and FreeBSD, are now able to scan multiple host with
a single invokation. But observere that the price to pay for neglecting
"-e limit" can be brutally felt. Not much in OpenBSD, but clearly so with
GNU/Linux, and even with FreeBSD. The success with FreeBSD convinces me
that the present implementation is (initially) correct.

Now I do deserve some rest. Two hard days have brought results,
but have taken their toll. Other activities are falling behind.

Regards,
  Mats Erik Andersson, DM
Description: Corrupt handling of file descriptor sets.
 The function gather() implement a corrupt bookeeping
 of which attempt structure is reclaimed. This leads
 to dropping of live sockets, and the file descriptor
 set growing beyond all bound.
 .
 Various small corrections are also implemented in order
 to provide the capabilities indicated in manual page
 an in incomplete code portions.
 .
 The manual page is augmented with capabilities that
 were fully available in the code, but not brought
 forward in the upstream manual page.
Author: Mats Erik Andersson <[email protected]>
Forwarded: no
Last-Update: 2011-02-19

diff -Naurp strobe.debian/strobe.1 strobe/strobe.1
--- strobe.debian/strobe.1	1999-03-21 06:49:27.000000000 +0100
+++ strobe/strobe.1	2011-02-18 12:32:14.000000000 +0100
@@ -84,12 +84,30 @@ Port number if you intend to scan a sing
 Local port to bind outgoing connection requests to.
 (you will normally need super-user privileges to bind ports smaller than 1024)
 .TP
+.B \-c number
+Amount of captured respons to a port connect.
+Defaults to 1024 bytes.
+.TP
+.B \-x
+Display captured response as hex dump, instead of printed ASCII.
+.TP
+.B \-L number
+Capture this number of text lines; default is one line.
+.TP
+.B \-D directory
+Store the captured data and parsed port and source information
+in a subdirectory tree, rooted at the stated directory.
+.TP
 .B \-A address
 Interface address to send outgoing connection requests from for multi-homed machines.
 .TP
 .B \-t number
 Time after which a connection attempt to a completely unresponsive host/port is
-aborted.
+aborted; defaults to 2 seconds.
+.TP
+.B \-T number
+Amount of time to listen for respons from a connected port. After that time
+the data collection will cease; defaults to 2 seconds.
 .TP
 .B \-n number
 Use this number of sockets in parallel (defaults to 64). 
@@ -162,6 +180,10 @@ may turn out to be connectionless,
 .I strobe
 will `abort the abort'. This is considered optimal, if unusual behaviour.
 .TP
+.B \-w number
+Wrap lines, i.e., insert a line break after this amount of printed text;
+defaults to 79 characters. Wrapping is disabled when specified as naught.
+.TP
 .B \-M
 Mail a bug report, or tcp/udp port description to the current source maintainer.
 .SH EXAMPLES
diff -Naurp strobe.debian/strobe.c strobe/strobe.c
--- strobe.debian/strobe.c	2011-02-17 10:56:44.000000000 +0100
+++ strobe/strobe.c	2011-02-19 00:18:57.000000000 +0100
@@ -5,7 +5,7 @@
  * $ cc strobe.c -o strobe
  */
 
-#define VERSION "1.05"
+#define VERSION "1.06"
 
 #include <stdio.h>
 #include <unistd.h>
@@ -17,9 +17,7 @@
 #include <time.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
-#ifdef _AIX
-#  include <sys/select.h>
-#endif
+#include <sys/select.h> /* POSIX 1003.1-2001 */
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
@@ -58,10 +56,10 @@ extern char *optarg;
 #  define LIB_STROBE_SERVICES "/usr/local/lib/strobe.services"
 #endif
 
-int a_timeout = 20;
-int a_data_timeout = 30;
+int a_timeout = 2;
+int a_data_timeout = 2;
 char *a_output = NULL;
-char *a_services = "strobe.services";
+char *a_services = NULL; /* "strobe.services"; */
 char *a_input = NULL;
 /* char *a_prescan = NULL; */
 int a_start = 1;
@@ -92,6 +90,9 @@ int hosts_done = 0;
 int attempts_done = 0;
 int attempts_outstanding = 0;
 struct timeval time_start;
+#if USE_SMALL_DELAY
+struct timeval tenth_of_a_sec = { 0, 100000 };
+#endif
 
 fd_set set_sel_check_r;
 fd_set set_sel_check_w;
@@ -254,7 +255,7 @@ attempt_clear (h)
 	if (h->port > h->host->attempts_highest_done)
 	    h->host->attempts_highest_done=h->port;
 	sock_unblock (h->sfd);
-/*	shutdown (h->sfd, 2); */
+  	shutdown (h->sfd, SHUT_RDWR);
 	close (h->sfd);
         if ( (FD_ISSET(h->sfd, &set_sel_check_r)) || (FD_ISSET(h->sfd, &set_sel_check_w)) )
 	{
@@ -346,6 +347,8 @@ sc_connect (h)
 	case ETIMEDOUT:
 	case ECONNREFUSED:
 	case EADDRNOTAVAIL:
+	case EHOSTUNREACH:
+	case ENETUNREACH:
 	    if (f_verbose)
 	    {
 		fprintf(stderr, "%s:%d ", h->name, h->port);
@@ -722,6 +725,8 @@ init_capture_tcp (h)
     h->status&=~HT_CONNECTING;
     h->status|=HT_CONNECTED;
     FD_CLR (h->sfd, &set_sel_check_w);
+    shutdown(h->sfd, SHUT_WR);
+    h->timeout = a_data_timeout;
 }
 
 void
@@ -798,9 +803,10 @@ gather (timeout_secs)
     int selected;
     time_t tim;
 
-    if (!attempts_outstanding) return 1;
-    set_sel_r=set_sel_check_r;
-    set_sel_w=set_sel_check_w;
+    if (!attempts_outstanding) return 0;
+
+    memcpy(&set_sel_r, &set_sel_check_r, sizeof(set_sel_r));
+    memcpy(&set_sel_w, &set_sel_check_w, sizeof(set_sel_w));
 
     if (timeout_secs)
     {
@@ -829,6 +835,7 @@ gather (timeout_secs)
               if ( (tim - h->sock_start.tv_sec) >= h->timeout)
               {
                 attempt_clear(h);
+                last = n;
               }
               continue;
             }
@@ -865,12 +872,14 @@ gather (timeout_secs)
 		    else
 			gatherer_tcp (h);
 		}
+	    /* Was the present attempt cleared? */
+	    if(h->sfd < 0)
+	        last = n;
 	    }
-	    last = n;
 	} else
 	{
 	    if ((h->status & HT_SOCKET) &&
-	        ((h->sock_start.tv_sec + h->timeout) < tim))
+	        ((h->sock_start.tv_sec + h->timeout) <= tim))
 	    {
 	        attempt_clear (h);
 		last = n;
@@ -884,6 +893,9 @@ bool
 add_attempt (add)
   struct htuple_s *add;
 {
+#if USE_SMALL_DELAY
+    struct timeval delay;
+#endif
     struct htuple_s *h;
     static time_t oldtime;
     int ret;
@@ -903,6 +915,11 @@ add_attempt (add)
 	   h = &attempt[last];
 	   goto foundfree;
 	}
+#if USE_SMALL_DELAY
+	/* Stuck for a long time, so relax system load. */
+	delay = tenth_of_a_sec;
+	select(0, NULL, NULL, NULL, &delay);
+#endif /* USE_SMALL_DELAY */
     }
     foundfree:
     *h = *add;
@@ -938,11 +955,20 @@ wait_end (t)
   int t;
 {
     time_t st;
+#if USE_SMALL_DELAY
+    struct timeval delay;
+#endif
+
     st = time (NULL);
     while ((st + t) > time (NULL))
     {
-	gather (a_timeout);
+	gather (t);
 	if (attempts_outstanding<1) break;
+
+#if USE_SMALL_DELAY
+	delay = tenth_of_a_sec;
+	select(0, NULL, NULL, NULL, &delay);
+#endif
     }
 }
 
@@ -960,7 +986,7 @@ resolve (name)
     }
     if (!(ent = gethostbyname (name)))
     {
-	perror (name);
+	fprintf(stderr, "Host \"%s\" does not exist.\n", name);
 	in.s_addr = INADDR_NONE;
 	return in;
     }
@@ -1140,7 +1166,7 @@ host_stats (h)
     timeval_subtract(&tv2, &tv, &(h->time_start));
     t = tv2.tv_sec+(float)tv2.tv_usec/1000000.0;
     st = h->time_used.tv_sec+(float)h->time_used.tv_usec/1000000.0;
-    fprintf(stderr, "stats: host = %s trys = %d cons = %d time = %.2fs trys/s = %.2f trys/ss = %.2f\n",
+    fprintf(stderr, "stats: host = %s tries = %d cons = %d time = %.2fs tries/s = %.2f tries/ss = %.2f\n",
 	h->name, h->attempts_done, h->connects, t, h->attempts_done/t, h->attempts_done/st);
 }
 
@@ -1152,7 +1178,7 @@ final_stats()
     gettimeofday(&tv, NULL);
     timeval_subtract(&tv2, &tv, &(time_start));
     t = tv2.tv_sec+(float)tv2.tv_usec/1000000.0;
-    fprintf(stderr, "stats: hosts = %d trys = %d cons = %d time = %.2fs trys/s = %.2f\n",
+    fprintf(stderr, "stats: hosts = %d tries = %d cons = %d time = %.2fs tries/s = %.2f\n",
 	hosts_done, attempts_done, connects, t, attempts_done/t);
 }
 
@@ -1290,7 +1316,8 @@ loaddescs ()
     char *fn;
     char prot[4];
     prot[3]='\0';
-    if (!(fh = fopen ((fn=STROBE_SERVICES), "r")) &&
+    if (!(a_services && (fh = fopen ((fn=a_services), "r"))) &&
+        !(fh = fopen ((fn=STROBE_SERVICES), "r")) &&
         !(fh = fopen ((fn=LIB_STROBE_SERVICES), "r")) &&
         !(fh = fopen ((fn=ETC_SERVICES), "r")))
     {
@@ -1480,6 +1507,13 @@ main (argc, argv)
 
     if (!f_quiet)
         fprintf (stderr, "strobe %s (c) 1995-1999 Julian Assange <[email protected]>.\n", VERSION);
+
+    /* Take nothing for granted. */
+    memset(&ho_initial, 0, sizeof(ho_initial));
+    memset(&ht_initial, 0, sizeof(ht_initial));
+    /* Mark the file descriptor as invalid. */
+    ht_initial.sfd = -1;
+
     if (a_input)
     {
         if ( ! strcmp("-",a_input) ) { /* Use stdin as input file */

Attachment: signature.asc
Description: Digital signature

Reply via email to