I get to write this because there's a typo in the original, as lots
of nice folks have pointed out. The name of the host that
has "ntop" on it is missing ".au" at the end, which is why lots
of you couldn't find it. My apologies.
BTW, there is some question as to whether or not "ntop" will run
under Solaris 2.X. The comments in the "README" that come with it
seem to indicate that it won't, but I haven't tried it yet myself.
Enclosed below are two things:
1. The summary with the corrected address for ntop, plus
another location for it courtesy of Andy Wagliardo. Also has
a pointer to a site with compiled, "package" versions of top
and lsof courtesy of Mark Bergman. (Thanks to them and to
everybody who pointed out the typo in the original.)
2. A sharchive'd copy of the ntop 1.18 distribution
to save you the trouble of ftp'ing it. I did *not* make it
a MIME attachment because I know that some folks don't have
MIME-capable mail agents. To unpack it, just save the
text between the "cut here" lines to a file and feed it to /bin/sh.
One more note: some folks wrote to suggest proctoool, tcpdump, etc.;
I think I may address those in another note. The reason I didn't include
them here is that I think of those tools as being somewhat more
special-purpose, and I don't tend to use them until I've used on these
tools to isolate the problem. To put it another way: a lot of times,
when I start the diagnostic process, I haven't got a clue where the
trouble may be, and using these tools at least tells me *that*. Then it's
time to figure out what tool is appropriate to go forward from there.
As always, your experience may be different than mine.
Cheers,
Rich
------------begin re-summary-----------------------------------
This is not actually a summary to a question that I asked, but
since this keeps coming up over and over again, I thought I'd
write this up for everyone's mutual benefit.
At least a third of the problems that I've read about people
having in the last couple of months can be addresssed in some
part by some simple tools that are freely available. I'd strongly
recommend that everyone running Sun systems get their hands on
these ASAP and learn how to use them. It's amazing how many
problems you can solve with such a small set of tools; but, then again,
these are pretty darn good tools. Below are brief descriptions
of each tool with a note about where you can get them.
This is by the no means an exhaustive list -- it's simply one person's
take on which tools solve the most problems the fastest.
==========
top:
==========
Top is an animated curses-driven ps with facilities for sorting
and manipulating processes.
ftp://eecs.nwu.edu/pub/top/top-3.4.tar.gz
Mark Bergman, bergman@phri.nyu.edu, points out that you
can find this in compiled, "package" form at:
http://smc.vnet.net/solaris_2.5.html
==========
ntop:
==========
Ntop is like top, only it deals with network connections; sort
of an animated netstat.
ftp://coombs.anu.edu.au/pub/net/ident/ntop1.18.tar.Z
Haven't found it anywhere else, but I expect it may be mirrored.
(Andy "speed-racer" Wagliardo, awagliar@cs.vt.edu, tells me that
it's also been seen at:
ftp://sun.rz.tu-clausthal.de/pub/unix/admin/ntop1.18.tar.Z
which might be more convenient for some of you.)
==========
nfswatch:
==========
Nfswatch doesn't just do NFS, it handles other kinds of traffic as well,
and includes extensive filtering and logging capabilities.
ftp://gatekeeper.dec.com/pub/net/ip/nfs/nfswatch4.3.tar.gz
Mirror in lots of places.
==========
lsof:
==========
Lsof tells you which files/sockets/etc. are open, who's got them open, and all
sorts of other useful info.
ftp://vic.cc.purdue.edu/pub/tools/unix/lsof/lsof_3.79_W.tar.gz
This site is also mirrored in numerous places; if you connect to
it and "cd" into the directory, you'll get a list of mirrors.
Mark Bergman, bergman@phri.nyu.edu, points out that you
can find this in compiled, "package" form at:
http://smc.vnet.net/solaris_2.5.html
==========
sysinfo:
==========
Sysinfo reports the basic configuration of your machine including the
bus layout, kernel parameters, etc.
ftp://usc.edu/pub/sysinfo/sysinfo-3.2.2.tar.gz
Probably also mirrored at other sites.
Cheers,
Rich Kulawiec
rsk@itw.com
------------end re-summary-----------------------------------
-------------cut here--------ntop 1.18-----------------------
#!/bin/sh
# This is a shell archive (produced by GNU shar 4.0).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 14094 -rw-r--r-- ntop-1.18/ntop.c
# 866 -rw-r--r-- ntop-1.18/kmem.c
# 2179 -rw-r--r-- ntop-1.18/file.c
# 3142 -rw-r--r-- ntop-1.18/auth.c
# 3868 -rw-r--r-- ntop-1.18/unix.c
# 4498 -rw-r--r-- ntop-1.18/cache.c
# 7894 -rw-r--r-- ntop-1.18/bsd.c
# 1094 -rw-r--r-- ntop-1.18/ntop.h
# 1425 -rw-r--r-- ntop-1.18/pcb.c
# 1343 -rw-r--r-- ntop-1.18/README
# 3587 -rw-r--r-- ntop-1.18/ntop.8
# 937 -rw-r--r-- ntop-1.18/CHANGES
# 1258 -rw-r--r-- ntop-1.18/Makefile
#
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
shar_touch=touch
else
shar_touch=:
echo 'WARNING: not restoring timestamps'
fi
rm -f 1231235999 $$.touch
#
# ============= ntop-1.18/ntop.c ==============
if test ! -d 'ntop-1.18'; then
echo 'x - creating directory ntop-1.18'
mkdir 'ntop-1.18'
fi
if test -f 'ntop-1.18/ntop.c' && test X"$1" != X"-c"; then
echo 'x - skipping ntop-1.18/ntop.c (File already exists)'
else
echo 'x - extracting ntop-1.18/ntop.c (text)'
sed 's/^X//' << 'SHAR_EOF' > 'ntop-1.18/ntop.c' &&
#ifndef __NetBSD__
#include <curses.h>
#endif
#ifdef __hpux
#include <termio.h>
#else
#include <sgtty.h>
#endif
#include "ntop.h"
#ifdef __NetBSD__
#include <curses.h>
#endif
#include <signal.h>
X
#ifndef lint
static char sccsid[] = "@(#)ntop.c 1.18 4/17/94 (C) 1992 Darren Reed";
#endif
X
NetL first;
NetL *ntop = &first;
struct winsize wsz;
X
#define NETSZ (sizeof(NetL))
X
char *MyMalloc();
void bye(), do_args(), help(), normal(), resize(), sig_bell();
int do_keyin();
X
static int expireNetList(), updateScreen();
X
extern char *get_portname(), *get_username(), *get_hostname();
extern void init_caches(), expireAuthCache(), initstats(), zerostats();
extern void filetableclean(), printunix(), setupsystem();
extern char *getenv(), *getauthname();
extern struct file **buildtcplist();
X
#define Home() mvcur(LINES-1,COLS-1,0,0)
X
static char rates[12];
static int estab = 0, listnn = 0;
X
static void printtable(), printline(), printonce();
X
int offset = 0, resolv = 1, seconds = 10, finishit = 0, winsize;
int number, showstats = 0, showlabel = 0;
int doauth = 0, dolist = 0, dounix = 0, showclose = 0, bandsort = 0;
u_long tsent = 0, trecv = 0;
X
main(argc,argv)
int argc;
char *argv[];
{
X do_args(argc,argv);
X
X bzero((char *)ntop, sizeof(*ntop));
X init_caches();
X initstats();
X
X (void)signal(SIGALRM, sig_bell);
X if (openkmem() == -1)
X {
X (void) fprintf(stderr, "can't open kernel memory!\n");
X exit(-1);
X }
X setupsystem();
X (void)setuid(getuid());
X if (winsize < 1 && !dolist)
X bye(1, "window too small");
X
X if (dolist)
X {
X printtable();
X exit(0);
X }
X else
X {
X printw("ntop V1.18 By Darren Reed, (C) Jan 1994.\n");
X refresh();
X }
X
X if (showstats)
X number -= 3;
X if (showlabel)
X number--;
X
X while (updateScreen())
X ;
X normal();
X exit(0);
}
X
static int updateScreen()
{
X fd_set read;
X struct timeval tim;
X long now;
X char *s, head[80], *cs = "", *cr = "";
X int rw = 4, sw = 4;
X
X FD_ZERO(&read);
X FD_SET(0,&read);
X listnn = 0;
X estab = 0;
X tsent = trecv = 0;
X printtable();
X now = time(NULL);
X strcpy(head, ctime(&now));
X if ((s = (char *)index(head,'\n')))
X *s = '\0';
X move(0,0);
X printw("%s Listen: %2d Estab.: %2d Cnt %2d St %2d Dly %2d",
X head, listnn, estab, number, offset, seconds);
X if (tsent > 9999)
X {
X sw = 3, tsent >>= 10, cs = "K";
X if (tsent > 9999)
X tsent >>= 10, cs = "M";
X }
X if (trecv > 9999)
X {
X rw = 3, trecv >>= 10, cr = "K";
X if (trecv > 9999)
X trecv >>= 10, cr = "M";
X }
X (void) sprintf(rates, " %*d%s %*d%s",
X rw, trecv, cr, sw, tsent, cs);
X printw(" %10.10s.", rates);
X addch('\n');
X if (showstats)
X printstats();
X if (showlabel)
X printw("\
Remote user@host:port Local user@host:port Sent/Recv\
X Idl");
X move(0,0);
X refresh();
X tim.tv_sec = seconds;
X tim.tv_usec = (seconds%2 == 1) ? 5 : 0;
X if (!seconds)
X tim.tv_usec = 100;
X if (select(32, &read, 0, 0, &tim)==1)
X do_keyin();
X if (finishit)
X return FALSE;
X return TRUE;
}
X
X
/*
X * Sort routine for qsort to sort on sum of bytes sent/recv, then idle time
X * then IP#-port# pair.
X */
int sort_bwidth(np1, np2)
NetL **np1, **np2;
{
X register NetL *n1 = *np1, *n2 = *np2;
X long r = (n2->rr + n2->sr) - (n1->rr + n1->sr);
X
X if (r)
X return r;
X r = n1->idle - n2->idle;
X if (r)
X return r;
X r = n2->fin.s_addr - n1->fin.s_addr;
X if (r)
X return r;
X r = n1->fp - n2->fp;
X if (r)
X return r;
X r = n1->lp - n2->lp;
X return r;
}
X
X
/*
X * Print the list of entries in the tcp table.
X * Currently only established and listening connections (as defined in
X * netinet/tcp_fsm.h) are listed.
X */
static void printtable()
{
X register NetL *net;
X register u_long faddr, laddr;
X register char *ruser;
X NetL **ntab;
X int cnt, pos = -1, wpos, size;
X tcp_seq sr, rr;
X
X (void) buildtcplist();
X size = expireNetList();
X ntop = &first;
X
X if (showstats)
X wpos = 3;
X else
X wpos = 0;
X if (showlabel)
X wpos++;
X
X ntab = (NetL **)MyMalloc(sizeof(NetL *) * size);
X for (net = ntop->next, cnt = 0; net; net = net->next, cnt++)
X ntab[cnt] = net;
X if (bandsort)
X qsort(ntab, size, sizeof(NetL *), sort_bwidth);
X
X for (cnt = 0; cnt < size; cnt++)
X {
X net = ntab[cnt];
X
X if (net->family == AF_INET)
X {
X if (net->lp == 0)
X continue;
X if (net->state == TCPS_LISTEN)
X listnn++;
X else if (net->state == TCPS_ESTABLISHED)
X estab++;
X sr = net->sr;
X rr = net->rr;
X tsent += sr;
X trecv += rr;
X }
X
X if (!dolist)
X {
X pos++;
X if (pos < offset || (cnt - offset + 1) > number)
X continue;
X wpos++;
X if (wpos > (winsize - 1))
X {
X if (showstats)
X wpos = 4;
X else
X wpos = 1;
X if (showlabel)
X wpos++;
X }
X move(wpos,0);
X }
X
X if (net->family == AF_UNIX)
X {
X estab++;
X printunix(net);
X continue;
X }
X
X faddr = net->fin.s_addr;
X laddr = net->lin.s_addr;
X ruser = (char *)NULL;
X if (faddr == laddr)
X ruser = get_username(net->fuid);
X else if (doauth)
X ruser = getauthname(faddr, net->fp, laddr, net->lp);
X if (!ruser)
X ruser = "?";
X
X if (dolist)
X printonce(net, ruser);
X else
X printline(net, ruser, sr, rr);
X }
X
X if (!dolist)
X for (; cnt < number; cnt++)
X {
X clrtoeol();
X addch('\n');
X }
X
X MyFree(ntab);
X filetableclean();
X expireAuthCache();
}
X
X
static void printline(net, ruser, sr, rr)
register NetL *net;
register char *ruser;
tcp_seq sr, rr;
{
X register u_long faddr, laddr;
X register u_short fp, lp;
X char fname[80], sname[80], pname[40], hname[50];
X char *cs = "", *cr = cs;
X int sw = 4, rw = 4;
X u_short id;
X
X lp = net->lp;
X if (net->state == TCPS_LISTEN)
X {
X printw("%8s:%s (LISTEN)\n", net->name,
X get_portname(lp, pname, sizeof(pname)));
X return;
X }
X
X fp = net->fp;
X if ((faddr = net->fin.s_addr))
X (void) sprintf(fname, "%8s@%.20s:%s", ruser,
X get_hostname(faddr, hname, sizeof(hname)),
X get_portname(fp, pname, sizeof(pname)));
X laddr = net->lin.s_addr;
X (void) sprintf(sname, "%8s@%.15s:%s", net->name,
X get_hostname(laddr, hname, sizeof(hname)),
X get_portname(lp, pname, sizeof(pname)));
X
X if (sr > 9999)
X {
X cs = "K", sw = 3, sr >>= 10;
X if (sr > 999)
X cs = "M", sr >>= 10;
X }
X if (rr > 9999)
X {
X cr = "K", rw = 3, rr >>= 10;
X if (rr > 999)
X cr = "M", rr >>= 10;
X }
X
X (void) sprintf(rates, "%*d%s/%*d%s",
X rw, rr, cr, sw, sr, cs);
X printw("%-35.35s %-29.29s %.9s ",
X fname, sname, rates);
X
X cr = "";
X rw = 3;
X if ((id = net->idle) > 60)
X {
X rw = 2;
X cr = "m";
X id /= 60;
X if (id > 59)
X {
X cr = "h";
X id /= 60;
X }
X }
X printw("%*d%s", rw, id, cr);
}
X
X
static void printonce(net, ruser)
register NetL *net;
register char *ruser;
{
X register u_long faddr, laddr;
X register u_short fp, lp;
X char fname[80], sname[80], pname[40], hname[50];
X
X lp = net->lp;
X if (net->state == TCPS_LISTEN)
X {
X (void) printf("%8s:%s (LISTEN)\n", net->name,
X get_portname(lp, pname, sizeof(pname)));
X return;
X }
X
X fp = net->fp;
X if ((faddr = net->fin.s_addr))
X (void) sprintf(fname, "%8s@%.60s:%.8s", ruser,
X get_hostname(faddr, hname, sizeof(hname)),
X get_portname(fp, pname, sizeof(pname)));
X laddr = net->lin.s_addr;
X (void) sprintf(sname, "%.8s@%.60:%.8s", net->name,
X get_hostname(laddr, hname, sizeof(hname)),
X get_portname(lp, pname, sizeof(pname)));
X if (laddr && faddr)
X (void) printf("%-39s %-30s %5d\n", fname, sname, net->idle);
X else
X {
X (void) printf("%-30.30s ", sname);
X if (net->state == TCPS_LISTEN)
X (void) printf(" (LISTEN)");
X putchar('\n');
X }
}
X
X
/*
X * gaurantee safe return for all malloc's this way.
X */
char *MyMalloc(len)
int len;
{
X char *ptr;
X
X if ((ptr = (char *)malloc(len))==NULL)
X {
X if (stdscr != NULL)
X endwin();
X bye(-1,"Malloc(%d) error-fatal", len);
X }
X return (ptr);
}
X
/*
X * done to let me log mallocs/frees to look for unfreed memory.
X */
void MyFree(ptr)
char *ptr;
{
X if (ptr)
X free(ptr);
}
X
X
/*
X * runtime commands...ooooo!
X */
int do_keyin()
{
X char buff[80], *s;
X int ret = 0;
X
X if (feof(stdin) || (read(0, buff, 1) <= 0))
X {
X ret = -1, finishit = 1;
X goto do_keyin_out;
X }
X
X if (buff[0] == ':')
X {
X nocrmode();
X
X move(0,0);
X clrtoeol();
X move(0,0);
X addch('>');
X refresh();
X echo();
X fgets(buff, sizeof(buff)-1, stdin);
X if ((s = (char *)index(buff, '\n')))
X *s = '\0';
X
X switch(buff[0])
X {
X case 'n' :
X number = atoi(&buff[1]);
X break;
X case 'o' :
X offset = atoi(&buff[1]);
X break;
X case 'q' :
X finishit = 1;
X break;
X case 's' :
X seconds = atoi(&buff[1]);
X break;
X case 'w' :
X winsize = atoi(&buff[1]);
X break;
X default :
X ret = -1;
X break;
X }
X noecho();
X crmode();
X move(0,0);
X printw("%s", buff);
X move(0,0);
X clrtoeol();
X }
X else
X {
X switch(buff[0])
X {
X case '+' :
X number++;
X break;
X case '-' :
X if (number > 0)
X number--;
X break;
X case '?' :
X help();
X break;
X case '\014' : /* ^L */
X clear();
X touchwin(stdscr);
X break;
X case '\n' : case '\r' :
X ret = 1;
X break;
X case '%' :
X bandsort = 1 - bandsort;
X break;
X case 'a' :
X doauth = 1 - doauth;
X break;
X case 'c' :
X showclose = 1 - showclose;
X break;
X case 'h' :
X showstats = 1 - showstats;
X if (showstats)
X {
X move(1,0);
X clrtoeol();
X move(2,0);
X clrtoeol();
X move(3,0);
X clrtoeol();
X number -= 3;
X }
X else
X number += 3;
X break;
X case 'H' :
X showlabel = 1 - showlabel;
X if (showlabel)
X {
X if (showstats)
X move(4,0);
X else
X move(1,0);
X clrtoeol();
X number--;
X }
X else
X number++;
X break;
X case 'j' :
X offset++;
X break;
X case 'k' :
X if (offset >0)
X offset--;
X break;
X case 'q' :
X finishit = 1;
X break;
X case 'r' :
X resolv = 1-resolv;
X break;
X case 'u' :
X dounix = 1 - dounix;
X break;
X case 'Z' :
X zerostats();
X break;
X case '1' :
X case '2' :
X case '3' :
X case '4' :
X case '5' :
X case '6' :
X case '7' :
X case '8' :
X case '9' :
X seconds = buff[0]-'0';
X break;
X default :
X ret = -1;
X break;
X }
X }
do_keyin_out:
X return ret;
}
X
/*
X * parse command line args passed to us.
X */
void do_args(argc, argv)
register int argc;
register char **argv;
{
X register char *s;
X int tmp;
X
X for (--argc, ++argv; argc > 0 && *argv; argv++, argc--)
X {
X s = *argv;
X if (*s == '-')
X for (++s; *s; s++)
X switch(*s)
X {
X case '%' :
X bandsort = 1 - bandsort;
X break;
X case 'a' :
X doauth = 1 - doauth;
X break;
X case 'c' :
X showclose = 1 - showclose;
X break;
X case 'h' :
X showstats = 1 - showstats;
X break;
X case 'H' :
X showlabel = 1 - showlabel;
X break;
X case 'l' :
X dolist = 1;
X break;
X /* number of entries to show */
X case 'n' :
X if ((tmp = atoi(s+1)))
X number = tmp;
X else if (argc > 0)
X {
X number = atoi(*++argv);
X --argc;
X }
X else
X break;
X break;
X /* offset count into list */
X case 'o' :
X if ((tmp = atoi(s+1)))
X offset = tmp;
X else if (argc > 0)
X {
X offset = atoi(*++argv);
X --argc;
X }
X else
X break;
X break;
X /* reverse address resolving flag */
X case 'r' :
X resolv = 1 - resolv;
X break;
X /* seconds for delay between updates */
X case 's' :
X if ((tmp = atoi(s+1)))
X seconds = tmp;
X else if (argc > 0)
X {
X seconds = atoi(*++argv);
X --argc;
X }
X else
X break;
X break;
X case 'v' :
X (void) printf("version 1.18\n");
X exit(0);
X case 'u' :
X dounix = 1 - dounix;
X break;
X /* window/screen size */
X case 'w' :
X if ((tmp = atoi(s+1)))
X winsize = tmp;
X else if (argc > 0)
X {
X winsize = atoi(*++argv);
X --argc;
X }
X else
X break;
X break;
X default:
X break;
X }
X }
}
X
X
/*
X * reset tty
X */
void normal()
{
X nocrmode();
X standend();
X clear();
X refresh();
X endwin();
}
X
X
/*
X * shutdown curses, print a message and exit
X */
void bye(st, msg, arg)
int st;
char *msg;
char *arg;
{
X if (stdscr)
X normal();
X if (msg)
X (void) fprintf(stderr, msg, arg);
X (void) fputc('\r', stderr);
X (void) fputc('\n', stderr);
X exit(st);
}
X
X
/*
X * resize the screen
X */
void resize()
{
X if (!ioctl(0, TIOCGWINSZ, &wsz))
X {
X winsize = wsz.ws_row;
X number = winsize - 1;
X if (showstats)
X number -= 3;
X if (showlabel)
X number--;
X endwin();
X initscr();
X scrollok(stdscr, FALSE);
X noecho();
X crmode();
X clear();
X touchwin(stdscr);
X refresh();
X clear();
X }
}
X
X
/*
X * remove non-current entries
X */
static int expireNetList()
{
X register NetL *n, **np;
X register int sz = 0;
X
X np = &first.next;
X
X while ((n = *np))
X {
X n->age--;
X if (n->age < 0)
X {
X *np = n->next;
X n->next = NULL;
X MyFree(n);
X }
X else
X {
X sz++;
X np = &n->next;
X }
X }
X return sz;
}
X
X
void sig_bell()
{
X return;
}
X
void help()
{
#define ISON(x) ((x) ? '*' : ' ')
X
X clear();
X refresh();
X do {
X move(0,0);
X printw("\
\t\tHelp screen for ntop keys (* = selected)\n\
\tPress <RETURN> to return, else use keys to change options\n\
\t---------------------------------------------------------\n\
X + - increase number of entries to show \
X - - decrease number of entries to show\n\
X ? - show this screen\t\t\t\
%c%% - toggle sort by traffic flow\n\
%ca - toggle use of ident\t\t\
%cc - toggle 'closing' connections\n",
X ISON(bandsort), ISON(doauth), ISON(showclose));
X printw("\
%ch - toggle stats in the top 3 rows\t%cH - toggle column headings\n\
X j - increment offset into display list \
X k - decrement offset into display list\n\
X q - quit\n\
%cr - toggle hostname resolution\t\t%cu - toggle unix domain display\n\
X Z - `zero' connection stats\n\
X 1-9 - set display interval time in seconds\n\
X : - enter an extended command at > prompt\n",
X ISON(showstats), ISON(showlabel),
X ISON(resolv), ISON(dounix));
X printw("\n\
\t\tExtended commands:\n\
\t\t------------------\n\
X n <x> - number of entries to show (%d)\n\
X o <x> - offset into list (%d)\n\
X q - quit\n\
X s <x> - delay between updates (%d)\n\
X w <x> - window size (%d)\n",
X number, offset, seconds, winsize);
X refresh();
X
X } while (do_keyin() != 1);
X
X clear();
X refresh();
}
SHAR_EOF
$shar_touch -am 0416224894 'ntop-1.18/ntop.c' &&
chmod 0644 'ntop-1.18/ntop.c' ||
echo 'restore of ntop-1.18/ntop.c failed'
shar_count="`wc -c < 'ntop-1.18/ntop.c'`"
test 14094 -eq "$shar_count" ||
echo "ntop-1.18/ntop.c: original size 14094, current size $shar_count"
fi
# ============= ntop-1.18/kmem.c ==============
if test -f 'ntop-1.18/kmem.c' && test X"$1" != X"-c"; then
echo 'x - skipping ntop-1.18/kmem.c (File already exists)'
else
echo 'x - extracting ntop-1.18/kmem.c (text)'
sed 's/^X//' << 'SHAR_EOF' > 'ntop-1.18/kmem.c' &&
/*
X * kmemcpy() - copies n bytes from kernel memory into user buffer.
X * returns 0 on success, -1 on error.
X */
X
#include <sys/types.h>
#include <sys/file.h>
X
#define KMEM "/dev/kmem"
X
#ifndef lint
static char sccsid[] = "@(#)kmem.c 1.2 3/10/93 (C) 1992 Darren Reed";
#endif
X
static int kmemfd = -1;
X
int openkmem()
{
X if ((kmemfd = open(KMEM,O_RDONLY)) == -1)
X {
X perror("kmeminit:open");
X return -1;
X }
X return kmemfd;
}
X
int kmemcpy(buf, pos, n)
register char *buf;
long pos;
register int n;
{
X register int r;
X
X if (!n)
X return 0;
X if (kmemfd == -1)
X if (openkmem() == -1)
X return -1;
X if (lseek(kmemfd, pos, 0) == -1)
X {
X perror("kmemcpy:lseek");
X return -1;
X }
X while ((r = read(kmemfd, buf, n)) < n)
X if (r <= 0)
X {
X perror("kmemcpy:read");
X return -1;
X }
X else
X {
X buf += r;
X n -= r;
X }
X return 0;
}
SHAR_EOF
$shar_touch -am 0904160293 'ntop-1.18/kmem.c' &&
chmod 0644 'ntop-1.18/kmem.c' ||
echo 'restore of ntop-1.18/kmem.c failed'
shar_count="`wc -c < 'ntop-1.18/kmem.c'`"
test 866 -eq "$shar_count" ||
echo "ntop-1.18/kmem.c: original size 866, current size $shar_count"
fi
# ============= ntop-1.18/file.c ==============
if test -f 'ntop-1.18/file.c' && test X"$1" != X"-c"; then
echo 'x - skipping ntop-1.18/file.c (File already exists)'
else
echo 'x - extracting ntop-1.18/file.c (text)'
sed 's/^X//' << 'SHAR_EOF' > 'ntop-1.18/file.c' &&
#include "ntop.h"
X
#ifndef lint
static char sccsid[]="@(#)file.c 1.3 4/17/94 (C)opyright 1992 Darren Reed";
#endif
X
#if BSD >= 199103
# include <sys/kinfo.h>
# include <sys/kinfo_proc.h>
# ifndef __NetBSD__
# include <sys/sysinfo.h>
# endif
#endif
X
extern int kmemcpy();
X
static int finit;
static struct file *filetable;
static short ftype, nftype;
static u_long fvalue, nfvalue;
#if defined(__hpux) || (BSD < 199103)
struct file *filebase;
#endif
int nfiles;
X
static int init_file()
{
X nftype = name_list[NL_NFILE].n_type;
X nfvalue = name_list[NL_NFILE].n_value;
#if defined(__hpux) || (BSD < 199103)
X ftype = name_list[NL_FILE].n_type;
X fvalue = name_list[NL_FILE].n_value;
#endif
X finit = 1;
X return 0;
}
X
/*
X * struct file *getfiletable() returns a pointer to a copy of the file table.
X * myfile is the base of the file table in real kernel memory
X */
struct file *getfiletable()
{
X int size;
X
X if (!finit)
X init_file();
X
X if (kmemcpy((char *)&nfiles, nfvalue, sizeof(nfiles)) == -1)
X bye(-1, "nfvalue = %x", nfvalue);
#if defined(__hpux) || (BSD < 199103)
X if (kmemcpy((char *)&filebase, fvalue, sizeof(filebase))==-1)
X bye(-1, "fvalue = %x", fvalue);
X size = (sizeof(struct file) * nfiles);
#else
X size = getkerninfo(KINFO_FILE, NULL, NULL, 0);
#endif
X
X if (filetable)
X MyFree((char *)filetable);
X
X filetable = (struct file *)MyMalloc(size);
X
#if defined(__hpux) || (BSD < 199103)
X if (kmemcpy((char *)filetable, filebase,
X sizeof(struct file) * nfiles) == -1)
X bye(-1, "filetable = %x", filetable);
X return filetable;
#else
X tmp = getkerninfo(KINFO_FILE, filetable, &size, 0);
X if (tmp != size)
X {
X fprintf(stderr, "getkerninfo(): %d != %d\r\n", tmp, size);
X exit(-1);
X }
X nfiles = (size - sizeof(struct file *)) / sizeof(struct file);
X return (struct file *)((struct file **)filetable + 1);
#endif
}
X
void filetableclean()
{
X MyFree(filetable);
X filetable = NULL;
}
X
X
/*
X * getfcred() - returns pointer to the ucred structure for the given open file
X */
X
static struct ucred uc;
X
struct ucred *getfcred(f)
register struct file *f;
{
X if (kmemcpy((char *)&uc, f->f_cred, sizeof(uc)) == -1)
X bye(-1, stderr, "f_cred = x%x", f->f_cred);
X return &uc;
}
SHAR_EOF
$shar_touch -am 0416225394 'ntop-1.18/file.c' &&
chmod 0644 'ntop-1.18/file.c' ||
echo 'restore of ntop-1.18/file.c failed'
shar_count="`wc -c < 'ntop-1.18/file.c'`"
test 2179 -eq "$shar_count" ||
echo "ntop-1.18/file.c: original size 2179, current size $shar_count"
fi
# ============= ntop-1.18/auth.c ==============
if test -f 'ntop-1.18/auth.c' && test X"$1" != X"-c"; then
echo 'x - skipping ntop-1.18/auth.c (File already exists)'
else
echo 'x - extracting ntop-1.18/auth.c (text)'
sed 's/^X//' << 'SHAR_EOF' > 'ntop-1.18/auth.c' &&
#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
X
#ifndef lint
static char sccsid[] = "@(#)auth.c 1.10 4/17/94 (C)1993 Darren Reed";
#endif
X
typedef struct authcache {
X struct authcache *ac_next;
X u_long ac_fa, ac_la;
X short ac_fp, ac_lp;
X int ac_touch;
X char ac_name[9];
} AuthCache;
X
void expireAuthCache();
X
static AuthCache *actop = NULL;
static char *scancache();
static void addtocache();
X
char *getauthname(fa, fp, la, lp)
u_long fa, la;
u_short fp, lp;
{
X static char namebuf[80];
X struct sockaddr_in rem;
X struct timeval tv;
X fd_set rd;
X char qbuf[50];
X char *s, *cl;
X int fd, len, n, foo, flag;
X
X if ((cl = scancache(fa, fp, la, lp)))
X return cl;
X bzero((char *)&rem, sizeof(rem));
X rem.sin_family = AF_INET;
X rem.sin_addr.s_addr = fa;
X rem.sin_port = htons(113);
X
X if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
X return NULL;
X (void) alarm(2);
X if (connect(fd, (struct sockaddr *)&rem, sizeof(rem)) == -1) {
X flag = (errno == ECONNREFUSED) ? -1 : -2;
X (void)alarm(0);
X (void)close(fd);
X (void)strcpy(namebuf, "?");
X /*
X * negative caching
X */
X addtocache(fa, 0, la, 0, namebuf, flag);
X return namebuf;
X }
X (void)alarm(0);
X
X (void)sprintf(qbuf, "%hu , %hu\r\n", ntohs(fp), ntohs(lp));
X len = strlen(qbuf);
X n = 0;
X s = qbuf;
X
X while (len && (n = write(fd, s, len)) >= 0)
X {
X len -= n;
X s += n;
X }
X
X len = sizeof(qbuf);
X s = qbuf;
X
X *namebuf = '\0';
X do
X {
X tv.tv_usec = 0;
X tv.tv_sec = 2;
X FD_ZERO(&rd);
X FD_SET(fd, &rd);
X if (select(NFDBITS, &rd, NULL, NULL, &tv) == 1 &&
X FD_ISSET(fd, &rd) && (n = read(fd, s, len)) > 0)
X {
X len -= n;
X s += n;
X *s = '\0';
X }
X else
X {
X (void)close(fd);
X len = 0;
X }
X } while (len > 0);
X (void)close(fd);
X
X if ((s = (char *)index(qbuf, '\r')))
X *s = '\0';
X if ((s = (char *)index(qbuf, '\n')))
X *s = '\0';
X
X if (sscanf(qbuf,"%d , %d : USERID :%*[^:]: %s",
X &foo, &foo, namebuf) != 3)
X (void)strcpy(namebuf, "?");
X addtocache(fa, fp, la, lp, namebuf, 0);
X return namebuf;
}
X
static char *scancache(fa, fp, la, lp)
register u_long fa, la;
register short fp, lp;
{
X register AuthCache *ap;
X
X for (ap = actop; ap; ap = ap->ac_next)
X if (fa == ap->ac_fa && (!ap->ac_fp || fp == ap->ac_fp) &&
X la == ap->ac_la && lp == ap->ac_lp) {
X if (ap->ac_fp)
X ap->ac_touch = 2;
X return ap->ac_name;
X }
X return NULL;
}
X
void expireAuthCache()
{
X register AuthCache *ap, **app;
X
X for (app = &actop; *app; ) {
X ap = *app;
X if (!--ap->ac_touch) {
X *app = ap->ac_next;
X (void)free((char *)ap);
X } else
X app = &((*app)->ac_next);
X }
}
X
static void addtocache(fa, fp, la, lp, namebuf, flag)
register u_long fa, la;
register short fp, lp;
char *namebuf;
int flag;
{
X register AuthCache *ap;
X
X ap = (AuthCache *)malloc(sizeof(AuthCache));
X ap->ac_fa = fa;
X if (!(ap->ac_fp = fp)) {
X if (flag == -1)
X ap->ac_touch = 0;
X else
X ap->ac_touch = 61;
X } else
X ap->ac_touch = 2;
X ap->ac_la = la;
X ap->ac_lp = lp;
X (void)strncpy(ap->ac_name, namebuf, 9);
X ap->ac_name[8] = '\0';
X ap->ac_next = actop;
X actop = ap;
}
SHAR_EOF
$shar_touch -am 0416224994 'ntop-1.18/auth.c' &&
chmod 0644 'ntop-1.18/auth.c' ||
echo 'restore of ntop-1.18/auth.c failed'
shar_count="`wc -c < 'ntop-1.18/auth.c'`"
test 3142 -eq "$shar_count" ||
echo "ntop-1.18/auth.c: original size 3142, current size $shar_count"
fi
# ============= ntop-1.18/unix.c ==============
if test -f 'ntop-1.18/unix.c' && test X"$1" != X"-c"; then
echo 'x - skipping ntop-1.18/unix.c (File already exists)'
else
echo 'x - extracting ntop-1.18/unix.c (text)'
sed 's/^X//' << 'SHAR_EOF' > 'ntop-1.18/unix.c' &&
#include <curses.h>
#include "ntop.h"
#include <pwd.h>
#ifdef __hpux
#include <termio.h>
#else
#include <sgtty.h>
#endif
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/un.h>
#include <sys/unpcb.h>
#ifdef __osf__
#include <sys/vnode.h>
#endif
X
#ifndef lint
static char sccsid[] = "@(#)unix.c 1.5 4/17/94 (C) 1993 Darren Reed";
#endif
X
extern NetL *ntop, first;
extern struct ucred *getfcred();
extern int dolist;
X
X
struct file **getunix(sfs, sfssize)
struct file **sfs;
int sfssize;
{
X static struct protosw *unixsw = NULL;
X struct file *fp;
X struct socket *sa, *sp, *sp2;
X struct ucred *uc;
X struct unpcb upcb, *unp = &upcb, con, *cnp = &con;
X struct mbuf mb, *m = &mb;
X struct sockaddr_un *su;
X NetL *net, *n;
X int i, j;
X
X su = (struct sockaddr_un *)m->m_dat;
X if (!unixsw)
X unixsw = (struct protosw *)name_list[NL_UNIXSW].n_value;
X sa = (struct socket *)malloc(sizeof(*sa) * sfssize);
X for (sp = sa, i = sfssize - 1; i >= 0; i--, sp++)
X if ((fp = sfs[i])->f_type == DTYPE_SOCKET)
X (void) kmemcpy((char *)sp, (long)fp->f_data,
X sizeof(*sp));
X
X for (i = sfssize - 1, sp = sa; i >= 0; i--, sp++)
X {
X fp = sfs[i];
X if (fp->f_type != DTYPE_SOCKET)
X continue;
X if ((sp->so_proto < unixsw || sp->so_proto > unixsw + 2) ||
X !sp->so_pcb || sp->so_type != SOCK_STREAM)
X continue;
X if (!(uc = getfcred(fp)))
X continue;
X
X if (kmemcpy((char *)unp, (long)sp->so_pcb, sizeof(*unp))==-1)
X bye(-1, "sp->so_pcb : %#x", sp->so_pcb);
X if (!unp->unp_conn || !unp->unp_addr)
X continue;
X for (n = ntop; n; n = n->next)
X if ((n->fin.s_addr == (u_long)sp->so_pcb) &&
X (n->lin.s_addr == (u_long)unp->unp_conn))
X break;
X if (n)
X continue;
X
X net = (NetL *)MyMalloc(sizeof(*net));
X bzero((char *)net, sizeof(*net));
X *net->path = '\0';
X *su->sun_path = '\0';
X net->fin.s_addr = (u_long)unp->unp_conn;
X net->lin.s_addr = (u_long)sp->so_pcb;
X net->fuid = 65534;
X net->age = 1;
X (void) strcpy(net->name, get_username(uc->cr_ruid));
X net->family = AF_UNIX;
X net->uid = uc->cr_ruid;
X net->next = ntop->next;
X ntop->next = net;
X ntop = net;
X
X if (unp->unp_addr)
X {
X if (kmemcpy((char *)m, unp->unp_addr, sizeof(m))==-1)
X bye(-1, "unp->unp_addr : %#x", unp->unp_addr);
X
X if (m->m_len > sizeof(su->sun_family))
X {
X m->m_len -= sizeof(su->sun_family);
X if (m->m_len > sizeof(su->sun_path))
X continue; /* XXX - hack */
X su->sun_path[m->m_len] = '\0';
X (void) strncpy(net->path, su->sun_path,
X NETPATHLEN);
X net->path[NETPATHLEN] = '\0';
X }
X else
X *m->m_dat = '\0';
X }
X
X if (!unp->unp_addr && unp->unp_conn)
X {
X if (kmemcpy((char *)cnp, unp->unp_conn,
X sizeof(*unp)) == -1)
X bye(-1, "unp->unp_conn : %#x", unp->unp_conn);
X if (cnp->unp_addr && kmemcpy((char *)m, cnp->unp_addr,
X sizeof(*m)) == -1)
X bye(-1, "cnp->unp_addrc: %#x", cnp->unp_addr);
X
X if (m->m_len > sizeof(su->sun_family))
X {
X m->m_len -= sizeof(su->sun_family);
X if (m->m_len > sizeof(su->sun_path))
X continue; /* XXX - hack */
X su->sun_path[m->m_len] = '\0';
X (void) strncpy(net->path, su->sun_path,
X NETPATHLEN);
X net->path[NETPATHLEN] = '\0';
X }
X else
X *m->m_dat = '\0';
X /*
X ** get the uid of the other side
X */
X for (sp2 = sa, j = sfssize - 1; j >= 0; j--, sp2++)
X {
X fp = sfs[j];
X if (fp->f_type != DTYPE_SOCKET)
X continue;
X if (sotounpcb(sp2) != unp->unp_conn)
X continue;
X if (!(uc = getfcred(fp)))
X continue;
X net->fuid = uc->cr_ruid;
X break;
X }
X }
X }
X (void) free((char *)sa);
X return sfs;
}
X
void printunix(np)
NetL *np;
{
X if (dolist)
X (void) printf("%8.8s <-> %8.8s : %-.50s\n",
X np->name, get_username(np->fuid), np->path);
X else
X {
X printw("%8.8s <-> %8.8s : %-50.50s\n",
X np->name, get_username(np->fuid), np->path);
X refresh();
X }
}
SHAR_EOF
$shar_touch -am 0416225494 'ntop-1.18/unix.c' &&
chmod 0644 'ntop-1.18/unix.c' ||
echo 'restore of ntop-1.18/unix.c failed'
shar_count="`wc -c < 'ntop-1.18/unix.c'`"
test 3868 -eq "$shar_count" ||
echo "ntop-1.18/unix.c: original size 3868, current size $shar_count"
fi
# ============= ntop-1.18/cache.c ==============
if test -f 'ntop-1.18/cache.c' && test X"$1" != X"-c"; then
echo 'x - skipping ntop-1.18/cache.c (File already exists)'
else
echo 'x - extracting ntop-1.18/cache.c (text)'
sed 's/^X//' << 'SHAR_EOF' > 'ntop-1.18/cache.c' &&
#include <pwd.h>
#include "ntop.h"
X
#ifndef lint
static char sccsid[] = "@(#)cache.c 1.2 4/17/94 (C) 1992 Darren Reed";
#endif
X
typedef struct cache {
X struct cache *next, *prev;
X long cac_num;
X char cac_name[1];
} Cache;
X
static Cache pfirst, *ports = &pfirst; /* list of port service names */
static Cache ufirst, *uids = &ufirst; /* list of username->uid mappings */
static Cache hfirst, *htop = &hfirst; /* list of IP#->hostname mappings */
X
static void load_services(), move_to_front();
char *get_portname(), *get_username(), *get_hostname();
X
extern char *MyMalloc();
extern int resolv;
X
/*
** Use the move-to-front heuristic on all linked-list based caches to
** increase the speed on lookup of 'popular' entries.
*/
static void move_to_front(ptr, top)
Cache *ptr, **top;
{
X if (ptr != *top) /* move to front of list */
X {
X if (ptr->prev)
X ptr->prev->next = ptr->next;
X if (ptr->next)
X ptr->next->prev = ptr->prev;
X ptr->prev = (*top)->prev;
X (*top)->prev = ptr;
X ptr->next = *top;
X *top = ptr;
X }
}
X
/*
X * search for a port number in the loaded list of defined services.
X * its name is returned if it is loaded else a ascii nu,ber is returned
X * for the name.
X */
char *get_portname(port, name, len)
char *name;
u_short port;
u_int len;
{
X register Cache *ptr;
X
X for (ptr = ports; ptr; ptr = ptr->next)
X if (port == ptr->cac_num)
X {
X move_to_front(ptr, &ports);
X (void) strncpy(name, ptr->cac_name, len);
X return name;
X }
X
X (void) sprintf(name, "%hu", ntohs(port));
X
X return name;
}
X
/*
X * Build cache of user names on the fly.
X * uid's are used for names if no real name entry is found.
X */
char *get_username(uid)
int uid;
{
X static char name[40];
X register Cache *ptr;
X struct passwd *pw;
X
X for (ptr = uids; ptr; ptr = ptr->next)
X if (uid == ptr->cac_num && *ptr->cac_name)
X {
X move_to_front(ptr, &uids);
X (void) strncpy(name, ptr->cac_name, sizeof(name));
X return name;
X }
X if ((pw = getpwuid(uid)))
X (void) strncpy(name, pw->pw_name, sizeof(name));
X else
X (void) sprintf(name,"%d", uid);
X ptr = (Cache *)MyMalloc(strlen(name)+sizeof(Cache));
X (void) strcpy(ptr->cac_name, name);
X ptr->cac_num = uid;
X ptr->next = uids;
X uids->prev = ptr;
X uids = ptr;
X
X return name;
}
X
/*
X * cache hostname queries! this is a huge saver.
X * If resolving has been turned off then dont make any queries or search
X * cache or make any aleterations to the cache.
X */
char *get_hostname(addr, name, len)
long addr;
char *name;
int len;
{
X static char myname[32];
X static int mylen = 0;
X register Cache *ptr;
X struct hostent *hp = NULL;
X unsigned char *ad;
X char *s;
X
X if (!*myname)
X {
X (void) gethostname(myname, sizeof(myname));
X mylen = strlen(myname);
X }
X
X if (resolv)
X for (ptr = htop; ptr; ptr = ptr->next)
X if (ptr->cac_num == addr)
X {
X move_to_front(ptr, &htop);
X (void) strncpy(name, ptr->cac_name,len);
X return name;
X }
X
X if (resolv)
X if ((hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET)))
X {
X if (!strncasecmp(myname, hp->h_name, mylen))
X if ((s = (char *)index(hp->h_name, '.')))
X *s = '\0';
X (void) strncpy(name, hp->h_name, len);
X }
X if (!hp || !resolv)
X {
X ad = (unsigned char *)&addr;
X (void) sprintf(name,"%u.%u.%u.%u",
X (unsigned) ad[0],(unsigned) ad[1],
X (unsigned) ad[2],(unsigned) ad[3]);
X }
X
X if (resolv)
X {
X ptr = (Cache *)MyMalloc(strlen(name)+sizeof(Cache));
X (void) strcpy(ptr->cac_name, name);
X ptr->cac_num = addr;
X ptr->next = htop;
X htop->prev = ptr;
X htop = ptr;
X }
X return name;
}
X
X
static void load_services()
{
X register Cache *ptmp, *ptmp2;
X register struct servent *serv;
X
X /*
X * free up old cache list.
X */
X if (ports != &pfirst)
X for (ptmp = ports; ptmp != &pfirst; ptmp = ptmp2)
X {
X ptmp2 = ptmp->next;
X (void) free(ptmp);
X }
X
X setservent(1);
X /*
X ** Load service name list this way since the list of names in
X ** /etc/services is a constant size compared to the range of
X ** port numbers available.
X */
X while ((serv = getservent()))
X {
X if (strcasecmp(serv->s_proto,"tcp"))
X continue;
X ptmp = (Cache *)MyMalloc(strlen(serv->s_name) +
X sizeof(Cache));
X bzero(ptmp, sizeof(Cache));
X (void) strcpy(ptmp->cac_name, serv->s_name);
X ptmp->cac_num = serv->s_port;
X ptmp->next = ports;
X ports->prev = ptmp;
X ports = ptmp;
X }
}
X
void init_caches()
{
X bzero((char *)ports, sizeof(*ports));
X bzero((char *)uids, sizeof(*uids));
X bzero((char *)htop, sizeof(*htop));
X load_services();
}
SHAR_EOF
$shar_touch -am 0416225194 'ntop-1.18/cache.c' &&
chmod 0644 'ntop-1.18/cache.c' ||
echo 'restore of ntop-1.18/cache.c failed'
shar_count="`wc -c < 'ntop-1.18/cache.c'`"
test 4498 -eq "$shar_count" ||
echo "ntop-1.18/cache.c: original size 4498, current size $shar_count"
fi
# ============= ntop-1.18/bsd.c ==============
if test -f 'ntop-1.18/bsd.c' && test X"$1" != X"-c"; then
echo 'x - skipping ntop-1.18/bsd.c (File already exists)'
else
echo 'x - extracting ntop-1.18/bsd.c (text)'
sed 's/^X//' << 'SHAR_EOF' > 'ntop-1.18/bsd.c' &&
#ifndef __NetBSD__
#include <curses.h>
#endif
#include <pwd.h>
#ifdef __hpux
#include <termio.h>
#else
#include <sgtty.h>
#endif
#include "ntop.h"
#ifdef __NetBSD__
#include <curses.h>
#endif
#include <sys/un.h>
#include <net/route.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/in_pcb.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp_timer.h>
#include <netinet/icmp_var.h>
#include <netinet/ip_var.h>
#ifdef __osf__
#include <netinet/tcpip.h>
#endif
#include <netinet/tcp_var.h>
X
#ifndef lint
static char sccsid[] = "@(#)bsd.c 1.6 4/17/94 (C) 1992 Darren Reed";
#endif
X
extern NetL first, *ntop;
struct winsize wsz;
X
#define NETSZ (sizeof(NetL))
X
struct file **buildtcplist();
X
extern int nfiles, zeroed;
extern char *getenv(), *getauthname(), *MyMalloc();
extern struct inpcb *next_inpb();
extern struct file *getfiletable(), **getunix();
extern struct ucred *getfcred();
extern void expireAuthCache(), normal(), resize();
X
extern int offset, resolv, seconds, finishit, winsize;
extern int number, list;
extern int doauth, dolist, dounix, showclose;
extern u_long invalue;
X
static struct icmpstat icmps, icmpso;
static struct ipstat ips, ipso;
static struct tcpstat tcps, tcpso;
static struct file **sfsarray = NULL;
static int zeroed = 0;
X
struct nlist name_list[] = {
#ifdef __hpux
X { "tcb" },
X { "udb" },
X { "unixsw" },
X { "icmpstat" },
X { "ipstat" },
X { "tcpstat" },
X { "nfile" },
X { "file" },
#else
X { "_tcb" },
X { "_udb" },
X { "_unixsw" },
X { "_icmpstat" },
X { "_ipstat" },
X { "_tcpstat" },
# if BSD >= 199103
X { "_nfiles" },
# else
X { "_nfile" },
X { "_file" },
# endif
#endif
X { NULL } };
X
#ifdef __hpux
# define _PATH_KERNEL "/hp-ux"
#else
# if BSD >= 199103
# include <paths.h>
# else
# define _PATH_KERNEL "/vmunix"
# endif
#endif
#if !defined(_PATH_KERNEL) && defined(_PATH_UNIX)
# define _PATH_KERNEL _PATH_UNIX
#endif
X
void setupsystem()
{
X int n;
X
X switch (n = nlist(_PATH_KERNEL, name_list)) {
X case -1:
X perror("nlist()");
X exit(1);
X case 0:
X /* all is well */
X break;
X default:
X fprintf(stderr, "nlist returned %d\n", n);
X exit(-1);
X }
X
X if (!dolist)
X {
X initscr();
X resize();
X
X (void) signal(SIGQUIT, normal);
X (void) signal(SIGINT, normal);
X (void) signal(SIGTERM, normal);
X (void) signal(SIGWINCH, resize);
X }
}
X
X
static NetL *lastN = (NetL *)NULL;
X
static NetL *findSock(fa, la, fp, lp)
u_long fa, la;
u_short fp, lp;
{
X register NetL *n;
X
X for (n = lastN->next; n; n = n->next)
X if ((la == n->lin.s_addr) && (lp == n->lp) &&
X (fa == n->fin.s_addr) && (fp == n->fp))
X {
X lastN = n;
X return n;
X }
X return (NetL *)NULL;
}
X
X
/*
X * read kmem and build a list of tcp sockets
X */
struct file **buildtcplist()
{
X register struct inpcb *inp = (struct inpcb *)NULL;
X register struct file *ft, *fp, **sfs;
X register NetL *net, *tmp;
X register int i;
X struct socket sock;
X struct ucred *uc;
X struct tcpcb tcpb;
X u_long faddr, laddr;
X short fport, lport;
X int numsfs;
X
X lastN = ntop = &first;
X
X if (!(ft = getfiletable()))
X bye(1, "error reading file table!");
X
X if (sfsarray)
X MyFree(sfsarray);
X sfs = sfsarray = (struct file **)MyMalloc(sizeof(int) * nfiles);
X
X /*
X * get some statistics :-)
X */
X (void) kmemcpy(&icmps, name_list[NL_ICMPS].n_value, sizeof(icmps));
X (void) kmemcpy(&tcps, name_list[NL_TCPS].n_value, sizeof(tcps));
X (void) kmemcpy(&ips, name_list[NL_IPS].n_value, sizeof(ips));
X
X for (fp = ft, numsfs = 0; fp < ft + nfiles; fp++)
X if (fp->f_count && fp->f_type == DTYPE_SOCKET)
X sfs[numsfs++] = fp;
X
X if (dounix)
X return getunix(sfs, numsfs);
X
X /*
X * Walk along list of protocol header structures in the kernel
X */
X while ((inp = next_inpb(inp)))
X {
X /*
X * No socket, and no protocol control block...next!
X */
X if (!inp->inp_socket || !inp->inp_ppcb)
X continue;
X for (i = 0, uc = NULL; i < numsfs; i++)
X if ((fp = sfs[i])->f_data == (char *)inp->inp_socket)
X {
X sfs[i] = sfs[--numsfs];
X if ((uc = getfcred(fp)))
X break;
X }
X
X faddr = inp->inp_faddr.s_addr;
X laddr = inp->inp_laddr.s_addr;
X fport = inp->inp_fport;
X lport = inp->inp_lport;
X
X if ((net = findSock(faddr, laddr, fport, lport)))
X {
X if (kmemcpy(&tcpb, inp->inp_ppcb,
X sizeof(struct tcpcb)) == -1)
X bye(-1, "inp->inp_ppcb %x", inp->inp_ppcb);
X if (!showclose && tcpb.t_state > TCPS_ESTABLISHED)
X continue;
X net->age = 1;
X net->state = tcpb.t_state;
X net->sr = tcpb.snd_nxt - net->snd;
X net->rr = tcpb.rcv_nxt - net->rcv;
X net->snd = tcpb.snd_nxt;
X net->rcv = tcpb.rcv_nxt;
X net->idle = tcpb.t_idle;
X continue;
X }
X
X if (faddr == laddr)
X {
X /*
X ** search for this connection elsewhere in list
X */
X for (tmp = ntop; tmp; tmp = tmp->next)
X if (faddr == tmp->lin.s_addr &&
X fport == tmp->lp &&
X laddr == tmp->fin.s_addr &&
X lport == tmp->fp)
X break;
X
X if (tmp)
X {
X tmp->fuid = uc->cr_ruid;
X continue;
X }
X }
X
X if (kmemcpy(&sock, inp->inp_socket, sizeof(struct socket))==-1)
X bye(-1, "inp->socket %x", inp->inp_socket);
X if (sock.so_type != SOCK_STREAM || sock.so_state & SS_NOFDREF)
X continue;
X
X if (kmemcpy(&tcpb, inp->inp_ppcb, sizeof(struct tcpcb))==-1)
X bye(-1, "inp->inp_ppcb %x", inp->inp_ppcb);
X
X if (tcpb.t_state != TCPS_LISTEN)
X {
X if (tcpb.t_state < TCPS_ESTABLISHED)
X continue;
X if (!showclose && tcpb.t_state != TCPS_ESTABLISHED)
X continue;
X }
X
X net = (NetL *)MyMalloc(NETSZ);
X bzero((char *)net, NETSZ);
X net->fin.s_addr = faddr;
X net->family = AF_INET;
X net->lin.s_addr = laddr;
X net->lp = inp->inp_lport;
X net->fp = inp->inp_fport;
X net->uid = uc->cr_ruid;
X net->state = tcpb.t_state;
X net->snd = tcpb.snd_nxt;
X net->rcv = tcpb.rcv_nxt;
X net->idle = tcpb.t_idle;
X net->next = ntop->next;
X net->sr = net->rr = 0;
X net->age = 1;
X *net->name = '\0';
X (void) strcpy(net->name, get_username(net->uid));
X ntop->next = net;
X ntop = net;
X }
X
X return sfs;
}
X
X
void initstats()
{
X bzero((char*)&ips, sizeof(ips));
X bzero((char*)&ipso, sizeof(ipso));
X bzero((char*)&tcps, sizeof(tcps));
X bzero((char*)&tcpso, sizeof(tcpso));
X bzero((char*)&icmps, sizeof(icmps));
X bzero((char*)&icmpso, sizeof(icmpso));
}
X
X
void printstats()
{
X if (zeroed)
X {
X int i;
X
X tcps.tcps_sndtotal -= tcpso.tcps_sndtotal;
X tcps.tcps_sndbyte -= tcpso.tcps_sndbyte;
X tcps.tcps_rcvtotal -= tcpso.tcps_rcvtotal;
X tcps.tcps_rcvbyte -= tcpso.tcps_rcvbyte;
X tcps.tcps_accepts -= tcpso.tcps_accepts;
X tcps.tcps_connects -= tcpso.tcps_connects;
X tcps.tcps_closed -= tcpso.tcps_closed;
X ips.ips_total -= ipso.ips_total;
X icmps.icps_error -= icmpso.icps_error;
X
X for (i = 0; i < ICMP_MAXTYPE; i++)
X {
X icmps.icps_inhist[i] -= icmpso.icps_inhist[i];
X icmps.icps_outhist[i] -= icmpso.icps_outhist[i];
X }
X }
X
X printw("IP Pkts %10lu ICMP %lu ", ips.ips_total, icmps.icps_error);
X printw("I/O ER %ld/%ld UR %ld/%ld SQ %ld/%ld\n\
TCP Ac %lu Es %lu Cl %lu\t RD %ld/%ld EC %ld/%ld TX %ld/%ld\n",
X icmps.icps_inhist[ICMP_ECHOREPLY],
X icmps.icps_outhist[ICMP_ECHOREPLY],
X icmps.icps_inhist[ICMP_UNREACH],
X icmps.icps_outhist[ICMP_UNREACH],
X icmps.icps_inhist[ICMP_SOURCEQUENCH],
X icmps.icps_outhist[ICMP_SOURCEQUENCH],
X tcps.tcps_accepts, tcps.tcps_connects, tcps.tcps_closed,
X icmps.icps_inhist[ICMP_REDIRECT],
X icmps.icps_outhist[ICMP_REDIRECT],
X icmps.icps_inhist[ICMP_ECHO],
X icmps.icps_outhist[ICMP_ECHO],
X icmps.icps_inhist[ICMP_TIMXCEED],
X icmps.icps_outhist[ICMP_TIMXCEED]);
X printw("Snd %10lu/%10lu Rcv %10lu/%10lu\n",
X tcps.tcps_sndtotal, tcps.tcps_sndbyte,
X tcps.tcps_rcvtotal, tcps.tcps_rcvbyte);
}
X
X
void zerostats()
{
X zeroed = 1;
X (void) kmemcpy(&ipso, name_list[NL_IPS].n_value, sizeof(ipso));
X (void) kmemcpy(&tcpso, name_list[NL_TCPS].n_value, sizeof(tcpso));
X (void) kmemcpy(&icmpso, name_list[NL_ICMPS].n_value, sizeof(icmpso));
}
SHAR_EOF
$shar_touch -am 0416225094 'ntop-1.18/bsd.c' &&
chmod 0644 'ntop-1.18/bsd.c' ||
echo 'restore of ntop-1.18/bsd.c failed'
shar_count="`wc -c < 'ntop-1.18/bsd.c'`"
test 7894 -eq "$shar_count" ||
echo "ntop-1.18/bsd.c: original size 7894, current size $shar_count"
fi
# ============= ntop-1.18/ntop.h ==============
if test -f 'ntop-1.18/ntop.h' && test X"$1" != X"-c"; then
echo 'x - skipping ntop-1.18/ntop.h (File already exists)'
else
echo 'x - extracting ntop-1.18/ntop.h (text)'
sed 's/^X//' << 'SHAR_EOF' > 'ntop-1.18/ntop.h' &&
#include <stdio.h>
#include <nlist.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/user.h>
#define KERNEL
#ifdef __osf__
#define KERNEL_FILE
#endif
#include <sys/file.h>
#undef KERNEL
#ifdef __osf__
#undef KERNEL_FILE
#endif
#include <netinet/in.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
X
#if BSD >= 199103
# define cr_ruid cr_uid
#endif
X
#define NL_TCP 0
#define NL_UDP 1
#define NL_UNIXSW 2
#define NL_ICMPS 3
#define NL_IPS 4
#define NL_TCPS 5
#define NL_NFILE 6
#if defined(__hpux) || (BSD < 199103)
#define NL_FILE 7
#endif
X
extern struct nlist name_list[];
X
#define NETPATHLEN 40
X
typedef struct netlist {
X struct netlist *next;
X struct tcpiphdr *hdr;
X struct tcpcb *cb;
X struct in_addr fin, lin;
X tcp_seq snd, rcv;
X u_long sr, rr;
X int family;
X int uid, fp, lp, state, fuid;
X char name[20];
X u_short idle;
X char path[NETPATHLEN+1];
X char age;
} NetL;
X
#define NETSZ (sizeof(NetL))
X
extern char *get_username();
extern void bye(), MyFree();
SHAR_EOF
$shar_touch -am 1116075396 'ntop-1.18/ntop.h' &&
chmod 0644 'ntop-1.18/ntop.h' ||
echo 'restore of ntop-1.18/ntop.h failed'
shar_count="`wc -c < 'ntop-1.18/ntop.h'`"
test 1094 -eq "$shar_count" ||
echo "ntop-1.18/ntop.h: original size 1094, current size $shar_count"
fi
# ============= ntop-1.18/pcb.c ==============
if test -f 'ntop-1.18/pcb.c' && test X"$1" != X"-c"; then
echo 'x - skipping ntop-1.18/pcb.c (File already exists)'
else
echo 'x - extracting ntop-1.18/pcb.c (text)'
sed 's/^X//' << 'SHAR_EOF' > 'ntop-1.18/pcb.c' &&
#include <fcntl.h>
#include "ntop.h"
#include <net/route.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <errno.h>
X
#ifndef lint
static char sccsid[] = "@(#)pcb.c 1.8 4/17/94 (C) 1992 Darren Reed";
#endif
X
extern int kmemcpy();
X
static int inpinit = 0;
u_long invalue = 0;
struct inpcb *inpcbloc = 0, inp;
X
static int init_inp()
{
X invalue = name_list[NL_TCP].n_value;
X inpinit = 1;
X bzero((char *)&inp, sizeof(inp));
X return 0;
}
X
/*
X * Return a pointer to the next PCB in the list.
X * If we reach the end (or head again) of the list, return NULL.
X * The block we start at is passed, if NULL, start over.
X */
struct inpcb *next_inpb(inpcb)
register struct inpcb *inpcb;
{
X static struct inpcb *pcb;
X register struct inpcb *p = &inp;
X
X if (!inpcb)
X {
X if (!inpinit)
X if (init_inp() == -1)
X return 0;
X if (kmemcpy((char *)p, invalue, sizeof(*p)) == -1)
X bye(-1, "invalue = %x", invalue);
X pcb = (struct inpcb *)invalue;
X return p;
X }
pcb_again:
X inpcbloc = inpcb->inp_next;
X if (inpcbloc == (struct inpcb *)invalue)
X return NULL;
X if (kmemcpy((char *)p, inpcbloc, sizeof(*p)) == -1)
X bye(-1, "inpcbloc = %x", inpcbloc);
X if (p->inp_head != (struct inpcb *)invalue || p->inp_prev != pcb)
X {
X if (kmemcpy((char *)inpcb, pcb, sizeof(*inpcb)) == -1)
X bye(-1, "pcb = %x", invalue);
X goto pcb_again;
X }
X pcb = (struct inpcb *)inpcbloc;
X return p;
}
SHAR_EOF
$shar_touch -am 0416225594 'ntop-1.18/pcb.c' &&
chmod 0644 'ntop-1.18/pcb.c' ||
echo 'restore of ntop-1.18/pcb.c failed'
shar_count="`wc -c < 'ntop-1.18/pcb.c'`"
test 1425 -eq "$shar_count" ||
echo "ntop-1.18/pcb.c: original size 1425, current size $shar_count"
fi
# ============= ntop-1.18/README ==============
if test -f 'ntop-1.18/README' && test X"$1" != X"-c"; then
echo 'x - skipping ntop-1.18/README (File already exists)'
else
echo 'x - extracting ntop-1.18/README (text)'
sed 's/^X//' << 'SHAR_EOF' > 'ntop-1.18/README' &&
X
The idea for ntop came from Daniel Bernstien's "netstatuids" from his
kstuff package of utilities, where it began as just an exercise to port
it to OSx 5.1 and try to understand what was happening.
X
I hope that the code, as presented, isn't too hard to port, I've
successfully compiled it on HP-UX 8, 9 and SunOS 4.1.x. I'm not sure
if it will work on Solaris2, there doesn't seem to be much evidence of
there being a linked list of network connections from the header files
I looked at, and examining the entire file table isn't something I
wanted to do. Thus, it should be fairly easy to run/compile of other
BSDish systems such as Ultrix. If people manage to port it to other
versions of Unix, I'd be more than willing to incorporate any patches
sent (or even patches for bugs :). Hopefully the code is organised in
such a way that would make porting it to uncouth versions of Unix such
as Linux (>;) possible. All operations are done using the symbol table
entries in "/unix" and retrieving them from /dev/kmem so appropriate
priviledges are required to see that it functions correctly.
X
SIGWINCH is handled, where available and ioctl's used to get the window
size rather than relying on termcap.
X
Suggestions on enhancements are also welcome (esp. for a way to make
better use of curses!).
X
Cheers,
Darren
X
avalon@cairo.anu.edu.au
SHAR_EOF
$shar_touch -am 1116075396 'ntop-1.18/README' &&
chmod 0644 'ntop-1.18/README' ||
echo 'restore of ntop-1.18/README failed'
shar_count="`wc -c < 'ntop-1.18/README'`"
test 1343 -eq "$shar_count" ||
echo "ntop-1.18/README: original size 1343, current size $shar_count"
fi
# ============= ntop-1.18/ntop.8 ==============
if test -f 'ntop-1.18/ntop.8' && test X"$1" != X"-c"; then
echo 'x - skipping ntop-1.18/ntop.8 (File already exists)'
else
echo 'x - extracting ntop-1.18/ntop.8 (text)'
sed 's/^X//' << 'SHAR_EOF' > 'ntop-1.18/ntop.8' &&
X.TH ntop 8
X
X.SH NAME
ntop - Host Network information retriever, top-style.
X
X.SH SYNOPSIS
X.B ntop
[-%ahlru] [-o <x>] [-n <x>] [-s <x>] [-w <x>]
X
X.B ntop
-v
X
X.SH OPTIONS
X.TP
X.B \-\%
Select sorting by sum of bytes transmitted and received rather than order in
which connections are read from memory.
X.B \-a
Toggle "auth" checking. When on, will attempt to use the TAP/IDENT
protocol to determine remote user identity. All positive replies are
cached for individual connections as well as negative caching for hosts.
X.TP
X.B \-h
Toggle `head' statistics (TCP/IP/ICMP numbders).
X.TP
X.B \-l
Toggle list option. When set,
X.B ntop
generates a `once through' list and exits.
X.TP
X.B \-n <x>
Sets the
X.B number
of entries to show. If this is larger than will fit (defaults to match the
current window size), the top overlaps.
X.TP
X.B \-o <x>
Sets the display
X.B offset
value to x. This determines how far into the list of TCP connections
X.B ntop
will go before it starts displaying them.
X.TP
X.B \-r
Toggles the `resolve' option, whether hostnames are looked up for IP#'s.
X.TP
X.B \-s <x>
Sets the update rate to
X.B x
seconds.
X.TP
X.B \-u
Toggles the `unix socket' option. When set, only unix domain sockets are
shown, rather than TCP sockets.
X.TP
X.B \-v
Using this option causes
X.B ntop
to print its version number and exit.
X.TP
X.B \-w <x>
Set the
X.B window size
to x lines in height.
X
X.SH DESCRIPTION
X.B ntop
is designed to supplement the presence of
X.B netstat(8)
by providing a system administrator with the means to monitor connections on
their machine in real time. It is not designed to replace
X.B netstat(8)
since it doesn't look at
X.B UDP
(or Unix domain datagram sockets) as they are connectionless and hard to
associate meaning to.
X.LP
When displaying connections in a real-time fashion, each TCP connection will
appear on its own line, showing, in order; "ruser@rhost:rport", the remote
username, hostname and portname; "luser@lhost:lport", the local username,
hostname and portname; bytes received from the remote host and bytes sent to
the remote host during the last update; and the idle time on that TCP
connection, which wraps at 65535, which is displayed as either "seconds",
"Xm" for X minutes or "Xh" for X hours. Bytes sent/received are determined
by examining the change in the sequence/acknowledge numbers as in the
X.B TCP
protocol block and are shown as "0-9999", "0-999K" and "1+M". The top line
is used for displaying the current time plus a few details about the
current display. Using the 'j' and 'k' keys, it is possible to change
the offset from the top of the display list.
X
The local hostname is usually the `hostname' of the machine itself, but may be
"localhost". The port name is looked up from
X.B /etc/services
and if not found, the number is used instead. The port number/name mapping
database is read in from
X.B /etc/services
when
X.B ntop
starts up and used as a cache from then on. Usernames and DNS lookups
are also cached to minimize lag time between updates. A negative cache
is used for IDENT to aid in this also on a per host basis, rather than
per connection as is used for positive caching.
X
X.SH FILES
/etc/passwd - used to map uids to usernames
/etc/services - used to map portnumbers to names
/dev/kmem
/vmunix
X
X.SH SEE ALSO
netstat(8)
X.SH BUGS
X.IP
It is possible for ntop to overlook a changed connection, in either the case
of ident reply or local userid if an old connection drops and a new one
appears with the same port numbers at both ends. It may also happen that
a connection may drop during the `critical' time before displaying.
X
SHAR_EOF
$shar_touch -am 1116075396 'ntop-1.18/ntop.8' &&
chmod 0644 'ntop-1.18/ntop.8' ||
echo 'restore of ntop-1.18/ntop.8 failed'
shar_count="`wc -c < 'ntop-1.18/ntop.8'`"
test 3587 -eq "$shar_count" ||
echo "ntop-1.18/ntop.8: original size 3587, current size $shar_count"
fi
# ============= ntop-1.18/CHANGES ==============
if test -f 'ntop-1.18/CHANGES' && test X"$1" != X"-c"; then
echo 'x - skipping ntop-1.18/CHANGES (File already exists)'
else
echo 'x - extracting ntop-1.18/CHANGES (text)'
sed 's/^X//' << 'SHAR_EOF' > 'ntop-1.18/CHANGES' &&
16/4/94:
X - merged patches from Paul Vixie, Arnt Gulbrandsen
X - added some stuff for NetBSD with Matthew Green's help
X - screen updating split printtable() 3 parts:
X updateScreen(), printline(), printonce()
X - added 'Z' to `zero' stats.
X - added 'H' to show/hide column headings
X
vixie:
X - added some casts, removed lint
X - generalized nlist usage
X - ported to BSD/386
John Little:
X - ignores openkmem() return which is bad for tty
X
1.17:
X - created this (CHANGES) file
X - added help screen (hit "?")
X - fixed #include order problem for SunOS4 in unix.c and removed vnode
X - changed authname caching from increasing negative values to
X decreasing +ve ones and expiring at 0
X - auth cache uses different negative cache timeout for ECONNREFUSED and
X EINTR (brought on by timeout)
X - chased bug which causes infinite looping to occur whilst updating the
X network connection list (hopefully caught)
X - fixed up ^L to work correctly
SHAR_EOF
$shar_touch -am 1116075396 'ntop-1.18/CHANGES' &&
chmod 0644 'ntop-1.18/CHANGES' ||
echo 'restore of ntop-1.18/CHANGES failed'
shar_count="`wc -c < 'ntop-1.18/CHANGES'`"
test 937 -eq "$shar_count" ||
echo "ntop-1.18/CHANGES: original size 937, current size $shar_count"
fi
# ============= ntop-1.18/Makefile ==============
if test -f 'ntop-1.18/Makefile' && test X"$1" != X"-c"; then
echo 'x - skipping ntop-1.18/Makefile (File already exists)'
else
echo 'x - extracting ntop-1.18/Makefile (text)'
sed 's/^X//' << 'SHAR_EOF' > 'ntop-1.18/Makefile' &&
CC=cc
#
CFLAGS=-g
#
LIBS=-lcurses -ltermcap
#
#MODE - mode to install ntop as
#
MODE=2711
#
#GROUP - group to install ntop as. Use this if you have /dev/kmem group
# readable to a group like kmem or sys or root rather than use
# setuid root.
#
GROUP=sys
#
#BINDIR - directory to install ntop in
#
BINDIR=/usr/local/bin
#
OBJ=ntop.o pcb.o kmem.o file.o auth.o unix.o cache.o bsd.o
SRC=ntop.c pcb.c kmem.c file.c auth.c unix.c cache.c bsd.c
X
all: ntop
X
ntop: $(OBJ)
X $(CC) $(CFLAGS) $(LDFLAGS) $(OBJ) -o $@ $(LIBS)
X
ntop.o: ntop.c ntop.h
X $(CC) $(CFLAGS) -c ntop.c
X
kmem.o: kmem.c ntop.h
X $(CC) $(CFLAGS) -c kmem.c
X
file.o: file.c ntop.h
X $(CC) $(CFLAGS) -c file.c
X
pcb.o: pcb.c ntop.h
X $(CC) $(CFLAGS) -c pcb.c
X
clean:
X /bin/rm -f *.o ntop core
X
install: all
X install -c -g $(GROUP) -m $(MODE) -s ntop $(BINDIR)
X
tar:
X version=`what ntop.c|tail -1|sed -e 's/[^0-9]*\([0-9.]*\).*/\1/'`; \
X fname=`pwd | sed -e 's/.*\/\([^\/]*\)$$/\1/'`; chdir ..;\
X tar cf - $$fname/ntop.c $$fname/kmem.c $$fname/file.c $$fname/auth.c \
X $$fname/unix.c $$fname/cache.c $$fname/bsd.c $$fname/ntop.h \
X $$fname/pcb.c $$fname/Makefile $$fname/README $$fname/ntop.8 \
X $$fname/CHANGES | compress -c > $$fname$$version.tar.Z; \
X echo "made ../$$fname$$version.tar.Z"
SHAR_EOF
$shar_touch -am 1116075396 'ntop-1.18/Makefile' &&
chmod 0644 'ntop-1.18/Makefile' ||
echo 'restore of ntop-1.18/Makefile failed'
shar_count="`wc -c < 'ntop-1.18/Makefile'`"
test 1258 -eq "$shar_count" ||
echo "ntop-1.18/Makefile: original size 1258, current size $shar_count"
fi
exit 0
-------------cut here--------ntop 1.18-----------------------
This archive was generated by hypermail 2.1.2 : Fri Sep 28 2001 - 23:11:16 CDT