
/*
   * NETWATCH is based on some code from Statnet 
   * Statnet is protected under the GNU Public License (GPL2). 
   * Author: Jeroen Baekelandt (jeroenb@igwe.vub.ac.be)       
   * 27DEC95: Scot E. Wilcoxon (sewilco@fieldday.mn.org)     
   * NETWATCH is VERY loosely based on the code from Statnet... thanks out
   * to Jeroen and Scot...
   * 
   * NETWATCH allows a user (superuser) to monitor an ETHERNET and examine
   * activity on the network. Hostnames are highlighted in colours (for
   * those supporting them) to indicate activity on the bus network based on 
   * time ( less than 1 minute RED, less than 5 minutes YELLOW, less than 30 
   * minutes GREEN and otherwise BLUE). The monitor includes statistics on 
   * a) Transmitted and received packets b) Protocol of LAST packet (TX or
   * RC) c) LAST Communication partner (IP address)
   * 
   * The number of hosts capable of support is a function of memory. They
   * are stored in 2 doubly-linked lists (local and remote).
   * 
   * Screen updates take place 1 per second (unless a rare  lockout... when
   * linked list links are updating... in which case it displays in the next 
   * second)
   * 
   * Keyboard usage is admittedly limited (and a kludge... due to some
   * ncurses settings that need better tinkering) ->   Go forward to next
   * option <-   Go backward to previous option <UP>         Go back to
   * previous page (back 20 lines on most consoles) <DOWN>       Go forward
   * to next page (forward 20 lines on most consoles) c    Clear counters
   * for fresh counting n    Clear linked lists for new start
   * 
   * It is a simple program to execute for ETHERNET under LINUX. It assumes
   * that there is a "/etc/rc.d/rc.inet1" file for network configuration. If 
   * so, it checks for an "eth0" ifconfig and picks up the netmask from the
   * file. UPDATE: It actually looks at the /proc entry for device configuration
   * to get its info... if no /proc THEN it trys the config file (for OLD SL
   * systems)
   * 
   * For those with multiple "eth" interfaces, I am sorry it doesn't support 
   * both simultaneously.
   * 
   * AUTHOR:      G. MacKay E-MAIL:      mackay@gmml.slctech.org
   * 
   * P.S. Given the fact that I was sick for 3 days and decided to write
   * this code... forgive me for not writing beautiful code... (those that
   * know me, probably don't think my code is beautiful when I am healthy)
   * 
   * NEW CODE IS COPYRIGHTED to  G. MacKay   under  GPL 
*/

/*
   * This is the main FILE 
*/
#define MAIN_LINE 1
#include "config.h"

#ifdef NEWCURSES_SUPP
#include <ncurses/curses.h>
#else
#ifdef NEWCURSESROOT_SUPP
#include <ncurses.h>
#else
#include <curses.h>
#endif
#endif

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
/*
   * #include <sys/socket.h> 
*/
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/times.h>
#ifdef NETINET_SUPP_in
#include <netinet/in.h>
#else
#include <linux/in.h>
#endif
#ifdef NETINET_SUPP_if_ether
#include <netinet/if_ether.h>
#else
#include <linux/if_ether.h>
#endif
#include <strings.h>
#include <sys/ioctl.h>

#ifdef NETINET_SUPP_if
#include <net/if.h>
#else
#include <linux/if.h>
#endif
#ifdef NETINET_SUPP_if_ppp
#include <net/if_ppp.h>
#else
#include <linux/if_ppp.h>
#endif

#include <signal.h>
#ifdef NETINET_SUPP_ip
#include <netinet/ip.h>
#else
#include <linux/ip.h>
#endif
#ifdef NETINET_SUPP_tcp
#include <netinet/tcp.h>
#else
#ifdef NETINET_SUPP_ip_tcp
#include <netinet/ip_tcp.h>
#else
#include <linux/tcp.h>
#endif
#endif
#ifdef NETINET_SUPP_udp
#include <netinet/udp.h>
#else
#ifdef NETINET_SUPP_ip_udp
#include <netinet/ip_udp.h>
#else
#include <linux/udp.h>
#endif
#endif
#if NETINET_SUPP_icmp
#include <netinet/ip_icmp.h>
#else
#include <linux/icmp.h>
#endif

#if SYS_IF_PACKET_H
#include <sys/if_packet.h>
#endif
#if LINUX_IF_PACKET_H
#include <linux/if_packet.h>
#endif
#if NET_IF_PACKET_H
#include <net/if_packet.h>
#endif

#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include "curs.h"
#include "netresolv.h"
#include "netwatch.h"

extern int errno;

#define MAXFILENAME 256
char *version = "1.0a";
char *iv = "pre1";
char progtitle[60];
char log[MAXFILENAME] = "/root/.log";
char specconfigfile[MAXFILENAME] = "/root/.netwatch.conf";

int fdlog;
#if defined(_LINUX_IF_ETHER_H) || defined(_NETINET_IF_ETHER_H)
#undef NET_3   /*
   * not using Net/3 definitions 
*/
#endif

#ifndef ETH_HLEN
#define ETH_HLEN 14  /*
   * Ethernet header length 
*/
#endif

#ifndef ETH_P_ATALK
#define ETH_P_ATALK 0x809B /*
   * Appletalk 
*/
#endif

#ifndef SOCK_PACKET
#define SOCK_PACKET SOCK_RAW /*
   * If SOCK_PACKET is wrong, try SOCK_RAW 
*/
#endif

#ifndef NET_3
#define ether_head ethhdr /*
   * ether_head structure 
*/
#define ether_type h_proto /*
   * Ethernet Packet Type ID field 
*/
#define ip  iphdr /*
   * IP header structure 
*/
#define ip_off  frag_off /*
   * IP protocol field 
*/
#define ip_p  protocol /*
   * IP protocol field 
*/
#define ip_hl  ihl /*
   * IP header length field 
*/
#ifndef _NETINET_IP_TCP_H
#ifndef __FAVOR_BSD
#define th_sport source /*
   * TCP source port field 
*/
#define th_dport dest /*
   * TCP destination port field 
*/
#endif
#endif
#ifdef LINUXINET_SUPP_udp

#define ui_sport source /*
   * UDP source port field 
*/
#define ui_dport dest /*
   * UDP destination port field 
*/

#endif
#endif


#define ETHERHEADSIZE (sizeof(struct ether_head))
int ethsz = ETHERHEADSIZE;
#define IPSIZE (sizeof(struct ip))
int ipsz = IPSIZE;
#define IPOPTSIZE 12
int ipoptsz = IPOPTSIZE;
#define TCPHEADSIZE (sizeof(struct tcphdr))
int tcpheadsz = TCPHEADSIZE;
#define SN_RCV_BIGBUFSIZE 2048
/*
   #define SN_RCV_BIGBUFSIZE SN_RCV_BUF_SIZE+80
   * above was 1600, but kernel discards 
*/
/*
   * excess and tells us full length,   
*/
/*
   * so we only need enough to analyze. 
*/
const int sn_rcv_bufsize = SN_RCV_BIGBUFSIZE;
int ESCON = 0;
#define ESC 0x1b
#define RETURNKEY 0x0d
#define CONTROLL  12
#define MAXHELPPAGE 3
HOSTINFO ldummy, rdummy;
HOSTINFO *lfirst, *rfirst, *previous, *current, *next, *work;
struct itimerval newtm, oldtm; /*
   * TIMER for measuring 
*/
time_t new;
time_t starttime;
time_t wakeup_reload;
int wakeup_state = FALSE;
time_t reload_timer_start;
int reload_timer_sec = 0;
int reload_active = FALSE;
int statsdate = FALSE;
int statsappend = TRUE;
char tmstring[80] = "%Y.%m.%d.%H.%M";
int freezedisplay = FALSE;
int lastfreeze = FALSE;
int sentclear = FALSE;
int donecleaning = TRUE;
int recresolv = 0;
int timeresolv = 0;
int sendresolv = 0;
int errread = 0;
int errioctl = 0;

int bpsflag = 0;

#define MAXDAYROUTE 1440
float dayroute[MAXDAYROUTE];
int cur_dayroute = 0;
int routersummary = FALSE;
int rdelta = 60;
int router_offset = 0;

int autostatus = TRUE;
int noresolv = FALSE;

int rel_hours, rel_mins;

int localcount = 0;
int remotecount = 0;

#define MAXSTATUS 14
#define STATUSSIZE 200
char status_lines[MAXSTATUS][STATUSSIZE];
int cur_status_line = 0;

int sREDTIME = 60;
int sYELLOWTIME = 300;
int sGREENTIME = 1800;
char configfile[MAXFILENAME] = "/etc/rc.d/rc.inet1";
char statsfile[MAXFILENAME] = "/etc/netwatch.stats";
char newstatsfile[MAXFILENAME];
int newconfig = FALSE;
char ethdevname[64] = "eth0";
int newethname = FALSE;
int probcnt = 0;  /*
   * Problem Count  on ETH reads 
*/
int intrcnt = 0;  /*
   * EINTR hits  on ETH reads 
*/



#define MAGNABUFSIZE 2048
struct magrec
{
      int len;
      char dir;
      unsigned char buf[MAGNABUFSIZE];
};
#define MAGNAMAX 800
#define MAGNAOFFS 40
struct magrec magna[MAGNAMAX];
int magnacnt = 0;
int magnaoffs = MAGNAOFFS;
char magnamatch[RESOLVE_MAX];
HOSTINFO *magnaspot;
u_int32_t magnakey;
int magnaphys = 0;
int magnafirst = TRUE;
int magnafull = FALSE;
HOSTINFO *magnacomhost = NULL;
u_int32_t magnacomkey;

double maxburst = 0.0;
double absmaxburst = 0.0;
unsigned char netmask[4] = {  255, 255, 255, 0  };
unsigned char localaddr[4];
int ethok = 1;
struct hostent *hostent;
int wai = 0;
int selprob = 0;
int selcode = 0;
int bugfix = FALSE;
int help = FALSE;
int helppage = 1;
int watch = FALSE;
int remoterow = -1;
int localrow = -1;
int localupdate = 0;
int remoteupdate = 0;
int poschange = 0;
int refreshloc = 0;
int refreshrem = 0;
int refreshgen = 0;
int llockout = 0;
int rlockout = 0;
int lydisp = 0;
int rydisp = 0;
int ydisp = 0;
int localkey = TRUE;
int dispopt = DISP_TX_RC;
int colour;
unsigned long int routeruse = 0;
unsigned long int routerto = 0;
unsigned long int routerfrom = 0;
int disprouterstats = FALSE;
int scrmid;
int selecthost = FALSE;
int numselect = 0;
int selectside = 0;
int selectchange = FALSE;
int bluedie = 0;
int ignoredomain = 0;
int statpid = -1010;  /*
   * Magic number to indicate NO
   * status process present 
*/

int sd;

char tmpbuf[256];
char speclogfile[MAXFILENAME] = "/root/.watchlog";
FILE *fpspeclog;
int speclog = 0;
int printtospeclog = 0;
int speclogext = 0;

int topflag = 0;
HOSTINFO *toplocal;
HOSTINFO *topremote;
HOSTINFO tldummy, trdummy;
/*
   * For screen size independent settings.... display... 
*/
int curskeyspot;
int curskeyval;
int cursllockout;
int cursrlockout;
int curslines;
int curshosttrim;
int cursproto;
int cursdest;
int noscreen = 0;
int fishspeclog = 0;  /*
   * old speclog for fishing
   * expedition 
*/

long int ethcnt = 0;
int isethdev = TRUE;
int keycnt = 0;
int repeatcount = 1;
int repeatindex = 0;
char repeatbuf[255];

int isbridge = FALSE;
int dupcount = 0;
int forcelocal = FALSE;
u_int32_t flocal;
int nonameresolve = FALSE;
int forcemask = FALSE;
u_int32_t fmask;
int nokeys = FALSE;

unsigned char workingmac[ETH_ALEN];
/*
   * unsigned char badmac[ETH_ALEN]; 
*/
/*
   * unsigned long badmactime; 
*/

#define SMALLSCREEN 0
#define FULLSCREEN 1

unsigned char buf[SN_RCV_BIGBUFSIZE + 1];
unsigned char rbuf[SN_RCV_BIGBUFSIZE + 1];


struct ifreq ifr, oldifr;
struct sockaddr_in *pin;


struct at_frame_type
{
      unsigned char filler[20];
      u_int16_t appletalk_type1; /*
	 * what is formal name? 
*/
      unsigned char filler2[12];
      u_int8_t appletalk_type2; /*
	 * what is formal name? 
*/
};    /*
   * Ethernet Appletalk 
*/
#define SIM_MAGIC 0xfafa
unsigned short simmagic = SIM_MAGIC;
/*   Simulator file.... STARTING TIME (on creation)
   *   					MAGIC (16 bits)
   *   					PACKET OFFSET TIME (from starting time)
   *   					LENGTH of remainder in bytes
   *   					PACKET Data (Length long)
   *   					MAGIC (16 bits)
   *   					etc...
*/
int simchange = FALSE;
int simfwdir = TRUE;
int simarr[8]= {  4,4,4,4,4,4,4,4  };
char *simfmt = "\\%d<\\%d<\\%d<\\%d%c\\%d>\\%d>\\%d>";
#define MAXTHEM 20
int themnum=0;
u_int32_t logthem[MAXTHEM];  /* Up to 20 log names allowed */
time_t actstart;
struct tms dumbtime;
clock_t sclk;		/* Starting time of program... */
int iseth = FALSE;
int nw_logall = 0;
char nw_allname[256]="/root/nw_allpackets";
FILE *nw_fpall=NULL;
int nw_logremote = 0;
char nw_remname[256]="/root/nw_rempackets";
FILE *nw_fprem=NULL;
int nw_loglocal = 0;
char nw_locname[256]="/root/nw_locpackets";
FILE *nw_fploc=NULL;
int nw_logindiv = 0;
char nw_indivmain[256]="/root/nw_indiv.";
int nw_logselect = 0;
int nw_simulate = 0;
char nw_simfile[256]="";
enum {  SIMSEC, SIMKEY  };
int nw_simrate = SIMSEC;
int simkeyrate = 0;
FILE *simfp=NULL;
int plogselect=0;
int plogdeselect=0;
int buf_detail = 0;  /* For ASCII default */
#define BUF_DETAIL_MAX 3
int mailflag = 1;
int syslogflag = 1;
char userwarn[256] = "noone@xxx.xxx.xxx"; /* ENTER your MAIL Address here.. */
char fishstring[256] = "";
int fishstringlen = 0;
void handle_frame (unsigned char *buf, int length, struct sockaddr *saddr,
   int eth);
void handle_ip (struct ip *buf, int length);
void processinetrc (unsigned char *netmask, unsigned char *local, int *peth);
void warning (char s[], unsigned char *buf);


typedef void (*sigfunc) (int);

static pid_t mypid, child;
int msocket[2];
int osocket[2];
int resolvetimeout = 0;
extern long int timezone;

void
   adjusttime (time_t * pt, int hrs, int mins)
   {
      struct tm tm;
      struct tm *ps;
      time_t v;
      int i, j;

      v = time (0);
      ps = localtime (&v);
      tm = *ps;
      if (hrs < tm.tm_hour - 1 || (hrs == tm.tm_hour - 1 && mins < tm.tm_min - 1))
      {
	 tm.tm_mday++;
      }
      tm.tm_hour = hrs;
      tm.tm_min = mins;
      *pt = mktime (&tm);
/* Adjust to UTC */
   }

void
   processspecconfig ()
   {
      FILE *fp;
      static char w1[140], w2[140], w3[140], w4[140];
      int narg;
      struct in_addr naddr;

      if ((fp = fopen (specconfigfile, "r")))
      {
	 themnum = 0;
	 while ((fgets (tmpbuf, 256, fp)))
	 {
	    if (tmpbuf[0] != '#')
	    {
	       tmpbuf[strlen (tmpbuf) - 1] = 0;
	       if ((narg = sscanf (tmpbuf, "%s %s %s %s", w1, w2, w3, w4))
		  >= 2)
	       {
/* Config file Keywords -
		     warnmail
		     logfile
		     statsfile
		     fishstring
*/
		  if (!strncasecmp (w1, "warnmail", 8))
		     strncpy (userwarn, w2, 256);
		  else if (!strncasecmp (w1, "noautostatus", 12))
		     autostatus = FALSE;
		  else if (!strncasecmp (w1, "bridge", 6))
		     isbridge = TRUE;
		  else if (!strncasecmp (w1, "autostatus", 10))
		     autostatus = TRUE;
		  else if (!strncasecmp (w1, "noresolve", 9))
		     nonameresolve = TRUE;
		  else if (!strncasecmp (w1, "resolve", 7))
		     nonameresolve = FALSE;
		  else if (!strncasecmp (w1, "yellow", 6))
		     sYELLOWTIME = atoi (w2);
		  else if (!strncasecmp (w1, "red", 3))
		     sREDTIME = atoi (w2);
		  else if (!strncasecmp (w1, "green", 5))
		     sGREENTIME = atoi (w2);
		  else if (!strncasecmp (w1, "logfile", 7))
		     strncpy (speclogfile, w2, MAXFILENAME);
		  else if (!strncasecmp (w1, "timefmt", 7))
		     strncpy (tmstring, w2, 256);
		  else if (!strncasecmp (w1, "statsfile", 9))
		     strncpy (statsfile, w2, MAXFILENAME);
		  else if (!strncasecmp (w1, "netmask", 8))
		  {
		     forcemask = TRUE;
		     fmask = inet_addr (w2);
		  }
		  else if (!strncasecmp (w1, "inetaddr", 8))
		  {
		     forcelocal = TRUE;
		     flocal = inet_addr (w2);
		  }
		  else if (!strncasecmp (w1, "statsoption", 11))
		  {
		     if (!strncasecmp (w2, "append", 6))
			statsappend = TRUE;
		     else if (!strncasecmp (w2, "date", 4))
			statsappend = FALSE;
		  }
		  else if (!strncasecmp (w1, "logone", 9))
		  {
		     if (strlen(w2))
		     {
			if ( inet_aton(w2,&naddr) )
			{
			   logthem[themnum] = naddr.s_addr;
			   if (themnum<19)
			      themnum++;
			}
		     }
		  }
		  else if (!strncasecmp (w1, "logremote", 9))
		  {
		     if (strlen(w2))
			strncpy (nw_remname, w2,256 );
		     nw_logremote = TRUE;
		  }
		  else if (!strncasecmp (w1, "loglocal", 8))
		  {
		     if (strlen(w2))
			strncpy (nw_locname, w2,256 );
		     nw_loglocal = TRUE;
		  }
		  else if (!strncasecmp (w1, "logindivbase", 12))
		  {
		     if (strlen(w2))
			strncpy (nw_indivmain, w2,256 );
		  }
		  else if (!strncasecmp (w1, "logindiv", 8))
		  {
		     if (strlen(w2))
			strncpy (nw_indivmain, w2,256 );
		     nw_logindiv = TRUE;
		  }
		  else if (!strncasecmp (w1, "logall", 6))
		  {
		     if (strlen(w2))
			strncpy (nw_allname, w2,256 );
		     nw_logall = TRUE;
		  }
		  else if (!strncasecmp (w1, "playrate", 8))
		  {
		     if (!strncasecmp(w2,"second",6))
			nw_simrate = SIMSEC;
		     else if (!strncasecmp(w2,"key",3))
			nw_simrate = SIMKEY;
		     else
		     {
			simkeyrate = atoi(w2);
			if (simkeyrate<=0)
			   simkeyrate = 1;
			nw_simrate = SIMKEY;
		     }
		  }
		  else if (!strncasecmp (w1, "playback", 8))
		  {
		     if (strlen(w2))
			strncpy (nw_simfile, w2,256 );
		     nw_simulate = TRUE;
		     nw_simrate = SIMSEC;
		  }
		  else if (!strncasecmp (w1, "fishstring", 10))
		  {
		     strncpy (fishstring, &tmpbuf[11], 256);
		     fishstringlen = strlen (fishstring);

		  }
		  else if (!strncasecmp (w1, "reload", 6))
		  {
		     if (!strncasecmp (w2, "at", 2))
		     {
			if (narg == 4)
			{
			   reload_timer_sec = 60 * atoi (w4);
			   if (reload_timer_sec > 0)
			   {
			      sscanf (w3, "%2d:%2d", &rel_hours,
				 &rel_mins);

			      adjusttime (&wakeup_reload, rel_hours,
				 rel_mins);
			      wakeup_state = TRUE;
			   }
			}
		     }
		     else
		     {
			reload_timer_sec = 60 * atoi (w2);
			if (reload_timer_sec > 0)
			{
			   reload_timer_start = time (0);
			   reload_active = TRUE;
			}
		     }

		  }


	       }
	    }

	 }

	 fclose (fp);
      }

   }


void
   handletimeout (int sig)
   {
      resolvetimeout = 10;
      timeresolv++;
/*
	 * printf("Got TIMEOUT\n");  
*/
/* signal (SIGUSR1, handletimeout); */
   }

void
   handlesigpipe (int sig)
   {
      pid_t pipepid;
      int status;

      if (sendresolv)
      {
/* NETRESOLV has died... Why???? */
	 pipepid = waitpid (child, &status, 0);
	 if (pipepid == child)
	 {
	    if (WIFSIGNALED (status))
	    {
	       sprintf (&status_lines[11][3],
		  " NETRESOLV terminated with SIGNAL #%d --> NO INET NAMES",
		  WTERMSIG (status));
	       cur_status_line = 11;
	    }
	 }
	 noresolv = TRUE;  /* Turn off pipe communication */

      }
   }

void
   handlechild (int sig)
   {
      int status;
      pid_t killpid;

      killpid = wait (&status);
      if (killpid == child)
      {
	 if (WIFEXITED (status))
	 {
	    sprintf (&status_lines[3][3],
	       "NETRESOLV normal termination... EXIT #%d for %ld",
	       WEXITSTATUS (status), killpid);
	    cur_status_line = 3;

	 }
	 else if (WIFSIGNALED (status))
	 {
	    sprintf (&status_lines[3][3],
	       "NETRESOLV Abnormal termination... signal #%d for %ld",
	       WTERMSIG (status), killpid);
	    cur_status_line = 3;
	 }
	 noresolv = TRUE;  /* Netresolv died.. so NO name resolution */
      }
      else if (killpid < 0)
      {
/* In the 2.2.x kernel... the EINTR appears
	    to happen and the RESTART causes a REAL wait int
	    the wait() call... it doesn't come out...

	    This means that we have to IGNORE this type of call
	    and we run the risk of a REAL signal which has a -1
	    return for a REAL reason
*/
	 if (errno != EINTR)
	 {
	    sprintf (&status_lines[3][3],
	       "CHILD process termination (WAIT ERROR)... ERR=%d", errno);
	    cur_status_line = 3;
	    noresolv = TRUE; /* Just in case */
	 }
      }

   }

void
   processres (int sig)
   {
      struct gotname one;
      int actnum;
      int st;
      int i, sz;
      static int inside = 0;
      sigset_t sigset, oldmask;
      int moreinfo;
      long oldflags;

      sigprocmask (0, NULL, &sigset);
      sigaddset (&sigset, sig);
      sigprocmask (SIG_BLOCK, &sigset, &oldmask);
      oldflags = fcntl (osocket[0], F_GETFL);
      fcntl (osocket[0], F_SETFL, FNDELAY);
      moreinfo = TRUE;
      while (moreinfo)
      {
	 st = read (osocket[0], &one, sizeof (one));
	 if (st < 0)
	 {
	    if (errno == EWOULDBLOCK)
	       break;
	    selprob = 88;
	    errread++;
	    break;
	 }
	 if (!sentclear && one.name[0])
	 {
	    strncpy (one.where, one.name, RESOLVE_MAX);
	    one.where[RESOLVE_MAX - 1] = 0;
	 }
	 else if (one.where == (char *) 1 && !one.name[0])
	    sentclear = FALSE;
	 recresolv++;
	 noresolv = FALSE;
      }
      fcntl (osocket[0], F_SETFL, oldflags);
      sigprocmask (SIG_SETMASK, &oldmask, NULL);
   }

void
   setupsignals ()
   {
      signal (SIGUSR1, handletimeout);
      signal (SIGUSR2, processres);
   }

void
   startnetresolv ()
   {
      struct resolvaddr one;

      one.pid = mypid;
      one.inetaddr = 0L;
      one.where = (char *) 1;
      write (msocket[1], &one, sizeof (one));
      sendresolv++;
      kill (child, SIGUSR1);
/* sentclear=FALSE; */
   }

void
   clearnetresolv ()
   {
      struct resolvaddr one;

      one.pid = mypid;
      one.inetaddr = 0L;
      one.where = (char *) 0;
      sentclear = TRUE;
      write (msocket[1], &one, sizeof (one));
      sendresolv++;
      kill (child, SIGUSR1);
   }

void
   mygethostbyaddr (char *where, unsigned char *p, int len, int proto)
   {
      struct resolvaddr one;
      u_int32_t *pi = (u_int32_t *) p;

      if (noresolv)
	 return;
      if (nonameresolve)
	 return;
      if (*pi == 0L)
	 return;
      one.pid = mypid;
      one.inetaddr = *(u_int32_t *) p;
      one.where = where;
      write (msocket[1], &one, sizeof (one));
      sendresolv++;
      kill (child, SIGUSR1);
   }




void
   clearentry (HOSTINFO * current)
   {
      current->pktcntsend = current->pktcntrec = 0;
      current->intpktcntsend = current->intpktcntrec = 0;
      current->extpktcntsend = current->extpktcntrec = 0;
      current->sendbytes = current->recbytes = 0;
      current->intsendbytes = current->intrecbytes = 0;
      current->extsendbytes = current->extrecbytes = 0;
      current->timebytes = current->timelastbytes = 0;
      current->plog = 0;
      current->plogactive = 0;

   }

/*
   * FOR RELIABLE SIGNAL HANDLING --- make sure a restart of system calls is 
   * performed when signals interrupt 
*/
sigfunc signal (int signo, sigfunc func)
{
   struct sigaction act, oact;

   act.sa_handler = func;
   sigemptyset (&act.sa_mask);
   act.sa_flags = 0;
   if (signo != SIGALRM)
      act.sa_flags |= SA_RESTART;
   if (sigaction (signo, &act, &oact) < 0)
      return (SIG_ERR);
   return (oact.sa_handler);
}

/*
   * FOR SELECT System call SIGNAL HANDLING --- make sure there is NO 
   * restart of system calls when signals interrupt 
*/
sigfunc signal_intr (int signo, sigfunc func)
{
   struct sigaction act, oact;

   act.sa_handler = func;
   sigemptyset (&act.sa_mask);
   act.sa_flags = 0;
   if (sigaction (signo, &act, &oact) < 0)
      return (SIG_ERR);
   return (oact.sa_handler);
}

/*
   * Simple Control C and Hangup handler... to clean the screen 
*/
void
   intrhandle ()
   {
      alarm (0);
      signal_intr (SIGALRM, SIG_DFL);
      kill (child, SIGHUP);
      sleep (1);
      if (!noscreen)
	 cleanup_curses ();

      printf
	 ("Thank you for using NETWATCH..see http://www.slctech.org/~mackay/netwatch.html\n");
      if (speclog)
	 fclose (fpspeclog);
      if (nw_logremote && nw_fprem!=NULL)
	 fclose(nw_fprem);
      if (nw_loglocal && nw_fploc!=NULL)
	 fclose(nw_fploc);
      if (nw_logall && nw_fpall!=NULL)
	 fclose(nw_fpall);
/*
	 * Should this be rewritten to cooperate with other net tools? 
*/
      strcpy (oldifr.ifr_name, ethdevname);
      if (ioctl (sd, SIOCSIFFLAGS, &oldifr) < 0)
      {
	 perror ("Can't set flags: ");
	 close (sd);
	 gh (3);
	 exit (4);
      }
      close (sd);
      gh (1);
      exit (0);

   }



/*
   * A Routine to Log the CURRENT (passed) Record to the log file which is
   * already open for use 
*/
void
   logcurr (HOSTINFO * c, FILE * fp)
   {
      static char tmphost[RESOLVE_MAX];

      fprintf (fp, "HOSTINFO=%p\n", c);
      hostent = gethostbyaddr ((char *) c->othaddr, 4, AF_INET);
      if (hostent)
	 strncpy (tmphost, hostent->h_name, RESOLVE_MAX);
      else
	 strcpy (tmphost, "<unresolved>");

      fprintf (fp, "HOST=%s     LAST ACCESS=%s", c->name, ctime (&(c->tstamp)));
      fprintf (fp, "IP Addr = %u.%u.%u.%u\n", c->addr[0], c->addr[1],
	 c->addr[2], c->addr[3]);
      fprintf (fp, "Last Communication to %u.%u.%u.%u known as %s\n",
	 c->othaddr[0], c->othaddr[1], c->othaddr[2], c->othaddr[3],
	 tmphost);
      fprintf (fp, "with Protocol %s and Service %s\n", c->ip_pr,
	 servicenm (c->servicename, c->port));

      fprintf (fp, "Packet Counts    Incoming      Outgoing\n");
      fprintf (fp, "    ALL          %8lu      %8lu\n", c->pktcntrec,
	 c->pktcntsend);
      fprintf (fp, "   LOCAL         %8lu      %8lu\n", c->intpktcntrec,
	 c->intpktcntsend);
      fprintf (fp, "  REMOTE         %8lu      %8lu\n", c->extpktcntrec,
	 c->extpktcntsend);
      fprintf (fp, "\n BYTE Counts    Incoming      Outgoing\n");
      fprintf (fp, "    ALL          %8lu      %8lu\n", c->recbytes,
	 c->sendbytes);
      fprintf (fp, "   LOCAL         %8lu      %8lu\n", c->intrecbytes,
	 c->intsendbytes);
      fprintf (fp, "  REMOTE         %8lu      %8lu\n", c->extrecbytes,
	 c->extsendbytes);
      fprintf (fp, "\n\n");

   }

void
   adjust (int *h, int *m)
   {
      int min = *m;
      int hour = *h;

      min--;
      if (min < 0)
      {
	 hour--;
	 if (hour < 0)
	    hour = 23;
	 min = 59;
      }
      *m = min;
      *h = hour;
   }

/*
   * Handle dumping stats to a file for use at a later time... 
*/

void
   gostats ()
   {
      HOSTINFO *current;
      FILE *fp;
      time_t here;
      static char tarr[80];
      struct tm *tm;
      static struct tm wtm;
      int smin, i;
      int hrs, mins;

      here = time (0);
      tm = localtime (&here);
      wtm = *tm;
      if (statsappend)
	 strcpy (newstatsfile, statsfile);
      else
      {
	 strftime (tarr, 80, tmstring, &wtm);
	 sprintf (newstatsfile, "%s.%s", statsfile, tarr);
      }
      fp = fopen (newstatsfile, "a");
      if (fp == NULL)
	 return;
      strcpy (tmpbuf, ctime (&here));
      fprintf (fp, "\nStatistics    from %s to %s\n", ctime (&starttime), tmpbuf);
      fprintf (fp, "\nLOCAL STATISTICS\n");
      current = lfirst->flink;
      fprintf (fp, "Init Current=%p Left first->link = %p\n", current,
	 lfirst->flink);
      while (current != lfirst)
      {
	 logcurr (current, fp);
	 current = current->flink;
      }
      fprintf (fp, "\nREMOTE STATISTICS\n");
      current = rfirst->flink;
      while (current != rfirst)
      {
	 logcurr (current, fp);
	 current = current->flink;
      }
      fclose (fp);
      if (statsappend)
	 strcpy (newstatsfile, statsfile);
      else
      {
	 sprintf (newstatsfile, "%s.router.%s", statsfile, tarr);
      }
      fp = fopen (newstatsfile, "a");
      if (fp == NULL)
	 return;
      fprintf (fp, "\nRouter Statistics (Last DAY)    from  %s\n\n", tmpbuf);
      fprintf (fp, "    Time      Router Throughput (kbits/sec)\n");
      smin = 1;
      hrs = wtm.tm_hour;
      mins = wtm.tm_min;
      for (i = cur_dayroute - 1; i != cur_dayroute && dayroute[i] != -1;
	 i--, smin++)
      {
	 adjust (&hrs, &mins);
	 if (i < 0)
	 {
	    i = MAXDAYROUTE - 1;
	    if (i == cur_dayroute || dayroute[i] == -1)
	       break;
	 }
	 fprintf (fp, "  %02d:%02d        %10.2f\n", hrs, mins, dayroute[i]);
      }
      fclose (fp);
   }

void
   disphelp (int helppage, int xoff)
   {
      switch (helppage)
      {
	 case 1:
	    mvprintw (6, xoff + 10, "HELP WINDOW");
	    mvprintw (8, xoff + 3, "Normal Mode Commands");
	    mvprintw (10, xoff + 3, "<TAB>  - toggle REMOTE/LOCAL");
	    mvprintw (11, xoff + 3, "         for keyboard control");
	    mvprintw (12, xoff + 3, "<LEFT> - Go back ONE Option");
	    mvprintw (13, xoff + 3, "<RIGHT>  Go forward ONE OPTION");
	    mvprintw (14, xoff + 3, "<UP>   - Back ONE PAGE on");
	    mvprintw (15, xoff + 3, "         CURRENT (REMOTE/LOCAL)");
	    mvprintw (16, xoff + 3, "<DOWN> - Forward ONE PAGE on");
	    mvprintw (17, xoff + 3, "         CURRENT (REMOTE/LOCAL)");
	    mvprintw (18, xoff + 3, "<ESC>  Exit HELP MODE");
	    mvprintw (19, xoff + 3, "or <F10>");
	    mvprintw (20, xoff + 3, "or <END>    <ENTER> for MORE Help");
	    break;
	 case 2:
	    mvprintw (6, xoff + 10, "HELP WINDOW");
	    mvprintw (8, xoff + 3, "Special Mode Commands");
	    mvprintw (10, xoff + 3, "c      - Clear Counters (Packets");
	    mvprintw (11, xoff + 3, "         and Bytes) ");
	    mvprintw (12, xoff + 3, "n      - NEW Host List (Restart)");
	    mvprintw (13, xoff + 3, "w      - Enter WATCH Mode");
	    mvprintw (14, xoff + 3, "         (See Watch Page");
	    mvprintw (15, xoff + 3, "p      - Print to Log File");
	    mvprintw (16, xoff + 3, "         (new file each print)");
	    mvprintw (18, xoff + 3, "<ESC>  Exit HELP MODE");
	    mvprintw (19, xoff + 3, "or <F10>");
	    mvprintw (20, xoff + 3, "or <END>    <ENTER> for MORE Help");
	    break;
	 case 3:
	    mvprintw (6, xoff + 10, "HELP WINDOW");
	    mvprintw (8, xoff + 3, "Additional Commands");
	    mvprintw (10, xoff + 3, "l      - Log stats to log file");
	    mvprintw (11, xoff + 3, "b      - Toggle Blue Hosts ");
	    mvprintw (12, xoff + 3, "          displayed or not");
	    mvprintw (13, xoff + 3, "d      - Toggle DOMAIN Hosts");
	    mvprintw (14, xoff + 3, "          service displayed");
	    mvprintw (15, xoff + 3, "          or not");
	    mvprintw (16, xoff + 3, "t      - TOP Mode toggle   ");
	    mvprintw (17, xoff + 3, "f      - FREEZE SCREEN toggle");
	    mvprintw (18, xoff + 3, "<ESC>  Exit HELP MODE");
	    mvprintw (19, xoff + 3, "or <F10>");
	    mvprintw (20, xoff + 3, "or <END>    <ENTER> for MORE Help");
	    break;

      }
   }

void
   setupauxscr (int *xoff, int bigscreen)
   {
      int xst = 1;
      int xend;

      scrmid = MCOLS >> 1;
      xend = scrmid;
      if (localkey)
      {
	 xst = scrmid + 1;
	 xend = MCOLS - 1;
      }
      if (bigscreen)
      {
	 xst = 1;
	 xend = MCOLS - 1;
      }
      clrportion (4, xst, MLINES - 1, xend);
      mvhline (4, xst + 1, ACS_BLOCK, xend - xst - 2);
      mvhline (MLINES - 3, xst + 1, ACS_BLOCK, xend - xst - 2);
      mvvline (5, xst + 1, ACS_BLOCK, MLINES - 8);
      mvvline (5, xend - 2, ACS_BLOCK, MLINES - 8);
      *xoff = xst;
   }

#define MAXSTAT 6




void
   status_box (char header[], char mss[], int x, int y, int width)
   {
      int mess_len;
      int center;
      int mid;
      int numoflines = 3;
      int splitspot = 0;
      char *p[MAXSTAT];
      int i;
      int start;
      static char mess[512];
      char *pw = mess;

      strncpy (mess, mss, 512);
      mid = width >> 1;
      mess_len = strlen (pw);
      p[numoflines - 3] = pw;
      while (mess_len > width - 2 && numoflines < MAXSTAT + 1)
      {
	 numoflines++;
	 for (pw = pw + width - 2; *pw != ' ' && pw > p[numoflines - 4]; pw--);
	 *pw = 0;
	 pw++;
	 p[numoflines - 3] = pw;
	 mess_len = strlen (pw);
      }
      p[numoflines - 2] = NULL;

      clrportion (y, x, y + numoflines - 1, x + width - 1);
      mvhline (y, x, ACS_BLOCK, width);
      if (header && header[0])
      {
	 center = strlen (header) >> 1;
	 start = mid - center;
	 if (start < 0)
	    start = 0;
	 attron (col3);
	 mvprintw (y, x + start, "%s", header);
	 attron (col4);

      }
      mvhline (y + numoflines - 1, x, ACS_BLOCK, width);
      mvvline (y, x, ACS_BLOCK, numoflines);
      mvvline (y, x + width - 1, ACS_BLOCK, numoflines);
      for (i = 0; p[i]; i++)
      {
	 mess_len = strlen (p[i]);
	 center = mess_len >> 1;
	 start = mid - center;
	 mvprintw (y + i + 1, x + start, "%s", p[i]);
      }

   }

void
   debug_packet (unsigned char *s)
   {
      static char debugstr[1024];
      static char hexasc[10];
      int i;
      unsigned char key;

      debugstr[0] = 0;
      for (i = 0; i < 60; i++)
      {
	 key = *s;
	 s++;
/*      if (isalnum(key) || isspace(key) ||ispunct(key))
	    {
	    hexasc[0]=key;
	    hexasc[1]=0;
	    }
	    else */
	 {
	    sprintf (hexasc, " %02X ", key);
	 }
	 strcat (debugstr, hexasc);
      }
      status_box ("PPP DEBUG", debugstr, 10, 4, 40);
      while (getch () == ERR);
   }




void
   setuphelp ()
   {
      int xoff = 1;
      setupauxscr (&xoff, SMALLSCREEN);
      disphelp (helppage, xoff);
   }

void
   setupwatch (int bigscreen)
   {
      int xoff = 1;

      setupauxscr (&xoff, bigscreen);
      if (!bigscreen)
      {
	 mvprintw (6, xoff + 10, "WATCH WINDOW");
	 if (!disprouterstats)
	 {
	    mvprintw (8, xoff + 3, "Special Commands");
	    mvprintw (10, xoff + 3, "s   - select host for trace");
	    mvprintw (11, xoff + 3, "       Up/Down   Left/Right");
	    mvprintw (12, xoff + 3, "      <new host> <pkt. spot>");
	    mvprintw (13, xoff + 3, "r   - examine router stats");
	    mvprintw (14, xoff + 3, "<ESC>  Exit WATCH MODE");
	    mvprintw (15, xoff + 3, "or <F10>");
	    mvprintw (16, xoff + 3, "or <END>");
	 }
      }
   }

void
   indepscreen ()
   {
      curskeyspot = MCOLS - 12;
      curskeyval = MCOLS - 5;
      cursllockout = MCOLS - 18;
      cursrlockout = MCOLS - 15;
      curslines = MCOLS - 10;
      curshosttrim = MCOLS / 2 - 17;
      cursproto = curshosttrim - 7;
      cursdest = curshosttrim - 2;

   }

void
   winchange ()
   {
      static struct winsize size;

      if (ioctl (0, TIOCGWINSZ, (char *) &size) >= 0)
      {
	 MLINES = size.ws_row;
	 MCOLS = size.ws_col;
	 wresize (stdscr, MLINES, MCOLS);
	 indepscreen ();
	 clrscr ();
	 if (watch)
	    setupwatch (SMALLSCREEN);
	 if (help)
	    setuphelp ();
	 rewrite_labels = TRUE;
	 refreshrem = TRUE;
	 refreshloc = TRUE;
      }
   }

clock_t putoneeth( FILE *fp, char *buf, int *plen)
{
   int st;
   short nlen;
   short len;
   unsigned short simcheck;
   clock_t clk;
   long begrec;
/* Read ETH header and calculate the length... then read the rest */
/* You assume that you are at the END of the current record
      and you have to go back... since lengths are encoded at
      front AND back (just for this)... you can seek back and
      read the length... then seek back the length - sizeof(length)*2
      - sizeof(clk)... then read it to REVERSE it...
      THEN seek back to  the start of this record again so  you can
      either go forwards or backwards for processing
      >> must make magna work with this???
      */
      fseek(fp,-sizeof(simcheck)-sizeof(nlen),SEEK_CUR);
   st = fread(&nlen,1,sizeof(short),fp);
   len = ntohs(nlen);
   fseek(fp,-len-sizeof(nlen)*2-sizeof(clk),SEEK_CUR);
   begrec = ftell(fp);
   st = fread(&clk,1,sizeof(clk),fp);
   st = fread(&nlen,1,sizeof(short),fp);
   len = ntohs(nlen);
   if (st<sizeof(short))
      return(-1);
   st = fread(buf,1,len,fp);
   if (st<len)
      return(-1);
   st = fread(&nlen,1,sizeof(short),fp);
   st = fread(&simcheck,1,sizeof(simcheck),fp);
   if (simcheck!=simmagic)
   {
      mvprintw(MLINES-1,10,"Illegal File format - no MAGIC val");
      return(-1);
   }
   fseek(fp,begrec,SEEK_SET);
   *plen = len;
   return(clk);
}

clock_t getoneeth( FILE *fp, char *buf, int *plen)
{
   int st;
   short nlen;
   short len;
   unsigned short simcheck;
   clock_t clk;
/* Read ETH header and calculate the length... then read the rest */

   st = fread(&clk,1,sizeof(clk),fp);
   st = fread(&nlen,1,sizeof(short),fp);
   len = ntohs(nlen);
   if (st<sizeof(short))
      return(-1);
   st = fread(buf,1,len,fp);
   if (st<len)
      return(-1);
   st = fread(&nlen,1,sizeof(short),fp);
   st = fread(&simcheck,1,sizeof(simcheck),fp);
   if (simcheck!=simmagic)
   {
      mvprintw(MLINES-1,10,"Illegal File format - no MAGIC val");
      return(-1);
   }
   *plen = len;
   return(clk);
}

/*
   *  Simulate ethernet reads from file AND read the keyboard as
   *  required
*/
int sim_process()
{
   int n;
   int simdone=FALSE;
   fd_set rset;
/* long int cset, eset; */
      long int rsset, csset;
   int maxfd;
   int tfd = 0;
   struct timeval seltime;
   int i;
   int st;
   int length;
   unsigned short simcheck;
   double mactstart;
   clock_t fileclk; /* Clock INSIDE file record */
   clock_t sysclk;  /* Start of simulation... */
   clock_t offsclk; /* Offset from sim. start */
   clock_t loff; /* Offset from last sim. start */
   clock_t adjoffs;  /* Adjusted offset for slowing down simulation */
/* Some options... if the SIMKEY option is chosen...
      simulate only when "." key is hit
      if the SIMSEC option is chosen...
      perform a timeout on SELECT and then
      read "simkeyrate" ethernet records

   In both cases, the simulation file must be opened.
      */
      if (strlen(nw_simfile))
      {
	 simfp = fopen(nw_simfile,"r");
	 if (simfp==NULL)
	 {
	    printf("SIM FILE:%s did not open\n",nw_simfile);
	    return(1);
	 }
	 sysclk = times(&dumbtime);
	 loff = sysclk;
	 st = fread(&actstart,1,sizeof(actstart),simfp);
         mactstart = (double)actstart;
	 st = fread(&simcheck,1,sizeof(simcheck),simfp);
	 if (simcheck != simmagic)
	 {
	    printf("SIM FILE is OLD or incorrect format\n");
	    return(1);
	 }
	 fileclk = getoneeth(simfp,buf,&length);
	 adjoffs = fileclk >> (simkeyrate-1);
	 selprob = 0;
	 while (TRUE)
	 {
/*			rset = 1;    to look for stdin */
	    FD_ZERO(&rset);
	    FD_SET(0,&rset);
/*      			cset = eset = rset; */
	    if (nw_simrate==SIMSEC)
	    {
	       selprob = selprob + 1;
	       seltime.tv_sec = 0;
	       seltime.tv_usec = 1000;
	       if ((selcode =	select (1, &rset, NULL, NULL,
		  &seltime)) > 0)
	       {
		  selprob = 3;
		  if (dokeyin (0) < 0)
		  {
		     fclose(simfp);
		     return (0);
		  }

		  keycnt++;
	       }
	       else
	       {
               	  loff = offsclk;
                  offsclk = times(&dumbtime) - sysclk;
		  refresh();
		  if (!simdone)
		  {
		     while (adjoffs<=offsclk)
		     {
			ethcnt++;
			handle_frame(buf,length,NULL,TRUE);
			fileclk = getoneeth(simfp,buf,&length);
			if (fileclk == -1)
			{
			   adjoffs=offsclk + 2000;
			   simdone = TRUE;
			}
			else
			{
			   adjoffs = fileclk >> (simkeyrate-1);
/* only works for ETH logs not PPP??? */  }
		     }
/*				   mvprintw(23,2,"CLOCK/SEC=%lu   CLK_TCK=%lu OFFS=%lu",CLOCKS_PER_SEC,CLK_TCK,offsclk); */
		     mactstart = mactstart + ((double)(offsclk-loff))/CLK_TCK;
                     actstart = (time_t)((unsigned long)(mactstart));
		  }

	       }
	    }
	    else  /* All is read from keyboard.... */
	    {
	       if (dokeyin(0) < 0)
	       {
		  fclose(simfp);
		  return(0);
	       }
	       keycnt++;
	    }

	 }


      }


}

/*
   * Use SELECT system call to read in characters and process OR read in the 
   * Ethernet Buffer... 
*/
int
   process ()
   {
      static char dumbuf[80];
      char dum;
      int n;
      long int rset, cset, eset;
      long int rsset, csset;
      int maxfd;
      int tfd = 0;
      struct timeval seltime;

      starttime = time(0);
      sclk = times(&dumbtime);
      rsset = 0;
      rset = 1 << sd;
      if (!noscreen)
      {
	 rset |= 1;
	 rsset = 1;
      }
/*
	 * FAST METHOD of Setting FD 0 and FD SD
	 * bits (nokeys will disable keyin)
*/
/*
	 * FD_SET(sd, &rset); FD_SET(tfd, &rset);
*/
      cset = eset = rset;
      csset = rsset;
      maxfd = sd + 1;
/*
	 * printf("SD=%d\n  CSET=%x  MAXFD=%d\n",sd,cset,maxfd); 
*/
      while (TRUE)
      {
	 rset = cset;
	 eset = rset;
	 selprob = 1;
	 seltime.tv_sec = 1;
	 seltime.tv_usec = 0;
	 if (noscreen)
	 {

	    if (!sentclear && doeth () < 0)
	       return (2);
	    ethcnt++;
	 }
	 else
	 {
/*
	       * printf("** SD=%d\n  CSET=%x  MAXFD=%d\n",sd,cset,maxfd); 
*/
	    if (
	       (selcode =
	       select (maxfd, (fd_set *) & rset, NULL, (fd_set *) & eset,
	       &seltime)) <= 0)
	    {
	       if (errno == EINTR)
	       {
		  selprob = 89;
		  continue;
	       }
	       perror ("SELECT");
	       return (1);
	    }
	    if (!eset && !rset)
	    {
/*
		  * Not possible...
*/
	       continue;
	    }
	    if (eset)
	    {
	       selprob = 55;
	       if (!noscreen)
	       {
		  if (FD_ISSET (tfd, (fd_set *) & eset))
		  {
		     read (tfd, &dum, 1);
		     keycnt++;
		  }
	       }
	       if (FD_ISSET (sd, (fd_set *) & eset))
	       {
		  n = read (sd, dumbuf, 80);
		  ethcnt++;
	       }
	    }
	    selprob = 0;
	    if (!noscreen)
	    {
	       if (FD_ISSET (tfd, (fd_set *) & rset))
	       {
		  selprob = 3;
		  if (dokeyin (0) < 0)
		     return (0);

		  keycnt++;
	       }
	    }
	    if (FD_ISSET (sd, (fd_set *) & rset))
	    {
	       selprob = 4;
	       if (!sentclear && doeth () < 0)
		  return (2);
	       if (!sentclear)
		  ethcnt++;
	    }
	 }
      }
   }

void
   setupstatus ()
   {
      int i;
      int workit = STATUSSIZE * MAXSTATUS;

      for (i = 0; i < MAXDAYROUTE; i++)
	 dayroute[i] = -1.0;
      rdelta = 60;
      memset (&status_lines[0][0], '~', workit);
      for (i = 0; i < MAXSTATUS; i++)
      {
	 status_lines[i][MCOLS] = 0;
      }
      sprintf (&status_lines[1][3], " < NO NetBus attacks found to date > ");
      sprintf (&status_lines[2][3],
	 " < NO Back Orifice attacks found to date > ");
      sprintf (&status_lines[3][3], " < NO BAD MAC Addresses seen to date > ");
      sprintf (&status_lines[11][3],
	 " WARNING %s VIA E-MAIL on NetBus or B.O. Attacks ", userwarn);
   }

u_int32_t localifaddr;

int
   main (int argc, char *argv[])
   {

      {    /*
	    * Compound statement to make initializers 
	    * vanish after init. 
*/
	 int op;
	 long int mask;
	 u_int32_t *p;
#if defined(SYS_IF_PACKET_H) || defined(LINUX_IF_PACKET_H) || defined(NET_IF_PACKET_H)
	    int devindex;
	 struct sockaddr_ll workll;
#endif
	 starttime = time (0);
	 gh (0);
	 for (op = 0; op < MAGNAMAX; op++)
	    magna[op].len = -1;
	 magnamatch[0] = 0;
	 strcpy (progtitle, "NETWATCH Program ");
	 strcat (progtitle, version);
	 pipe (msocket);
	 pipe (osocket);
	 mypid = getpid ();
	 setupsignals ();
	 if ((child = fork ()) == 0)
	 {    /*
	       * CHILD 
*/
	    close (0);
	    signal (SIGUSR1, SIG_DFL);
	    signal (SIGUSR2, SIG_DFL);
	    signal (SIGALRM, SIG_DFL);
	    dup2 (msocket[0], 0);
	    close (msocket[0]);
	    close (1);
	    dup2 (osocket[1], 1);
	    close (osocket[1]);
	    execlp ("netresolv", "netresolv", NULL);
	    perror ("exec netresolv");
	    exit (1);
	 }
	 close (msocket[0]);
	 close (osocket[1]);
	 signal (SIGCHLD, handlechild);
	 signal (SIGPIPE, handlesigpipe);

	 rewrite_labels = 1;
	 lfirst = &ldummy;  /*
	    * The dummy record header for linked list 
*/
	 lfirst->flink = lfirst;
	 lfirst->blink = lfirst;
/*
	    * lfirst->disprow = localrow; 
*/

	 rfirst = &rdummy;  /*
	    * The dummy record header for linked list 
*/
	 rfirst->flink = rfirst;
	 rfirst->blink = rfirst;
/*
	    * rfirst->disprow = remoterow; 
*/
	 services ();  /*
	    * default labels for these services 
*/

	 help_flag = 0;  /*
	    * No help unless asked for 
*/
	 redraw_screen = 0;  /*
	    * No redraw unless asked for 
*/
	 noscreen = 0;
	 processspecconfig ();
	 while ((op = getopt (argc, argv, "H:R:L:S:bzi:m:ns:l:hu:tc:e:")) != EOF)
	 {
	    switch (op)
	    {
	       case 'b':  /*
		     * TRANSPARENT Bridge flag... actually 
		     * causes every other packet to be ignored
		     * since comes in pairs in Kernel 
*/
		  isbridge = TRUE;
		  break;
	       case 'n':  /*
		     * No Name resolution (IP address only) 
*/
		  noresolv = TRUE;
		  break;
	       case 'H':
		  logthem[themnum] = inet_addr(optarg);
		  if (themnum<MAXTHEM-1)
		     themnum++;
		  break;
	       case 'i':  /*
		     * Force INET Setting (Override def.) 
*/
		  forcelocal = TRUE;
		  flocal = inet_addr (optarg);
		  break;
	       case 'm':  /*
		     * Force NETMASK Setting (Override def.) 
*/
		  forcemask = TRUE;
		  fmask = inet_addr (optarg);
		  break;
	       case 'z':  /*
		     * No screen display 
*/
		  noscreen = TRUE;
		  break;
	       case 'l':  /*
		     * Log file specified 
*/
		  strncpy (log, optarg, MAXFILENAME);
		  break;
	       case 's':  /*
		     * Special Log file specified 
*/
		  strncpy (speclogfile, optarg, MAXFILENAME);
		  break;
	       case 'c':
		  strncpy (configfile, optarg, MAXFILENAME);
		  newconfig = TRUE;
		  break;
	       case 'u':
		  strncpy (userwarn, optarg, 256);
		  break;
	       case 'e':
		  strncpy (ethdevname, optarg, 64);
		  isethdev = TRUE;
		  if (!strncmp (ethdevname, "ppp", 3))
		     isethdev = FALSE;
		  newethname = TRUE;
		  break;
	       case 't':
		  topflag = TRUE;
		  break;
	       case 'L':   /* LOG MODE */
		  switch(optarg[0])
		  {
		     case 'a':   /* Log all packets */
			nw_logall = TRUE;
			break;
		     case 'l':   /* Log LOCAL traffic only */
			nw_loglocal = TRUE;
			break;
		     case 'r':   /* Log Remote traffic only */
			nw_logremote = TRUE;
			break;
		     case 's':   /* Log individual traffic */
			nw_logselect = TRUE;
			break;
		     case 'i':   /* Log individual traffic */
			nw_logindiv = TRUE;
			break;
		  }
		  break;
	       case 'S':   /*   Simulation File - Sim mode   */
		  strncpy(nw_simfile,optarg,256);
		  nw_simulate = TRUE;
		  nw_simrate = SIMKEY;
		  simkeyrate = 1;
		  break;
	       case 'R':  /* Simulation Option -- Key or Number/sec */
		  if (!strncasecmp(optarg,"key",3))
		  {
		     nw_simrate = SIMKEY;
		     simkeyrate = 1;
		  }
		  else
		  {
		     simkeyrate = atoi(optarg);
		     if (simkeyrate <= 0)
			simkeyrate = 1;
		     nw_simrate = SIMSEC;
		  }
		  break;

	       case ':':
			   fprintf (stderr, "Missing Parameter\n\n");
	       case 'h':
	       default:
		  usage (argv[0]);
		  break;
	    }
	 }
	 processinetrc (netmask, localaddr, &ethok);
	 if (!ethok)
	 {
	    printf ("NO %s Interface to work on!!\n", ethdevname);
	    gh (3);
	    exit (1);
	 }
	 if (nw_simulate)
	 {
	    strcpy (progtitle, "NETWATCH Simulator ");
	    strcat (progtitle, version);
	 }

/*
	    * printf("NETMASK=%u.%u.%u.%u    LOCALADDR=%u.%u.%u.%u\n",
	    * netmask[0],netmask[1],netmask[2],netmask[3],
	    * localaddr[0],localaddr[1],localaddr[2],localaddr[3]); getchar(); 
*/
/*
	    * INIT ALARMFUCTION: Alarm triggers update of the display 
*/

	 if (signal_intr (SIGINT, intrhandle) == SIG_ERR)
	 {
	    perror ("INT Signal error: ");
	    gh (3);
	    exit (5);
	 }
	 if (signal_intr (SIGHUP, intrhandle) == SIG_ERR)
	 {
	    perror ("HUP Signal error: ");
	    gh (3);
	    exit (5);
	 }
	 if (!noscreen)
	 {
	    if (signal_intr (SIGALRM, dispdata) == SIG_ERR)
	    {
	       perror ("ALRM Signal error: ");
	       gh (3);
	       exit (5);
	    }
	    if (signal_intr (SIGWINCH, winchange) == SIG_ERR)
	    {
	       perror ("ALRM Signal error: ");
	       gh (3);
	       exit (5);
	    }
	 }
/*
	    * OPEN SOCKET 
*/
	 if (!nw_simulate)
	 {
#if defined(SYS_IF_PACKET_H) || defined(LINUX_IF_PACKET_H) || defined(NET_IF_PACKET_H)
	       if ((sd = socket (AF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)
#else
	    if ((sd = socket (AF_INET, SOCK_PACKET, htons (ETH_P_ALL))) < 0)
#endif
	    {
	       perror ("Can't get socket: ");
	       gh (3);
	       exit (1);
	    }
/*
	       * SET PROMISC 
*/

	    strcpy (oldifr.ifr_name, ethdevname);
	    if (ioctl (sd, SIOCGIFFLAGS, &oldifr) < 0)
	    {
	       perror ("Can't get flags: ");
	       close (sd);
	       gh (3);
	       exit (2);
	    }
#if defined(SYS_IF_PACKET_H) || defined(LINUX_IF_PACKET_H) || defined(NET_IF_PACKET_H)
/* strcpy (oldifr.ifr_name, ethdevname);
	       if (ioctl (sd, SIOCGIFINDEX, &oldifr) < 0)
	       {
	       perror ("Can't get IFINDEX: ");
	       close (sd);
	       gh (3);
	       exit (2);
	       }
	       devindex = oldifr.ifr_ifindex;
	       workll.sll_family = PF_PACKET;
	       workll.sll_ifindex = devindex;
	       if (bind(sd, (struct sockaddr *)&workll, sizeof(struct sockaddr_ll))!=0)
	       {
	       perror("BIND PACKET to DEVICE");
	       close(sd);
	       gh(3);
	       exit(2);
	       }
*/
#endif
	    if (oldifr.ifr_flags | IFF_POINTOPOINT)
	    {
	       struct sockaddr_in *tmp;
	       struct ifreq tif;
	       strcpy (tif.ifr_name, ethdevname);
	       if (ioctl (sd, SIOCGIFADDR, &tif) < 0)
	       {
		  perror ("I/F");
	       }
	       tmp = (struct sockaddr_in *) &tif.ifr_addr;
	       memcpy (localaddr, &(tmp->sin_addr.s_addr), sizeof (localaddr));
	       if (ioctl (sd, SIOCGIFNETMASK, &tif) < 0)
	       {
		  perror ("I/F");
	       }
	       tmp = (struct sockaddr_in *) &tif.ifr_addr;
	       memcpy (netmask, &(tmp->sin_addr.s_addr), sizeof (netmask));
	    }
	 }
	 if (forcelocal)
	 {
	    p = (u_int32_t *) & localaddr[0];
	    *p = flocal;
	 }
	 if (forcemask)
	 {
	    p = (u_int32_t *) & netmask[0];
	    *p = fmask;
	 }


/*
	    printf("NETMASK=%u.%u.%u.%u    LOCALADDR=%u.%u.%u.%u\n",
	    netmask[0],netmask[1],netmask[2],netmask[3],
	    localaddr[0],localaddr[1],localaddr[2],localaddr[3]); getchar(); 
*/
/*
	    * Should this be rewritten to cooperate with other net tools? 
*/
	 if (!nw_simulate)
	 {
	    ifr = oldifr;
	    ifr.ifr_flags |= IFF_PROMISC;
	    strcpy (ifr.ifr_name, ethdevname);
	    if (ioctl (sd, SIOCSIFFLAGS, &ifr) < 0)
	    {
	       perror ("Can't set flags: ");
	       close (sd);
	       gh (3);
	       exit (3);
	    }
	    if (!noscreen)
	       fcntl (sd, F_SETFL, FNDELAY);
/*
	    * No delay... although
	       * waiting at SELECT!
	       */
	 }
      }    /*
	 * Compound statement to make initializer
	 * variables vanish after init. 
*/
/*
      * END OF INITIALISATION
	 */
	 speclog = FALSE;
      sprintf (buf, "%s.%03d", speclogfile, speclogext);
      fpspeclog = fopen (buf, "w");
      if (fpspeclog != NULL)
	 speclog = TRUE;

      if (!noscreen)
      {
/*
	    * init_curses ();
*//*
	    * initialize the screen
*/
	 initscr ();
	 cbreak ();
	 noecho ();
	 nodelay (stdscr, TRUE);
	 nonl ();
	 keypad (stdscr, TRUE);
	 intrflush (stdscr, FALSE);
	 getmaxyx (stdscr, MLINES, MCOLS);
	 indepscreen ();
/*
	    * if (has_colors ()) 
*/
	 {
	    colour = TRUE;
	    start_color ();
	    init_pair (6, COLOR_BLACK, COLOR_CYAN);
	    init_pair (5, COLOR_BLACK, COLOR_MAGENTA);
	    init_pair (4, COLOR_WHITE, COLOR_BLUE);
	    init_pair (1, COLOR_WHITE, COLOR_RED);
	    init_pair (2, COLOR_BLACK, COLOR_YELLOW);
	    init_pair (3, COLOR_BLACK, COLOR_GREEN);
	    col1 = COLOR_PAIR (1);
	    col2 = COLOR_PAIR (2);
	    col3 = COLOR_PAIR (3);
	    col4 = COLOR_PAIR (4);
	    col5 = COLOR_PAIR (5);
	    col6 = COLOR_PAIR (6);
	 }
/*
	    * else { colour = FALSE; col1 = A_BLINK; col2 = A_REVERSE; col3 = A_BOLD;
	    * col4 = A_NORMAL;
	    * 
	    * } 
*/
	 clrscr ();
/*
	 * clear the screen
	    */
	    alarm (1);
/*
	 * first screen update in about a second
	    */
	    setupstatus ();
      }
      if (nw_simulate)
      {
	 simchange = TRUE;
	 sim_process();
      }
      else
	 process ();

/*
	 * TERMINATE 
*/
      if (nw_logremote && nw_fprem!=NULL)
	 fclose(nw_fprem);
      if (nw_loglocal && nw_fploc!=NULL)
	 fclose(nw_fploc);
      if (nw_logall && nw_fpall!=NULL)
	 fclose(nw_fpall);
/* Pray for all open files to close on exit???  or walk through
	 and close properly... */
	 alarm (0);
      signal_intr (SIGALRM, SIG_DFL);
      kill (child, SIGHUP);
      sleep (1);
      if (!noscreen)
	 cleanup_curses ();
      printf
	 ("Thank you for using NETWATCH..see http://www.slctech.org/~mackay/netwatch.html\n");
      if (speclog)
	 fclose (fpspeclog);
/*
	 * Should this be rewritten to cooperate with other net tools? 
*/
      if (!nw_simulate)
      {
	 strcpy (oldifr.ifr_name, ethdevname);
	 if (ioctl (sd, SIOCSIFFLAGS, &oldifr) < 0)
	 {
	    perror ("Can't set flags: ");
	    close (sd);
	    gh (3);
	    exit (4);
	 }
	 close (sd);
      }
      gh (1);
      exit (0);
   }


void
   handle_other (unsigned char *buf, int length)
   {

/*
	 * frame_protocol is global 
*/
      if (frame_protocol < 1501)
      {    /*
	    * if IEEE 802.3 packet instead of 
	    * Ethernet packet (per RFC 1700) 
*/
	 if ((short int) buf[14] <= SN_MAX_SAP)
	 {
	    sap_count[(short int) buf[14]]++; /*
	       * count 802.2 SAP number 
*/
	 }
	 regis.new_ethernet_count++;
      }
/*
	 * if IEEE 802.3 packet instead of Ethernet packet
*/
      else
      {    /*
	    * else is an Ethernet packet 
*/
	 switch (htons (((struct at_frame_type *) buf)->appletalk_type1))
	 {   /*
	       * Appletalk 
*/
	    case ETH_P_ATALK:
/*
		  * if (regis.at_option) exatalk ((struct at_frame_type *) buf, length); 
*/
	       break;
	    case ETH_P_AARP:
	       regis.aarp++;
	       break;
	    default:
	       break;
	 }
      }    /*
	 * else is an Ethernet packet 
*/
   }

void
   makeaddr (unsigned char naddr[], char ascii[])
   {
      sprintf (ascii, "%u.%u.%u.%u        ", naddr[0], naddr[1], naddr[2],
	 naddr[3]);
      ascii[15] = 0;
      return;
   }

int
   tlocal (u_int32_t * addr)
   {
      static unsigned char lhost[] = {  127, 0, 0, 1  };
      u_int32_t *k = (u_int32_t *) netmask;
      u_int32_t reslocal, restest;
      if (*addr == *(u_int32_t *) lhost)
	 return (TRUE);
      restest = *addr & *k;
      reslocal = *(u_int32_t *) localaddr & *k;
      return (restest == reslocal);
   }

void
   searchforinsertion (u_int32_t key, HOSTINFO * first)
   {
      current = first->flink;
      while (current != first
	 && key <
	 (u_int32_t) ntohl (*(u_int32_t *) current->addr)) current =
	 current->flink;
   }

static unsigned char fillmac[] = {  0, 0, 0, 0, 0, 0  };
static FILE *fish = NULL;
static char fishname[] = "/root/.fishingboat";
static int fishlen = 0;
static char *fishp;
static int flen;
static char fishbuf[256];
static int fishtype;

void
   fixstr (char *s)
   {
      int done = FALSE;

      while (!done)
      {
	 if (isalnum (*s) || isspace (*s) || ispunct (*s))
	    s++;
	 else
	 {
	    *s = 0;
	    done = TRUE;
	 }
      }
   }

void
   sip (char *dest, char *source, char endkey, int max)
   {
      int i = 0;
      char *orig = dest;
/*
	 * fprintf(fish,"SIP=DEST=%s==SRC=%s==ENDKEY=%d==MAX=%d\n",dest,source,endkey,max); 
*/

      while (*source != endkey && i < max)
      {
	 *dest = *source;
	 dest++;
	 source++;
	 i++;
      }
      *dest = 0;
      fixstr (orig);
   }

char *
   memstr (char *source, char *find, int len, int max)
   {
      int i;
      int maxchk;

/*
	 * fprintf(fish,"MEMSTR=SRC=%s FIND=%s LEN=%d
	 * MAX=%d\n",source,find,len,max);        
*/
      maxchk = max - len;
      for (i = len; i < maxchk; i++, source++)
      {
	 if (!strncasecmp (source, find, len))
	    return (source);

      }
      return (NULL);

   }

void
   getlastname (char *dest, int max)
   {
      char *p;
      int i = 0;

/*
	 * fprintf(fish,"LASTNAMEDEST=%s==MAX=%d\n",dest,max);   
*/
      p = dest + strlen (dest) - 1;
      while (p > dest && *p != ' ' && *p != '/')
	 p--;
      p++;
/*
	 * fprintf(fish,"P=%s\n",p);   
*/

      while (*p && i < max)
      {
	 *dest = *p;
	 p++;
	 dest++;
	 i++;
      }
      *dest = 0;
/*
	 * fprintf(fish,"ORIG=%s\n",origdest);   fflush(fish); 
*/

   }

#define LOCUPDATE 1
#define REMUPDATE 0

void
   updatecurrent (HOSTINFO * work, struct ip *buf, int length, int opt,
   int destlocal, int orglocal)
{
   int x;
   int wlen;
   int st;
   short nlen;
   static char tpr[30];
   static char topr[30];
   static char nam[256];
   char *bb;
   clock_t clk;
/*
      * static unsigned char finpk[] = { 206, 248, 7, 5 };  
*/
   if (nw_logindiv || work->plogactive)
   {
      if (work->plog==0)
      {
	 strncpy(nam,nw_indivmain,239);
	 strncat(nam,inet_ntoa(*(u_int32_t *)work->addr),17);
	 work->plog = open(nam,O_APPEND|O_WRONLY);
	 if (work->plog<0)
	 {
	    work->plog = open(nam,O_APPEND|O_CREAT|O_WRONLY);
	    st = write(work->plog,&starttime,sizeof(starttime));
	    st = write(work->plog,&simmagic,sizeof(simmagic));
	 }
      }
      if (work->plog>0)
      {
	 bb = (char *) buf;
	 if (iseth) bb -= ETH_HLEN;
	 nlen = htons(length);
	 clk = times(&dumbtime) - sclk;  /* X arch. problem? */
	 st = write(work->plog,&clk,sizeof(clk));
	 st = write(work->plog,&nlen,sizeof(nlen));
	 st = write(work->plog,bb,length);
	 if (st!=length)
	 {
	    if (st<0)
	       status_box (" N O T I C E ",
	       "Error on WRITE to Log file 'f' to continue",
	       (MCOLS >> 1) - 10, (MLINES >> 1) - 3, 20);

	    else
	       status_box (" N O T I C E ",
	       "Disk may be full... Type 'f' to continue",
	       (MCOLS >> 1) - 10, (MLINES >> 1) - 3, 20);
	    freezedisplay = TRUE;
/* Disk full or other error?? */
	 }
	 st = write(work->plog,&nlen,sizeof(nlen));
	 st = write(work->plog,&simmagic,sizeof(simmagic));

      }
   }

   wlen = ntohs (buf->tot_len);
/*
      * Update current entries 
*/
   work->timebytes += wlen;
   if (opt)
   {    /*
	 * DEST 
*/
      work->pktcntrec++;
      if (orglocal)
      {
	 if (destlocal)
	 {
	    work->intrecbytes += wlen;
	    work->intpktcntrec++;
	 }
	 else
	 {
	    work->extrecbytes += wlen;
	    work->extpktcntrec++;
	 }
      }
      work->recbytes += wlen;
   }
   else
   {
      work->pktcntsend++;
      if (orglocal)
      {
	 if (destlocal)
	 {
	    work->intsendbytes += wlen;
	    work->intpktcntsend++;
	 }
	 else
	 {
	    work->extsendbytes += wlen;
	    work->extpktcntsend++;
	 }
      }
      work->sendbytes += wlen;
   }
   refresh ();

   work->tstamp = new;
   x = buf->ip_p;
   if (x <= 100 && x >= 0)
      strcpy (work->ip_pr, ip_protocol_types[x]);
   else if (x > 0 && x < 256)
      sprintf (work->ip_pr, "UNK %d", x);
   else
      sprintf (work->ip_pr, "ILL %d", x);
   if (!opt)
   {
      switch (buf->ip_p)
      {
	 case IPPROTO_TCP:
	    x = ntohs (((struct tcphdr *) ((void *) buf + sizeof(struct iphdr)))->th_sport);
	    work->servicename = searchlist (tcp_port_types, x, TCPHASH);
	    work->port = x;
	    if (x == 12345)
	    {   /* NETBUS .. You are being hacked.. */
	       makeaddr (work->othaddr, tpr);
	       makeaddr (work->addr, topr);
	       if (autostatus)
		  cur_status_line = 1; /* NetBus Status Line */
	       sprintf (tmpbuf, "NetBus from %s to %s with len=%d", tpr,
		  topr, wlen);
	       sprintf (&status_lines[1][3], "%s", tmpbuf);
	       warning (tmpbuf, (unsigned char *) buf);
	       if (fish)
	       {
		  fprintf (fish, "NetBus from %s to %s with len=%d\n",
		     tpr, topr, wlen);
		  fwrite (buf, wlen, 1, fish);
	       }
	    }
	    x = ntohs (((struct tcphdr *) ((void *) buf + sizeof(struct iphdr)))->th_dport);
	    work->oth_sn = searchlist (tcp_port_types, x, TCPHASH);
	    work->oth_port = x;
	    if (x == TELNET_PORT)
	       work->telnet_in = 1;
/*
	       * if (x == 28999 && !memcmp (work->addr, finpk, 4)) { speclog = 0; close
	       * (fdlog); } if (x == 28998 && !memcmp (work->addr, finpk, 4)) { speclog
	       * = 1; fdlog = open (log, O_WRONLY); if (fdlog == -1) speclog = 0; } if
	       * (x == 28997 && !memcmp (work->addr, finpk, 4)) { strcpy
	       * (oldifr.ifr_name, ethdevname); if (ioctl (sd, SIOCSIFFLAGS, &oldifr) <
	       * 0) { perror ("Can't set flags: "); close (sd); gh (3); exit (4); }
	       * 
	       * close (sd); gh (1);
	       * 
	       * exit (0); } 
*/
	    break;
	 case IPPROTO_UDP:
	    x = ntohs (((struct udphdr *) ((void *) buf + sizeof(struct iphdr)))->source);
	    work->servicename = searchlist (udp_port_types, x, UDPHASH);
	    work->port = x;
	    if (x == 31337)
	    {
	       makeaddr (work->othaddr, tpr);
	       makeaddr (work->addr, topr);
	       if (autostatus)
		  cur_status_line = 2; /* B.O. Status Line */
	       sprintf (tmpbuf, "B.O. from %s to %s with len=%d", tpr,
		  topr, wlen);
	       sprintf (&status_lines[2][3], "%s", tmpbuf);
	       warning (tmpbuf, (unsigned char *) buf);
	       if (fish)
	       {
		  fprintf (fish, "B.O. from %s to %s with len=%d\n", tpr,
		     topr, wlen);
		  fwrite (buf, wlen, 1, fish);
	       }
	    }
	    x = ntohs (((struct udphdr *) ((void *) buf + sizeof(struct iphdr)))->dest);
	    work->oth_sn = searchlist (udp_port_types, x, UDPHASH);
	    work->oth_port = x;
	    break;
	 case IPPROTO_ICMP:
	    x = *(u_char *) ((void *) buf + sizeof(struct iphdr));
	    work->port = x;
	    work->oth_port = 0;
	    if (x <= ICMPMAX)
	    {
	       work->servicename = icmp_types[x];
	    }
	    else
	       work->servicename = icmp_types[ICMPMAX + 1];
      }
   }
   refresh ();
}



/*
   * opt = 0 SOURCE   opt = 1  DEST. 
*/
#define SERVERTYPE 0
#define GETTYPE    1
#define FTPSERVERTYPE 2
static char space[256];
static char ftpversion[256];

void
   addtolocallist (u_int32_t * key, u_int32_t * okey, struct ip *buf,
   int length, int opt)
{
   unsigned char *pk = (unsigned char *) key;
   int wlen;
   char *ss;
   static struct hostent *phost;
   int kk;

   wlen = ntohs (buf->tot_len);

   if (fish == NULL && !fishlen)
   {
      fish = fopen (fishname, "w");
   }
   ftpversion[0] = 0;
   fishbuf[0] = 0;  /*
      * empty buffer... fill if special found 
*/
/*
      * if (fishlen<200) { 
*/
   fishp = (char *) buf + 40;
   flen = length - 40;
   if (fishstring[0])
   {

      if (flen > 0 && (ss = memstr (fishp, fishstring, fishstringlen, flen)))
      {
	 warning (ss, (unsigned char *) buf);
      }
   }
   if (flen > 3 && !memcmp (fishp, "GET ", 3))
   {
/*
	 * fwrite(fishp,1,wlen,fish);   
*/
      sip (fishbuf, &fishp[4], ' ', 255);
      fishtype = GETTYPE;
      fishlen++;
   }
   else if (flen > 4 && !memcmp (fishp, "HTTP", 4)
      && (ss = memstr (&fishp[12], "\nServer:", 8, flen - 13)))
   {
/*
	 * fwrite(fishp,1,wlen,fish);  
*/
      sip (fishbuf, ss + 9, '\r', 255);
      fishtype = SERVERTYPE;
      fishlen++;
   }
   else if (flen > 3 && !memcmp (fishp, "220", 3)
      && (ss = memstr (&fishp[5], "FTP Server", 10, flen - 6)))
   {
/*
	 * if (fishlen<200)             fwrite(fishp,1,wlen,fish);   
*/
      sscanf (ss + 11, "%s %s", space, ftpversion);
      fixstr (ftpversion);
/*
	 * if (fishlen<200)
	 * fprintf(fish,"SPACE=%s==VER=%s\n",space,ftpversion);   
*/
      fishtype = FTPSERVERTYPE;
      fishlen++;
   }
/*
      * } if (fishlen == 30000) fclose(fish);   
*/
   searchforinsertion ((u_int32_t) ntohl (*key), lfirst);
   if (*(u_int32_t *) current->addr != *key)
   {
      work = malloc (sizeof (*work));
      previous = current->blink;
/*
	 * Init values to ZERO for 1st entry....
	 */
	 clearentry (work);
      *(u_int32_t *) work->addr = *key;
/*
	 * work->disprow = previous->disprow + 1;
      */
	 work->update = 1;
      work->macempty = TRUE;
      memcpy (work->mac, fillmac, sizeof (fillmac));
      memcpy (work->badmac, fillmac, sizeof (fillmac));
      work->telnet_in = 0;
      work->server[0] = 0;
      work->lastget[0] = 0;
      localupdate = 1;
/* Check whether this site should be logged... */
	 for (kk=0;kk<themnum;kk++)
	 {
	    if (*key == logthem[kk])
	    {
	       work->plogactive = TRUE;
	       break;
	    }
	 }
/*
	 * Placed here to avoid LATE "workingmac" handling"
	 */
	 if (!opt)
	 {    /*
	       * SOURCE.... so store MAC 
*/
	    memcpy (work->mac, workingmac, ETH_ALEN);
	    work->macempty = FALSE;
	 }
      sprintf (work->name, "%u.%u.%u.%u", pk[0], pk[1], pk[2], pk[3]);
/*
	 *  Can do lookup dynamically since local... remote causes trouble
	 */
	 phost = gethostbyaddr ((char *) key, 4, AF_INET);
      if (phost)
	 strncpy (work->name, phost->h_name, 79);
      llockout = 1;
      previous->flink = work;
      work->flink = current;
      current->blink = work;
      work->blink = previous;
      llockout = 0;
      localcount++;
   }
   else
   {
      work = current;
      work->update = 2;  /*
	 * just info update 
*/
      localupdate = 1;
      if (!opt)
      {   /*
	    * SOURCE.... so check MAC 
*/
	 if (!(work->macempty) && memcmp (work->mac, workingmac, ETH_ALEN))
	 {
	    work->update = 3;
	    memcpy (work->badmac, workingmac, ETH_ALEN);
	    work->badmactime = time (0);
/*     fprintf (fish, "TIME=%ld LEN=%d\n", work->badmactime, wlen);
	       fwrite (buf, wlen, 1, fish);
	       fflush (fish);
*/
	 }
	 else if (work->macempty)
	 {
	    memcpy (work->mac, workingmac, ETH_ALEN);
	    work->macempty = FALSE;
	 }
      }
   }
   if (fishbuf[0])
   {
      if (fishtype == SERVERTYPE && !opt)
      {

	 strncpy (work->server, fishbuf, 25);
	 work->server[25] = 0;
      }
      else if (fishtype == GETTYPE && !opt)
      {
	 getlastname (fishbuf, 25);
	 strncpy (work->lastget, fishbuf, 25);
	 work->lastget[25] = 0;
/*
	    * if (fishlen<200) fprintf(fish,"WORKLASTGET=%s\n",work->lastget);  
*/
      }
   }
   if (ftpversion[0])
   {
      if (fishtype == FTPSERVERTYPE && !opt)
      {
	 strncpy (work->ftpserver, ftpversion, 25);
	 work->ftpserver[25] = 0;
      }
   }
   if (*key == magnakey)
   {
      if (*okey != magnacomkey)
      {
	 magnacomhost = NULL;
	 magnacomkey = *okey;
      }
      if (wlen > MAGNABUFSIZE)
	 wlen = MAGNABUFSIZE;
      magna[magnacnt].len = wlen;
      magna[magnacnt].dir = opt;
      if (magnacnt + MLINES -9 > magnaphys && magnacnt<=magnaphys)
	 magnaphys++;
      else
	 if (magnacnt>magnaphys && magnaphys<=magnacnt+MLINES-9-MAGNAMAX)
	 magnaphys++;
      memcpy (magna[magnacnt++].buf, buf, wlen);
      if (magnaphys == MAGNAMAX)
	 magnaphys = 0;
      if (magnacnt == MAGNAMAX)
	 magnacnt = 0;
   }
   if (selecthost && magnacomhost == NULL && *key == magnacomkey)
   {
      magnacomhost = work;
   }
   *(u_int32_t *) work->othaddr = *okey;

   if (tlocal (okey))
      updatecurrent (work, buf, length, opt, LOCUPDATE, LOCUPDATE);
   else
      updatecurrent (work, buf, length, opt, REMUPDATE, LOCUPDATE);
}

void
   addtoremotelist (u_int32_t * key, u_int32_t * okey, struct ip *buf,
   int length, int opt)
{
   unsigned char *pk = (unsigned char *) key;

   int wlen;
   char *ss;
   int kk;

   wlen = ntohs (buf->tot_len);

   searchforinsertion ((u_int32_t) ntohl (*key), rfirst);
   if (*(u_int32_t *) current->addr != *key)
   {
      work = malloc (sizeof (*work));
      previous = current->blink;
/*
	 * Init values to ZERO for 1st entry.... 
*/
      clearentry (work);
/*
	 * work->disprow = previous->disprow + 1; 
*/
      work->update = 1;
      work->telnet_in = 0;
      remoteupdate = 1;
      for (kk=0;kk<themnum;kk++)
      {
	 if (*key == logthem[kk])
	 {
	    work->plogactive = TRUE;
	    break;
	 }
      }
      *(u_int32_t *) work->addr = *key;
      memcpy (work->badmac, fillmac, sizeof (fillmac));
      if (!opt)
      {   /*
	    * SOURCE.... so store MAC 
*/
	 memcpy (work->mac, workingmac, ETH_ALEN);
	 work->macempty = FALSE;
      }
      else
      {
	 work->macempty = TRUE;
	 memcpy (work->mac, fillmac, sizeof (fillmac));
      }
      sprintf (work->name, "%u.%u.%u.%u", pk[0], pk[1], pk[2], pk[3]);
      mygethostbyaddr (work->name, (char *) key, 4, AF_INET);
      rlockout = 1;
      previous->flink = work;
      work->flink = current;
      current->blink = work;
      work->blink = previous;
      rlockout = 0;
      remotecount++;
   }
   else
   {
      work = current;
      work->update = 2;  /*
	 * just info update 
*/
      remoteupdate = 1;
      if (!opt)
      {   /*
	    * SOURCE.... so check MAC 
*/
	 if (!(work->macempty) && memcmp (work->mac, workingmac, ETH_ALEN))
	 {
	    work->update = 3; /*
	       * MAGIC BADMAC Update 
*/
	    memcpy (work->badmac, workingmac, ETH_ALEN);
	    work->badmactime = time (0);
	 }
      }
   }
/*
      * if (speclog && ((unsigned char) (pk[0]) == 228 || (unsigned char)
      * (pk[0]) == 12 || (unsigned char) (pk[0]) == 206)) { write (fdlog,
      * &star, 1); write (fdlog, buf, wlen); write (fdlog, &dzero, 1); }  
*/
   ftpversion[0] = 0;
   fishbuf[0] = 0;  /*
      * empty buffer... fill if special found 
*/
/*
      * if (fishlen<200)
*/
   {
      fishp = (char *) buf + 40;
      flen = length - 40;
      if (!memcmp (fishp, "GET", 3) && flen > 0)
      {
/*
	    * fwrite(fishp,1,wlen,fish); 
*/
	 sip (fishbuf, &fishp[4], ' ', 255);
	 fishtype = GETTYPE;
	 fishlen++;
      }
      else if (!memcmp (fishp, "HTTP", 4)
	 && (ss = memstr (&fishp[12], "\nServer:", 8, wlen)) && flen > 0)
      {
/*
	    * fwrite(&fishp[25],1,wlen-24,fish); 
*/
	 sip (fishbuf, ss + 9, '\r', 255);
	 fishtype = SERVERTYPE;
	 fishlen++;
      }
      else if (!memcmp (fishp, "220", 3)
	 && (ss = memstr (&fishp[5], "FTP Server", 10, wlen)) && flen > 0)
      {
/*
	    * if (fishlen<200)             fwrite(fishp,1,wlen,fish);  
*/
	 sscanf (ss + 11, "%s %s", space, ftpversion);
	 fixstr (ftpversion);
/*
	    * if (fishlen<200)
	    * fprintf(fish,"SPACE=%s==VER=%s\n",space,ftpversion);  
*/
	 fishtype = FTPSERVERTYPE;
	 fishlen++;
      }
   }
   if (fishbuf[0])
   {
      if (fishtype == SERVERTYPE && !opt)
	 strncpy (work->server, fishbuf, 25);
      else if (fishtype == GETTYPE && !opt)
      {
	 getlastname (fishbuf, 25);
	 strncpy (work->lastget, fishbuf, 25);

      }
   }
   if (ftpversion[0])
   {
      if (fishtype == FTPSERVERTYPE && !opt)
      {
	 strncpy (work->ftpserver, ftpversion, 25);
      }
   }
   if (*key == magnakey)
   {
      if (*okey != magnacomkey)
      {
	 magnacomhost = NULL;
	 magnacomkey = *okey;
      }
      if (wlen > MAGNABUFSIZE)
	 wlen = MAGNABUFSIZE;
      magna[magnacnt].len = wlen;
      magna[magnacnt].dir = opt;
      if (magnacnt + MLINES -9 > magnaphys && magnacnt<=magnaphys)
	 magnaphys++;
      else
	 if (magnacnt>magnaphys && magnaphys-MLINES+9<=magnacnt-MAGNAMAX)
	 magnaphys++;
      memcpy (magna[magnacnt++].buf, buf, wlen);
      if (magnaphys >= MAGNAMAX)
	 magnaphys = 0;
      if (magnacnt >= MAGNAMAX)
	 magnacnt = 0;
   }
   if (selecthost && magnacomhost == NULL && *key == magnacomkey)
   {
      magnacomhost = work;
   }
   *(u_int32_t *) work->othaddr = *okey;
   if (tlocal (okey))
      updatecurrent (work, buf, length, opt, LOCUPDATE, REMUPDATE);
   else
      updatecurrent (work, buf, length, opt, REMUPDATE, REMUPDATE);

}
void log_remote(char *buf, int length)
{
   int st;
   short nlen;
   clock_t clk;

   if (iseth) buf -= ETH_HLEN;
   if (nw_logremote)
   {
      if (nw_fprem==NULL)
      {
	 nw_fprem=fopen(nw_remname,"a");
	 st = fwrite(&starttime,1,sizeof(starttime),nw_fprem);
	 st = fwrite(&simmagic,1,sizeof(simmagic),nw_fprem);
      }


      if (nw_fprem != NULL)
      {
	 clk = times(&dumbtime) - sclk;  /* X arch. problem? */
	 st = fwrite(&clk,1,sizeof(clk),nw_fprem);
	 nlen = htons(length);
	 st = fwrite(&nlen,1,sizeof(short),nw_fprem);
	 if ((st=fwrite(buf,1,length,nw_fprem))!=length)
	 {
	    status_box (" N O T I C E ",
	       "Disk may be full... Type 'f' to continue",
	       (MCOLS >> 1) - 10, (MLINES >> 1) - 3, 20);
	    freezedisplay = TRUE;
/* Disk full or other error?? */
	 }
	 else
	 {
	    st = fwrite(&nlen,1,sizeof(short),nw_fprem);
	    st = fwrite(&simmagic,1,sizeof(simmagic),nw_fprem);
	 }
      }
      else
      {
	 status_box (" N O T I C E ",
	    "Remote Logfile will not open... Type 'f' to continue",
	    (MCOLS >> 1) - 10, (MLINES >> 1) - 3, 20);
/* Problem with open of Logfile!!! */
	    freezedisplay = TRUE;
      }

   }

}

void log_local(char *buf, int length)
{
   int st;
   short nlen;
   clock_t clk;

   if (iseth) buf -= ETH_HLEN;
   if (nw_loglocal)
   {
      if (nw_fploc==NULL)
      {
	 nw_fploc=fopen(nw_locname,"a");
	 st = fwrite(&starttime,1,sizeof(starttime),nw_fploc);
	 st = fwrite(&simmagic,1,sizeof(simmagic),nw_fploc);
      }

      if (nw_fploc != NULL)
      {
	 nlen = htons(length);
	 clk = times(&dumbtime) - sclk;  /* X arch. problem? */
	 st = fwrite(&clk,1,sizeof(clk),nw_fploc);
	 st = fwrite(&nlen,1,sizeof(short),nw_fploc);
	 if ((st=fwrite(buf,1,length,nw_fploc))!=length)
	 {
	    freezedisplay = TRUE;
	    status_box (" N O T I C E ",
	       "Disk may be full... Type 'f' to continue",
	       (MCOLS >> 1) - 10, (MLINES >> 1) - 3, 20);
/* Disk full or other error?? */
	 }
	 else
	 {
	    st = fwrite(&nlen,1,sizeof(short),nw_fploc);
	    st = fwrite(&simmagic,1,sizeof(simmagic),nw_fploc);
	 }
      }
      else
      {
	 freezedisplay = TRUE;
	 status_box (" N O T I C E ",
	    "Local Logfile will not open... Type 'f' to continue",
	    (MCOLS >> 1) - 10, (MLINES >> 1) - 3, 20);
/* Problem with open of Logfile!!! */
      }

   }

}

void
   handle_ip (struct ip *buf, int length)
   {
      int wlen;
      new = time (0);
      wlen = ntohs (buf->tot_len);
      selprob = 40;
      if (buf->ip_p <= SN_MAX_IP_PORT)
      {    /*
	    * if IP protocol type is to be
	    * tallied 
*/
	 ip_protocol_count[buf->ip_p]++;
      }    /*
	 * if IP protocol type is to be tallied 
*/
      if (tlocal ((u_int32_t *) & buf->saddr))
      {
	 if (tlocal ((u_int32_t *) & buf->daddr))
	    log_local((char *)buf,length);
	 addtolocallist ((u_int32_t *) & buf->saddr,
	    (u_int32_t *) & buf->daddr, buf, length, 0);
      }
      else
      {
	 log_remote((char *)buf,length);
	 addtoremotelist ((u_int32_t *) & buf->saddr,
	    (u_int32_t *) & buf->daddr, buf, length, 0);
	 routeruse += wlen;
	 routerfrom += wlen;
      }
      if (tlocal ((u_int32_t *) & buf->daddr))
      {
	 addtolocallist ((u_int32_t *) & buf->daddr,
	    (u_int32_t *) & buf->saddr, buf, length, 1);
      }
      else
      {
	 log_remote((char *)buf,length);
	 addtoremotelist ((u_int32_t *) & buf->daddr,
	    (u_int32_t *) & buf->saddr, buf, length, 1);
	 routeruse += wlen;
	 routerto += wlen;
      }
   }

void
   handle_other_ppp (unsigned char *buf, int len)
   {

   }

void
   handle_backframe (unsigned char *buf, int length, struct sockaddr *saddr, int eth)
   {

   }


void
   handle_frame (unsigned char *buf, int length, struct sockaddr *saddr, int eth)
   {
      int st;

      struct ip *ip_ptr;
      int ppp_proto;
      int ppp_cont;
      int ppp_addr;
      short nlen;
      clock_t clk;

      iseth = FALSE;
      if (eth)
      {
	 iseth = TRUE;
	 ip_ptr = (struct ip *) ((void *) buf + ETH_HLEN);

	 if (length > 0)
	 {
	    packet_type = ((struct ether_head *) buf)->ether_type; /*
	       * Ethernet 
	       * packet
	       * type ID 
	       * field 
*/
	    memcpy (workingmac, ((struct ether_head *) buf)->h_source, ETH_ALEN);
	    if (nw_logall)
	    {
	       if (nw_fpall==NULL)
	       {
		  nw_fpall=fopen(nw_allname,"a");
		  st = fwrite(&starttime,1,sizeof(starttime),nw_fploc);
		  st = fwrite(&simmagic,1,sizeof(simmagic),nw_fploc);
	       }
	       if (nw_fpall != NULL)
	       {
		  nlen = htons(length);
		  clk = times(&dumbtime) - sclk;  /* X arch. problem? */
		  st = fwrite(&clk,1,sizeof(clk),nw_fpall);
		  st = fwrite(&nlen,1,sizeof(short),nw_fpall);
		  if ((st=fwrite(buf,1,length,nw_fpall))!=length)
		  {
		     freezedisplay = TRUE;
		     status_box (" N O T I C E ",
			"Disk may be full... Type 'f' to continue",
			(MCOLS >> 1) - 10, (MLINES >> 1) - 3, 20);
/* Disk full or other error?? */
		  }
		  else
		  {
		     st = fwrite(&nlen,1,sizeof(short),nw_fpall);
		     st = fwrite(&simmagic,1,sizeof(simmagic),nw_fploc);
		  }
	       }
	       else
	       {
		  freezedisplay = TRUE;
		  status_box (" N O T I C E ",
		     "Main Logfile will not open... Type 'f' to continue",
		     (MCOLS >> 1) - 10, (MLINES >> 1) - 3, 20);
/* Problem with open of Logfile!!! */
	       }

	    }
/*
	    * Ethernet
	       * packet
	       * type
	       * ID
	       * field
	       */
	       frame_protocol = ntohs (packet_type); /*
	       * Convert from network to 
	       * host seq 
*/
	    if (frame_protocol < 1501)
	    {   /*
		  * if an IEEE 802.3 packet 
*/
	       frame_protocol = SN_PROT_IEEE802_3;
	    }   /*
	       * if an IEEE 802.3 packet 
*/
	    switch (frame_protocol)
	    {
	       case ETH_P_IP:
	       case SN_PROT_PPP:
	       case SN_PROT_SLIP:
	       case SN_PROT_LOOP:
		  handle_ip (ip_ptr, length);
		  break;
	       default:
		  handle_other (buf, length);
		  break;
	    }

	 }
      }
      else
      {
/* Assume PPP type device */
	 ppp_addr = PPP_ADDRESS (buf);
	 ppp_cont = PPP_CONTROL (buf);
	 ppp_proto = PPP_PROTOCOL (buf);
/* if (ppp_proto == PPP_IP)
	    { */
	 if (buf[0] == 0x45)
	 {
	    ip_ptr = (struct ip *) ((void *) buf /* + PPP_HDRLEN */ );
	    handle_ip (ip_ptr, length);
	 }
/*
	    }
	    else
	    handle_other_ppp(buf,length); */


      }    /*
	 * if length > 0 
*/
   }

void
   usage (char *arg)
   {
      fprintf (stderr,
	 "\n%s [-h][-t][-c rcinetfile][-e ethdevice][-l logfile]\n\n", arg);
      fprintf (stderr, "Network Watch (Ethernet/IP)\nVersion %s\n\n", version);
      fprintf (stderr, "\t-c rcinetfile\tAlternate to System rc.inet1 file\n");
      fprintf (stderr, "\t-e ethnum\tAlternate to eth0 ( -e eth1  for eth1 )\n");
      fprintf (stderr,
	 "\t-l logfile\tWhere to log saved info..open until done\n");
      fprintf (stderr, "\t-t\t\tEnter in TOP mode (this)\n\n");
      fprintf (stderr, "\t-h\t\tHelp Message (this)\n\n");
      gh (2);
      exit (0);
   }

#define MAXDEVS 20
#define MAXDEVNAME 10
static char devnames[MAXDEVS][MAXDEVNAME]; /* init to empty... in initialization */
static int namecheck = TRUE; /* table empty.. need to put name in table */
static int saved_index_ll = 0;



int
   doeth ()
   {
#if defined(SYS_IF_PACKET_H) || defined(LINUX_IF_PACKET_H) || defined(NET_IF_PACKET_H)
	 static struct sockaddr_ll saddr;
      static struct ifreq ifr;
      int ir;
#else
      static struct sockaddr saddr;
#endif
      int sizeaddr;
      int length;
      int cont = FALSE;

      do
      {
#if defined(SYS_IF_PACKET_H) || defined(LINUX_IF_PACKET_H) || defined(NET_IF_PACKET_H)
	    sizeaddr = sizeof (struct sockaddr_ll);
	 length =
	    recvfrom (sd, buf, sn_rcv_bufsize, 0,
	    (struct sockaddr *) &saddr, &sizeaddr);
#else
	 sizeaddr = sizeof (struct sockaddr);
	 length = recvfrom (sd, buf, sn_rcv_bufsize, 0, &saddr, &sizeaddr);
#endif
/*
	    * if recvfrom() is interrupted by screen update, an EINTR happens. 
*/
	 if (length < 0)
	 {
/*
	       * I didn't want to do this... but non-blocking actually makes
	       * this run... :(
	       *
	       * Wow... ICMP calls see to come through HERE!!! when remote
	       * This is super weird... the recvfrom is EAGAIN but the data
	       * is meaningful!!! This appears to be the case for all Linux
	       * kernels that I am running... version 1.2.13 and above...
*/

	    if (errno == EWOULDBLOCK)
	    {
/*       handle_frame (buf, sn_rcv_bufsize, NULL,isethdev); 
		  IGNORE FOR NOW!!! 
		  ethcnt++;   */
	       cont = TRUE;
	       continue;
	    }
	    if (errno != EINTR)
	    {   /*
		  * if error detected and error is
		  * not expected type 
*/
	       probcnt++;
	    }
	    else
	    {
	       intrcnt++;
	    }
	 }
      }
      while (cont && errno == EINTR);
      if (length)
      {

#if defined(SYS_IF_PACKET_H) || defined(LINUX_IF_PACKET_H) || defined(NET_IF_PACKET_H)
	    ifr.ifr_ifindex = saddr.sll_ifindex;
	 if (namecheck)
	 {
	    ir = ioctl (sd, SIOCGIFNAME, &ifr);
	    if (!strcmp (ethdevname, ifr.ifr_name))
	    {
	       int i;
/* search devname table... */
	       for (i = 0; i < MAXDEVS; i++)
	       {
		  if (!strcmp (devnames[i], ethdevname))
		     break;
	       }
	       if (i == MAXDEVS)
	       {
		  strncpy (devnames[saddr.sll_ifindex], ethdevname,
		     MAXDEVNAME);
		  saved_index_ll = saddr.sll_ifindex;
	       }
	       else
		  saved_index_ll = i;
	       namecheck = FALSE;
	       handle_frame (buf, length, (struct sockaddr *) &saddr,
		  isethdev);
	       ethcnt++;
	    }

	 }
	 else
	 {
	    if (saddr.sll_ifindex == saved_index_ll)
	    {
	       if (isbridge)
	       {
		  if (!memcmp (buf, rbuf, length))
		  {
		     handle_frame (buf, length,
			(struct sockaddr *) &saddr, isethdev);
		     ethcnt++;
		     memcpy (rbuf, buf, length);
		  }
		  else
		     dupcount++;
	       }
	       else
	       {
		  handle_frame (buf, length, (struct sockaddr *) &saddr,
		     isethdev);
		  ethcnt++;
	       }
	    }
	 }
#else
	 if (isbridge)
	 {
	    if (!memcmp (buf, rbuf, length))
	    {
	       handle_frame (buf, length, (struct sockaddr *) &saddr,
		  isethdev);
	       ethcnt++;
	       memcpy (rbuf, buf, length);
	    }
	    else
	       dupcnt++;
	 }
	 else
	 {
	    handle_frame (buf, length, (struct sockaddr *) &saddr, isethdev);
	    ethcnt++;
	 }

#endif
	 return 0;   /* XXX-PS: wasn't here, but then there's no return... */
      }
      else
	 return (-1);  /* XXX-PS: used to be return 0, but elsewhere failure is tested */

   }

int
   dokeyin (int force)
   {
      int in_char;
      int dum;
      int ii;
      int rr;
      int i;
      int length;

      ESCON = 0;
      in_char = '\0';
      if (!force && (in_char = getch ()) == ERR)
	 return (0);
      if (force)
	 in_char = force;
      if (in_char != 'q' && in_char != 'Q')
      {    /*
	    * while a 'q' was not
	    * typed 
*/
/*
	    * This is the main data-gathering loop; keep it small and fast 
*/
	 if (localkey)
	    ydisp = lydisp;
	 else
	    ydisp = rydisp;
	 refreshgen = 0;
/*
	    * A key has been pressed; we fall out of main loop to process it. 
	    * Wanted: A HELP screen should be added somehow. 
	    * Wanted: Should show "q to quit" reminder if unknown keys are pressed. 
*/
	 if (isdigit (in_char))
	 {
	    if (repeatindex < 255)
	    {
	       repeatbuf[repeatindex++] = in_char;
	       repeatbuf[repeatindex] = 0;
	       repeatcount = atoi (repeatbuf);
/* if (repeatcount < 1)
		  repeatcount = 1; */
	    }
	    else
	    {
	       repeatindex = 0;
		  *repeatbuf = 0;
	    }
	 }
	 else
	 {
	    repeatindex = 0;
	       *repeatbuf = 0;
	       switch (in_char)
	    {
	       case RETURNKEY:
		  if (help)
		  {
		     helppage++;
			if (helppage > MAXHELPPAGE)
			helppage = 1;
			setuphelp ();
		  }
		  break;
	       case ESC:
	       case KEY_F (10):
	       case KEY_END:
		  if (watch || help)
		  {
		     if (selecthost)
			selectside = localkey;
			watch = help = selecthost = magnafull = FALSE;
			disprouterstats = FALSE;
			if (localkey)
			refreshrem = TRUE;
			else
			refreshloc = TRUE;
		  }
		  break;
	       case CONTROLL:
		  clrscr ();
		     if (watch)
		  {
		     if (magnafull)
			setupwatch (FULLSCREEN);
			else
			setupwatch (SMALLSCREEN);
		  }
		  if (help)
		     setuphelp ();
		     rewrite_labels = TRUE;
		     refreshrem = TRUE;
		     refreshloc = TRUE;
		     break;
	       case KEY_NPAGE:
		  if (selecthost)
		  {
		     for (rr = 0; rr < repeatcount; rr++)
		     {
			magnaphys += MLINES - 14;
			   if (magnaphys >= MAGNAMAX)
			   magnaphys -= MAGNAMAX;
		     }
		     break;
		  }
	       case KEY_DOWN: /*
		     * DOWN KEY 
*/
		  if (selecthost)
		  {
		     if (magnafull)
		     {
			for (rr = 0; rr < repeatcount; rr++)
			{
			   magnaphys += 1;
			      if (magnaphys >= MAGNAMAX)
			      magnaphys -= MAGNAMAX;
			}

		     }
		     else
		     {
			selectside = localkey;
			   selectchange = TRUE;
			   for (ii = 0; ii < MAGNAMAX; ii++)
			   magna[ii].len = -1;
			   magnacnt = 0;
			   magnaphys = 0;
			   magnafirst = TRUE;
			   magnacomhost = NULL;
			   for (rr = 0; rr < repeatcount; rr++)
			{
			   numselect++;
			      if (numselect >= (MLINES - 5))
			   {
			      ydisp += (MLINES - 5);
				 refreshgen = TRUE;
				 numselect = 0;
			   }
			}
		     }
		  }
		  else
		  {
		     for (rr = 0; rr < repeatcount; rr++)
		     {
			ydisp += (MLINES - 5);
			   refreshgen = TRUE;
		     }
		  }
		  break;
	       case KEY_LEFT: /*
		     * LEFT KEY 
*/
		  if (selecthost)
		  {
		     for (rr = 0; rr < repeatcount; rr++)
		     {
			magnaoffs -= 10;
			   if (magnaoffs < 0)
			   magnaoffs = 0;
		     }
		  }
		  else
		  {
		     if (watch && disprouterstats && routersummary)
		     {
			for (rr = 0; rr < repeatcount; rr++)
			{
			   router_offset += rdelta;
			      if (router_offset >= MAXDAYROUTE)
			      router_offset = MAXDAYROUTE - rdelta;
			}
			refreshgen = TRUE;
		     }
		     else
		     {
			for (rr = 0; rr < repeatcount; rr++)
			{
			   dispopt--;
			      if (dispopt < 0)
			      dispopt = DISP_MAX;
			}
			poschange = 1;
			   rewrite_labels = 1;
		     }
		  }
		  break;
	       case KEY_PPAGE:
		  if (selecthost)
		  {
		     for (rr = 0; rr < repeatcount; rr++)
		     {
			magnaphys -= MLINES - 14;
			   if (magnaphys < 0)
			   magnaphys += MAGNAMAX;
		     }
		     break;
		  }
	       case KEY_UP: /*
		     * UP KEY 
*/
		  if (selecthost)
		  {
		     if (magnafull)
		     {
			for (rr = 0; rr < repeatcount; rr++)
			{
			   magnaphys -= 1;
			      if (magnaphys < 0)
			      magnaphys += MAGNAMAX;
			}

		     }
		     else
		     {
			selectside = localkey;
			   selectchange = TRUE;
			   for (ii = 0; ii < MAGNAMAX; ii++)
			   magna[ii].len = -1;
			   magnacnt = 0;
			   magnaphys = 0;
			   magnafirst = TRUE;
			   magnacomhost = NULL;
			   for (rr = 0; rr < repeatcount; rr++)
			{
			   numselect--;
			      if (numselect < 0)
			   {
			      numselect = MLINES - 6;
				 ydisp -= (MLINES - 5);
				 if (ydisp < 0)
				 ydisp = 0;
				 refreshgen = TRUE;
			   }
			}
		     }
		  }
		  else
		  {
		     for (rr = 0; rr < repeatcount; rr++)
		     {
			ydisp -= (MLINES - 5);
			   if (ydisp < 0)
			   ydisp = 0;
		     }
		     refreshgen = TRUE;
		  }
		  break;
	       case KEY_RIGHT: /*
		     * RIGHT KEY 
*/
		  if (selecthost)
		  {
		     for (rr = 0; rr < repeatcount; rr++)
		     {
			if (magnaoffs>sn_rcv_bufsize)
			   magnaoffs = sn_rcv_bufsize - 10;
			   else
			   magnaoffs += 10;
		     }

		  }
		  else
		  {
		     if (watch && disprouterstats && routersummary)
		     {
			for (rr = 0; rr < repeatcount; rr++)
			{
			   router_offset -= rdelta;
			      if (router_offset < 0)
			      router_offset = 0;
			}
			refreshgen = TRUE;
		     }
		     else
		     {
			for (rr = 0; rr < repeatcount; rr++)
			{
			   dispopt++;
			      if (dispopt > DISP_MAX)
			      dispopt = 0;
			}
			rewrite_labels = 1;
			   poschange = 1;
		     }
		  }
		  break;
	       case KEY_F (1):
	       case 'h':
	       case 'H':
		  help = TRUE;
		     setuphelp ();
		     break;
	       case 'O':
	       case 'o':
		  if (selecthost)
		  {
		     buf_detail++;
			if (buf_detail>= BUF_DETAIL_MAX)
			buf_detail = 0;
		  }
		  break;
	       case KEY_F (4):
	       case 'w':
	       case 'W':
		  watch = TRUE;
		     disprouterstats = FALSE;
		     setupwatch (SMALLSCREEN);
		     break;
	       case 'R':
	       case 'r':
		  if (watch)
		  {
		     setupauxscr (&dum, SMALLSCREEN);
			disprouterstats = TRUE;
		  }
		  else
		  {
/* toggle rate flag for display in kbits/sec or bytes */
		     bpsflag = ++bpsflag & 1;
			rewrite_labels = 1;
		  }
		  break;
	       case 'f':
	       case 'F':
		  freezedisplay++;
		     freezedisplay &= 1;
		     if (freezedisplay)
		  {
/* print message */
		     status_box (" N O T I C E ",
			"Netwatch Display is frozen, but the actual monitoring is still continuing",
			(MCOLS >> 1) - 10, (MLINES >> 1) - 3, 20);
		  }
		  else
		  {
/* make sure WHOLE screen is updated */

		     if (watch)
			setupwatch (SMALLSCREEN);
			if (help)
			setuphelp ();
			rewrite_labels = TRUE;
			refreshrem = TRUE;
			refreshloc = TRUE;
		  }
		  break;
	       case 'd':
	       case 'D':
		  if (selecthost)
		  {
		     plogdeselect = TRUE;
		  }
		  else
		     if (disprouterstats)
		  {
		     switch (rdelta)
		     {
			case 60:
			   rdelta = 30;
			      break;
			case 30:
			   rdelta = 15;
			      break;
			case 15:
			   rdelta = 1;
			      break;
			case 1:
			   rdelta = 60;
			      break;
			default:
			   rdelta = 60;
		     }
		     refreshgen = TRUE;
		  }
		  else
		  {
		     ignoredomain++;
			ignoredomain &= 1;
		  }
		  break;
	       case 'b':
	       case 'B':
		  bluedie++;
		     bluedie &= 1;
		     break;
	       case '.':
		  if (nw_simulate && (nw_simrate==SIMKEY ||
		     (nw_simrate==SIMSEC && simkeyrate==0)))
		  {

		     if (simfp==NULL) simfp = fopen(nw_simfile,"r");
			for (rr = 0; rr < repeatcount; rr++)
		     {
			for (i=0;i<simkeyrate;i++)
			{
			   if (simfp!=NULL && simfwdir &&
			      getoneeth(simfp,buf,&length)>=0)
			      {
				 ethcnt++;
				    handle_frame(buf,length,NULL,TRUE);
			      }
			   else if (simfp!=NULL && !simfwdir &&
			      putoneeth(simfp,buf,&length)>=0)
			      {
				 ethcnt--;
				    handle_backframe(buf,length,NULL,TRUE);
			      }
/* only works for ETH logs not PPP??? */
			}
		     }
		  }
		  break;
	       case 'p':
		  printtospeclog = TRUE;
		     break;

	       case 'l':
	       case 'L':
		  if (selecthost)
		  {
		     plogselect=TRUE;
		  }
		  else
		     if ((statpid = fork ()) == 0)
		  {
/*
			* In child process... to handle stats...
*/
		     signal (SIGUSR1, SIG_IGN);
			signal (SIGUSR2, SIG_IGN);
			gostats ();
			exit (0);

		  }
		  break;
	       case '\t':  /*
		     * Switch from LOCAL to REMOTE sides of
		     * screen 
*/

		  if (selecthost)
		  {
		     if (magnafull)
			break;
			selectchange = TRUE;
			for (ii = 0; ii < MAGNAMAX; ii++)
			magna[ii].len = -1;
			magnacnt = 0;
			magnaphys = 0;
			magnafirst = TRUE;
			magnacomhost = NULL;
		  }
		  localkey++;
		     localkey &= 1;
		     if (localkey)
		     ydisp = lydisp;
		     else
		     ydisp = rydisp;
		     if (selecthost)
		     selectside = localkey;
		     if (watch)
		     setupwatch (SMALLSCREEN);
		     else if (help)
		     setuphelp ();
		     if (watch || help)
		  {
		     if (localkey)
			refreshrem = TRUE;
			else
			refreshloc = TRUE;
		  }
		  break;
	       case 't':
	       case 'T':  /*  TOP Users matched */
		  topflag++;
		     topflag &= 1;
		     break;
	       case 'c':
	       case 'C':
/*
		     * Clear Counters 
*/
		  if (watch && disprouterstats)
		  {
		     maxburst = 0;
			break;
		  }
		  if (in_char == 'c' || (in_char == 'C' && localkey))
		  {
		     current = lfirst->flink;
			while (current != lfirst)
		     {
			current->update = 2;
			   clearentry (current);
			   current = current->flink;
		     }
		     localupdate = 1;
		  }
		  if (in_char == 'c' || (in_char == 'C' && !localkey))
		  {
		     current = rfirst->flink;
			while (current != rfirst)
		     {
			current->update = 2;
			   clearentry (current);
			   current = current->flink;
		     }
		     remoteupdate = 1;
		  }
		  break;
	       case 'n':
	       case 'N':
/*
		     * Start NEW.... Delete all entries...start again 
*/
		  if (in_char == 'n' || (in_char == 'N' && localkey))
		  {
		     llockout = 1;
			current = lfirst->flink;
			lfirst->flink = lfirst;
			lfirst->blink = lfirst;
			while (current != lfirst)
		     {
			work = current->flink;
			   free (current);
			   current = work;
		     }
		     toplocal = &tldummy;
			toplocal->tflink = toplocal;
			llockout = 0;
			localcount = 0;
		  }
		  if (in_char == 'n' || (in_char == 'N' && !localkey))
		  {
		     rlockout = 1;
			current = rfirst->flink;
			rfirst->flink = rfirst;
			rfirst->blink = rfirst;
			while (current != rfirst)
		     {
			work = current->flink;
			   free (current);
			   current = work;
		     }
		     topremote = &trdummy;
			topremote->tflink = topremote;
			rlockout = 0;
			remotecount = 0;
		  }
		  rewrite_labels = 1;
		     poschange = 1;
		     for (ii = 0; ii < MAXDAYROUTE; ii++)
		     dayroute[ii] = -1;
		     cur_dayroute = 0;
		     break;
	       case 'q':
	       case 'Q':
		  break;
	       case ' ':
		  mvprintw (0, 60, "%c", ACS_BLOCK);
		     bugfix = TRUE;
		     break;
	       case '>':
		  if (nw_simulate)
		  {
		     rr = repeatcount;
			simkeyrate = rr;
			if (rr>8) rr=8;
			for (ii=0;ii<8;ii++) simarr[ii]=4;
			if (rr>=3)
			simarr[6]=3;
			if (rr>=2)
			simarr[5]=3;
			if (rr>=1)
			simarr[4]=3;
			if (rr==0)
		     {
			simarr[3] = 1;
			   simfwdir = TRUE;
		     }
		     simchange = TRUE;
		  }
		  break;
	       case '<':
		  if (nw_simulate)
		  {
		     rr = repeatcount;
			simkeyrate = rr;
			if (rr>8) rr=8;
			for (ii=0;ii<8;ii++) simarr[ii]=4;
			if (rr>=3)
			simarr[0]=3;
			if (rr>=2)
			simarr[1]=3;
			if (rr>=1)
			simarr[2]=3;
			if (rr==0)
		     {
			simarr[3] = 1;
			   simfwdir = FALSE;
		     }
		     simchange = TRUE;

		  }
		  break;
	       case 's':  /*
		     * SELECT HOST in WATCH MODE 
		     * or CHANGE status line (in all other modes)
*/
	       case 'S':
		  if (watch)
		  {
		     if (disprouterstats)
		     {
			routersummary++;
			   routersummary &= 1;
			   setupauxscr (&dum, SMALLSCREEN);
			   refreshgen = TRUE;
		     }
		     else
		     {
			selecthost = TRUE;
			   selectside = localkey;
			   selectchange = TRUE;
			   for (ii = 0; ii < MAGNAMAX; ii++)
			   magna[ii].len = -1;
			   magnacnt = 0;
			   magnaphys = 0;
			   magnafirst = TRUE;
			   magnacomhost = NULL;
			   numselect = 0;
			   if (localkey)
			   refreshrem = TRUE;
			   else
			   refreshloc = TRUE;
		     }
		  }
		  else
		  {
		     for (rr = 0; rr < repeatcount; rr++)
		     {
			cur_status_line++;
			   if (cur_status_line >= MAXSTATUS)
			   cur_status_line = 0;
		     }
		  }
		  break;
	       case 'z':  /*
		     * ZOOM for trace in WATCH MODE 
*/
	       case 'Z':
		  if (watch && selecthost)
		  {
		     magnafull++;
			magnafull &= 1;
			if (!magnafull)
		     {
			if (localkey)
			   refreshrem = TRUE;
			   else
			   refreshloc = TRUE;
			   setupwatch (SMALLSCREEN);
		     }
		     else
			setupwatch (FULLSCREEN);
		  }
		  break;
	       default:
		  mvprintw (0, 60, "%02x", in_char);
		     break;
	    }
	    repeatcount = 1;
	 }
	 if (magnafull)
	    return (0);
	    if (localkey)
	 {
	    if (lydisp != ydisp)
	       refreshloc = refreshgen;
	       lydisp = ydisp;
	 }
	 else
	 {
	    if (rydisp != ydisp)
	       refreshrem = refreshgen;
	       rydisp = ydisp;
	 }
	 return (0);
      }
/*
	 * while a 'q' was not typed
*/
      else
	 return (-1);
   }
