/*
 
 * Strobe (c) 1995 Julian Assange (proff@suburbia.net),
 
 * All rights reserved.
 
 *
 
 * $ cc strobe.c -o strobe
 
 */
 
 
 
#define VERSION "1.03"
 
 
 
#include <stdio.h>
 
#include <unistd.h>
 
#include <stdlib.h>
 
#include <sys/types.h>
 
#include <sys/time.h>
 
#include <ctype.h>
 
#include <fcntl.h>
 
#include <sys/stat.h>
 
#include <sys/socket.h>
 
#ifdef _AIX
 
#include <sys/select.h>
 
#endif
 
#include <netinet/in.h>
 
#include <arpa/inet.h>
 
#include <netdb.h>
 
#include <string.h>
 
#include <errno.h>
 
 
 
#if defined(solaris) || defined(linux) || defined(__FreeBSD__) || \
 
defined(__NetBSD__) || defined(__GCC__)
 
#define fvoid void
 
#else
 
#define fvoid
 
extern int optind;
 
extern char *optarg;
 
#endif
 
#define bool char
 
 
 
#ifndef INADDR_NONE
 
#define INADDR_NONE ((unsigned long)-1)
 
#endif
 
 
 
#define port_t (unsigned short)
 
 
 
/*
 
 * the below should be set via the Makefile, but if not...
 
 */
 
 
 
#ifndef ETC_SERVICES
 
#define ETC_SERVICES "/etc/services"
 
#endif
 
#ifndef STROBE_SERVICES
 
#define STROBE_SERVICES "strobe.services"
 
#endif
 
#ifndef LIB_STROBE_SERVICES
 
#define LIB_STROBE_SERVICES "/usr/local/lib/strobe.services"
 
#endif
 
 
 
int a_timeout = 20;
 
char *a_output = NULL;
 
char *a_services = "strobe.services";
 
char *a_input = NULL;
 
/* char *a_prescan = NULL; */
 
int a_start = 1;
 
int a_end = 65535;
 
int a_sock_max = 64;
 
int a_abort = 0;
 
int a_bindport = 0;
 
char *a_bindaddr = NULL;
 
struct in_addr bindaddr;
 
bool f_linear = 0;
 
bool f_verbose = 0;
 
bool f_verbose_stats = 0;
 
bool f_fast = 0;
 
bool f_stats = 0;
 
bool f_quiet = 0;
 
bool f_delete_dupes = 0;
 
bool f_minimise = 0;
 
bool f_dontgetpeername = 0;
 
 
 
int connects = 0;
 
int hosts_done = 0;
 
int attempts_done = 0;
 
int attempts_outstanding = 0;
 
struct timeval time_start;
 
 
 
fd_set set_sel;
 
fd_set set_sel_r;
 
fd_set set_sel_w;
 
 
 
int host_n;
 
int Argc;
 
char **Argv;
 
 
 
FILE *fh_input;
 
 
 
#define HO_ACTIVE 1
 
#define HO_ABORT 2
 
#define HO_COMPLETING 4
 
 
 
struct hosts_s {
 
        char *name;
 
        struct in_addr in_addr;
 
        int port;
 
        int portlist_ent;
 
        struct timeval time_used;
 
        struct timeval time_start;
 
        int attempts;
 
        int attempts_done;
 
        int attempts_highest_done;
 
        int connects;
 
        time_t notice_abort;
 
        int status;
 
};
 
struct hosts_s ho_initial;
 
struct hosts_s *hosts;
 
 
 
#define HT_SOCKET 1
 
#define HT_CONNECTING 2
 
 
 
struct htuple_s {
 
        char *name;
 
        struct in_addr in_addr;
 
        int port;
 
        int sfd;
 
        int status;
 
        struct timeval sock_start;
 
        int timeout;
 
        struct hosts_s *host;
 
};
 
 
 
struct htuple_s ht_initial;
 
struct htuple_s *attempt;
 
 
 
struct port_desc_s {
 
        int port;
 
        char *name;
 
        char *portname;
 
        struct port_desc_s *next;
 
        struct port_desc_s *next_port;
 
};
 
 
 
struct port_desc_s **port_descs;
 
 
 
int *portlist = NULL;
 
int portlist_n = 0;
 
 
 
char *Srealloc(ptr, len)
 
char *ptr;
 
int len;
 
{
 
        char *p;
 
        int retries = 10;
 
                if (!--retries) {
 
                }
 
                if (!f_quiet)
 
                                "Smalloc: couldn't allocate %d bytes...\
 
                                sleeping\n",
 
                                len);
 
                sleep(2);
 
        }
 
        return p;
 
}
 
 
 
char *Smalloc(len)
 
int len;
 
{
 
        return Srealloc(NULL, len);
 
}
 
 
 
fvoid sock_block(sfd)
 
int sfd;
 
{
 
        int flags;
 
        flags = (~O_NONBLOCK) & fcntl(sfd, F_GETFL);
 
        fcntl(sfd, F_SETFL, flags);
 
}
 
 
 
fvoid sock_unblock(sfd)
 
int sfd;
 
{
 
        int flags;
 
        flags = O_NONBLOCK | fcntl(sfd, F_GETFL);
 
        fcntl(sfd, F_SETFL, flags);
 
}
 
 
 
int timeval_subtract(result, x, y)      /* from gnu c-lib info.texi */
 
struct timeval *result, *x, *y;
 
{
 
/* Perform the carry for the later subtraction by updating y. */
 
        if (x->tv_usec < y->tv_usec) {
 
                int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
 
                y->tv_usec -= 1000000 * nsec;
 
                y->tv_sec += nsec;
 
        }
 
        if (x->tv_usec - y->tv_usec > 1000000) {
 
                int nsec = (y->tv_usec - x->tv_usec) / 1000000;
 
                y->tv_usec += 1000000 * nsec;
 
                y->tv_sec -= nsec;
 
        }
 
 
 
/* Compute the time remaining to wait.
 
  `tv_usec' is certainly positive. */
 
        result->tv_sec = x->tv_sec - y->tv_sec;
 
        result->tv_usec = x->tv_usec - y->tv_usec;
 
 
 
/* Return 1 if result is negative. */
 
        return x->tv_sec < y->tv_sec;
 
}
 
 
 
fvoid attempt_clear(h)
 
struct htuple_s *h;
 
{
 
        if (h->status & HT_SOCKET) {
 
                struct timeval tv1, tv2;
 
                gettimeofday(&tv1, NULL);
 
                timeval_subtract(&tv2, &tv1, &(h->sock_start));
 
                h->host->time_used.tv_sec += tv2.tv_sec;
 
                if ((h->host->time_used.tv_usec += tv2.tv_usec) >= 1000000) {
 
                        h->host->time_used.tv_usec -= 1000000;
 
                        h->host->time_used.tv_sec++;
 
                }
 
                attempts_done++;
 
                h->host->attempts_done++;
 
                if (h->port > h->host->attempts_highest_done)
 
                        h->host->attempts_highest_done = h->port;
 
                sock_unblock(h->sfd);
 
/*      shutdown (h->sfd, 2); */
 
                close(h->sfd);
 
                if (FD_ISSET(h->sfd, &set_sel)) {
 
                        FD_CLR(h->sfd, &set_sel);
 
                        attempts_outstanding--;
 
                }
 
        }
 
        *h = ht_initial;
 
}
 
 
 
fvoid clear_all()
 
{
 
        int n;
 
        for (n = 0; n < a_sock_max; n++)
 
                attempt_clear(&attempt[n]);
 
}
 
 
 
fvoid attempt_init()
 
{
 
        int n;
 
        for (n = 0; n < a_sock_max; n++)
 
                attempt[n] = ht_initial;
 
}
 
 
 
fvoid hosts_init()
 
{
 
        int n;
 
        for (n = 0; n < a_sock_max; n++)
 
                hosts[n] = ho_initial;
 
}
 
 
 
fvoid fdsets_init()
 
{
 
        FD_ZERO(&set_sel_r);        /* yes, we have to do this, despite the later */
 
        FD_ZERO(&set_sel_w);        /* assisgnments */
 
        FD_ZERO(&set_sel);
 
}
 
 
 
int sc_connect(h)
 
struct htuple_s *h;
 
{
 
        struct sockaddr_in sa_in;
 
        int sopts1 = 1;
 
        struct linger slinger;
 
        if ((h->sfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
 
                return 0;
 
        memset(&
;sa_in
, 0, sizeof(sa_in
));  
        h->status |= HT_SOCKET;
 
        gettimeofday(&(h->sock_start), NULL);
 
        sock_unblock(h->sfd);
 
        setsockopt(h->sfd, SOL_SOCKET, SO_REUSEADDR, (char *)&sopts1,
 
                   sizeof(sopts1));
 
        setsockopt(h->sfd, SOL_SOCKET, SO_OOBINLINE, (char *)&sopts1,
 
                   sizeof(sopts1));
 
        slinger.l_onoff = 0;    /* off */
 
        setsockopt(h->sfd, SOL_SOCKET, SO_LINGER, (char *)&slinger,
 
                   sizeof(slinger));
 
        sa_in.sin_family = AF_INET;
 
        if (a_bindport)
 
                sa_in.sin_port = a_bindport;
 
        if (a_bindaddr)
 
                sa_in.sin_addr = bindaddr;
 
        if (a_bindaddr || a_bindport)
 
                if (bind(h->sfd, (struct sockaddr *)&sa_in, sizeof(sa_in)) ==
 
                    -1) {
 
                        fprintf(stderr
, "
;couldn
't bind %s : %d  ",  
                                a_bindaddr ? a_bindaddr : "0.0.0.0",
 
                                ntohs(a_bindport));
 
                        perror("");
 
                        if (errno == EACCES)
 
                                exit(1);
 
                        return 0;
 
                }
 
        sa_in.sin_addr = h->in_addr;
 
        sa_in.sin_port = htons(h->port);
 
 
 
        if (connect(h->sfd, (struct sockaddr *)&sa_in, sizeof(sa_in)) == -1) {
 
                switch (errno) {
 
                case EINPROGRESS:
 
                case EWOULDBLOCK:
 
                        break;
 
                case ETIMEDOUT:
 
                case ECONNREFUSED:
 
                case EADDRNOTAVAIL:
 
                        if (f_verbose) {
 
                                fprintf(stderr, "%s:%d ", h->name, h->port);
 
                                perror("");
 
                        }
 
                        h->host->attempts++;
 
                        attempt_clear(h);
 
                        return 1;
 
                default:
 
                        if (!f_quiet) {
 
                                fprintf(stderr, "%s:%d ", h->name, h->port);
 
                                perror("");
 
                        }
 
                        attempt_clear(h);
 
                        return 0;
 
                }
 
        }
 
        h->host->attempts++;
 
        h->status |= HT_CONNECTING;
 
        sock_block(h->sfd);
 
        FD_SET(h->sfd, &set_sel);
 
        attempts_outstanding++;
 
        return 1;
 
}
 
 
 
int gatherer_tcp(h)
 
struct htuple_s *h;
 
{
 
        struct port_desc_s *pd;
 
        if (f_minimise)
 
                printf("%s\t%d\n", h->name, h->port);
 
        else {
 
                if ((pd = port_descs[h->port])) {
 
                        printf("%-30s %-16s %5d/tcp %s\n", h->name,
 
                               pd->portname, h->port, pd->name);
 
                        while (!f_delete_dupes && !f_minimise
 
                               && (pd = pd->next))
 
                                printf("#%-29s %-16s %5d/tcp %s\n", h->name,
 
                                       pd->portname, h->port, pd->name);
 
                } else
 
                        printf("%-30s %-16s %5d/tcp unassigned\n", h->name,
 
                               "unknown", h->port);
 
        }
 
        h->host->connects++;
 
        connects++;
 
        attempt_clear(h);
 
        return 1;
 
}
 
 
 
bool gather()
 
{
 
        struct timeval timeout;
 
        struct htuple_s *h;
 
        int n;
 
        int selected;
 
        time_t tim;
 
 
 
        if (!attempts_outstanding)
 
                return 1;
 
        set_sel_r = set_sel_w = set_sel;
 
        timeout.tv_sec = 0;
 
        timeout.tv_usec = 250000;       /* 1/4 of a second */
 
 
 
        selected = select(FD_SETSIZE, &set_sel_r, &set_sel_w, 0, &timeout);
 
        /* Look for timeouts */
 
 
 
        tim = time(NULL);
 
        for (n = 0; n < a_sock_max; n++) {
 
                h = &attempt[n];
 
                if ((h->status & HT_SOCKET) &&
 
                    ((h->sock_start.tv_sec + h->timeout) < tim))
 
                        attempt_clear(h);
 
        }
 
 
 
        switch (selected) {
 
        case -1:
 
                perror("select");
 
                return 0;
 
        case 0:
 
                return 1;
 
        }
 
        for (n = 0; selected && (n < a_sock_max); n++) {
 
                h = &attempt[n];
 
                if (h->status & HT_CONNECTING) {
 
                        if (FD_ISSET(h->sfd, &set_sel_r)
 
                            || FD_ISSET(h->sfd, &set_sel_w)) {
 
                                struct sockaddr_in in;
 
                                int len = sizeof(in);
 
                                selected--;
 
                                /* select() lies occasionaly
 
                                 */
 
                                if (!f_dontgetpeername) {
 
                                /* but solaris2.3 crashes occasionally ;-| */
 
                                        if (getpeername
 
                                            (h->sfd, (struct sockaddr *)&in,
 
                                             &len) == 0)
 
                                                gatherer_tcp(h);
 
                                        else
 
                                                attempt_clear(h);
 
                                } else
 
                                        gatherer_tcp(h);
 
                        }
 
                }
 
        }
 
        return 1;
 
}
 
 
 
bool add_attempt(add)
 
struct htuple_s *add;
 
{
 
        struct htuple_s *h;
 
        static time_t oldtime;
 
        static int n;
 
        for (;;) {
 
                for (; n < a_sock_max; n++) {
 
                        h = &attempt[n];
 
                        if (!h->status)
 
                                goto foundfree;
 
                }
 
                n = 0;
 
                gather();
 
                continue;
 
foundfree:
 
                *h = *add;
 
                if (!sc_connect(h)) {
 
                        gather();
 
                        continue;
 
                }
 
                if ((oldtime + 1) < time(NULL)) {
 
                        oldtime = time(NULL);
 
                        gather();
 
                }
 
                break;
 
        }
 
        return 1;
 
}
 
 
 
int scatter(host, timeout)
 
struct hosts_s *host;
 
int timeout;
 
{
 
        static struct htuple_s add;
 
        add = ht_initial;
 
        add.host = host;
 
        add.name = host->name;
 
        add.in_addr = host->in_addr;
 
        add.port = host->port;
 
        add.timeout = timeout;
 
        if (f_verbose)
 
                fprintf(stderr, "attempting port=%d host=%s\n", add.port,
 
                        add.name);
 
        add_attempt(&add);
 
        return 1;
 
}
 
 
 
fvoid wait_end(t)
 
int t;
 
{
 
        time_t st;
 
        st = time(NULL);
 
        while ((st + t) > time(NULL)) {
 
                gather();
 
                if (attempts_outstanding < 1)
 
                        break;
 
        }
 
}
 
 
 
struct in_addr resolve(name)
 
char *name;
 
{
 
        static struct in_addr in;
 
        unsigned long l;
 
        struct hostent *ent;
 
        if ((l = inet_addr(name)) != INADDR_NONE) {
 
                in.s_addr = l;
 
                return in;
 
        }
 
        if (!(ent = gethostbyname(name))) {
 
                perror(name);
 
                in.s_addr = INADDR_NONE;
 
                return in;
 
        }
 
        return *(struct in_addr *)ent->h_addr;
 
}
 
 
 
char *next_host()
 
{
 
        static char lbuf[512];
 
        hosts_done++;
 
        if (a_input) {
 
                int n;
 
reread:
 
                if (!fgets(lbuf, sizeof(lbuf), fh_input)) {
 
                        fclose(fh_input);
 
                        a_input = NULL;
 
                        return next_host();
 
                }
 
                if (strchr("# \t\n\r", lbuf[0]))
 
                        goto reread;
 
                n = strcspn(lbuf, " \t\n\r");
 
                if (n)
 
                        lbuf[n] = '\0';
 
                return lbuf;
 
        }
 
        if (host_n >= Argc)
 
                return NULL;
 
 
 
        return Argv[host_n++];
 
}
 
 
 
bool host_init(h, name, nocheck)
 
struct hosts_s *h;
 
char *name;
 
bool nocheck;
 
{
 
        int n;
 
        *h = ho_initial;
 
        h->in_addr = resolve(name);
 
        if (h->in_addr.s_addr == INADDR_NONE)
 
                return 0;
 
        if (!nocheck)
 
                for (n = 0; n < a_sock_max; n++) {
 
                        if (hosts[n].name
 
                            && hosts[n].in_addr.s_addr == h->in_addr.s_addr) {
 
                                if (!f_quiet)
 
                                        fprintf(stderr,
 
                                                "ip duplication: %s == %s (\
 
                                                last host ignored)\n",
 
                                                hosts[n].name, name);
 
                                return 0;
 
                        }
 
                }
 
        h->name = (char *)Smalloc(strlen(name) + 1);
 
        strcpy(h->name, name);
 
        h->port = a_start;
 
        h->status = HO_ACTIVE;
 
        gettimeofday(&(h->time_start), NULL);
 
        return 1;
 
}
 
 
 
fvoid host_clear(h)
 
struct hosts_s *h;
 
{
 
        if (h->name) {
 
                free(h->name);
 
        }
 
        *h = ho_initial;
 
}
 
 
 
fvoid host_stats(h)
 
struct hosts_s *h;
 
{
 
        struct timeval tv, tv2;
 
        float t, st;
 
        gettimeofday(&tv, NULL);
 
        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",
 
                h->name, h->attempts_done, h->connects, t, h->attempts_done / t,
 
                h->attempts_done / st);
 
}
 
 
 
fvoid final_stats()
 
{
 
        struct timeval tv, tv2;
 
        float t;
 
        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",
 
                hosts_done, attempts_done, connects, t, attempts_done / t);
 
}
 
 
 
bool skip_host(h)
 
struct hosts_s *h;
 
{
 
        if (a_abort && !h->connects && (h->attempts_highest_done >= a_abort)) {
 
        /* async pain */
 
                if (h->status & HO_ABORT) {
 
                        if ((time(NULL) - h->notice_abort) > a_timeout) {
 
                                if (f_verbose)
 
                                        fprintf(stderr,
 
                                                "skipping: %s (no connects \
 
                                                in %d attempts)\n",
 
                                                h->name, h->attempts_done);
 
                                return 1;
 
                        }
 
                } else {
 
                        h->notice_abort = time(NULL);
 
                        h->status |= HO_ABORT;
 
                }
 
        }
 
        return 0;
 
}
 
 
 
int next_port(h)
 
struct hosts_s *h;
 
{
 
        int n;
 
        for (n = h->port; ++n <= a_end;) {
 
                if (!f_fast)
 
                        return n;
 
                if (++h->portlist_ent > portlist_n)
 
                        return -1;
 
                return (portlist[h->portlist_ent - 1]);
 
        }
 
        return -1;
 
}
 
 
 
fvoid scan_ports_linear()
 
{
 
        struct hosts_s host;
 
        char *name;
 
        while ((name = next_host())) {
 
                if (!host_init(&host, name, 1))
 
                        continue;
 
                for (;;) {
 
                        scatter(&host, a_timeout);
 
                        if (skip_host(&host))
 
                                break;
 
                        if ((host.port = next_port(&host)) == -1)
 
                                break;
 
                }
 
                wait_end(a_timeout);
 
                if (f_verbose_stats)
 
                        host_stats(&host);
 
                clear_all();
 
                host_clear(&host);
 
        }
 
}
 
 
 
/* Huristics:
 
 *  o  fast connections have priority == maximise bandwidth i.e 
 
 *     a port in the hand is worth two in the bush
 
 *
 
 *  o  newer hosts have priority == lower ports checked more quickly
 
 *
 
 *  o  all hosts eventually get equal "socket time" == despite
 
 *     priorities let no one host hog the sockets permanently
 
 *
 
 *  o  when host usage times are equal (typically on or shortly after
 
 *     initial startup) distribute hosts<->sockets evenly rather than
 
 *     play a game of chaotic bifurcatic ping-pong
 
 */
 
 
 
fvoid scan_ports_paralell()
 
{
 
        int n;
 
        struct timeval smallest_val;
 
        int smallest_cnt;
 
        char *name;
 
        struct hosts_s *h, *smallest = &hosts[0];
 
        while (smallest) {
 
                smallest_val.tv_sec = 0xfffffff;
 
                smallest_val.tv_usec = 0;
 
                for (n = 0, smallest_cnt = 0xfffffff, smallest = NULL;
 
                     n < a_sock_max; n++) {
 
                        h = &hosts[n];
 
 
 
                        if (((h->status & HO_COMPLETING) &&
 
                             (h->attempts_done == h->attempts)) ||
 
                            skip_host(h)) {
 
                                if (f_verbose_stats)
 
                                        host_stats(h);
 
                                host_clear(h);
 
                        }
 
 
 
                        if (!h->name && ((name = next_host())))
 
                                if (!host_init(h, name, 0)) {
 
                                        host_clear(h);
 
                                        continue;
 
                                }
 
 
 
                        if (h->name) {
 
                                if (((h->time_used.tv_sec < smallest_val.tv_sec)
 
                                     ||
 
                                     ((h->time_used.tv_sec ==
 
                                       smallest_val.tv_sec)
 
                                      && (h->time_used.tv_usec <=
 
                                          smallest_val.tv_usec)))
 
                                    &&
 
                                    (((h->time_used.tv_sec !=
 
                                       smallest_val.tv_sec)
 
                                      && (h->time_used.tv_usec !=
 
                                          smallest_val.tv_usec))
 
                                     || (h->attempts < smallest_cnt))) {
 
                                        smallest_cnt = h->attempts;
 
                                        smallest_val = h->time_used;
 
                                        smallest = h;
 
                                }
 
                        }
 
                }
 
 
 
                if (smallest) {
 
                        if (!(smallest->status & HO_COMPLETING)) {
 
                                scatter(smallest, a_timeout);
 
                                if ((smallest->port =
 
                                     next_port(smallest)) == -1)
 
                                        smallest->status |= HO_COMPLETING;
 
                        } else
 
                                gather();
 
                }
 
        }
 
}
 
 
 
fvoid loaddescs()
 
{
 
        FILE *fh;
 
        char lbuf[1024];
 
        char desc[256];
 
        char portname[17];
 
        unsigned int port;
 
        char *fn;
 
        char prot[4];
 
        prot[3] = '\0';
 
        if (!(fh = fopen((fn = a_services), "r")) &&
 
            !(fh = fopen((fn = LIB_STROBE_SERVICES), "r")) &&
 
            !(fh = fopen((fn = ETC_SERVICES), "r"))) {
 
                perror(fn);
 
                exit(1);
 
        }
 
        port_descs =
 
            (struct port_desc_s **)Smalloc(sizeof(struct port_descs_s *) *
 
                                           65536);
 
        memset(port_descs, 0, 65536);
 
        while (fgets(lbuf, sizeof(lbuf), fh)) {
 
                char *p;
 
                struct port_desc_s *pd, *pdp;
 
                if (strchr("*# \t\n", lbuf[0]))
 
                        continue;
 
                if (!(p = strchr(lbuf, '/')))
 
                        continue;
 
                *p = ' ';
 
                desc[0] = '\0';
 
                if (sscanf
 
                    (lbuf, "%16s %u %3s %255[^\r\n]", portname, &port, prot,
 
                     desc) < 3 || strcmp(prot, "tcp") || (port > 65535))
 
                        continue;
 
                pd = port_descs[port];
 
                if (!pd) {
 
                        portlist =
 
                            (int *)Srealloc((char *)portlist,
 
                                            ++portlist_n * sizeof(int));
 
                        portlist[portlist_n - 1] = port;
 
                }
 
                if (!f_minimise) {
 
                        pdp =
 
                            (struct port_desc_s *)Smalloc(sizeof(*pd) +
 
                                                          strlen(desc) + 1 +
 
                                                          strlen(portname) + 1);
 
                        if (pd) {
 
                                for (; pd->next; pd = pd->next) ;
 
                                pd->next = pdp;
 
                                pd = pd->next;
 
                        } else {
 
                                pd = pdp;
 
                                port_descs[port] = pd;
 
                        }
 
                        pd->next = NULL;
 
                        pd->name = (char *)(pd) + sizeof(*pd);
 
                        pd->portname = pd->name + strlen(desc) + 1;
 
                        strcpy(pd->name, desc);
 
                        strcpy(pd->portname, portname);
 
                } else
 
                        port_descs[port] = (struct port_desc_s *)-1;
 
        }
 
        if (f_minimise)
 
                free(port_descs);
 
}
 
 
 
fvoid usage()
 
{
 
        fprintf(stderr, "\
 
usage: %8s [options]\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 output_file]\n\
 
\t\t[-b begin_port_n]\n\
 
\t\t[-e end_port_n]\n\
 
\t\t[-p single_port_n]\n\
 
\t\t[-P bind_port_n]\n\
 
\t\t[-A bind_addr_n]\n\
 
\t\t[-t timeout_n]\n\
 
\t\t[-n num_sockets_n]\n\
 
\t\t[-S services_file]\n\
 
\t\t[-i hosts_input_file]\n\
 
\t\t[-l(inear)]\n\
 
\t\t[-f(ast)]\n\
 
\t\t[-a abort_after_port_n]\n\
 
\t\t[-M(ail_author)]\n\
 
\t\t[host1 [...host_n]]\n", Argv[0]);
 
        exit(1);
 
}
 
 
 
int main(argc, argv)
 
int argc;
 
char **argv;
 
{
 
        int c;
 
        Argc = argc;
 
        Argv = argv;
 
 
 
        while ((c =
 
                getopt(argc, argv, "o:dvVmgb:e:p:P:a:A:t:n:S:i:lfsqM")) != -1)
 
                switch (c) {
 
                case 'o':
 
                        a_output = optarg;
 
                        break;
 
                case 'd':
 
                        f_delete_dupes = 1;
 
                        break;
 
                case 'v':
 
                        f_verbose = 1;
 
                        break;
 
                case 'V':
 
                        f_verbose_stats = 1;
 
                        break;
 
                case 'm':
 
                        f_minimise = 1;
 
                        break;
 
                case 'g':
 
                        f_dontgetpeername = 1;
 
                        break;
 
                case 'b':
 
                        a_start = atoi(optarg);
 
                        break;
 
                case 'e':
 
                        a_end = atoi(optarg);
 
                        break;
 
                case 'P':
 
                        a_bindport = htons(atoi(optarg));
 
                        break;
 
                case 'A':
 
                        a_bindaddr = optarg;
 
                        bindaddr = resolve(a_bindaddr);
 
                        if (bindaddr.s_addr == INADDR_NONE) {
 
                                perror(a_bindaddr);
 
                                exit(1);
 
                        }
 
                        break;
 
                case 'p':
 
                        a_start = a_end = atoi(optarg);
 
                        break;
 
                case 'a':
 
                        a_abort = atoi(optarg);
 
                        break;
 
                case 't':
 
                        a_timeout = atoi(optarg);
 
                        break;
 
                case 'n':
 
                        a_sock_max = atoi(optarg);
 
                        break;
 
                case 'S':
 
                        a_services = optarg;
 
                        break;
 
                case 'i':
 
                        a_input = optarg;
 
                        break;
 
                case 'l':
 
                        f_linear = 1;
 
                        break;
 
                case 'f':
 
                        f_fast = 1;
 
                        break;
 
                case 's':
 
                        f_stats = 1;
 
                        break;
 
                case 'q':
 
                        f_quiet = 1;
 
                        break;
 
                case 'M':
 
                        fprintf(stderr,
 
                                "Enter mail to author below. End with ^D or .\n");
 
                        system("mail strobe@suburbia.net");
 
                        break;
 
                case '?':
 
                default:
 
                        fprintf(stderr, "unknown option %s\n",
 
                                argv[optind - 1]);
 
                        usage();
 
                        /* NOT_REACHED */
 
                }
 
        host_n = optind;
 
 
 
        if (!f_quiet)
 
                fprintf(stderr,
 
                        "strobe %s (c) 1995 Julian Assange (proff@suburbia.net).\n",
 
                        VERSION);
 
        if (a_input) {
 
                if (!strcmp("-", a_input)) {  /* Use stdin as input file */
 
                        fh_input = stdin;
 
                } else {
 
                        if (!(fh_input = fopen(a_input, "r"))) {
 
                                perror(a_input);
 
                                exit(1);
 
                        }
 
                }
 
        } else {
 
                switch (argc - host_n) {        /* Number of hosts found on command line */
 
                case 0:
 
                        fh_input = stdin;
 
                        a_input = "stdin";    /* Needed in "next_host()" */
 
                        break;
 
                case 1:
 
                        f_linear = 1;
 
                        break;
 
                }
 
        }
 
 
 
        if ((fh_input == stdin) && !f_quiet)
 
                fprintf(stderr, "Reading host names from stdin...\n");
 
 
 
        if (a_output) {
 
                int fd;
 
                if ((fd =
 
                     open(a_output, O_WRONLY | O_CREAT | O_TRUNC,
 
                          0666)) == -1) {
 
                        perror(a_output);
 
                        exit(1);
 
                }
 
                dup2(fd, 1);
 
        }
 
        attempt =
 
            (struct htuple_s *)Smalloc(a_sock_max * sizeof(struct htuple_s));
 
        attempt_init();
 
        if (!f_linear) {
 
                hosts =
 
                    (struct hosts_s *)Smalloc(a_sock_max *
 
                                              sizeof(struct hosts_s));
 
                hosts_init();
 
        }
 
        if (!f_minimise || f_fast)
 
                loaddescs();
 
        fdsets_init();
 
        gettimeofday(&time_start, NULL);
 
        f_linear ? scan_ports_linear() : scan_ports_paralell();
 
        if (f_stats || f_verbose_stats)
 
                final_stats();
 
        exit(0);
 
}
 
 
 
]]>