* Strobe (c) 1995 Julian Assange (proff@suburbia.
* All rights
*
*
* $ cc strobe.c -o
*/
*/
#define VERSION
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef
#include
#endif
#endif
#include
#include
#include
#include
#include
#if defined(solaris) || defined(linux) || defined(__FreeBSD__) ||
defined(__NetBSD__) ||
#define fvoid
#else
#else
#define
extern int
extern char
#endif
#endif
#define bool
#ifndef
#define INADDR_NONE ((unsigned
#endif
#endif
#define port_t (unsigned
/*
/*
* the below should be set via the Makefile, but if
*/
*/
#ifndef
#define ETC_SERVICES
#endif
#endif
#ifndef
#define STROBE_SERVICES
#endif
#endif
#ifndef
#define LIB_STROBE_SERVICES
#endif
#endif
int a_timeout =
char *a_output =
char *a_services =
char *a_input =
/* char *a_prescan = NULL;
int a_start =
int a_end =
int a_sock_max =
int a_abort =
int a_bindport =
char *a_bindaddr =
struct in_addr
bool f_linear =
bool f_verbose =
bool f_verbose_stats =
bool f_fast =
bool f_stats =
bool f_quiet =
bool f_delete_dupes =
bool f_minimise =
bool f_dontgetpeername =
int connects =
int hosts_done =
int attempts_done =
int attempts_outstanding =
struct timeval
fd_set
fd_set
fd_set
int
int
char
FILE
#define HO_ACTIVE
#define HO_ABORT
#define HO_COMPLETING
struct hosts_s
char
struct in_addr
int
int
struct timeval
struct timeval
int
int
int
int
time_t
int
};
};
struct hosts_s
struct hosts_s
#define HT_SOCKET
#define HT_CONNECTING
struct htuple_s
char
struct in_addr
int
int
int
struct timeval
int
struct hosts_s
};
};
struct htuple_s
struct htuple_s
struct port_desc_s
int
char
char
struct port_desc_s
struct port_desc_s
};
};
struct port_desc_s
int *portlist =
int portlist_n =
char *Srealloc(ptr,
char
int
{
{
char
int retries =
while (!(p = ptr ? realloc(ptr, len) : malloc(len)))
if (!--retries)
perror("malloc");
exit(1);
}
perror("malloc");
exit(1);
}
if
fprintf(stderr,
"Smalloc:
fprintf(stderr,
"Smalloc: couldn't allocate %d bytes...
sleeping\n",
len);
sleep(2);
}
sleeping\n",
len);
sleep(2);
}
return
}
}
char
int
{
{
return Srealloc(NULL,
}
}
fvoid
int
{
{
int
flags = (~O_NONBLOCK)
fcntl(sfd, F_SETFL,
}
}
fvoid
int
{
{
int
flags = O_NONBLOCK | fcntl(sfd,
fcntl(sfd, F_SETFL,
}
}
int timeval_subtract(result, x, y) /* from gnu c-lib info.texi
struct timeval *result, *x,
{
{
/* Perform the carry for the later subtraction by updating y.
if
int nsec =
y->tv_usec
y->tv_usec -= 1000000 *
y->tv_sec
y->tv_sec +=
}
}
if
int nsec =
y->tv_usec
y->tv_usec += 1000000 *
y->tv_sec
y->tv_sec -=
}
}
/* Compute the time remaining to
`tv_usec' is certainly positive.
result->tv_sec
result->tv_sec =
result->tv_usec
result->tv_usec =
/* Return 1 if result is negative.
return
}
}
fvoid
struct htuple_s
{
{
if
struct timeval tv1,
gettimeofday(&tv1, NULL);
timeval_subtract(&tv2, &tv1, &(h->sock_start));
h->host->time_used.
gettimeofday(&tv1, NULL);
timeval_subtract(&tv2, &tv1, &(h->sock_start));
h->host->time_used.tv_sec += tv2.
if
h->host->time_used.
h->host->time_used.tv_usec -=
h->host->time_used.tv_sec++;
}
attempts_done++;
h->host->attempts_done++;
h->host->time_used.tv_sec++;
}
attempts_done++;
h->host->attempts_done++;
if
h->host->attempts_highest_done
h->host->attempts_highest_done =
sock_unblock(h->sfd);
sock_unblock(h->sfd);
/* shutdown
close(h->sfd);
close(h->sfd);
if
FD_CLR(h->sfd, &set_sel);
attempts_outstanding--;
}
}
FD_CLR(h->sfd, &set_sel);
attempts_outstanding--;
}
}
*h =
}
}
fvoid
{
{
int
for (n = 0; n
attempt_clear(&attempt[n]);
}
attempt_clear(&attempt[n]);
}
fvoid
{
{
int
for (n = 0; n
attempt[n] =
}
}
fvoid
{
{
int
for (n = 0; n
hosts[n] =
}
}
fvoid
{
FD_ZERO(&set_sel_r);
{
FD_ZERO(&set_sel_r); /* yes, we have to do this, despite the later
FD_ZERO(&set_sel_w);
FD_ZERO(&set_sel_w); /* assisgnments
FD_ZERO(&set_sel);
}
FD_ZERO(&set_sel);
}
int
struct htuple_s
{
{
struct sockaddr_in
int sopts1 =
struct linger
if
return
memset(&sa_in,
memset(&sa_in, 0,
h->status
h->status |=
gettimeofday(&(h->sock_start), NULL);
sock_unblock(h->sfd);
setsockopt(h->sfd,
gettimeofday(&(h->sock_start), NULL);
sock_unblock(h->sfd);
setsockopt(h->sfd, SOL_SOCKET, SO_REUSEADDR, (char
sizeof(sopts1));
setsockopt(h->sfd,
sizeof(sopts1));
setsockopt(h->sfd, SOL_SOCKET, SO_OOBINLINE, (char
sizeof(sopts1));
sizeof(sopts1));
slinger.l_onoff = 0; /* off
setsockopt(h->sfd,
setsockopt(h->sfd, SOL_SOCKET, SO_LINGER, (char
sizeof(slinger));
sizeof(slinger));
sa_in.sin_family =
if
sa_in.sin_port =
if
sa_in.sin_addr =
if (a_bindaddr ||
if
-1)
fprintf(stderr,
a_bindaddr ? a_bindaddr :
ntohs(a_bindport));
perror("");
ntohs(a_bindport));
perror("");
if (errno ==
exit(1);
exit(1);
return
}
}
sa_in.sin_addr =
sa_in.sin_port =
if
switch (errno)
case
case
break;
break;
case
case
case
if (f_verbose)
fprintf(stderr,
perror("");
}
h->host->attempts++;
attempt_clear(h);
perror("");
}
h->host->attempts++;
attempt_clear(h);
return
default:
default:
if (!f_quiet)
fprintf(stderr,
perror("");
}
attempt_clear(h);
perror("");
}
attempt_clear(h);
return
}
}
h->host->attempts++;
h->status
}
}
h->host->attempts++;
h->status |=
sock_block(h->sfd);
FD_SET(h->sfd, &set_sel);
attempts_outstanding++;
sock_block(h->sfd);
FD_SET(h->sfd, &set_sel);
attempts_outstanding++;
return
}
}
int
struct htuple_s
{
{
struct port_desc_s
if
printf("%s\t%d\n", h->name, h->port);
printf("%s\t%d\n", h->name, h->port);
else
if ((pd =
printf("%-30s
printf("%-30s %-16s %5d/tcp
pd->portname, h->port, pd->name);
pd->portname, h->port, pd->name);
while (!f_delete_dupes
&&
&& (pd =
printf("#%-29s
printf("#%-29s %-16s %5d/tcp
pd->portname, h->port, pd->name);
pd->portname, h->port, pd->name);
}
printf("%-30s
printf("%-30s %-16s %5d/tcp
"unknown", h->port);
}
h->host->connects++;
connects++;
attempt_clear(h);
"unknown", h->port);
}
h->host->connects++;
connects++;
attempt_clear(h);
return
}
}
bool
{
{
struct timeval
struct htuple_s
int
int
time_t
if
return
set_sel_r = set_sel_w =
timeout.tv_sec =
timeout.tv_usec = 250000; /* 1/4 of a second
selected = select(FD_SETSIZE,
/* Look for timeouts
tim =
for (n = 0; n
h =
if
((h->sock_start.
((h->sock_start.tv_sec +
attempt_clear(h);
}
attempt_clear(h);
}
switch (selected)
case
perror("select");
perror("select");
return
case
return
}
}
for (n = 0; selected
h =
if
if
||
struct sockaddr_in
int len =
selected--;
selected--;
/* select() lies
*/
*/
if (!f_dontgetpeername)
/* but solaris2.3 crashes occasionally ;-|
if
(h->sfd,
(h->sfd, (struct sockaddr
&len)
&len) ==
gatherer_tcp(h);
else
attempt_clear(h);
gatherer_tcp(h);
else
attempt_clear(h);
}
gatherer_tcp(h);
}
}
}
gatherer_tcp(h);
}
}
}
return
}
}
bool
struct htuple_s
{
{
struct htuple_s
static time_t
static int
for (;;)
for (; n
h =
if
goto
}
}
n =
gather();
continue;
foundfree:
gather();
continue;
foundfree:
*h =
if (!sc_connect(h))
gather();
continue;
}
gather();
continue;
}
if ((oldtime + 1)
oldtime =
gather();
}
break;
}
gather();
}
break;
}
return
}
}
int scatter(host,
struct hosts_s
int
{
{
static struct htuple_s
add =
add.host =
add.name =
add.in_addr =
add.port =
add.timeout =
if
fprintf(stderr,
add.
add_attempt(&add);
add_attempt(&add);
return
}
}
fvoid
int
{
{
time_t
st =
while ((st + t)
gather();
gather();
if (attempts_outstanding
break;
}
}
break;
}
}
struct in_addr
char
{
{
static struct in_addr
unsigned long
struct hostent
if ((l = inet_addr(name)) != INADDR_NONE)
in.s_addr =
return
}
}
if (!(ent = gethostbyname(name)))
perror(name);
perror(name);
in.s_addr =
return
}
}
return *(struct in_addr
}
}
char
{
{
static char
hosts_done++;
hosts_done++;
if (a_input)
int
reread:
reread:
if (!fgets(lbuf, sizeof(lbuf), fh_input))
fclose(fh_input);
fclose(fh_input);
a_input =
return
}
}
if
goto
n = strcspn(lbuf,
if
lbuf[n] =
return
}
}
if (host_n
return
return
}
}
bool host_init(h, name,
struct hosts_s
char
bool
{
{
int
*h =
h->in_addr
h->in_addr =
if
return
if
for (n = 0; n
if (hosts[n].
&&
&& hosts[n].in_addr.s_addr ==
if
fprintf(stderr,
"ip
fprintf(stderr,
"ip duplication: %s == %s
last host
hosts[n].name,
return
}
}
h->name
}
}
h->name = (char *)Smalloc(strlen(name) +
strcpy(h->name, name);
h->port
strcpy(h->name, name);
h->port =
h->status
h->status =
gettimeofday(&(h->time_start), NULL);
gettimeofday(&(h->time_start), NULL);
return
}
}
fvoid
struct hosts_s
{
{
if
free(h->name);
}
free(h->name);
}
*h =
}
}
fvoid
struct hosts_s
{
{
struct timeval tv,
float t,
gettimeofday(&tv, NULL);
timeval_subtract(&tv2, &tv, &(h->time_start));
gettimeofday(&tv, NULL);
timeval_subtract(&tv2, &tv, &(h->time_start));
t = tv2.tv_sec + (float)tv2.tv_usec / 1000000.
st =
fprintf(stderr,
"stats:
fprintf(stderr,
"stats: host = %s trys = %d cons = %d time = %.2fs
= %.2f trys/ss = %.
h->name, h->attempts_done, h->connects,
h->name, h->attempts_done, h->connects, t,
h->attempts_done
h->attempts_done /
}
}
fvoid
{
{
struct timeval tv,
float
gettimeofday(&tv, NULL);
timeval_subtract(&tv2, &tv, &(time_start));
gettimeofday(&tv, NULL);
timeval_subtract(&tv2, &tv, &(time_start));
t = tv2.tv_sec + (float)tv2.tv_usec / 1000000.
fprintf(stderr,
"stats:
fprintf(stderr,
"stats: hosts = %d trys = %d cons = %d time = %.2fs trys/s = %.
hosts_done, attempts_done, connects, t, attempts_done /
}
}
bool
struct hosts_s
{
{
if (a_abort
/* async pain
if
if ((time(NULL) -
if
fprintf(stderr,
"skipping:
fprintf(stderr,
"skipping: %s (no connects
in %d
h->name, h->attempts_done);
h->name, h->attempts_done);
return
}
}
} else
h->notice_abort
h->notice_abort =
h->status
h->status |=
}
}
}
}
return
}
}
int
struct hosts_s
{
{
int
for (n =
if
return
if
return
return
}
}
return
}
}
fvoid
{
{
struct hosts_s
char
while ((name = next_host()))
if
continue;
continue;
for (;;)
scatter(&host, a_timeout);
scatter(&host, a_timeout);
if
break;
break;
if ((host.port =
break;
}
wait_end(a_timeout);
break;
}
wait_end(a_timeout);
if
host_stats(&host);
clear_all();
host_clear(&host);
}
}
host_stats(&host);
clear_all();
host_clear(&host);
}
}
/*
* o fast connections have priority == maximise bandwidth i.
* a port in the hand is worth two in the
*
*
* o newer hosts have priority == lower ports checked more
*
*
* o all hosts eventually get equal
* priorities let no one host hog the sockets
*
*
* o when host usage times are equal (typically on or shortly
* initial startup) distribute
* play a game of chaotic bifurcatic
*/
*/
fvoid
{
{
int
struct timeval
int
char
struct hosts_s *h, *smallest =
while (smallest)
smallest_val.tv_sec =
smallest_val.tv_usec =
for (n = 0, smallest_cnt = 0xfffffff, smallest =
n
h =
if
(h->attempts_done
(h->attempts_done ==
skip_host(h))
if
host_stats(h);
host_clear(h);
}
host_stats(h);
host_clear(h);
}
if
if (!host_init(h, name, 0))
host_clear(h);
continue;
}
host_clear(h);
continue;
}
if
if
||
((h->time_used.
||
((h->time_used.tv_sec
smallest_val.
&& (h->time_used.
&& (h->time_used.tv_usec
smallest_val.
&&
(((h->time_used.
&&
(((h->time_used.tv_sec
smallest_val.
&& (h->time_used.
&& (h->time_used.tv_usec
smallest_val.
||
smallest_cnt =
smallest_val =
smallest =
}
}
}
}
}
}
if (smallest)
if
scatter(smallest,
if
next_port(smallest)) ==
smallest->status
smallest->status |=
}
gather();
}
}
}
gather();
}
}
}
fvoid
{
{
FILE
char
char
char
unsigned int
char
char
prot[3] =
if (!(fh = fopen((fn = a_services),
!(fh = fopen((fn = LIB_STROBE_SERVICES),
!(fh = fopen((fn = ETC_SERVICES),
perror(fn);
exit(1);
}
perror(fn);
exit(1);
}
port_descs
(struct port_desc_s **)Smalloc(sizeof(struct port_descs_s *)
65536);
65536);
memset(port_descs, 0,
while (fgets(lbuf, sizeof(lbuf), fh))
char
struct port_desc_s *pd,
if
continue;
continue;
if (!(p = strchr(lbuf,
continue;
continue;
*p = '
desc[0] =
if
(lbuf,
desc)
continue;
continue;
pd =
if (!pd)
portlist
(int *)Srealloc((char
++portlist_n *
portlist[portlist_n - 1] =
}
}
if (!f_minimise)
pdp
(struct port_desc_s *)Smalloc(sizeof(*pd)
strlen(desc) + 1
strlen(portname) +
if (pd)
for (;
pd->next
pd->next =
pd =
} else
pd =
port_descs[port] =
}
pd->next
}
pd->next =
pd->name
pd->name = (char *)(pd) +
pd->portname
pd->portname =
strcpy(pd->name, desc);
strcpy(pd->portname, portname);
strcpy(pd->name, desc);
strcpy(pd->portname, portname);
}
port_descs[port] = (struct port_desc_s
}
}
if
free(port_descs);
}
free(port_descs);
}
fvoid
{
{
fprintf(stderr,
usage: %8s
\t\t[-v(erbose)]\n\
\t\t[-V(erbose_stats]\n\
\t\t[-m(inimise)]\n\
\t\t[-d(elete_dupes)]\n\
\t\t[-g(etpeername_disable)]\n\
\t\t[-s(tatistics)]\n\
\t\t[-q(uiet)]\n\
\t\t[-v(erbose)]\n\
\t\t[-V(erbose_stats]\n\
\t\t[-m(inimise)]\n\
\t\t[-d(elete_dupes)]\n\
\t\t[-g(etpeername_disable)]\n\
\t\t[-s(tatistics)]\n\
\t\t[-q(uiet)]\n\
\t\t[-o
\t\t[-b
\t\t[-e
\t\t[-p
\t\t[-P
\t\t[-A
\t\t[-t
\t\t[-n
\t\t[-S
\t\t[-i
\t\t[-l(inear)]\n\
\t\t[-f(ast)]\n\
\t\t[-l(inear)]\n\
\t\t[-f(ast)]\n\
\t\t[-a
\t\t[-M(ail_author)]\n\
\t\t[-M(ail_author)]\n\
\t\t[host1 [...
exit(1);
}
exit(1);
}
int main(argc,
int
char
{
{
int
Argc =
Argv =
while ((c
getopt(argc, argv,
switch (c)
case
a_output =
break;
break;
case
f_delete_dupes =
break;
break;
case
f_verbose =
break;
break;
case
f_verbose_stats =
break;
break;
case
f_minimise =
break;
break;
case
f_dontgetpeername =
break;
break;
case
a_start =
break;
break;
case
a_end =
break;
break;
case
a_bindport =
break;
break;
case
a_bindaddr =
bindaddr =
if (bindaddr.s_addr == INADDR_NONE)
perror(a_bindaddr);
exit(1);
}
break;
perror(a_bindaddr);
exit(1);
}
break;
case
a_start = a_end =
break;
break;
case
a_abort =
break;
break;
case
a_timeout =
break;
break;
case
a_sock_max =
break;
break;
case
a_services =
break;
break;
case
a_input =
break;
break;
case
f_linear =
break;
break;
case
f_fast =
break;
break;
case
f_stats =
break;
break;
case
f_quiet =
break;
break;
case
fprintf(stderr,
"Enter
fprintf(stderr,
"Enter mail to author below. End with ^D or .
system("mail
system("mail strobe@suburbia.
break;
break;
case
default:
default:
fprintf(stderr,
argv[optind -
usage();
usage();
/* NOT_REACHED
}
}
host_n =
if
fprintf(stderr,
"strobe
fprintf(stderr,
"strobe %s (c) 1995 Julian Assange (proff@suburbia.net).
VERSION);
VERSION);
if (a_input)
if
fh_input =
} else
if (!(fh_input = fopen(a_input,
perror(a_input);
exit(1);
}
}
perror(a_input);
exit(1);
}
}
} else
switch (argc - host_n) { /* Number of hosts found on command line
case
fh_input =
a_input =
break;
break;
case
f_linear =
break;
}
}
break;
}
}
if ((fh_input == stdin)
fprintf(stderr,
if (a_output)
int
if ((fd
open(a_output, O_WRONLY | O_CREAT |
0666)) == -1)
perror(a_output);
exit(1);
}
perror(a_output);
exit(1);
}
dup2(fd,
}
}
attempt
(struct htuple_s *)Smalloc(a_sock_max * sizeof(struct
attempt_init();
attempt_init();
if (!f_linear)
hosts
(struct hosts_s *)Smalloc(a_sock_max
sizeof(struct
hosts_init();
}
hosts_init();
}
if (!f_minimise ||
loaddescs();
fdsets_init();
gettimeofday(&time_start, NULL);
loaddescs();
fdsets_init();
gettimeofday(&time_start, NULL);
f_linear ? scan_ports_linear() :
if (f_stats ||
final_stats();
exit(0);
}
final_stats();
exit(0);
}