/*
 * |-----------------------------------------------------------|
 * | Copyright (c) 1991, 1990 MIPS Computer Systems, Inc.      |
 * | All Rights Reserved                                       |
 * |-----------------------------------------------------------|
 * |          Restricted Rights Legend                         |
 * | Use, duplication, or disclosure by the Government is      |
 * | subject to restrictions as set forth in                   |
 * | subparagraph (c)(1)(ii) of the Rights in Technical        |
 * | Data and Computer Software Clause of DFARS 252.227-7013.  |
 * |         MIPS Computer Systems, Inc.                       |
 * |         950 DeGuigne Avenue                               |
 * |         Sunnyvale, California 94088-3650, USA             |
 * |-----------------------------------------------------------|
 */
#ident	"$Header: trace.c,v 1.5.2.1 92/06/24 13:39:22 marker Exp $"
/*
 *   CENTER FOR THEORY AND SIMULATION IN SCIENCE AND ENGINEERING
 *			CORNELL UNIVERSITY
 *
 *      Portions of this software may fall under the following
 *      copyrights: 
 *
 *	Copyright (c) 1983 Regents of the University of California.
 *	All rights reserved.  The Berkeley software License Agreement
 *	specifies the terms and conditions for redistribution.
 *
 *  GATED - based on Kirton's EGP, UC Berkeley's routing daemon (routed),
 *	    and DCN's HELLO routing Protocol.
 */

#ifndef	lint
static char *rcsid = "$Header: trace.c,v 1.5.2.1 92/06/24 13:39:22 marker Exp $";
#endif	not lint

/* trace_egp.c
 *
 * Tracing functions for route changes, received packets and EGP messages.
 *
 * Functions: traceaction (modified from routed/trace.c), tracercv, traceegp
 */

#include "include.h"
#ifndef vax11c
#include <sys/stat.h>
#endif	vax11c
#if	defined(AGENT_SNMP) || defined(AGENT_SGMP)
#ifndef RISCOS
#include <snmp.h>
#endif RISCOS
#endif	defined(AGENT_SNMP) || defined(AGENT_SGMP)

extern FILE *conf_open();

/*
 * traceaction() traces changes to the routing tables
 */
traceaction(fd, action, rt)
	FILE *fd;			/* trace logfile */
	char *action;
	struct rt_entry *rt;
{
  struct sockaddr_in *dst, *gate;
  register struct bits *p;
  register int first;
  char *cp;

  if (fd == NULL)
    return;
  fprintf(fd, "%-8s ", action);
  dst = (struct sockaddr_in *)&rt->rt_dst;
  gate = (struct sockaddr_in *)&rt->rt_router;
  fprintf(fd, "%4s %-15s ", (rt->rt_state & RTS_HOSTROUTE ? "host" : "net" ), inet_ntoa(dst->sin_addr));
  fprintf(fd, "gw %-15s metric %5d  proto ", inet_ntoa(gate->sin_addr), rt->rt_metric);
  cp = "%s";
  for (first = 1, p = protobits; p->t_bits; p++) {
    if ((rt->rt_proto & p->t_bits) == 0)
      continue;
    fprintf(fd, cp, p->t_name);
    if (first) {
      cp = "|%s";
      first = 0;
    }
  }
  fprintf(fd, "  flags");
  cp = " %s";
  for (first = 1, p = flagbits; p->t_bits; p++) {
    if ((rt->rt_flags & p->t_bits) == 0)
      continue;
    fprintf(fd, cp, p->t_name);
    if (first) {
      cp = "|%s";
      first = 0;
    }
  }
  fprintf(fd, "  state");
  cp = " %s";
  for (first = 1, p = statebits; p->t_bits; p++) {
    if ((rt->rt_state & p->t_bits) == 0)
      continue;
    fprintf(fd, cp, p->t_name);
    if (first) {
      cp = "|%s";
      first = 0;
    }
  }
#ifndef	NSS
  if (rt->rt_proto & RTPROTO_HELLO) {
    printf("  hwin_min %d ", rt->rt_hwindow.h_min);
  }
#endif	NSS
  if ( rt->rt_fromproto != rt->rt_proto) {
    printf("  fromproto ");
    cp = "%s";
    for (first = 1, p = protobits; p->t_bits; p++) {
      if ((rt->rt_fromproto & p->t_bits) == 0)
        continue;
      fprintf(fd, cp, p->t_name);
      if (first) {
        cp = "|%s";
        first = 0;
      }
    }
  }
  if ( rt->rt_state & RTS_EXTERIOR ) {
    printf("  extmetric %d", rt->rt_metric_exterior);
  }
  if ( rt->rt_as != mysystem ) {
    printf("  as %d", rt->rt_as);
  }
  (void) fprintf(fd, "\n");

#ifdef	notdef
  if ((rt->rt_announcelist != NULL) && (tracing & TR_INT)) {
    dst = (struct sockaddr_in *)&rt->rt_announcelist->rdst;
    fprintf(fd, "ANNOUNCE net %s, ", inet_ntoa(dst->sin_addr));
    fprintf(fd, "metric %d, proto %d\n",rt->rt_announcelist->regpmetric, rt->rt_announcelist->rproto);
  }
  if ((rt->rt_noannouncelist != NULL) && (tracing & TR_INT)) {
    dst = (struct sockaddr_in *)&rt->rt_noannouncelist->rdst;
    fprintf(fd, "NOANNOUNCE net %s, ", inet_ntoa(dst->sin_addr));
    fprintf(fd, "metric %d, proto %d\n",rt->rt_noannouncelist->regpmetric, rt->rt_noannouncelist->rproto);
  }
#endif	notdef
}


/*
 * Turn off tracing.
 */
traceoff(tracetype)
	int tracetype;
{
  int tracedel = 0;

#ifndef	NSS
  if (tracetype & RIP_TRACE) {
    tracedel |= (TR_UPDATE|TR_RIP);
  }
  if (tracetype & HELLO_TRACE) {
    tracedel |= (TR_UPDATE|TR_HELLO);
  }
#endif	NSS
  if (!tracing) {
    return;
  }
  tracing &= ~tracedel;  /* unflag added tracing options */
  if ((ftrace != NULL) && (tracetype & GEN_TRACE)) {
    TRACE_TRC("Tracing to %s suspended at %s", logfile, strtime);
    tracing = 0;
#ifdef	notdef
    (void) fflush(ftrace);
    (void) fflush(stdout);
    (void) fflush(stderr);
#endif	notdef
    (void) fclose(ftrace);
    (void) fclose(stdout);
    (void) fclose(stderr);
    ftrace = NULL;
    syslog(LOG_ERR, "tracing to %s suspended", logfile);
  }
  return;
}

/*
 * Turn on tracing.
 */
traceon(file, tracetype)
	char *file;
	int tracetype;
{
#ifndef vax11c
  struct stat stbuf;
#endif	vax11c
  int traceadd = 0;

  switch (tracetype) {
#ifndef	NSS
    case RIP_TRACE:
      traceadd |= (TR_UPDATE|TR_RIP);
      break;
    case HELLO_TRACE:
      traceadd |= (TR_UPDATE|TR_HELLO);
      break;
#endif	NSS
    case GEN_TRACE:
      traceadd |= savetrace;
      break;
  }

  if ((ftrace == NULL) && (file != NULL)) {
#ifndef vax11c
    if ((stat(file, &stbuf) >= 0) && ((stbuf.st_mode & S_IFMT) != S_IFREG)) {
      return;
    }
#endif	vax11c
    if ((ftrace = fopen(file, "a")) == NULL) {
      syslog(LOG_ERR, "error opening %s: %m", file);
      return;
    }
#ifndef vax11c
    setlinebuf(ftrace);
#endif	vax11c
    if ( freopen(file, "a", stdout) == NULL ) {
      syslog(LOG_ERR, "error opening %s: %m", file);
      return;
    }
#ifndef vax11c
    setlinebuf(stdout);
#endif	vax11c
    if ( freopen(file, "a", stderr) == NULL ) {
      syslog(LOG_ERR, "error opening %s: %m", file);
      return;
    }
#ifndef vax11c
    setlinebuf(stderr);
#endif	vax11c
    syslog(LOG_ERR, "tracing to %s started", file);
    printf("\fTracing to %s started at %s", file, strtime);
  }
  tracing |= traceadd;
  tracedisplay(tracing);
}


/*
 * Read tracing information from conf file
 */
traceflags()
{
	FILE	*fd;
	int	more_flags, new_flags, trace_flags = 0;
	char	c, keyword[MAXHOSTNAMELENGTH+1];
	struct	bits *flag_ptr;
	char line[256], *lp;

	if ( (fd = conf_open()) == NULL) {
		return(trace_flags);
	}
	while (fgets(line, sizeof(line), fd) != NULL) {
		if ( (*line == '\n') || (*line == '#') ) {
			continue;
		}
		lp = line;
		(void) sscanf(lp, "%s", keyword);
		lp += strlen(keyword);
		if (strcasecmp(keyword, "traceflags") != 0) {
			continue;
		}
		more_flags = TRUE;
		while (more_flags) {
			switch (c= *lp++) {
			case '\n':
				*--lp = c;
			case '\0':
			case '#':
				more_flags = FALSE;
				break;
			case ' ':
			case '\t':
				break;
			default:
				*--lp = c;
				(void) sscanf(lp, "%s", keyword);
				lp += strlen(keyword);
				new_flags = 0;
				for ( flag_ptr = trace_types; flag_ptr->t_name; flag_ptr++ ) {
					if ( strcasecmp(keyword, flag_ptr->t_name) == 0 ) {
						new_flags = flag_ptr->t_bits;
						break;
					}
				}
				if ( new_flags == 0 ) {
					TRACE_INT("traceflags: invalid trace flag '%s' ignored\n", keyword);
					syslog(LOG_ERR, "traceflags: invalid trace flag '%s' ignored\n", keyword);
				}
				trace_flags |= new_flags;
			}
		}
	}
	(void) fclose(fd);

	return(trace_flags);
}


/*
 *	Display trace options enabled
 */
tracedisplay(trace_flags)
int	trace_flags;
{
  struct bits *flag_ptr, *last_ptr;

  printf("\nTracing flags enabled: ");
  if ( trace_flags ) {	
    last_ptr = &trace_types[1];
    for ( flag_ptr = trace_types; flag_ptr->t_name; last_ptr = flag_ptr++ ) {
      if ( ((trace_flags & flag_ptr->t_bits) == flag_ptr->t_bits) &&
           (flag_ptr->t_bits != last_ptr->t_bits) ) {
        printf("%s ", flag_ptr->t_name);
      }
    }
    printf("\n\n");
  } else {
    printf("none\n\n");
  }
}


/*
 * trace packets received
 *
 * Only trace data part - EGP packets include IP header but ICMP packets do
 * not (but on 4.3BSD they DO, well it is passed to the RAW ICMP socket.
 */
tracercv(sock, protocol, packet, length, frompt)
	int sock, protocol, length;
	struct sockaddr_in *frompt;
	char *packet;
{
  struct sockaddr_in  sockname;
  int  socklen = sizeof (sockname), i;
  struct ip *pkt;
  int hlen;

  pkt = (struct ip *)packet;
  switch (protocol) {
    case IPPROTO_EGP: 
      hlen = pkt->ip_hl;
      hlen <<= 2;			/* IP header length in octets */
      TRACE_EGPPKT(EGP RECV, pkt->ip_src, pkt->ip_dst,
			(struct egppkt *)(packet+hlen), pkt->ip_len);
      break;
#ifdef IMPLINK_IP
    case IMPLINK_IP: 	/* not implemented */
#endif IMPLINK_IP
    case IPPROTO_ICMP: 	/* IP header not passed with ICMP messages */
      if (getsockname (sock, (char *)&sockname, &socklen))
        p_error ("tracercv: getsockname");
      printf("\nPacket received at time %s", strtime);
      printf("protocol %d, from addr %s",protocol,inet_ntoa(frompt->sin_addr));
      printf(", on interface addr %s\n", inet_ntoa(sockname.sin_addr));
      printf("Data octets (decimal):\n");
      for (i = 0; i < length; i++)
        printf ("%d ", packet[i]);
      printf ("\n");
      break;
  }
  return;
}

/*
 * Trace EGP packet
 */
traceegp(comment, src, dst, egp, length)
	char  *comment;
	struct in_addr	src, dst;
	struct	egppkt	*egp;
	int	length;
{
  struct egppkt	*ep;
  int reason;
  char *type, *code, *status;
  static char *no_codes[1] = { "0" };
  static struct  {
	char *et_type;
	short et_ncodes;
	char **et_codes;
	char et_nstatus;
	char **et_status;
	} egp_types[9] = {
	"Invalid",	-1,	(char **) 0,	-1,	(char **)0,	/* 0 - Error */
	"UPDATE",	0,	no_codes,	3,	egp_nr_status,	/* 1 - Nets Reachable */
	"POLL",		0,	no_codes,	3,	egp_nr_status,	/* 2 - Poll */
	"ACQUIRE",	5,	egp_acq_codes,	7,	egp_acq_status,	/* 3 - Neighbor Aquisition */
	"Invalid",	-1,	(char **) 0,	-1,	(char **)0,	/* 4 - Error */
	"NEIGHBOR",	2,	egp_reach_codes, 3,	egp_nr_status,	/* 5 - Neighbor Reachability */
	"Invalid",	-1,	(char **) 0,	-1,	(char **)0,	/* 6 - Error */
	"Invalid",	-1,	(char **) 0,	-1,	(char **)0,	/* 7 - Error */
	"ERROR",	-1,	(char **) 0,	3,	egp_nr_status};	/* 8 - Error packet */

  printf("%s", comment);
  if (src.s_addr != INADDR_ANY)
    printf(" %s", inet_ntoa(src));
  printf(" -> %s length %d at %s", inet_ntoa(dst), length, strtime);

  if ( egp->egp_type <= EGPERR ) {
    type = egp_types[egp->egp_type].et_type;
    if ( (short)(egp->egp_code % UNSOLICITED) <= egp_types[egp->egp_type].et_ncodes ) {
      code = egp_types[egp->egp_type].et_codes[(egp->egp_code % UNSOLICITED)];
    } else {
      if ( (egp->egp_code % UNSOLICITED) == 0 ) {
	code = "";
      } else {
        code = "Invalid";
      }
    }
    if ( egp->egp_status <= egp_types[egp->egp_type].et_nstatus ) {
      status = egp_types[egp->egp_type].et_status[egp->egp_status];
    } else {
      status = "Invalid";
    }
  } else {
    type = "Invalid";
  }
  printf("%s vers %d, type %s(%d), code %s(%d), status %s(%d)%s, AS# %d, id %d",
		comment,
		egp->egp_ver,
		type, egp->egp_type,
		code, egp->egp_code,
		status, egp->egp_status,
		egp->egp_code & UNSOLICITED ? " UNSOLICITED" : "",
		ntohs(egp->egp_system), ntohs(egp->egp_id));
  if (length > sizeof( struct egppkt))
    switch (egp->egp_type) {
      case EGPACQ:
        printf(", hello int %d, poll int %d", 
                       ntohs(((struct egpacq *)egp)->ea_hint),
                       ntohs(((struct egpacq *)egp)->ea_pint));
        break;
      case EGPPOLL:
        printf(", src net %s", inet_ntoa(((struct egppoll *)egp)->ep_net));
        break;
      case EGPNR:
        printf(", src net %s, #int %d, #ext %d\n",
                       inet_ntoa(((struct egpnr *)egp)->en_net),
                       ((struct egpnr *)egp)->en_igw,
                       ((struct egpnr *)egp)->en_egw);
        if (length > sizeof(struct egpnr) && ( tracing & TR_UPDATE) ) {
#ifdef	EGP_UPDATE_FORMAT
          NR_format((struct egpnr *)egp, length);
#else	EGP_UPDATE_FORMAT
          register u_char *data, *dataf;

          data = (u_char *)egp + sizeof(struct egpnr);
          dataf = (u_char *)egp + length;
          for ( ; data < dataf; data++) 
             printf( "%d ", *data);
          printf("\n");
#endif	EGP_UPDATE_FORMAT
        }
        break;
      case EGPERR:
        reason = ntohs(((struct egperr *)egp)->ee_rsn);
	if ( reason > 7 ) {
	        printf(", error %d (invalid)\nreturned header: ",
			reason);
	} else {
		printf(", error: %s\nreturned header: ",
			egp_reasons[reason]);
	}
        ep = (struct egppkt *)((struct egperr*)egp)->ee_egphd;
        printf("vers %d, typ %d, code %d, status %d, AS# %d,",
                       ep->egp_ver, ep->egp_type, ep->egp_code,
                       ep->egp_status, ntohs(ep->egp_system));
        printf(" id %d, %d, %d", ntohs(ep->egp_id),
                       ((struct egperr *)egp)->ee_egphd[10],
                       ((struct egperr *)egp)->ee_egphd[11]);
        break;
    }
  printf("\n\n");
  return;
}

#ifndef	NSS
tracerip(dir, who, cp, size)
	struct sockaddr_in *who;		/* should be sockaddr */
	char *dir, *cp;
	register int size;
{
  register struct rip *rpmsg = (struct rip *)cp;
  register struct netinfo *n;
  register char *cmd = "Invalid";

  if (rpmsg->rip_cmd && rpmsg->rip_cmd < RIPCMD_MAX) {
    cmd = ripcmds[rpmsg->rip_cmd];
  }
  printf("RIP %s %s.%d vers %d, cmd %s, length %d",
                   dir,
                   inet_ntoa(who->sin_addr),
                   ntohs(who->sin_port),
                   rpmsg->rip_vers,
                   cmd, size);
  switch (rpmsg->rip_cmd) {
#ifdef	RIPCMD_POLL
    case RIPCMD_POLL:
#endif	RIPCMD_POLL
    case RIPCMD_REQUEST:
    case RIPCMD_RESPONSE:
      printf(" at %s", strtime);
      if (tracing & TR_UPDATE) {
        size -= 4 * sizeof (char);
        n = rpmsg->rip_nets;
        for (; size > 0; n++, size -= sizeof (struct netinfo)) {
          if (size < sizeof (struct netinfo)) {
            break;
          }
          printf("\tnet %-15s  metric %2d  size %d\n", inet_ntoa(sock_inaddr(&n->rip_dst)),
                      ntohl((u_long)n->rip_metric), size);
         }
      }
      break;
    case RIPCMD_TRACEON:
      printf(", file %*s at %s", size, rpmsg->rip_tracefile, strtime);
      break;
#ifdef	RIPCMD_POLLENTRY
    case RIPCMD_POLLENTRY:
      n = rpmsg->rip_nets;
      printf(", net %s at %s",
                  inet_ntoa(sock_inaddr(&n->rip_dst)),
                  strtime);
      break;
#endif	RIPCMD_POLLENTRY
    default:
      printf(" at %s", strtime);
      break;
  }
  printf("\n");
}

/* ARGSUSED */
tracehello(comment, src, dst, hello, length, nets)
	char  *comment;
	struct in_addr	src, dst;
	char	*hello;
	int	length, nets;
{
  printf("%s %s -> ", comment, inet_ntoa(src));
  printf("%s length %d", inet_ntoa(dst), length);
  if (nets < 0) {
    printf(", %d nets", nets);
  }
  printf(" at %s\n", strtime);
}
#endif	NSS

#if	defined(AGENT_SNMP) || defined(AGENT_SGMP)
tracesnmp(comment, dst, packet, length)
  char *comment;
  struct sockaddr_in *dst;
  char *packet;
  int length;
{
  int size, integer;
  char *cp;
  char *pkt = packet;
  register struct bits *p;
#ifdef	AGENT_SNMP
  struct in_addr ipaddr;
#endif	AGENT_SNMP
#ifndef RISCOS
  cp = "Unknown";
  for (p = snmp_types; p->t_bits > (u_int)0; p++) {
    if ( p->t_bits == *pkt ) {
      cp = p->t_name;
      break;
    }
  }

  printf("%s %s.%d type %s(%d) length %d at %s",
  	comment,
  	inet_ntoa(dst->sin_addr),
  	ntohs(dst->sin_port),
  	cp, *pkt++, length,
  	strtime);
 
  if (tracing & TR_UPDATE) {
    if ((pkt-packet) <= length) {
      switch (*packet) {
      case AGENT_RSP:
        while ((pkt-packet) <= length-1) {
          switch (*pkt++) {
            case INT:
              size = *pkt++;
              bcopy(pkt, (char *) &integer, size);
              pkt += size;
              printf("%s\tinteger length %d value: %d 0x%x\n", comment, size, integer, integer);
              break;
            case STR:
              size = *pkt++; 	
              printf("%s\tstring length %d value: ", comment, size);
              for (; size; size--) {
                printf("%c", *pkt++);
              }
              printf("\n");
              break;
#ifdef	AGENT_SNMP
            case IPADD:
              size = *pkt++;
              bcopy(pkt, (char *) &ipaddr.s_addr, size);
              pkt += size;
              printf("%s\tIP address length %d value: %s 0x%x\n", comment, size, inet_ntoa(ipaddr), ipaddr.s_addr);
              break;
            case CNTR:
              size = *pkt++;
              bcopy(pkt, (char *) &integer, size);
              pkt += size;
              printf("%s\tcounter length %d value: %u 0x%x\n", comment, size, integer, integer);
              break;
            case GAUGE:
              size = *pkt++;
              bcopy(pkt, (char *) &integer, size);
              pkt += size;
              printf("%s\tgauge length %d value: %u 0x%x\n", comment, size, integer, integer);
              break;
            case TIME:
              size = *pkt++;
              bcopy(pkt, (char *) &integer, size);
              pkt += size;
              printf("%s\ttimer length %d value: %u 0x%x\n", comment, size, integer, integer);
              break;
#endif	AGENT_SNMP
          }
        }
        break;
      case AGENT_ERR:
        break;
      case AGENT_REQ:
      case AGENT_REG:
        while ((pkt-packet) <= length-1) {
	  size = *pkt++; 	
          printf("%s\tlength %d variable: ", comment, size);
          for (; size; size--) {
            printf("%02x", *pkt++ & 0xff);
          }
          printf("\n");
        }
        break;
      }
    }
  } else {
    printf("\n");
  }
#endif RISCOS
}
#endif	defined(AGENT_SNMP) || defined(AGENT_SGMP)

dumpinfo()
{
  FILE *fd;
  register struct interface *ifp;

#define HELLO_REPORT	8	/* how far back we will report */

  register struct bits *p;
  register int first;
  char *cp, *ch;
  struct rthash	*rh;
  struct active_gw *agp;
  struct rthash	*base = hosthash;
  struct rt_entry *rt;
  int doinghost = 1, cnt, ind, cntr;
  struct in_addr tmpos;
  struct advlist *mptr;
  struct egpngh *ngp;

  if ((fd = fopen(DUMPFILE, "a")) <= (FILE *)0) {
    p_error("dumpinfo: ");
    return;
  }
#ifndef vax11c
  setlinebuf(fd);
#endif	vax11c
  syslog(LOG_NOTICE, "dumpinfo: processing dump to %s", DUMPFILE);
  TRACE_TRC("dumpinfo: processing dump to %s at %s", DUMPFILE, strtime);
  fprintf(fd, "\f\n\t%s[%d] version %s memory dump on %s at %s\n", my_name, my_pid, version, my_hostname, strtime);
  if (version_kernel) {
    fprintf(fd, "\t\t%s\n\n", version_kernel);
  }
  /*
   * Print out all of the interface stuff.
   */
  fprintf(fd, "Interface Stats:\n\n");
  for (ifp = ifnet; ifp; ifp = ifp->int_next) {
    fprintf(fd, "\tInterface: %s\t\t\tMetric: %d\n", ifp->int_name, ifp->int_metric);
    fprintf(fd, "\tAddress: %s\n", inet_ntoa(sock_inaddr(&ifp->int_addr)));
    fprintf(fd, "\tUp-down transitions: %u\n", ifp->int_transitions);
    if (ifp->int_flags & IFF_BROADCAST) {
      fprintf(fd, "\tBroadcast Address:   %s\n", inet_ntoa(sock_inaddr(&ifp->int_broadaddr)));
    }
    if (ifp->int_flags & IFF_POINTOPOINT) {
      fprintf(fd, "\tDestination Address: %s\n", inet_ntoa(sock_inaddr(&ifp->int_dstaddr)));
    }
#ifdef	NSS
	fprintf(fd, "\tIntra-NSS Address: %s\n", inet_ntoa(ifp->intra_nss_int.sin_addr));
#endif	NSS
    tmpos.s_addr = ntohl(ifp->int_net);
    fprintf(fd, "\tNet Number:    %s\t\tNet Mask:    %lx\n",
                       inet_ntoa(tmpos),
                       ifp->int_netmask);
    tmpos.s_addr = ntohl(ifp->int_subnet);
    fprintf(fd, "\tSubnet Number: %s\t\tSubnet Mask: %lx\n",
                       inet_ntoa(tmpos),
                       ifp->int_subnetmask);
    fprintf(fd, "\tFlags: <");
    cp = "%s";
    for (first = 1, p = intfbits; p->t_bits > (u_int)0; p++) {
      if ((ifp->int_flags & p->t_bits) == 0)
        continue;
      fprintf(fd, cp, p->t_name);
      if (first) {
        cp = "|%s";
        first = 0;
      }
    }
    fprintf(fd, ">\n");
#ifndef	NSS
    fprintf(fd, "\tFixed Metrics:\n");
    fprintf(fd, "\t\t\tRIP:\t");
    if (ifp->int_flags & IFF_RIPFIXEDMETRIC) {
      fprintf(fd, "%d\n", ifp->int_ripfixedmetric);
    } else {
      fprintf(fd, "NONE\n");
    }
    fprintf(fd, "\t\t\tHELLO:\t");
    if (ifp->int_flags & IFF_HELLOFIXEDMETRIC) {
      fprintf(fd, "%d\n", ifp->int_hellofixedmetric);
    } else {
      fprintf(fd, "NONE\n");
    }
#endif	NSS
    fprintf(fd, "\tActive gateways on interface:");
    if (ifp->int_active_gw == NULL) {
      fprintf(fd, "\tNONE\n");
    } else {
      fprintf(fd, "\n");
      for (agp = ifp->int_active_gw; agp; agp = agp->next) {
         tmpos.s_addr = agp->addr;
         fprintf(fd, "\t\t\t%s\t<", inet_ntoa(tmpos));
         cp = "%s";
         for (first = 1, p = protobits; p->t_bits > (u_int)0; p++) {
           if ((agp->proto & p->t_bits) == 0)
             continue;
           fprintf(fd, cp, p->t_name);
           if (first) {
             cp = "|%s";
             first = 0;
           }
         }
         fprintf(fd, ">\t%d\n", agp->timer);
      }
    }
    fprintf(fd, "\n");
  }
  /*
   *	EGP neighbor status
   */
  if ( doing_egp ) {
    struct tm *tmp;
    fprintf(fd, "EGP status:\n\tN_remote_nets: %d\t\tdefaultegpmetric: %d\n", n_remote_nets, conv_factor);
    fprintf(fd, "\tAutonomous System: %d\t\tacquired: %d/%d\n", mysystem, n_acquired, maxacq);
    fprintf(fd, "\tMaxage: %d\t\t\tMaxpollint: %d\n", rt_maxage, maxpollint);
    fprintf(fd, "\tPackets In: %d\t\t\tErrors In: %d\n", egp_stats.inmsgs, egp_stats.inerrors);
    fprintf(fd, "\tPackets Out: %d\t\t\tErrors Out: %d\n", egp_stats.outmsgs, egp_stats.outerrors);
    fprintf(fd, "\t\t\t\t\tTotal Errors: %d\n", egp_stats.outerrors+egp_stats.inerrors);
    for (ngp = egpngh; ngp != NULL; ngp = ngp->ng_next) {
      fprintf(fd, "\n\tNeighbor: %s",inet_ntoa(ngp->ng_addr));
      fprintf(fd, "\t\tInterface: %s\n", inet_ntoa(ngp->ng_myaddr));
      tmp = localtime(&ngp->ng_htime);
      fprintf(fd, "\tHello time: %2d:%02d:%02d\t\tHello interval: %d\n",
                  tmp->tm_hour, tmp->tm_min, tmp->tm_sec, ngp->ng_hint);
      tmp = localtime(&ngp->ng_stime);
      fprintf(fd, "\tPoll time: %2d:%02d:%02d\t\tPoll interval: %d\n",
                  tmp->tm_hour, tmp->tm_min, tmp->tm_sec, ngp->ng_spint);
      fprintf(fd, "\tState: <");
      for (p = egp_states; p->t_bits != (u_int) -1; p++) {
        if ( p->t_bits == ngp->ng_state ) {
          fprintf(fd, p->t_name);
          break;
        }
      }
      fprintf(fd, ">\t\tReachability: <%s|%s>\n",
        (ngp->ng_reach & NG_DOWN) ? "NG_DOWN" : "NG_UP",
        (ngp->ng_reach & ME_DOWN) ? "ME_DOWN" : "ME_UP");
     fprintf(fd, "\tLast poll received: %s", inet_ntoa(ngp->ng_paddr));
     fprintf(fd, "\tNet to poll: %s\n", inet_ntoa(ngp->ng_saddr));
     fprintf(fd, "\tFlags: %X <", ngp->ng_flags);
      cp = "%s";
      for (first = 1, p = egp_flags; p->t_bits > (u_int)0; p++) {
        if ((ngp->ng_flags & p->t_bits)) {
          fprintf(fd, cp, p->t_name);
          if (first) {
            cp = "|%s";
            first = 0;
          }
        }
      }
      fprintf(fd, ">\n");
      fprintf(fd, "\tMetricOut: ");
      if ( (ngp->ng_flags & NG_METRICOUT) ) {
        fprintf(fd, "%d", ngp->ng_metricout);
      } else {
        fprintf(fd, "N/A");
      }
      fprintf(fd, "\t\t\tMetricIn: ");
      if ( (ngp->ng_flags & NG_METRICIN) ) {
        fprintf(fd, "%d", ngp->ng_metricin);
      } else {
        fprintf(fd, "N/A");
      }
      fprintf(fd, "\n\tASout: ");
      if ( (ngp->ng_flags & NG_ASOUT) ) {
        fprintf(fd, "%d", ngp->ng_asout);
      } else {
        fprintf(fd, "N/A");
      }
      fprintf(fd, "\t\t\tASin: ");
      if ((ngp->ng_flags & NG_ASIN) || ngp->ng_asin) {
        fprintf(fd, "%d", ngp->ng_asin);
      } else {
        fprintf(fd, "N/A");
      }
      fprintf(fd, "\n\tAS: ");
      if ((ngp->ng_flags & NG_AS) || ngp->ng_as) {
      	fprintf(fd, "%d", ngp->ng_as);
      }
      fprintf(fd, "\n\tDefaultMetric: ");
      if ( (ngp->ng_flags & NG_DEFAULTOUT) ) {
        fprintf(fd, "%d", ngp->ng_defaultmetric);
      } else {
        fprintf(fd, "N/A");
      }
      fprintf(fd, "\t\tGateway: ");
      if ( (ngp->ng_flags & NG_GATEWAY) ) {
        fprintf(fd, "%s", inet_ntoa(ngp->ng_gateway));
      } else {
	fprintf(fd, "N/A");
      }
      fprintf(fd, "\n");
    }
    fprintf(fd, "\n");
  }
  /*
   *	List all of the {no,}annoucetoAS clauses
   */
  if (sendas) {
    struct as_list *tmp_list;
    struct as_entry *tmp_entry;

    fprintf(fd, "AS restriction lists:\n");
    for (tmp_list = sendas; tmp_list; tmp_list = tmp_list->next) {
      fprintf(fd, "\tAS %d %s AS(s):",
                  tmp_list->as,
                  tmp_list->flags & AS_DONOTSEND ? "Does not receive" : "receives");
      for (tmp_entry = tmp_list->as_ptr; tmp_entry; tmp_entry = tmp_entry->next) {
        fprintf(fd, " %d", tmp_entry->as);
      }
      if (tmp_list == my_aslist) {
        fprintf(fd, "*\n");
      } else {
        fprintf(fd, "\n");
      }
    }
    fprintf(fd, "\n");
  }
  /*
   *	Dump the validAS list
   */
  if (validas) {
    struct as_valid *tmp_valid;

    fprintf(fd, "AS validation:\n");
    for (tmp_valid = validas; tmp_valid; tmp_valid = tmp_valid->next) {
      fprintf(fd, "\tvalidAS %s AS %d metric %d\n",
        inet_ntoa(tmp_valid->dst), tmp_valid->as, tmp_valid->metric);
    }
    fprintf(fd, "\n");
  }
  /*
   *	Dump the list of martian networks
   */
  fprintf(fd, "Martian networks:\n\t");
  cnt = 0;
  for (mptr = martians; mptr; mptr = mptr->next) {
    cp = inet_ntoa(mptr->destnet);
    if ( (cnt+strlen(cp)+1) > 64 ) {
      fprintf(fd, "\n\t");
      cnt = 0;
    }
    cnt += strlen(cp) + 1;
    fprintf(fd, "%s ", cp);
  }
  fprintf(fd, "\n");
#ifdef	notdef
  fprintf(fd, "\n-----------------------------------------------------------\n");
#endif	notdef
  /*
   * Dump all the routing information
   */
  fprintf(fd, "\n\nRouting Tables:\nEntries:\t%d\n", n_routes);
#ifndef	NSS
  fprintf(fd, "\tUnits:\n\t\tInternal metric:\tmilliseconds\n\t\tAge:\t\t\tseconds\n\n");
#else	NSS
  fprintf(fd, "\tUnits:\n\t\tInternal metric:\treachability\n\t\tAge:\tseconds\n\n");
#endif	NSS
onemoretime:
  for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
    for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
      fprintf(fd,"\tDestination:       %s\n", inet_ntoa(sock_inaddr(&rt->rt_dst)));
      if (rt->rt_as != mysystem) {
        fprintf(fd,"\tAutonomous System: %d\n", rt->rt_as);
      }
      fprintf(fd,"\tGateway:           %s\n", inet_ntoa(sock_inaddr(&rt->rt_router)));
#ifndef	NSS
      fprintf(fd,"\tInterface:         %s\n", rt->rt_ifp->int_name);
#endif	NSS
      fprintf(fd,"\tAge:               %d\n", rt->rt_timer);
      ch = "Unknown";
      for (p = protobits; p->t_bits > (u_int)0; p++) {
        if ( (rt->rt_proto == p->t_bits) ) {
          ch = p->t_name;
          break;
        }
      }
      fprintf(fd, "\tProtocol:          %s\n", ch);
      fprintf(fd, "\tMetric:            %d\n", rt->rt_metric);
      if ( rt->rt_state & RTS_EXTERIOR ) {
        fprintf(fd, "\tExterior Metric:   %d\n", rt->rt_metric_exterior);
      }
      fprintf(fd, "\tFlags:             <");
      cp = "%s";
      for (first = 1, p = flagbits; p->t_bits > (u_int)0; p++) {
        if ((rt->rt_flags & p->t_bits) == 0)
          continue;
        fprintf(fd, cp, p->t_name);
        if (first) {
          cp = "|%s";
          first = 0;
        }
      }
      fprintf(fd, ">\n");
      fprintf(fd, "\tState:             <");
      cp = "%s";
      for (first = 1, p = statebits; p->t_bits > (u_int)0; p++) {
        if ((rt->rt_state & p->t_bits) == 0)
          continue;
        fprintf(fd, cp, p->t_name);
        if (first) {
          cp = "|%s";
          first = 0;
        }
      }
      fprintf(fd, ">\n");
      fprintf(fd, "\tFrom Protocol:     <");
      cp = "%s";
      for (first = 1, p = protobits; p->t_bits > (u_int)0; p++) {
        if ((rt->rt_fromproto & p->t_bits) == 0)
          continue;
        fprintf(fd, cp, p->t_name);
        if (first) {
          cp = "|%s";
          first = 0;
        }
      }
      fprintf(fd, ">\n");
      if (rt->rt_proto & RTPROTO_HELLO) {
        fprintf(fd, "\tMinimum HELLO time delay in last %d updates: %d\n",
                       HWINSIZE, rt->rt_hwindow.h_min);
        fprintf(fd, "\tLast %d HELLO time delays:\n\t\t", HELLO_REPORT);
        cnt = 0;
        ind = rt->rt_hwindow.h_index;
        while (cnt < HELLO_REPORT) {
          fprintf(fd, "%d ", rt->rt_hwindow.h_win[ind]);
          cnt++;
          ind++;
          if (ind >= HWINSIZE)
            ind = 0;
        }
        fprintf(fd, "\n");
      }
      if (rt->rt_announcelist || rt->rt_noannouncelist || rt->rt_listenlist || rt->rt_srclisten ) {
        fprintf(fd, "\tRestrictions:\n");
        if (rt->rt_announcelist != NULL) {
          fprintf(fd, "\t\tANNOUNCED via <");
          cp = "%s";
          for (first = 1, p = protobits; p->t_bits > (u_int)0; p++) {
             if ((rt->rt_announcelist->rproto & p->t_bits) == 0) {
               continue;
             }
             fprintf(fd, cp, p->t_name);
             if (first) {
               cp = "|%s";
               first = 0;
             }
           }
           fprintf(fd, "> ");
           if (rt->rt_announcelist->rproto & RTPROTO_EGP) {
             fprintf(fd, "EGP metric %d ", rt->rt_announcelist->regpmetric);
           }
           cntr = 0;
           if (rt->rt_announcelist->rintf[cntr] == 0) {
             fprintf(fd, "OUT ALL INTERFACES\n");
           } else {
             fprintf(fd, "OUT INTERFACES:\n");
             while ((rt->rt_announcelist->rintf[cntr] != 0) || (cntr >= MAXINTERFACE)) {
               fprintf(fd, "\t\t\t\t");
               tmpos.s_addr = rt->rt_announcelist->rintf[cntr];
               fprintf(fd, "%s\n", inet_ntoa(tmpos));
               cntr++;
             }
           }
        }
        if (rt->rt_noannouncelist != NULL) {
          fprintf(fd, "\t\tNOT ANNOUNCED via <");
          cp = "%s";
          for (first = 1, p = protobits; p->t_bits > (u_int)0; p++) {
            if ((rt->rt_noannouncelist->rproto & p->t_bits) == 0) {
               continue;
            }
             fprintf(fd, cp, p->t_name);
             if (first) {
               cp = "|%s";
               first = 0;
             }
           }
           fprintf(fd, "> ");
           if (rt->rt_noannouncelist->rproto & RTPROTO_EGP) {
             fprintf(fd, "EGP metric %d ", rt->rt_noannouncelist->regpmetric);
           }
           cntr = 0;
           if (rt->rt_noannouncelist->rintf[cntr] == 0) {
             fprintf(fd, "OUT ALL INTERFACES\n");
           } else {
             fprintf(fd, "OUT INTERFACES:\n");
             while ((rt->rt_noannouncelist->rintf[cntr] != 0) || (cntr >= MAXINTERFACE)) {
               fprintf(fd, "\t\t\t\t");
               tmpos.s_addr = rt->rt_noannouncelist->rintf[cntr];
               fprintf(fd, "%s\n", inet_ntoa(tmpos));
               cntr++;
             }
           }
        }
        if (rt->rt_listenlist != NULL) {
          fprintf(fd, "\t\tNOTLISTENEDTO via <");
          cp = "%s";
          for (first = 1, p = protobits; p->t_bits > (u_int)0; p++) {
            if ((rt->rt_listenlist->rproto & p->t_bits) == 0) {
              continue;
            }
            fprintf(fd, cp, p->t_name);
            if (first) {
              cp = "|%s";
              first = 0;
            }
          }
          fprintf(fd, "> ");
          if (rt->rt_listenlist->rproto & RTPROTO_EGP) {
            fprintf(fd, "EGP metric %d ", rt->rt_listenlist->regpmetric);
          }
          cntr = 0;
          if (rt->rt_listenlist->rintf[cntr] == 0) {
            fprintf(fd, "FROM ALL INTERFACES\n");
          } else {
            fprintf(fd, "FROM INTERFACES:\n");
            while ((rt->rt_listenlist->rintf[cntr] != 0) || (cntr >= MAXINTERFACE)) {
              fprintf(fd, "\t\t\t\t");
              tmpos.s_addr = rt->rt_listenlist->rintf[cntr];
              fprintf(fd, "%s\n", inet_ntoa(tmpos));
              cntr++;
            }
          }
        }
        if (rt->rt_srclisten != NULL) {
          fprintf(fd, "\t\tLISTENEDTO via <");
          cp = "%s";
          for (first = 1, p = protobits; p->t_bits > (u_int)0; p++) {
            if ((rt->rt_srclisten->rproto & p->t_bits) == 0) {
               continue;
            }
            fprintf(fd, cp, p->t_name);
            if (first) {
              cp = "|%s";
              first = 0;
            }
          }
          fprintf(fd, "> ");
          if (rt->rt_srclisten->rproto & RTPROTO_EGP) {
            fprintf(fd, "EGP metric %d ", rt->rt_srclisten->regpmetric);
          }
          cntr = 0;
          if (rt->rt_srclisten->rintf[cntr] == 0) {
            fprintf(fd, "FROM ALL GATEWAYS\n");
          } else {
            fprintf(fd, "FROM GATEWAYS:\n");
            while ((rt->rt_srclisten->rintf[cntr] != 0) || (cntr >= MAXINTERFACE)) {
              fprintf(fd, "\t\t\t\t");
              tmpos.s_addr = rt->rt_srclisten->rintf[cntr];
              fprintf(fd, "%s\n", inet_ntoa(tmpos));
              cntr++;
            }
          }
        }
      }
      fprintf(fd, "\n");
    }
  }
  if (doinghost) {
    base = nethash;
    doinghost = 0;
    goto onemoretime;
  }
  (void) fflush(fd);
  (void) fclose(fd);
  syslog(LOG_NOTICE, "dumpinfo: dump completed to %s", DUMPFILE);
  TRACE_TRC("dumpinfo: dump completed to %s at %s", DUMPFILE, strtime);
}


#ifdef	NSS
gated_trace(sock, pkt, size, src, dst)
int	sock;
char	*pkt;
int	size;
struct sockaddr_in	src, dst;
{
  if (tracing & TR_EGP) {
    tracercv(sock, IPPROTO_EGP, pkt, size, &src);
  }
}
#endif	NSS


#ifdef	EGP_UPDATE_FORMAT
/*
 *	Format an EGP network update packet
 */

NR_format(nr, nr_length)
struct egpnr *nr;
int	nr_length;
{
	int gateways, distances, networks;
	int distance, t_gateways;
	int shared_net_class, net_class;
	char class;
	u_char *nr_ptr, *nr_end;
	struct in_addr gateway, network;

	shared_net_class = gd_inet_class((u_char *)&nr->en_net);
	bcopy((char *) &nr->en_net, (char *)&gateway, shared_net_class);
	nr_ptr = (u_char *)nr + sizeof(struct egpnr);
	nr_end = (u_char *)nr + nr_length;
	printf("net %s (%c) - %d interior gateways, %d exterior gateways\n",
		inet_ntoa(nr->en_net), 'A' - 1 + shared_net_class,
		nr->en_igw, nr->en_egw);
	t_gateways = nr->en_igw + nr->en_egw;
	for ( gateways = 0; gateways < t_gateways; gateways++) {
		bcopy((char *)nr_ptr, (char *)&gateway + shared_net_class, 4 - shared_net_class);
		nr_ptr += 4 - shared_net_class;
		distances = (u_char) *nr_ptr;
		nr_ptr++;
		printf("\t%s gateway %s, %d distances\n",
			gateways < nr->en_igw ? "interior" : "exterior", 
			inet_ntoa(gateway), distances);
		for ( ; distances; distances-- ) {
			distance = (u_char) *nr_ptr;
			nr_ptr++;
			networks = (u_char) *nr_ptr;
			nr_ptr++;
			printf("\t\tdistance %d, %d networks\n",
				distance, networks);
			for ( ; networks; networks-- ) {
				bzero((char *)&network, sizeof(struct in_addr));
				if ( (net_class = gd_inet_class(nr_ptr)) == 0 ) {
					net_class = CLAC;
					class = '?';
				} else {
					class = 'A' - 1 + net_class;
				}
				bcopy((char *)nr_ptr, (char *)&network, net_class);
				nr_ptr += net_class;
				printf("\t\t\t(%c) %s\n",
					class, inet_ntoa(network));
				if ( nr_ptr > nr_end ) {
					printf("\tpacket smashed\n");
					return;
				}
			}
		}
	}
	return;
}
#endif	EGP_UPDATE_FORMAT
