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 */
signature.asc
Description: Digital signature

