fix import.
authormickey <mickey@openbsd.org>
Thu, 5 Sep 1996 14:31:10 +0000 (14:31 +0000)
committermickey <mickey@openbsd.org>
Thu, 5 Sep 1996 14:31:10 +0000 (14:31 +0000)
mention that routed is from vjs@sgi.com

18 files changed:
sbin/routed/Makefile
sbin/routed/af.c [deleted file]
sbin/routed/af.h [deleted file]
sbin/routed/defs.h
sbin/routed/if.c
sbin/routed/inet.c [deleted file]
sbin/routed/input.c
sbin/routed/interface.h [deleted file]
sbin/routed/main.c
sbin/routed/output.c
sbin/routed/pathnames.h
sbin/routed/routed.8
sbin/routed/startup.c [deleted file]
sbin/routed/table.h [deleted file]
sbin/routed/tables.c [deleted file]
sbin/routed/timer.c [deleted file]
sbin/routed/trace.c
sbin/routed/trace.h [deleted file]

index 930e279..35ebc31 100644 (file)
@@ -1,13 +1,15 @@
-#      $OpenBSD: Makefile,v 1.3 1996/06/23 14:32:24 deraadt Exp $
-#      $NetBSD: Makefile,v 1.14 1995/06/20 22:25:51 christos Exp $
-
-# disable an undesirable feature
-#CFLAGS=-DTRACING
+#      $OpenBSD: Makefile,v 1.4 1996/09/05 14:31:10 mickey Exp $
+#      @(#)Makefile    8.1 (Berkeley) 6/19/93
 
 PROG=  routed
-SRCS=  af.c if.c input.c main.c output.c startup.c tables.c timer.c \
-       trace.c inet.c
+SRCS=  if.c input.c main.c output.c parms.c radix.c rdisc.c table.c trace.c
 MAN=   routed.8
-#SUBDIR=       query trace
+CFLAGS+=-D_ROUTED -D'min(a,b)=(a < b ? a : b)' -D'log=syslog'
+CFLAGS+=-D'panic(s)={log(LOG_ERR,s); exit(1);}'
+SUBDIR=        rtquery
+DPADD= ${LIBCOMPAT}
+LDADD= -lcompat
+
+.PATH: ${.CURDIR}/../../sys/net
 
 .include <bsd.prog.mk>
diff --git a/sbin/routed/af.c b/sbin/routed/af.c
deleted file mode 100644 (file)
index e58ea8d..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-/*     $OpenBSD: af.c,v 1.2 1996/06/23 14:32:24 deraadt Exp $  */
-/*     $NetBSD: af.c,v 1.12 1995/07/24 13:03:25 ws Exp $       */
-
-/*
- * Copyright (c) 1983, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)af.c       8.1 (Berkeley) 6/5/93";
-#else
-static char rcsid[] = "$OpenBSD: af.c,v 1.2 1996/06/23 14:32:24 deraadt Exp $";
-#endif
-#endif /* not lint */
-
-#include "defs.h"
-
-/*
- * Address family support routines
- */
-static void inet_canon __P((struct sockaddr *));
-static int inet_checkhost __P((struct sockaddr *));
-static char *inet_format __P((struct sockaddr *, char *buf, size_t sz));
-static void inet_hash __P((struct sockaddr *, struct afhash *));
-static int inet_netmatch __P((struct sockaddr *, struct sockaddr *));
-static int inet_portcheck __P((struct sockaddr *));
-static int inet_portmatch __P((struct sockaddr *));
-static void inet_output __P((int, int, struct sockaddr *, int));
-static int inet_get __P((int, void *, struct sockaddr *));
-static void inet_put __P((void *, struct sockaddr *));
-
-#define NIL    { 0 }
-#define        INET \
-       { inet_hash,            inet_netmatch,          inet_output, \
-         inet_portmatch,       inet_portcheck,         inet_checkhost, \
-         inet_rtflags,         inet_sendroute,         inet_canon, \
-         inet_format,          inet_get,               inet_put \
-       }
-
-struct afswitch afswitch[AF_MAX] = {
-       NIL,            /* 0- unused */
-       NIL,            /* 1- Unix domain, unused */
-       INET,           /* Internet */
-};
-
-int af_max = sizeof(afswitch) / sizeof(afswitch[0]);
-
-struct sockaddr_in inet_default = {
-#ifdef RTM_ADD
-       sizeof (inet_default),
-#endif
-       AF_INET, INADDR_ANY };
-
-static void
-inet_hash(sa, hp)
-       struct sockaddr *sa;
-       struct afhash *hp;
-{
-       struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-       register u_long n;
-
-       n = inet_netof_subnet(sin->sin_addr);
-       if (n)
-           while ((n & 0xff) == 0)
-               n >>= 8;
-       hp->afh_nethash = n;
-       hp->afh_hosthash = ntohl(sin->sin_addr.s_addr);
-       hp->afh_hosthash &= 0x7fffffff;
-}
-
-static int
-inet_netmatch(sa1, sa2)
-       struct sockaddr *sa1, *sa2;
-{
-       struct sockaddr_in *sin1 = (struct sockaddr_in *) sa1;
-       struct sockaddr_in *sin2 = (struct sockaddr_in *) sa2;
-
-       return (inet_netof_subnet(sin1->sin_addr) ==
-               inet_netof_subnet(sin2->sin_addr));
-}
-
-/*
- * Verify the message is from the right port.
- */
-static int
-inet_portmatch(sa)
-       struct sockaddr *sa;
-{
-       struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-       
-       return (sin->sin_port == sp->s_port);
-}
-
-/*
- * Verify the message is from a "trusted" port.
- */
-static int
-inet_portcheck(sa)
-       struct sockaddr *sa;
-{
-       struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-
-       return (ntohs(sin->sin_port) <= IPPORT_RESERVED);
-}
-
-/*
- * Internet output routine.
- */
-static void
-inet_output(s, flags, sa, size)
-       int s, flags;
-       struct sockaddr *sa;
-       int size;
-{
-       struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-       struct sockaddr_in dst;
-
-       dst = *sin;
-       sin = &dst;
-       if (sin->sin_port == 0)
-               sin->sin_port = sp->s_port;
-       if (sin->sin_len == 0)
-               sin->sin_len = sizeof (*sin);
-       if (sendto(s, packet, size, flags,
-           (struct sockaddr *)sin, sizeof (*sin)) < 0)
-               perror("sendto");
-}
-
-/*
- * Return 1 if the address is believed
- * for an Internet host -- THIS IS A KLUDGE.
- */
-static int
-inet_checkhost(sa)
-       struct sockaddr *sa;
-{
-       struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-       u_long i = ntohl(sin->sin_addr.s_addr);
-
-#ifndef IN_EXPERIMENTAL
-#define        IN_EXPERIMENTAL(i)      (((long) (i) & 0xe0000000) == 0xe0000000)
-#endif
-
-       if (IN_EXPERIMENTAL(i) || sin->sin_port != 0)
-               return (0);
-       if (i != 0 && (i & 0xff000000) == 0)
-               return (0);
-       for (i = 0; i < sizeof(sin->sin_zero)/sizeof(sin->sin_zero[0]); i++)
-               if (sin->sin_zero[i])
-                       return (0);
-       return (1);
-}
-
-static void
-inet_canon(sa)
-       struct sockaddr *sa;
-{
-       struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-
-       sin->sin_port = 0;
-       sin->sin_len = sizeof(*sin);
-}
-
-static char *
-inet_format(sa, buf, sz)
-       struct sockaddr *sa;
-       char *buf; size_t sz;
-{
-       struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-
-       strncpy(buf, inet_ntoa(sin->sin_addr), sz);
-       buf[sz - 1] = '\0';
-       return buf;
-}
-
-static int
-inet_get(what, pck, sa)
-       int what;
-       void *pck;
-       struct sockaddr *sa;
-{
-       struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-       struct netinfo *n = pck;
-       /* XXX: Internet only */
-       memset(sin, 0, sizeof(*sin));
-       switch (what) {
-       case DESTINATION:
-               sin->sin_addr.s_addr = n->rip_dst;
-               break;
-       case NETMASK:
-               if (n->rip_netmask == 0)
-                       return 0;
-               sin->sin_addr.s_addr = n->rip_netmask;
-               break;
-       case GATEWAY:
-               if (n->rip_router == 0)
-                       return 0;
-               sin->sin_addr.s_addr = n->rip_router;
-               break;
-       default:
-               abort();
-               break;
-       }
-
-       sin->sin_family = n->rip_family;
-#if BSD >= 198810
-       sin->sin_len = sizeof(*sin);
-#endif
-       return 1;
-}
-
-static void
-inet_put(pck, sa)
-       void *pck;
-       struct sockaddr *sa;
-{
-       struct netinfo *n = pck;
-       struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-#if BSD >= 198810
-       n->rip_family = htons(sin->sin_family);
-#else
-       n->rip_family = sin->sin_family;
-#endif
-       n->rip_dst = sin->sin_addr.s_addr;
-}
diff --git a/sbin/routed/af.h b/sbin/routed/af.h
deleted file mode 100644 (file)
index b80a54f..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*     $OpenBSD: af.h,v 1.2 1996/06/23 14:32:25 deraadt Exp $  */
-/*     $NetBSD: af.h,v 1.8 1995/06/20 22:26:45 christos Exp $  */
-
-/*
- * Copyright (c) 1983, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *     @(#)af.h        8.1 (Berkeley) 6/5/93
- */
-
-/*
- * Routing table management daemon.
- */
-
-/*
- * Structure returned by af_hash routines.
- */
-struct afhash {
-       u_int   afh_hosthash;           /* host based hash */
-       u_int   afh_nethash;            /* network based hash */
-};
-
-/*
- * Per address family routines.
- */
-struct afswitch {
-       /* returns keys based on address */
-       void    (*af_hash) __P((struct sockaddr *, struct afhash *));
-       /* verifies net # matching */
-       int     (*af_netmatch) __P((struct sockaddr *, struct sockaddr *));
-       /* interprets address for sending */
-       void    (*af_output) __P((int, int, struct sockaddr *, int));
-       /* packet from some other router? */
-       int     (*af_portmatch) __P((struct sockaddr *));
-       /* packet from privileged peer? */
-       int     (*af_portcheck) __P((struct sockaddr *));
-       /* tells if address is valid */
-       int     (*af_checkhost) __P((struct sockaddr *));
-       /* get flags for route (host or net) */
-       int     (*af_rtflags) __P((struct sockaddr *));
-       /* check bounds of subnet broadcast */
-       int     (*af_sendroute) __P((struct rt_entry *, struct sockaddr *));
-       /* canonicalize address for compares */
-       void    (*af_canon) __P((struct sockaddr *));
-       /* convert address to string */
-       char    *(*af_format) __P((struct sockaddr *, char *, size_t));
-       /* get address from packet */
-#define DESTINATION    0
-#define        GATEWAY         1
-#define NETMASK                2
-       int     (*af_get) __P((int, void *, struct sockaddr *));
-       /* put address to packet */
-       void    (*af_put) __P((void *, struct sockaddr *));
-};
-
-extern struct  afswitch afswitch[];    /* table proper */
-extern int     af_max;                 /* number of entries in table */
index b363a46..6e61b27 100644 (file)
@@ -1,5 +1,4 @@
-/*     $OpenBSD: defs.h,v 1.2 1996/06/23 14:32:26 deraadt Exp $        */
-/*     $NetBSD: defs.h,v 1.11 1995/06/20 22:26:57 christos Exp $       */
+/*     $OpenBSD: defs.h,v 1.3 1996/09/05 14:31:18 mickey Exp $ */
 
 /*
  * Copyright (c) 1983, 1988, 1993
  * SUCH DAMAGE.
  *
  *     @(#)defs.h      8.1 (Berkeley) 6/5/93
+ *
  */
 
-/*
- * Internal data structure definitions for
- * user routing process.  Based on Xerox NS
- * protocol specs with mods relevant to more
- * general addressing scheme.
+/* Definitions for RIPv2 routing process.
+ *
+ * This code is based on the 4.4BSD `routed` daemon, with extensions to
+ * support:
+ *     RIPv2, including variable length subnet masks.
+ *     Router Discovery
+ *     aggregate routes in the kernel tables.
+ *     aggregate advertised routes.
+ *     maintain spare routes for faster selection of another gateway
+ *             when the current gateway dies.
+ *     timers on routes with second granularity so that selection
+ *             of a new route does not wait 30-60 seconds.
+ *     tolerance of static routes.
+ *     tell the kernel hop counts
+ *     do not advertise if ipforwarding=0
+ *
+ * The vestigual support for other protocols has been removed.  There
+ * is no likelihood that IETF RIPv1 or RIPv2 will ever be used with
+ * other protocols.  The result is far smaller, faster, cleaner, and
+ * perhaps understandable.
+ *
+ * The accumulation of special flags and kludges added over the many
+ * years have been simplified and integrated.
  */
+
+#include <stdio.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <time.h>
+#include <sys/types.h>
 #include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
 #include <sys/socket.h>
-#include <sys/time.h>
-
+#include <net/radix.h>
+#include <net/if.h>
 #include <net/route.h>
+#include <net/if_dl.h>
 #include <netinet/in.h>
-#include <protocols/routed.h>
 #include <arpa/inet.h>
+#define RIPVERSION RIPv2
+#include <protocols/routed.h>
 
-#include <netdb.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
 
-#include "table.h"
-#include "trace.h"
-#include "interface.h"
-#include "af.h"
+/* Type of an IP address.
+ *     Some systems do not like to pass structures, so do not use in_addr.
+ *     Some systems think a long has 64 bits, which would be a gross waste.
+ * So define it here so it can be changed for the target system.
+ * It should be defined somewhere netinet/in.h, but it is not.
+ */
+#define naddr u_int32_t
+#define _HAVE_SA_LEN
+#define _HAVE_SIN_LEN
+
+/* Turn on if IP_DROP_MEMBERSHIP and IP_ADD_MEMBERSHIP do not look at
+ * the dstaddr of point-to-point interfaces.
+ */
+/* #define MCAST_PPP_BUG */
 
-/*
- * When we find any interfaces marked down we rescan the
- * kernel every CHECK_INTERVAL seconds to see if they've
- * come up.
+#define NEVER (24*60*60)               /* a long time */
+#define EPOCH NEVER                    /* bias time by this to avoid <0 */
+
+/* Scan the kernel regularly to see if any interfaces have appeared or been
+ * turned off.  These must be less than STALE_TIME.
+ */
+#define        CHECK_BAD_INTERVAL      5       /* when an interface is known bad */
+#define        CHECK_ACT_INTERVAL      30      /* when advertising */
+#define        CHECK_QUIET_INTERVAL    300     /* when not */
+
+#define LIM_SEC(s,l) ((s).tv_sec = MIN((s).tv_sec, (l)))
+
+
+/* Router Discovery parameters */
+#ifndef sgi
+#define INADDR_ALLROUTERS_GROUP                0xe0000002  /* 224.0.0.2 */
+#endif
+#define        MaxMaxAdvertiseInterval         1800
+#define        MinMaxAdvertiseInterval         4
+#define        DefMaxAdvertiseInterval         600
+#define DEF_PreferenceLevel            0
+#define MIN_PreferenceLevel            0x80000000
+
+#define        MAX_INITIAL_ADVERT_INTERVAL     16
+#define        MAX_INITIAL_ADVERTS             3
+#define        MAX_RESPONSE_DELAY              2
+
+#define        MAX_SOLICITATION_DELAY          1
+#define        SOLICITATION_INTERVAL           3
+#define        MAX_SOLICITATIONS               3
+
+
+/* typical packet buffers */
+union pkt_buf {
+       char    packet[MAXPACKETSIZE+1];
+       struct  rip rip;
+};
+
+
+/* no more routes than this, to protect ourself in case something goes
+ * whacko and starts broadcast zillions of bogus routes.
+ */
+#define MAX_ROUTES  (128*1024)
+extern int total_routes;
+
+/* Main, daemon routing table structure
+ */
+struct rt_entry {
+       struct  radix_node rt_nodes[2]; /* radix tree glue */
+       u_int   rt_state;
+#          define RS_IF        0x001   /* for network interface */
+#          define RS_NET_INT   0x002   /* authority route */
+#          define RS_NET_SYN   0x004   /* fake net route for subnet */
+#          define RS_NO_NET_SYN (RS_LOCAL | RS_LOCAL | RS_IF)
+#          define RS_SUBNET    0x008   /* subnet route from any source */
+#          define RS_LOCAL     0x010   /* loopback for pt-to-pt */
+#          define RS_MHOME     0x020   /* from -m */
+#          define RS_STATIC    0x040   /* from the kernel */
+#          define RS_RDISC     0x080   /* from router discovery */
+#          define RS_PERMANENT (RS_MHOME | RS_STATIC | RS_NET_SYN | RS_RDISC)
+       struct sockaddr_in rt_dst_sock;
+       naddr   rt_mask;
+       struct rt_spare {
+           struct interface *rts_ifp;
+           naddr   rts_gate;           /* forward packets here */
+           naddr   rts_router;         /* on the authority of this router */
+           char    rts_metric;
+           u_short rts_tag;
+           time_t  rts_time;           /* timer to junk stale routes */
+#define NUM_SPARES 4
+       } rt_spares[NUM_SPARES];
+       u_int   rt_seqno;               /* when last changed */
+       char    rt_poison_metric;       /* to notice maximum recently */
+       time_t  rt_poison_time;         /*      advertised metric */
+};
+#define rt_dst rt_dst_sock.sin_addr.s_addr
+#define rt_ifp rt_spares[0].rts_ifp
+#define rt_gate        rt_spares[0].rts_gate
+#define rt_router rt_spares[0].rts_router
+#define rt_metric rt_spares[0].rts_metric
+#define rt_tag rt_spares[0].rts_tag
+#define rt_time        rt_spares[0].rts_time
+
+#define HOST_MASK      0xffffffff
+#define RT_ISHOST(rt)  ((rt)->rt_mask == HOST_MASK)
+
+/* age all routes that
+ *     are not from -g, -m, or static routes from the kernel
+ *     not unbroken interface routes
+ *             but not broken interfaces
+ *     nor non-passive, remote interfaces that are not aliases
+ *             (i.e. remote & metric=0)
+ */
+#define AGE_RT(rt_state,ifp) (0 == ((rt_state) & RS_PERMANENT)         \
+                             && (!((rt_state) & RS_IF)                 \
+                                 || (ifp) == 0                         \
+                                 || (((ifp)->int_state & IS_REMOTE)    \
+                                     && !((ifp)->int_state & IS_PASSIVE))))
+
+/* true if A is better than B
+ * Better if
+ *     - A is not a poisoned route
+ *     - and A is not stale
+ *     - and A has a shorter path
+ *             - or is the router speaking for itself
+ *             - or the current route is equal but stale
+ *             - or it is a host route advertised by a system for itself
  */
-#define        CHECK_INTERVAL  (1*60)
-
-#define equal(a1, a2) \
-       (memcmp((a1), (a2), sizeof (struct sockaddr)) == 0)
-
-struct sockaddr_in addr;       /* address of daemon's socket */
-
-int    s;                      /* source and sink of all data */
-int    r;                      /* routing socket */
-pid_t  pid;                    /* process id for identifying messages */
-uid_t  uid;                    /* user id for identifying messages */
-int    seqno;                  /* sequence number for identifying messages */
-int    kmem;
-int    supplier;               /* process should supply updates */
-int    install;                /* if 1 call kernel */
-int    lookforinterfaces;      /* if 1 probe kernel for new up interfaces */
-int    performnlist;           /* if 1 check if /vmunix has changed */
-int    externalinterfaces;     /* # of remote and local interfaces */
-struct timeval now;            /* current idea of time */
-struct timeval lastbcast;      /* last time all/changes broadcast */
-struct timeval lastfullupdate; /* last time full table broadcast */
-struct timeval nextbcast;      /* time to wait before changes broadcast */
-int    needupdate;             /* true if we need update at nextbcast */
-
-char   packet[MAXPACKETSIZE+1];
-struct rip *msg;
-
-char   **argv0;
-struct servent *sp;
-
-/* inet.c */
-struct in_addr inet_makeaddr __P((u_long, u_long ));
-u_long inet_netof_subnet __P((struct in_addr));
-u_long inet_lnaof_subnet __P((struct in_addr));
-int inet_maskof __P((u_long));
-int inet_rtflags __P((struct sockaddr *));
-int inet_sendroute __P((struct rt_entry *, struct sockaddr *));
-
-/* input.c */
-void rip_input __P((struct sockaddr *, struct rip *, int));
-
-/* main.c */
-int main __P((int, char *[]));
-void process __P((int));
-int getsocket __P((int, int , struct sockaddr_in *));
-
-/* output.c */
-void toall __P((void (*)(struct sockaddr *, int, struct interface *, int),
-               int, struct interface *));
-void sndmsg __P((struct sockaddr *, int, struct interface *, int));
-void supply __P((struct sockaddr *, int, struct interface *, int));
-
-/* startup.c */
-void quit __P((char *));
-void rt_xaddrs __P((caddr_t, caddr_t , struct rt_addrinfo *));
-void ifinit __P((void));
-void addrouteforif __P((struct interface *));
-void add_ptopt_localrt __P((struct interface *));
-void gwkludge __P((void));
-int getnetorhostname __P((char *, char *, struct sockaddr_in *));
-int gethostnameornumber __P((char *, struct sockaddr_in *));
-
-/* timer.c */
-void timer __P((int));
-void hup __P((int));
-
-#define ADD 1
-#define DELETE 2
-#define CHANGE 3
+#define BETTER_LINK(rt,A,B) ((A)->rts_metric < HOPCNT_INFINITY \
+                            && now_stale <= (A)->rts_time              \
+                            && ((A)->rts_metric < (B)->rts_metric      \
+                                || ((A)->rts_gate == (A)->rts_router   \
+                                    && (B)->rts_gate != (B)->rts_router) \
+                                || ((A)->rts_metric == (B)->rts_metric \
+                                    && now_stale > (B)->rts_time)      \
+                                || (RT_ISHOST(rt)                      \
+                                    && (rt)->rt_dst == (A)->rts_router \
+                                    && (A)->rts_metric == (B)->rts_metric)))
+
+
+/* An "interface" is similar to a kernel ifnet structure, except it also
+ * handles "logical" or "IS_REMOTE" interfaces (remote gateways).
+ */
+struct interface {
+       struct  interface *int_next, *int_prev;
+       char    int_name[IFNAMSIZ+15+1];    /* big enough for IS_REMOTE */
+       u_short int_index;
+       naddr   int_addr;               /* address on this host (net order) */
+       naddr   int_brdaddr;            /* broadcast address (n) */
+       naddr   int_dstaddr;            /* other end of pt-to-pt link (n) */
+       naddr   int_net;                /* working network # (host order)*/
+       naddr   int_mask;               /* working net mask (host order) */
+       naddr   int_ripv1_mask;         /* for inferring a mask (n) */
+       naddr   int_std_addr;           /* class A/B/C address (n) */
+       naddr   int_std_net;            /* class A/B/C network (h) */
+       naddr   int_std_mask;           /* class A/B/C netmask (h) */
+       int     int_rip_sock;           /* for queries */
+       int     int_if_flags;           /* copied from kernel */
+       u_int   int_state;
+       time_t  int_act_time;           /* last thought healthy */
+       u_short int_transitions;        /* times gone up-down */
+       char    int_metric;
+       char    int_d_metric;           /* for faked default route */
+       struct int_data {
+               u_int   ipackets;       /* previous network stats */
+               u_int   ierrors;
+               u_int   opackets;
+               u_int   oerrors;
+#ifdef sgi
+               u_int   odrops;
+#endif
+               time_t  ts;             /* timestamp on network stats */
+       } int_data;
+       char    int_passwd[RIP_AUTH_PW_LEN];    /* RIPv2 password */
+       int     int_rdisc_pref;         /* advertised rdisc preference */
+       int     int_rdisc_int;          /* MaxAdvertiseInterval */
+       int     int_rdisc_cnt;
+       struct timeval int_rdisc_timer;
+};
+
+#define IS_ALIAS           0x0000001   /* interface alias */
+#define IS_SUBNET          0x0000002   /* interface on subnetted network */
+#define        IS_REMOTE           0x0000004   /* interface is not on this machine */
+#define        IS_PASSIVE          0x0000008   /* remote and does not do RIP */
+#define IS_EXTERNAL        0x0000010   /* handled by EGP or something */
+#define IS_CHECKED         0x0000020   /* still exists */
+#define IS_ALL_HOSTS       0x0000040   /* in INADDR_ALLHOSTS_GROUP */
+#define IS_ALL_ROUTERS     0x0000080   /* in INADDR_ALLROUTERS_GROUP */
+#define IS_RIP_QUERIED     0x0000100   /* query broadcast */
+#define IS_BROKE           0x0000200   /* seems to be broken */
+#define IS_SICK                    0x0000400   /* seems to be broken */
+#define IS_DUP             0x0000800   /* has a duplicate address */
+#define IS_ACTIVE          0x0001000   /* heard from it at least once */
+#define IS_NEED_NET_SYN            0x0002000   /* need RS_NET_SYN route */
+#define IS_NO_AG           0x0004000   /* do not aggregate subnets */
+#define IS_NO_SUPER_AG     0x0008000   /* do not aggregate networks */
+#define IS_NO_RIPV1_IN     0x0010000   /* no RIPv1 input at all */
+#define IS_NO_RIPV2_IN     0x0020000   /* no RIPv2 input at all */
+#define IS_NO_RIP_IN   (IS_NO_RIPV1_IN | IS_NO_RIPV2_IN)
+#define IS_RIP_IN_OFF(s) (((s) & IS_NO_RIP_IN) == IS_NO_RIP_IN)
+#define IS_NO_RIPV1_OUT            0x0040000   /* no RIPv1 output at all */
+#define IS_NO_RIPV2_OUT            0x0080000   /* no RIPv2 output at all */
+#define IS_NO_RIP_OUT  (IS_NO_RIPV1_OUT | IS_NO_RIPV2_OUT)
+#define IS_NO_RIP      (IS_NO_RIP_OUT | IS_NO_RIP_IN)
+#define IS_RIP_OUT_OFF(s) (((s) & IS_NO_RIP_OUT) == IS_NO_RIP_OUT)
+#define IS_RIP_OFF(s)  (((s) & IS_NO_RIP) == IS_NO_RIP)
+#define IS_NO_ADV_IN       0x0100000
+#define IS_NO_SOL_OUT      0x0200000   /* no solicitations */
+#define IS_SOL_OUT         0x0400000   /* send solicitations */
+#define GROUP_IS_SOL   (IS_NO_ADV_IN|IS_NO_SOL_OUT)
+#define IS_NO_ADV_OUT      0x0800000   /* do not advertise rdisc */
+#define IS_ADV_OUT         0x1000000   /* advertise rdisc */
+#define GROUP_IS_ADV   (IS_NO_ADV_OUT|IS_ADV_OUT)
+#define IS_BCAST_RDISC     0x2000000   /* broadcast instead of multicast */
+#define IS_NO_RDISC    (IS_NO_ADV_IN | IS_NO_SOL_OUT | IS_NO_ADV_OUT)
+#define IS_PM_RDISC        0x4000000   /* poor-man's router discovery */
+
+#ifdef sgi
+#define IFF_UP_RUNNING (IFF_RUNNING|IFF_UP)
+#else
+#define IFF_UP_RUNNING IFF_UP
+#endif
+#define iff_alive(f) (((f) & IFF_UP_RUNNING) == IFF_UP_RUNNING)
+
+
+/* Information for aggregating routes */
+#define NUM_AG_SLOTS   32
+struct ag_info {
+       struct ag_info *ag_fine;        /* slot with finer netmask */
+       struct ag_info *ag_cors;        /* more coarse netmask */
+       naddr   ag_dst_h;               /* destination in host byte order */
+       naddr   ag_mask;
+       naddr   ag_gate;
+       naddr   ag_nhop;
+       char    ag_metric;              /* metric to be advertised */
+       char    ag_pref;                /* aggregate based on this */
+       u_int   ag_seqno;
+       u_short ag_tag;
+       u_short ag_state;
+#define            AGS_SUPPRESS    0x001       /* combine with coaser mask */
+#define            AGS_PROMOTE     0x002       /* synthesize combined routes */
+#define            AGS_REDUN0      0x004       /* redundant, finer routes output */
+#define            AGS_REDUN1      0x008
+#define            AG_IS_REDUN(state) (((state) & (AGS_REDUN0 | AGS_REDUN1)) \
+                               == (AGS_REDUN0 | AGS_REDUN1))
+#define            AGS_GATEWAY     0x010       /* tell kernel RTF_GATEWAY */
+#define            AGS_IF          0x020       /* for an interface */
+#define            AGS_RIPV2       0x040       /* send only as RIPv2 */
+#define            AGS_FINE_GATE   0x080       /* ignore differing ag_gate when this
+                                        * has the finer netmask */
+#define            AGS_CORS_GATE   0x100       /* ignore differing gate when this
+                                        * has the coarser netmaks */
+#define            AGS_SPLIT_HZ    0x200       /* suppress for split horizon */
+
+       /* some bits are set if they are set on either route */
+#define            AGS_PROMOTE_EITHER (AGS_RIPV2 | AGS_GATEWAY |   \
+                               AGS_SUPPRESS | AGS_CORS_GATE)
+};
+
+
+/* parameters for interfaces */
+extern struct parm {
+       struct parm *parm_next;
+       char    parm_name[IFNAMSIZ+1];
+       naddr   parm_addr_h;
+       naddr   parm_mask;
+
+       char    parm_d_metric;
+       u_int   parm_int_state;
+       int     parm_rdisc_pref;
+       int     parm_rdisc_int;
+       char    parm_passwd[RIP_AUTH_PW_LEN+1];
+} *parms;
+
+/* authority for internal networks */
+extern struct intnet {
+       struct intnet *intnet_next;
+       naddr   intnet_addr;
+       naddr   intnet_mask;
+       char    intnet_metric;
+} *intnets;
+
+
+
+extern pid_t   mypid;
+extern naddr   myaddr;                 /* main address of this system */
+
+extern int     stopint;                /* !=0 to stop */
+
+extern int     sock_max;
+extern int     rip_sock;               /* RIP socket */
+extern struct interface *rip_sock_mcast;    /* current multicast interface */
+extern int     rt_sock;                /* routing socket */
+extern int     rt_sock_seqno;
+extern int     rdisc_sock;             /* router-discovery raw socket */
+
+extern int     seqno;                  /* sequence number for messages */
+extern int     supplier;               /* process should supply updates */
+extern int     lookforinterfaces;      /* 1=probe for new up interfaces */
+extern int     supplier_set;           /* -s or -q requested */
+extern int     ridhosts;               /* 1=reduce host routes */
+extern int     mhome;                  /* 1=want multi-homed host route */
+extern int     advertise_mhome;        /* 1=must continue adverising it */
+extern int     auth_ok;                /* 1=ignore auth if we do not care */
+
+extern struct timeval epoch;           /* when started */
+extern struct timeval now;             /* current idea of time */
+extern time_t  now_stale;
+extern time_t  now_expire;
+extern time_t  now_garbage;
+
+extern struct timeval next_bcast;      /* next general broadcast */
+extern struct timeval age_timer;       /* next check of old routes */
+extern struct timeval no_flash;                /* inhibit flash update until then */
+extern struct timeval rdisc_timer;     /* next advert. or solicitation */
+extern int rdisc_ok;                   /* using solicited route */
+
+extern struct timeval ifinit_timer;    /* time to check interfaces */
+
+extern naddr   loopaddr;               /* our address on loopback */
+extern int     tot_interfaces;         /* # of remote and local interfaces */
+extern int     rip_interfaces;         /* # of interfaces doing RIP */
+extern struct interface *ifnet;                /* all interfaces */
+extern int     have_ripv1_out;         /* have a RIPv1 interface */
+extern int     have_ripv1_in;
+extern int     need_flash;             /* flash update needed */
+extern struct timeval need_kern;       /* need to update kernel table */
+extern int     update_seqno;           /* a route has changed */
+
+extern u_int   tracelevel, new_tracelevel;
+#define MAX_TRACELEVEL 4
+#define TRACEKERNEL (tracelevel >= 4)  /* log kernel changes */
+#define        TRACECONTENTS (tracelevel >= 3) /* display packet contents */
+#define TRACEPACKETS (tracelevel >= 2) /* note packets */
+#define        TRACEACTIONS (tracelevel != 0)
+extern FILE    *ftrace;                /* output trace file */
+
+extern struct radix_node_head *rhead;
+
+
+#ifdef sgi
+/* Fix conflicts */
+#define        dup2(x,y)               BSDdup2(x,y)
+#endif /* sgi */
+
+extern void fix_sock(int, char *);
+extern void fix_select(void);
+extern void rip_off(void);
+extern void rip_on(struct interface *);
+
+enum output_type {OUT_QUERY, OUT_UNICAST, OUT_BROADCAST, OUT_MULTICAST,
+       NO_OUT_MULTICAST, NO_OUT_RIPV2};
+extern int     output(enum output_type, struct sockaddr_in *,
+                      struct interface *, struct rip *, int);
+extern void rip_query(void);
+extern void rip_bcast(int);
+extern void supply(struct sockaddr_in *, struct interface *,
+                  enum output_type, int, int);
+
+extern void    msglog(char *, ...);
+#define        LOGERR(msg) msglog(msg ": %s", strerror(errno))
+extern void    logbad(int, char *, ...);
+#define        BADERR(dump,msg) logbad(dump,msg ": %s", strerror(errno))
+#ifdef DEBUG
+#define        DBGERR(dump,msg) BADERR(dump,msg)
+#else
+#define        DBGERR(dump,msg) LOGERR(msg)
+#endif
+extern char    *naddr_ntoa(naddr);
+extern char    *saddr_ntoa(struct sockaddr *);
+
+extern void    *rtmalloc(size_t, char *);
+extern void    timevaladd(struct timeval *, struct timeval *);
+extern void    intvl_random(struct timeval *, u_long, u_long);
+extern int     getnet(char *, naddr *, naddr *);
+extern int     gethost(char *, naddr *);
+extern void    gwkludge(void);
+extern char    *parse_parms(char *);
+extern char    *check_parms(struct parm *);
+extern void    get_parms(struct interface *);
+
+extern void    lastlog(void);
+extern void    trace_on(char *, int);
+extern void    trace_off(char*, ...);
+extern void    trace_flush(void);
+extern void    set_tracelevel(void);
+extern void    trace_kernel(char *, ...);
+extern void    trace_act(char *, ...);
+extern void    trace_pkt(char *, ...);
+extern void    trace_add_del(char *, struct rt_entry *);
+extern void    trace_change(struct rt_entry *, u_int, naddr, naddr, int,
+                            u_short, struct interface *, time_t, char *);
+extern void    trace_if(char *, struct interface *);
+extern void    trace_upslot(struct rt_entry *, struct rt_spare *,
+                            naddr, naddr,
+                            struct interface *, int, u_short, time_t);
+extern void    trace_rip(char*, char*, struct sockaddr_in *,
+                         struct interface *, struct rip *, int);
+extern char    *addrname(naddr, naddr, int);
+
+extern void    rdisc_age(naddr);
+extern void    set_rdisc_mg(struct interface *, int);
+extern void    set_supplier(void);
+extern void    if_bad_rdisc(struct interface *);
+extern void    if_ok_rdisc(struct interface *);
+extern void    read_rip(int, struct interface *);
+extern void    read_rt(void);
+extern void    read_d(void);
+extern void    rdisc_adv(void);
+extern void    rdisc_sol(void);
+
+extern void    sigalrm(int);
+extern void    sigterm(int);
+
+extern void    sigtrace_on(int);
+extern void    sigtrace_off(int);
+
+extern void    flush_kern(void);
+extern void    age(naddr);
+
+extern void    ag_flush(naddr, naddr, void (*)(struct ag_info *));
+extern void    ag_check(naddr, naddr, naddr, naddr, char, char, u_int,
+                        u_short, u_short, void (*)(struct ag_info *));
+extern void    del_static(naddr, naddr, int);
+extern void    del_redirects(naddr, time_t);
+extern struct rt_entry *rtget(naddr, naddr);
+extern struct rt_entry *rtfind(naddr);
+extern void    rtinit(void);
+extern void    rtadd(naddr, naddr, naddr, naddr,
+                     int, u_short, u_int, struct interface *);
+extern void    rtchange(struct rt_entry *, u_int, naddr,naddr, int, u_short,
+                        struct interface *ifp, time_t, char *);
+extern void    rtdelete(struct rt_entry *);
+extern void    rtbad_sub(struct rt_entry *);
+extern void    rtswitch(struct rt_entry *, struct rt_spare *);
+extern void    rtbad(struct rt_entry *);
+
+
+#define S_ADDR(x)      (((struct sockaddr_in *)(x))->sin_addr.s_addr)
+#define INFO_DST(I)    ((I)->rti_info[RTAX_DST])
+#define INFO_GATE(I)   ((I)->rti_info[RTAX_GATEWAY])
+#define INFO_MASK(I)   ((I)->rti_info[RTAX_NETMASK])
+#define INFO_IFA(I)    ((I)->rti_info[RTAX_IFA])
+#define INFO_IFP(I)    ((I)->rti_info[RTAX_IFP])
+#define INFO_AUTHOR(I) ((I)->rti_info[RTAX_AUTHOR])
+#define INFO_BRD(I)    ((I)->rti_info[RTAX_BRD])
+void rt_xaddrs(struct rt_addrinfo *, struct sockaddr *, struct sockaddr *,
+              int);
+
+extern naddr   std_mask(naddr);
+extern naddr   ripv1_mask_net(naddr, struct interface *);
+extern naddr   ripv1_mask_host(naddr,struct interface *);
+#define                on_net(a,net,mask) (((ntohl(a) ^ (net)) & (mask)) == 0)
+extern int     check_dst(naddr);
+extern void    addrouteforif(register struct interface *);
+extern void    ifinit(void);
+extern int     walk_bad(struct radix_node *, void *);
+extern int     if_ok(struct interface *, char *);
+extern void    if_sick(struct interface *);
+extern void    if_bad(struct interface *);
+extern struct interface *ifwithaddr(naddr, int, int);
+extern struct interface *ifwithname(char *, naddr);
+extern struct interface *ifwithindex(u_short);
+extern struct interface *iflookup(naddr);
index 7bf0084..946c797 100644 (file)
@@ -1,5 +1,4 @@
-/*     $OpenBSD: if.c,v 1.2 1996/06/23 14:32:26 deraadt Exp $  */
-/*     $NetBSD: if.c,v 1.8 1995/06/20 22:27:21 christos Exp $  */
+/*     $OpenBSD: if.c,v 1.3 1996/09/05 14:31:21 mickey Exp $   */
 
 /*
  * Copyright (c) 1983, 1993
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-#if 0
+#if !defined(lint)
 static char sccsid[] = "@(#)if.c       8.1 (Berkeley) 6/5/93";
 #else
-static char rcsid[] = "$OpenBSD: if.c,v 1.2 1996/06/23 14:32:26 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: if.c,v 1.3 1996/09/05 14:31:21 mickey Exp $";
 #endif
-#endif /* not lint */
 
-/*
- * Routing Table Management Daemon
- */
 #include "defs.h"
+#include "pathnames.h"
 
-extern struct interface *ifnet;
+struct interface *ifnet;               /* all interfaces */
+int    tot_interfaces;                 /* # of remote and local interfaces */
+int    rip_interfaces;                 /* # of interfaces doing RIP */
+int    foundloopback;                  /* valid flag for loopaddr */
+naddr  loopaddr;                       /* our address on loopback */
 
-/*
- * Find the interface with address addr.
+struct timeval ifinit_timer;
+
+int    have_ripv1_out;                 /* have a RIPv1 interface */
+int    have_ripv1_in;
+
+
+/* Find the interface with an address
  */
 struct interface *
-if_ifwithaddr(addr)
-       struct sockaddr *addr;
+ifwithaddr(naddr addr,
+          int  bcast,                  /* notice IFF_BROADCAST address */
+          int  remote)                 /* include IS_REMOTE interfaces */
 {
-       register struct interface *ifp;
+       struct interface *ifp, *possible = 0;
 
-#define        same(a1, a2) \
-       (memcmp((a1)->sa_data, (a2)->sa_data, 14) == 0)
        for (ifp = ifnet; ifp; ifp = ifp->int_next) {
-               if (ifp->int_flags & IFF_REMOTE)
-                       continue;
-               if (ifp->int_addr.sa_family != addr->sa_family)
-                       continue;
-               if (same(&ifp->int_addr, addr))
-                       break;
-               if ((ifp->int_flags & IFF_BROADCAST) &&
-                   same(&ifp->int_broadaddr, addr))
-                       break;
+               if (ifp->int_addr == addr
+                   || ((ifp->int_if_flags & IFF_BROADCAST)
+                       && ifp->int_brdaddr == addr
+                       && bcast)) {
+                       if ((ifp->int_state & IS_REMOTE) && !remote)
+                               continue;
+
+                       if (!(ifp->int_state & IS_BROKE)
+                           && !(ifp->int_state & IS_PASSIVE))
+                               return ifp;
+
+                       possible = ifp;
+               }
        }
-       return (ifp);
+
+       return possible;
 }
 
-/*
- * Find the point-to-point interface with destination address addr.
+
+/* find the interface with a name
  */
 struct interface *
-if_ifwithdstaddr(addr)
-       struct sockaddr *addr;
+ifwithname(char *name,                 /* "ec0" or whatever */
+          naddr addr)                  /* 0 or network address */
 {
-       register struct interface *ifp;
+       struct interface *ifp;
 
-       for (ifp = ifnet; ifp; ifp = ifp->int_next) {
-               if ((ifp->int_flags & IFF_POINTOPOINT) == 0)
-                       continue;
-               if (same(&ifp->int_dstaddr, addr))
-                       break;
+
+       for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
+               if (!strcmp(ifp->int_name, name)
+                   && (ifp->int_addr == addr
+                       || (addr == 0 && !(ifp->int_state & IS_ALIAS))))
+                       return ifp;
        }
-       return (ifp);
+       return 0;
 }
 
-/*
- * Find the interface on the network 
- * of the specified address.
- */
+
 struct interface *
-if_ifwithnet(addr)
-       register struct sockaddr *addr;
+ifwithindex(u_short index)
 {
-       register struct interface *ifp;
-       register int af = addr->sa_family;
-       register int (*netmatch) __P((struct sockaddr *, struct sockaddr *));
+       struct interface *ifp;
 
-       if (af >= af_max)
-               return (0);
-       netmatch = afswitch[af].af_netmatch;
-       for (ifp = ifnet; ifp; ifp = ifp->int_next) {
-               if (ifp->int_flags & IFF_REMOTE)
-                       continue;
-               if (af != ifp->int_addr.sa_family)
-                       continue;
-               if ((*netmatch)(addr, &ifp->int_addr))
-                       break;
+
+       for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
+               if (ifp->int_index == index)
+                       return ifp;
        }
-       return (ifp);
+       return 0;
 }
 
-/*
- * Find an interface from which the specified address
+
+/* Find an interface from which the specified address
  * should have come from.  Used for figuring out which
  * interface a packet came in on -- for tracing.
  */
 struct interface *
-if_iflookup(addr)
-       struct sockaddr *addr;
+iflookup(naddr addr)
 {
-       register struct interface *ifp, *maybe;
-       register int af = addr->sa_family;
-       register int (*netmatch) __P((struct sockaddr *, struct sockaddr *));
+       struct interface *ifp, *maybe;
 
-       if (af >= af_max)
-               return (0);
        maybe = 0;
-       netmatch = afswitch[af].af_netmatch;
        for (ifp = ifnet; ifp; ifp = ifp->int_next) {
-               if (ifp->int_addr.sa_family != af)
+               if (ifp->int_if_flags & IFF_POINTOPOINT) {
+                       if (ifp->int_dstaddr == addr)
+                               /* finished with a match */
+                               return ifp;
+
+               } else {
+                       /* finished with an exact match */
+                       if (ifp->int_addr == addr)
+                               return ifp;
+                       if ((ifp->int_if_flags & IFF_BROADCAST)
+                           && ifp->int_brdaddr == addr)
+                               return ifp;
+
+                       /* Look for the longest approximate match.
+                        */
+                       if (on_net(addr, ifp->int_net, ifp->int_mask)
+                           && (maybe == 0
+                               || ifp->int_mask > maybe->int_mask))
+                               maybe = ifp;
+               }
+       }
+
+       return maybe;
+}
+
+
+/* Return the classical netmask for an IP address.
+ */
+naddr
+std_mask(naddr addr)                   /* in network order */
+{
+       NTOHL(addr);                    /* was a host, not a network */
+
+       if (addr == 0)                  /* default route has mask 0 */
+               return 0;
+       if (IN_CLASSA(addr))
+               return IN_CLASSA_NET;
+       if (IN_CLASSB(addr))
+               return IN_CLASSB_NET;
+       return IN_CLASSC_NET;
+}
+
+
+/* Find the netmask that would be inferred by RIPv1 listeners
+ *     on the given interface for a given network.
+ *     If no interface is specified, look for the best fitting interface.
+ */
+naddr
+ripv1_mask_net(naddr addr,             /* in network byte order */
+              struct interface *ifp)   /* as seen on this interface */
+{
+       naddr mask = 0;
+
+       if (addr == 0)                  /* default always has 0 mask */
+               return mask;
+
+       if (ifp != 0) {
+               /* If the target network is that of the associated interface
+                * on which it arrived, then use the netmask of the interface.
+                */
+               if (on_net(addr, ifp->int_net, ifp->int_std_mask))
+                       mask = ifp->int_ripv1_mask;
+
+       } else {
+               /* Examine all interfaces, and if it the target seems
+                * to have the same network number of an interface, use the
+                * netmask of that interface.  If there is more than one
+                * such interface, prefer the interface with the longest
+                * match.
+                */
+               for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
+                       if (on_net(addr, ifp->int_std_net, ifp->int_std_mask)
+                           && ifp->int_ripv1_mask > mask)
+                               mask = ifp->int_ripv1_mask;
+               }
+       }
+
+       /* Otherwise, make the classic A/B/C guess.
+        */
+       if (mask == 0)
+               mask = std_mask(addr);
+
+       return mask;
+}
+
+
+naddr
+ripv1_mask_host(naddr addr,            /* in network byte order */
+               struct interface *ifp)  /* as seen on this interface */
+{
+       naddr mask = ripv1_mask_net(addr, ifp);
+
+
+       /* If the computed netmask does not mask the address,
+        * then assume it is a host address
+        */
+       if ((ntohl(addr) & ~mask) != 0)
+               mask = HOST_MASK;
+       return mask;
+}
+
+
+/* See if a IP address looks reasonable as a destination
+ */
+int                                    /* 0=bad */
+check_dst(naddr addr)
+{
+       NTOHL(addr);
+
+       if (IN_CLASSA(addr)) {
+               if (addr == 0)
+                       return 1;       /* default */
+
+               addr >>= IN_CLASSA_NSHIFT;
+               return (addr != 0 && addr != IN_LOOPBACKNET);
+       }
+
+       return (IN_CLASSB(addr) || IN_CLASSC(addr));
+}
+
+
+/* Delete an interface.
+ */
+static void
+ifdel(struct interface *ifp)
+{
+       struct ip_mreq m;
+       struct interface *ifp1;
+
+
+       trace_if("Del", ifp);
+
+       ifp->int_state |= IS_BROKE;
+
+       /* unlink the interface
+        */
+       if (rip_sock_mcast == ifp)
+               rip_sock_mcast = 0;
+       if (ifp->int_next != 0)
+               ifp->int_next->int_prev = ifp->int_prev;
+       if (ifp->int_prev != 0)
+               ifp->int_prev->int_next = ifp->int_next;
+       else
+               ifnet = ifp->int_next;
+
+       if (!(ifp->int_state & IS_ALIAS)) {
+               /* delete aliases
+                */
+               for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) {
+                       if (ifp1 != ifp
+                           && !strcmp(ifp->int_name, ifp1->int_name))
+                               ifdel(ifp1);
+               }
+
+               if ((ifp->int_if_flags & IFF_MULTICAST)
+#ifdef MCAST_PPP_BUG
+                   && !(ifp->int_if_flags & IFF_POINTOPOINT)
+#endif
+                   && rip_sock >= 0) {
+                       m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP);
+                       m.imr_interface.s_addr = ((ifp->int_if_flags
+                                                  & IFF_POINTOPOINT)
+                                                 ? ifp->int_dstaddr
+                                                 : ifp->int_addr);
+                       if (setsockopt(rip_sock,IPPROTO_IP,IP_DROP_MEMBERSHIP,
+                                      &m, sizeof(m)) < 0
+                           && errno != EADDRNOTAVAIL
+                           && !TRACEACTIONS)
+                               LOGERR("setsockopt(IP_DROP_MEMBERSHIP RIP)");
+               }
+               if (ifp->int_rip_sock >= 0) {
+                       (void)close(ifp->int_rip_sock);
+                       ifp->int_rip_sock = -1;
+                       fix_select();
+               }
+
+               tot_interfaces--;
+               if (!IS_RIP_OFF(ifp->int_state))
+                       rip_interfaces--;
+
+               /* Zap all routes associated with this interface.
+                * Assume routes just using gateways beyond this interface will
+                * timeout naturally, and have probably already died.
+                */
+               (void)rn_walktree(rhead, walk_bad, 0);
+
+               set_rdisc_mg(ifp, 0);
+               if_bad_rdisc(ifp);
+       }
+
+       free(ifp);
+}
+
+
+/* Mark an interface ill.
+ */
+void
+if_sick(struct interface *ifp)
+{
+       if (0 == (ifp->int_state & (IS_SICK | IS_BROKE))) {
+               ifp->int_state |= IS_SICK;
+               trace_if("Chg", ifp);
+
+               LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL);
+       }
+}
+
+
+/* Mark an interface dead.
+ */
+void
+if_bad(struct interface *ifp)
+{
+       struct interface *ifp1;
+
+
+       if (ifp->int_state & IS_BROKE)
+               return;
+
+       LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL);
+
+       ifp->int_state |= (IS_BROKE | IS_SICK);
+       ifp->int_state &= ~(IS_RIP_QUERIED | IS_ACTIVE);
+       ifp->int_data.ts = 0;
+
+       trace_if("Chg", ifp);
+
+       if (!(ifp->int_state & IS_ALIAS)) {
+               for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) {
+                       if (ifp1 != ifp
+                           && !strcmp(ifp->int_name, ifp1->int_name))
+                               if_bad(ifp1);
+               }
+               (void)rn_walktree(rhead, walk_bad, 0);
+               if_bad_rdisc(ifp);
+       }
+}
+
+
+/* Mark an interface alive
+ */
+int                                    /* 1=it was dead */
+if_ok(struct interface *ifp,
+      char *type)
+{
+       struct interface *ifp1;
+
+
+       if (!(ifp->int_state & IS_BROKE)) {
+               if (ifp->int_state & IS_SICK) {
+                       trace_act("%sinterface %s to %s working better\n",
+                                 type,
+                                 ifp->int_name, naddr_ntoa(ifp->int_addr));
+                       ifp->int_state &= ~IS_SICK;
+               }
+               return 0;
+       }
+
+       msglog("%sinterface %s to %s restored",
+              type, ifp->int_name, naddr_ntoa(ifp->int_addr));
+       ifp->int_state &= ~(IS_BROKE | IS_SICK);
+       ifp->int_data.ts = 0;
+
+       if (!(ifp->int_state & IS_ALIAS)) {
+               for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) {
+                       if (ifp1 != ifp
+                           && !strcmp(ifp->int_name, ifp1->int_name))
+                               if_ok(ifp1, type);
+               }
+               if_ok_rdisc(ifp);
+       }
+       return 1;
+}
+
+
+/* disassemble routing message
+ */
+void
+rt_xaddrs(struct rt_addrinfo *info,
+         struct sockaddr *sa,
+         struct sockaddr *lim,
+         int addrs)
+{
+       int i;
+#ifdef _HAVE_SA_LEN
+       static struct sockaddr sa_zero;
+#endif
+#ifdef sgi
+#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) \
+                   : sizeof(__uint64_t))
+#else
+#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \
+                   : sizeof(long))
+#endif
+
+
+       bzero(info, sizeof(*info));
+       info->rti_addrs = addrs;
+       for (i = 0; i < RTAX_MAX && sa < lim; i++) {
+               if ((addrs & (1 << i)) == 0)
                        continue;
-               if (same(&ifp->int_addr, addr))
-                       break;
-               if ((ifp->int_flags & IFF_BROADCAST) &&
-                   same(&ifp->int_broadaddr, addr))
-                       break;
-               if ((ifp->int_flags & IFF_POINTOPOINT) &&
-                   same(&ifp->int_dstaddr, addr))
+#ifdef _HAVE_SA_LEN
+               info->rti_info[i] = (sa->sa_len != 0) ? sa : &sa_zero;
+               sa = (struct sockaddr *)((char*)(sa)
+                                        + ROUNDUP(sa->sa_len));
+#else
+               info->rti_info[i] = sa;
+               sa = (struct sockaddr *)((char*)(sa)
+                                        + ROUNDUP(_FAKE_SA_LEN_DST(sa)));
+#endif
+       }
+}
+
+
+/* Find the network interfaces which have configured themselves.
+ *     This must be done regularly, if only for extra addresses
+ *     that come and go on interfaces.
+ */
+void
+ifinit(void)
+{
+       static char *sysctl_buf;
+       static size_t sysctl_buf_size = 0;
+       uint complaints = 0;
+       static u_int prev_complaints = 0;
+#      define COMP_NOT_INET    0x001
+#      define COMP_WIERD       0x002
+#      define COMP_NOADDR      0x004
+#      define COMP_NODST       0x008
+#      define COMP_NOBADR      0x010
+#      define COMP_NOMASK      0x020
+#      define COMP_DUP         0x040
+#      define COMP_BAD_METRIC  0x080
+#      define COMP_NETMASK     0x100
+
+       struct interface ifs, ifs0, *ifp, *ifp1;
+       struct rt_entry *rt;
+       size_t needed;
+       int mib[6];
+       struct if_msghdr *ifm;
+       struct ifa_msghdr *ifam, *ifam_lim, *ifam2;
+       struct sockaddr_dl *sdl;
+       int in, ierr, out, oerr;
+       struct intnet *intnetp;
+       struct rt_addrinfo info;
+#ifdef SIOCGIFMETRIC
+       struct ifreq ifr;
+#endif
+
+
+       ifinit_timer.tv_sec = now.tv_sec + (supplier
+                                           ? CHECK_ACT_INTERVAL
+                                           : CHECK_QUIET_INTERVAL);
+
+       /* mark all interfaces so we can get rid of thost that disappear */
+       for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next)
+               ifp->int_state &= ~(IS_CHECKED | IS_DUP);
+
+       /* Fetch the interface list, without too many system calls
+        * since we do it repeatedly.
+        */
+       mib[0] = CTL_NET;
+       mib[1] = PF_ROUTE;
+       mib[2] = 0;
+       mib[3] = AF_INET;
+       mib[4] = NET_RT_IFLIST;
+       mib[5] = 0;
+       for (;;) {
+               if ((needed = sysctl_buf_size) != 0) {
+                       if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0)
+                               break;
+                       if (errno != ENOMEM && errno != EFAULT)
+                               BADERR(1, "ifinit: get interface table");
+                       free(sysctl_buf);
+                       needed = 0;
+               }
+               if (sysctl(mib, 6, 0, &needed, 0, 0) < 0)
+                       BADERR(1,"ifinit: route-sysctl-estimate");
+               sysctl_buf = rtmalloc(sysctl_buf_size = needed, "ifinit");
+       }
+
+       ifam_lim = (struct ifa_msghdr *)(sysctl_buf + needed);
+       for (ifam = (struct ifa_msghdr *)sysctl_buf;
+            ifam < ifam_lim;
+            ifam = ifam2) {
+
+               ifam2 = (struct ifa_msghdr*)((char*)ifam + ifam->ifam_msglen);
+
+               if (ifam->ifam_type == RTM_IFINFO) {
+                       ifm = (struct if_msghdr *)ifam;
+                       /* make prototype structure for the IP aliases
+                        */
+                       bzero(&ifs0, sizeof(ifs0));
+                       ifs0.int_rip_sock = -1;
+                       ifs0.int_index = ifm->ifm_index;
+                       ifs0.int_if_flags = ifm->ifm_flags;
+                       ifs0.int_state = IS_CHECKED;
+                       ifs0.int_act_time = now.tv_sec;
+                       ifs0.int_data.ts = now.tv_sec;
+                       ifs0.int_data.ipackets = ifm->ifm_data.ifi_ipackets;
+                       ifs0.int_data.ierrors = ifm->ifm_data.ifi_ierrors;
+                       ifs0.int_data.opackets = ifm->ifm_data.ifi_opackets;
+                       ifs0.int_data.oerrors = ifm->ifm_data.ifi_oerrors;
+#ifdef sgi
+                       ifs0.int_data.odrops = ifm->ifm_data.ifi_odrops;
+#endif
+                       sdl = (struct sockaddr_dl *)(ifm + 1);
+                       sdl->sdl_data[sdl->sdl_nlen] = 0;
+                       continue;
+               }
+               if (ifam->ifam_type != RTM_NEWADDR) {
+                       logbad(1,"ifinit: out of sync");
+                       continue;
+               }
+
+               rt_xaddrs(&info, (struct sockaddr *)(ifam+1),
+                         (struct sockaddr *)ifam2,
+                         ifam->ifam_addrs);
+
+               if (INFO_IFA(&info) == 0) {
+                       if (iff_alive(ifs.int_if_flags)) {
+                               if (!(prev_complaints & COMP_NOADDR))
+                                       msglog("%s has a bad address",
+                                              sdl->sdl_data);
+                               complaints |= COMP_NOADDR;
+                       }
+                       continue;
+               }
+               if (INFO_IFA(&info)->sa_family != AF_INET) {
+                       if (iff_alive(ifs.int_if_flags)) {
+                               if (!(prev_complaints & COMP_NOT_INET))
+                                       trace_act("%s: not AF_INET\n",
+                                                 sdl->sdl_data);
+                               complaints |= COMP_NOT_INET;
+                       }
+                       continue;
+               }
+
+               bcopy(&ifs0, &ifs, sizeof(ifs0));
+               ifs0.int_state |= IS_ALIAS;     /* next will be an alias */
+
+               ifs.int_addr = S_ADDR(INFO_IFA(&info));
+
+               if (ifs.int_if_flags & IFF_BROADCAST) {
+                       if (INFO_MASK(&info) == 0) {
+                               if (iff_alive(ifs.int_if_flags)) {
+                                       if (!(prev_complaints & COMP_NOMASK))
+                                               msglog("%s has no netmask",
+                                                      sdl->sdl_data);
+                                       complaints |= COMP_NOMASK;
+                               }
+                               continue;
+                       }
+                       ifs.int_dstaddr = ifs.int_addr;
+                       ifs.int_mask = ntohl(S_ADDR(INFO_MASK(&info)));
+                       ifs.int_ripv1_mask = ifs.int_mask;
+                       ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask;
+                       ifs.int_std_mask = std_mask(ifs.int_addr);
+                       if (ifs.int_mask != ifs.int_std_mask)
+                               ifs.int_state |= IS_SUBNET;
+
+                       if (INFO_BRD(&info) == 0) {
+                               if (iff_alive(ifs.int_if_flags)) {
+                                       if (!(prev_complaints & COMP_NOBADR))
+                                               msglog("%s has no"
+                                                      " broadcast address",
+                                                      sdl->sdl_data);
+                                       complaints |= COMP_NOBADR;
+                               }
+                               continue;
+                       }
+                       ifs.int_brdaddr = S_ADDR(INFO_BRD(&info));
+
+               } else if (ifs.int_if_flags & IFF_POINTOPOINT) {
+                       if (INFO_BRD(&info) == 0
+                           || INFO_BRD(&info)->sa_family != AF_INET) {
+                               if (iff_alive(ifs.int_if_flags)) {
+                                       if (!(prev_complaints & COMP_NODST))
+                                               msglog("%s has a bad"
+                                                      " destination address",
+                                                      sdl->sdl_data);
+                                       complaints |= COMP_NODST;
+                               }
+                               continue;
+                       }
+                       ifs.int_dstaddr = S_ADDR(INFO_BRD(&info));
+                       ifs.int_mask = HOST_MASK;
+                       ifs.int_ripv1_mask = ntohl(S_ADDR(INFO_MASK(&info)));
+                       ifs.int_net = ntohl(ifs.int_dstaddr);
+                       ifs.int_std_mask = std_mask(ifs.int_dstaddr);
+
+               } else if (ifs.int_if_flags & IFF_LOOPBACK) {
+                       ifs.int_state |= IS_PASSIVE | IS_NO_RIP;
+                       ifs.int_dstaddr = ifs.int_addr;
+                       ifs.int_mask = HOST_MASK;
+                       ifs.int_ripv1_mask = HOST_MASK;
+                       ifs.int_net = ntohl(ifs.int_dstaddr);
+                       ifs.int_std_mask = std_mask(ifs.int_dstaddr);
+                       if (!foundloopback) {
+                               foundloopback = 1;
+                               loopaddr = ifs.int_addr;
+                       }
+
+               } else {
+                       if (!(prev_complaints & COMP_WIERD))
+                               trace_act("%s is neither broadcast"
+                                         " nor point-to-point nor loopback",
+                                         sdl->sdl_data);
+                       complaints |= COMP_WIERD;
+                       continue;
+               }
+               ifs.int_std_net = ifs.int_net & ifs.int_std_mask;
+               ifs.int_std_addr = htonl(ifs.int_std_net);
+
+               /* Use a minimum metric of one.  Treat the interface metric
+                * (default 0) as an increment to the hop count of one.
+                *
+                * The metric obtained from the routing socket dump of
+                * interface addresses is wrong.  It is not set by the
+                * SIOCSIFMETRIC ioctl.
+                */
+#ifdef SIOCGIFMETRIC
+               strncpy(ifr.ifr_name, sdl->sdl_data, sizeof(ifr.ifr_name));
+               if (ioctl(rt_sock, SIOCGIFMETRIC, &ifr) < 0) {
+                       DBGERR(1, "ioctl(SIOCGIFMETRIC)");
+                       ifs.int_metric = 0;
+               } else {
+                       ifs.int_metric = ifr.ifr_metric;
+               }
+#else
+               ifs.int_metric = ifam->ifam_metric;
+#endif
+               if (ifs.int_metric > HOPCNT_INFINITY) {
+                       ifs.int_metric = 0;
+                       if (!(prev_complaints & COMP_BAD_METRIC)
+                           && iff_alive(ifs.int_if_flags)) {
+                               complaints |= COMP_BAD_METRIC;
+                               msglog("%s has a metric of %d",
+                                      sdl->sdl_data, ifs.int_metric);
+                       }
+               }
+
+               /* See if this is a familiar interface.
+                * If so, stop worrying about it if it is the same.
+                * Start it over if it now is to somewhere else, as happens
+                * frequently with PPP and SLIP.
+                */
+               ifp = ifwithname(sdl->sdl_data, ((ifs.int_state & IS_ALIAS)
+                                                ? ifs.int_addr
+                                                : 0));
+               if (ifp != 0) {
+                       ifp->int_state |= IS_CHECKED;
+
+                       if (0 != ((ifp->int_if_flags ^ ifs.int_if_flags)
+                                 & (IFF_BROADCAST
+                                    | IFF_LOOPBACK
+                                    | IFF_POINTOPOINT
+                                    | IFF_MULTICAST))
+                           || 0 != ((ifp->int_state ^ ifs.int_state)
+                                    & IS_ALIAS)
+                           || ifp->int_addr != ifs.int_addr
+                           || ifp->int_brdaddr != ifs.int_brdaddr
+                           || ifp->int_dstaddr != ifs.int_dstaddr
+                           || ifp->int_mask != ifs.int_mask
+                           || ifp->int_metric != ifs.int_metric) {
+                               /* Forget old information about
+                                * a changed interface.
+                                */
+                               trace_act("interface %s has changed\n",
+                                         ifp->int_name);
+                               ifdel(ifp);
+                               ifp = 0;
+                       }
+               }
+
+               if (ifp != 0) {
+                       /* The primary representative of an alias worries
+                        * about how things are working.
+                        */
+                       if (ifp->int_state & IS_ALIAS)
+                               continue;
+
+                       /* note interfaces that have been turned off
+                        */
+                       if (!iff_alive(ifs.int_if_flags)) {
+                               if (iff_alive(ifp->int_if_flags)) {
+                                       msglog("interface %s to %s turned off",
+                                              ifp->int_name,
+                                              naddr_ntoa(ifp->int_addr));
+                                       if_bad(ifp);
+                                       ifp->int_if_flags &= ~IFF_UP_RUNNING;
+                               }
+                               continue;
+                       }
+                       /* or that were off and are now ok */
+                       if (!iff_alive(ifp->int_if_flags)) {
+                               ifp->int_if_flags |= IFF_UP_RUNNING;
+                               (void)if_ok(ifp, "");
+                       }
+
+                       /* If it has been long enough,
+                        * see if the interface is broken.
+                        */
+                       if (now.tv_sec < ifp->int_data.ts+CHECK_BAD_INTERVAL)
+                               continue;
+
+                       in = ifs.int_data.ipackets - ifp->int_data.ipackets;
+                       ierr = ifs.int_data.ierrors - ifp->int_data.ierrors;
+                       out = ifs.int_data.opackets - ifp->int_data.opackets;
+                       oerr = ifs.int_data.oerrors - ifp->int_data.oerrors;
+#ifdef sgi
+                       /* Through at least IRIX 6.2, PPP and SLIP
+                        * count packets dropped by  the filters.
+                        * But FDDI rings stuck non-operational count
+                        * dropped packets as they wait for improvement.
+                        */
+                       if (!(ifp->int_if_flags & IFF_POINTOPOINT))
+                               oerr += (ifs.int_data.odrops
+                                        - ifp->int_data.odrops);
+#endif
+                       /* If the interface just awoke, restart the counters.
+                        */
+                       if (ifp->int_data.ts == 0) {
+                               ifp->int_data = ifs.int_data;
+                               continue;
+                       }
+                       ifp->int_data = ifs.int_data;
+
+                       /* Withhold judgement when the short error
+                        * counters wrap or the interface is reset.
+                        */
+                       if (ierr < 0 || in < 0 || oerr < 0 || out < 0) {
+                               LIM_SEC(ifinit_timer,
+                                       now.tv_sec+CHECK_BAD_INTERVAL);
+                               continue;
+                       }
+
+                       /* Withhold judgement when there is no traffic
+                        */
+                       if (in == 0 && out == 0 && ierr == 0 && oerr == 0)
+                               continue;
+
+                       /* It is bad if input or output is not working.
+                        * Require presistent problems before marking it dead.
+                        */
+                       if ((in <= ierr && ierr > 0)
+                           || (out <= oerr && oerr > 0)) {
+                               if (!(ifp->int_state & IS_SICK)) {
+                                       trace_act("interface %s to %s"
+                                                 " sick: in=%d ierr=%d"
+                                                 " out=%d oerr=%d\n",
+                                                 ifp->int_name,
+                                                 naddr_ntoa(ifp->int_addr),
+                                                 in, ierr, out, oerr);
+                                       if_sick(ifp);
+                                       continue;
+                               }
+                               if (!(ifp->int_state & IS_BROKE)) {
+                                       msglog("interface %s to %s bad:"
+                                              " in=%d ierr=%d out=%d oerr=%d",
+                                              ifp->int_name,
+                                              naddr_ntoa(ifp->int_addr),
+                                              in, ierr, out, oerr);
+                                       if_bad(ifp);
+                               }
+                               continue;
+                       }
+
+                       /* otherwise, it is active and healthy
+                        */
+                       ifp->int_act_time = now.tv_sec;
+                       (void)if_ok(ifp, "");
+                       continue;
+               }
+
+               /* This is a new interface.
+                * If it is dead, forget it.
+                */
+               if (!iff_alive(ifs.int_if_flags))
+                       continue;
+
+               /* See if it duplicates an existing interface.
+                */
+               for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
+                       if (ifp->int_mask != ifs.int_mask)
+                               continue;
+                       if (((ifp->int_addr != ifs.int_addr
+                             && ifs.int_mask != HOST_MASK)
+                            || (ifp->int_dstaddr != ifs.int_dstaddr
+                                && ifs.int_mask == HOST_MASK)))
+                               continue;
+                       if (!iff_alive(ifp->int_if_flags))
+                               continue;
+                       /* Let one of our real interfaces be marked
+                        * passive.
+                        */
+                       if ((ifp->int_state & IS_PASSIVE)
+                           && !(ifp->int_state & IS_EXTERNAL))
+                               continue;
+
+                       /* It does duplicate an existing interface,
+                        * so complain about it, mark the other one
+                        * duplicated, and for get this one.
+                        */
+                       if (!(prev_complaints & COMP_DUP)) {
+                               complaints |= COMP_DUP;
+                               msglog("%s is duplicated by %s at %s",
+                                      sdl->sdl_data, ifp->int_name,
+                                      naddr_ntoa(ifp->int_addr));
+                       }
+                       ifp->int_state |= IS_DUP;
                        break;
-               if (maybe == 0 && (*netmatch)(addr, &ifp->int_addr))
-                       maybe = ifp;
+               }
+               if (ifp != 0)
+                       continue;
+
+               /* It is new and ok.  So make it real
+                */
+               strncpy(ifs.int_name, sdl->sdl_data,
+                       MIN(sizeof(ifs.int_name)-1, sdl->sdl_nlen));
+               get_parms(&ifs);
+
+               /* Add it to the list of interfaces
+                */
+               ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit");
+               bcopy(&ifs, ifp, sizeof(*ifp));
+               if (ifnet != 0) {
+                       ifp->int_next = ifnet;
+                       ifnet->int_prev = ifp;
+               }
+               ifnet = ifp;
+               trace_if("Add", ifp);
+
+               /* Notice likely bad netmask.
+                */
+               if (!(prev_complaints & COMP_NETMASK)
+                   && !(ifp->int_if_flags & IFF_POINTOPOINT)) {
+                       for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) {
+                               if (ifp1->int_mask == ifp->int_mask)
+                                       continue;
+                               if (ifp1->int_if_flags & IFF_POINTOPOINT)
+                                       continue;
+                               if (on_net(ifp->int_addr,
+                                          ifp1->int_net, ifp1->int_mask)
+                                   || on_net(ifp1->int_addr,
+                                             ifp->int_net, ifp->int_mask)) {
+                                       msglog("possible netmask problem"
+                                              " betwen %s:%s and %s:%s",
+                                              ifp->int_name,
+                                              addrname(htonl(ifp->int_net),
+                                                       ifp->int_mask, 1),
+                                              ifp1->int_name,
+                                              addrname(htonl(ifp1->int_net),
+                                                       ifp1->int_mask, 1));
+                                       complaints |= COMP_NETMASK;
+                               }
+                       }
+               }
+
+               /* Count the # of directly connected networks.
+                */
+               if (!(ifp->int_state & IS_ALIAS)) {
+                       if (!(ifp->int_if_flags & IFF_LOOPBACK))
+                               tot_interfaces++;
+                       if (!IS_RIP_OFF(ifp->int_state))
+                               rip_interfaces++;
+               }
+
+               if_ok_rdisc(ifp);
+               rip_on(ifp);
+       }
+
+       /* If we are multi-homed and have at least one interface
+        * listening to RIP, then output by default.
+        */
+       if (!supplier_set && rip_interfaces > 1)
+               set_supplier();
+
+       /* If we are multi-homed, optionally advertise a route to
+        * our main address.
+        */
+       if (advertise_mhome
+           || (tot_interfaces > 1
+               && mhome
+               && (ifp = ifwithaddr(myaddr, 0, 0)) != 0
+               && foundloopback)) {
+               advertise_mhome = 1;
+               rt = rtget(myaddr, HOST_MASK);
+               if (rt != 0) {
+                       if (rt->rt_ifp != ifp
+                           || rt->rt_router != loopaddr) {
+                               rtdelete(rt);
+                               rt = 0;
+                       } else {
+                               rtchange(rt, rt->rt_state | RS_MHOME,
+                                        loopaddr, loopaddr,
+                                        0, 0, ifp, rt->rt_time, 0);
+                       }
+               }
+               if (rt == 0)
+                       rtadd(myaddr, HOST_MASK, loopaddr, loopaddr,
+                             0, 0, RS_MHOME, ifp);
+       }
+
+       for (ifp = ifnet; ifp != 0; ifp = ifp1) {
+               ifp1 = ifp->int_next;   /* because we may delete it */
+
+               /* Forget any interfaces that have disappeared.
+                */
+               if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) {
+                       trace_act("interface %s has disappeared\n",
+                                 ifp->int_name);
+                       ifdel(ifp);
+                       continue;
+               }
+
+               if ((ifp->int_state & IS_BROKE)
+                   && !(ifp->int_state & IS_PASSIVE))
+                       LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL);
+
+               /* If we ever have a RIPv1 interface, assume we always will.
+                * It might come back if it ever goes away.
+                */
+               if (!(ifp->int_if_flags & IFF_LOOPBACK)) {
+                       if (!(ifp->int_state & IS_NO_RIPV1_OUT))
+                               have_ripv1_out = 1;
+                       if (!(ifp->int_state & IS_NO_RIPV1_IN))
+                               have_ripv1_in = 1;
+               }
+       }
+
+       for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
+               /* Ensure there is always a network route for interfaces,
+                * after any dead interfaces have been deleted, which
+                * might affect routes for point-to-point links.
+                */
+               addrouteforif(ifp);
+
+               /* Add routes to the local end of point-to-point interfaces
+                * using loopback.
+                */
+               if ((ifp->int_if_flags & IFF_POINTOPOINT)
+                   && !(ifp->int_state & IS_REMOTE)
+                   && foundloopback) {
+                       /* Delete any routes to the network address through
+                        * foreign routers. Remove even static routes.
+                        */
+                       del_static(ifp->int_addr, HOST_MASK, 0);
+                       rt = rtget(ifp->int_addr, HOST_MASK);
+                       if (rt != 0 && rt->rt_router != loopaddr) {
+                               rtdelete(rt);
+                               rt = 0;
+                       }
+                       if (rt != 0) {
+                               if (!(rt->rt_state & RS_LOCAL)
+                                   || rt->rt_metric > ifp->int_metric) {
+                                       ifp1 = ifp;
+                               } else {
+                                       ifp1 = rt->rt_ifp;
+                               }
+                               rtchange(rt,((rt->rt_state & ~RS_NET_SYN)
+                                            | (RS_IF|RS_LOCAL)),
+                                        loopaddr, loopaddr,
+                                        0, 0, ifp1, rt->rt_time, 0);
+                       } else {
+                               rtadd(ifp->int_addr, HOST_MASK,
+                                     loopaddr, loopaddr,
+                                     0, 0, (RS_IF | RS_LOCAL), ifp);
+                       }
+               }
+       }
+
+       /* add the authority routes */
+       for (intnetp = intnets; intnetp!=0; intnetp = intnetp->intnet_next) {
+               rt = rtget(intnetp->intnet_addr, intnetp->intnet_mask);
+               if (rt != 0
+                   && !(rt->rt_state & RS_NO_NET_SYN)
+                   && !(rt->rt_state & RS_NET_INT)) {
+                       rtdelete(rt);
+                       rt = 0;
+               }
+               if (rt == 0)
+                       rtadd(intnetp->intnet_addr, intnetp->intnet_mask,
+                             loopaddr, loopaddr, intnetp->intnet_metric-1,
+                             0, RS_NET_SYN | RS_NET_INT, 0);
+       }
+
+       prev_complaints = complaints;
+}
+
+
+static void
+check_net_syn(struct interface *ifp)
+{
+       struct rt_entry *rt;
+
+
+       /* Turn on the need to automatically synthesize a network route
+        * for this interface only if we are running RIPv1 on some other
+        * interface that is on a different class-A,B,or C network.
+        */
+       if (have_ripv1_out || have_ripv1_in) {
+               ifp->int_state |= IS_NEED_NET_SYN;
+               rt = rtget(ifp->int_std_addr, ifp->int_std_mask);
+               if (rt != 0
+                   && 0 == (rt->rt_state & RS_NO_NET_SYN)
+                   && (!(rt->rt_state & RS_NET_SYN)
+                       || rt->rt_metric > ifp->int_metric)) {
+                       rtdelete(rt);
+                       rt = 0;
+               }
+               if (rt == 0)
+                       rtadd(ifp->int_std_addr, ifp->int_std_mask,
+                             ifp->int_addr, ifp->int_addr,
+                             ifp->int_metric, 0, RS_NET_SYN, ifp);
+
+       } else {
+               ifp->int_state &= ~IS_NEED_NET_SYN;
+
+               rt = rtget(ifp->int_std_addr,
+                          ifp->int_std_mask);
+               if (rt != 0
+                   && (rt->rt_state & RS_NET_SYN)
+                   && rt->rt_ifp == ifp)
+                       rtbad_sub(rt);
+       }
+}
+
+
+/* Add route for interface if not currently installed.
+ * Create route to other end if a point-to-point link,
+ * otherwise a route to this (sub)network.
+ */
+void
+addrouteforif(struct interface *ifp)
+{
+       struct rt_entry *rt;
+       naddr dst, gate;
+
+
+       /* skip sick interfaces
+        */
+       if (ifp->int_state & IS_BROKE)
+               return;
+
+       /* If the interface on a subnet, then install a RIPv1 route to
+        * the network as well (unless it is sick).
+        */
+       if (ifp->int_state & IS_SUBNET)
+               check_net_syn(ifp);
+
+       if (ifp->int_state & IS_REMOTE) {
+               dst = ifp->int_addr;
+               gate = ifp->int_dstaddr;
+               /* If we are going to send packets to the gateway,
+                * it must be reachable using our physical interfaces
+                */
+               if (!(ifp->int_state && IS_EXTERNAL)
+                   && !rtfind(ifp->int_dstaddr)
+                   && ifp->int_transitions == 0) {
+                       msglog("unreachable gateway %s in "
+                              _PATH_GATEWAYS" entry %s",
+                              naddr_ntoa(gate), ifp->int_name);
+                       return;
+               }
+
+       } else {
+               dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT
+                                                 | IFF_LOOPBACK))
+                      ? ifp->int_dstaddr
+                      : htonl(ifp->int_net));
+               gate = ifp->int_addr;
+       }
+
+       /* We are finished if the correct main interface route exists.
+        * The right route must be for the right interface, not synthesized
+        * from a subnet, be a "gateway" or not as appropriate, and so forth.
+        */
+       del_static(dst, ifp->int_mask, 0);
+       rt = rtget(dst, ifp->int_mask);
+       if (rt != 0) {
+               if ((rt->rt_ifp != ifp
+                    || rt->rt_router != ifp->int_addr)
+                   && (!(ifp->int_state & IS_DUP)
+                       || rt->rt_ifp == 0
+                       || (rt->rt_ifp->int_state & IS_BROKE))) {
+                       rtdelete(rt);
+                       rt = 0;
+               } else {
+                       rtchange(rt, ((rt->rt_state | RS_IF)
+                                     & ~(RS_NET_SYN | RS_LOCAL)),
+                                ifp->int_addr, ifp->int_addr,
+                                ifp->int_metric, 0, ifp, now.tv_sec, 0);
+               }
+       }
+       if (rt == 0) {
+               if (ifp->int_transitions++ > 0)
+                       trace_act("re-install interface %s\n",
+                                 ifp->int_name);
+
+               rtadd(dst, ifp->int_mask, gate, gate,
+                     ifp->int_metric, 0, RS_IF, ifp);
        }
-       if (ifp == 0)
-               ifp = maybe;
-       return (ifp);
 }
diff --git a/sbin/routed/inet.c b/sbin/routed/inet.c
deleted file mode 100644 (file)
index bbb5d1a..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/*     $OpenBSD: inet.c,v 1.2 1996/06/23 14:32:27 deraadt Exp $        */
-/*     $NetBSD: inet.c,v 1.9 1995/06/20 22:27:40 christos Exp $        */
-
-/*
- * Copyright (c) 1983, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)inet.c     8.2 (Berkeley) 8/14/93";
-#else
-static char rcsid[] = "$OpenBSD: inet.c,v 1.2 1996/06/23 14:32:27 deraadt Exp $";
-#endif
-#endif /* not lint */
-
-/*
- * Temporarily, copy these routines from the kernel,
- * as we need to know about subnets.
- */
-#include "defs.h"
-
-extern struct interface *ifnet;
-
-/*
- * Formulate an Internet address from network + host.
- */
-struct in_addr
-inet_makeaddr(net, host)
-       u_long net, host;
-{
-       register struct interface *ifp;
-       register u_long mask;
-       u_long addr;
-
-       if (IN_CLASSA(net))
-               mask = IN_CLASSA_HOST;
-       else if (IN_CLASSB(net))
-               mask = IN_CLASSB_HOST;
-       else
-               mask = IN_CLASSC_HOST;
-       for (ifp = ifnet; ifp; ifp = ifp->int_next)
-               if ((ifp->int_netmask & net) == ifp->int_net) {
-                       mask = ~ifp->int_subnetmask;
-                       break;
-               }
-       addr = net | (host & mask);
-       addr = htonl(addr);
-       return (*(struct in_addr *)&addr);
-}
-
-/*
- * Return the network number from an internet address.
- */
-u_long
-inet_netof_subnet(in)
-       struct in_addr in;
-{
-       register u_long i = ntohl(in.s_addr);
-       register u_long net;
-       register struct interface *ifp;
-
-       if (IN_CLASSA(i))
-               net = i & IN_CLASSA_NET;
-       else if (IN_CLASSB(i))
-               net = i & IN_CLASSB_NET;
-       else
-               net = i & IN_CLASSC_NET;
-
-       /*
-        * Check whether network is a subnet;
-        * if so, return subnet number.
-        */
-       for (ifp = ifnet; ifp; ifp = ifp->int_next)
-               if ((ifp->int_netmask & net) == ifp->int_net)
-                       return (i & ifp->int_subnetmask);
-       return (net);
-}
-
-#ifdef notdef
-/*
- * Return the host portion of an internet address.
- * XXX THIS FUNCTION UNUSED.
- */
-u_long
-inet_lnaof_subnet(in)
-       struct in_addr in;
-{
-       register u_long i = ntohl(in.s_addr);
-       register u_long net, host;
-       register struct interface *ifp;
-
-       if (IN_CLASSA(i)) {
-               net = i & IN_CLASSA_NET;
-               host = i & IN_CLASSA_HOST;
-       } else if (IN_CLASSB(i)) {
-               net = i & IN_CLASSB_NET;
-               host = i & IN_CLASSB_HOST;
-       } else {
-               net = i & IN_CLASSC_NET;
-               host = i & IN_CLASSC_HOST;
-       }
-
-       /*
-        * Check whether network is a subnet;
-        * if so, use the modified interpretation of `host'.
-        */
-       for (ifp = ifnet; ifp; ifp = ifp->int_next)
-               if ((ifp->int_netmask & net) == ifp->int_net)
-                       return (host &~ ifp->int_subnetmask);
-       return (host);
-}
-#endif
-
-/*
- * Return the netmask pertaining to an internet address.
- */
-int
-inet_maskof(inaddr)
-       u_long inaddr;
-{
-       register u_long i = ntohl(inaddr);
-       register u_long mask;
-       register struct interface *ifp;
-
-       if (i == 0) {
-               mask = 0;
-       } else if (IN_CLASSA(i)) {
-               mask = IN_CLASSA_NET;
-       } else if (IN_CLASSB(i)) {
-               mask = IN_CLASSB_NET;
-       } else
-               mask = IN_CLASSC_NET;
-
-       /*
-        * Check whether network is a subnet;
-        * if so, use the modified interpretation of `host'.
-        */
-       for (ifp = ifnet; ifp; ifp = ifp->int_next)
-               if ((ifp->int_netmask & i) == ifp->int_net)
-                       mask = ifp->int_subnetmask;
-       return (htonl(mask));
-}
-
-/*
- * Return RTF_HOST if the address is
- * for an Internet host, RTF_SUBNET for a subnet,
- * 0 for a network.
- */
-int
-inet_rtflags(sa)
-       struct sockaddr *sa;
-{
-       struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-       register u_long i = ntohl(sin->sin_addr.s_addr);
-       register u_long net, host;
-       register struct interface *ifp;
-
-       if (IN_CLASSA(i)) {
-               net = i & IN_CLASSA_NET;
-               host = i & IN_CLASSA_HOST;
-       } else if (IN_CLASSB(i)) {
-               net = i & IN_CLASSB_NET;
-               host = i & IN_CLASSB_HOST;
-       } else {
-               net = i & IN_CLASSC_NET;
-               host = i & IN_CLASSC_HOST;
-       }
-
-       /*
-        * Check whether this network is subnetted;
-        * if so, check whether this is a subnet or a host.
-        */
-       for (ifp = ifnet; ifp; ifp = ifp->int_next)
-               if (net == ifp->int_net) {
-                       if (host &~ ifp->int_subnetmask)
-                               return (RTF_HOST);
-                       else if (ifp->int_subnetmask != ifp->int_netmask)
-                               return (RTF_SUBNET);
-                       else
-                               return (0);             /* network */
-               }
-       if (host == 0)
-               return (0);     /* network */
-       else
-               return (RTF_HOST);
-}
-
-/*
- * Return true if a route to subnet/host of route rt should be sent to dst.
- * Send it only if dst is on the same logical network if not "internal",
- * otherwise only if the route is the "internal" route for the logical net.
- */
-int
-inet_sendroute(rt, sa)
-       struct rt_entry *rt;
-       struct sockaddr *sa;
-{
-       struct sockaddr_in *dst = (struct sockaddr_in *) sa;
-       register u_long r =
-           ntohl(((struct sockaddr_in *)&rt->rt_dst)->sin_addr.s_addr);
-       register u_long d = ntohl(dst->sin_addr.s_addr);
-
-       if (IN_CLASSA(r)) {
-               if ((r & IN_CLASSA_NET) == (d & IN_CLASSA_NET)) {
-                       if ((r & IN_CLASSA_HOST) == 0)
-                               return ((rt->rt_state & RTS_INTERNAL) == 0);
-                       return (1);
-               }
-               if (r & IN_CLASSA_HOST)
-                       return (0);
-               return ((rt->rt_state & RTS_INTERNAL) != 0);
-       } else if (IN_CLASSB(r)) {
-               if ((r & IN_CLASSB_NET) == (d & IN_CLASSB_NET)) {
-                       if ((r & IN_CLASSB_HOST) == 0)
-                               return ((rt->rt_state & RTS_INTERNAL) == 0);
-                       return (1);
-               }
-               if (r & IN_CLASSB_HOST)
-                       return (0);
-               return ((rt->rt_state & RTS_INTERNAL) != 0);
-       } else {
-               if ((r & IN_CLASSC_NET) == (d & IN_CLASSC_NET)) {
-                       if ((r & IN_CLASSC_HOST) == 0)
-                               return ((rt->rt_state & RTS_INTERNAL) == 0);
-                       return (1);
-               }
-               if (r & IN_CLASSC_HOST)
-                       return (0);
-               return ((rt->rt_state & RTS_INTERNAL) != 0);
-       }
-}
index 9417250..c17e4fd 100644 (file)
@@ -1,5 +1,4 @@
-/*     $OpenBSD: input.c,v 1.3 1996/06/23 14:32:27 deraadt Exp $       */
-/*     $NetBSD: input.c,v 1.16 1995/07/13 23:20:10 christos Exp $      */
+/*     $OpenBSD: input.c,v 1.4 1996/09/05 14:31:27 mickey Exp $        */
 
 /*
  * Copyright (c) 1983, 1988, 1993
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-#if 0
+#if !defined(lint)
 static char sccsid[] = "@(#)input.c    8.1 (Berkeley) 6/5/93";
 #else
-static char rcsid[] = "$OpenBSD: input.c,v 1.3 1996/06/23 14:32:27 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: input.c,v 1.4 1996/09/05 14:31:27 mickey Exp $";
 #endif
-#endif /* not lint */
 
-/*
- * Routing Table Management Daemon
- */
 #include "defs.h"
-#include <syslog.h>
 
+static void input(struct sockaddr_in *, struct interface*, struct rip *, int);
+static void input_route(struct interface *, naddr,
+                       naddr, naddr, naddr, struct netinfo *);
 
-/*
- * "Authenticate" router from which message originated.
- * We accept routing packets from routers directly connected
- * via broadcast or point-to-point networks,
- * and from those listed in /etc/gateways.
+
+/* process RIP input
  */
-static struct interface *
-rip_verify(from)
-       struct sockaddr *from;
+void
+read_rip(int sock,
+        struct interface *ifp)
 {
-       struct interface *ifp;
-       char buf[256];
-
-       if ((ifp = if_iflookup(from)) == 0) {
-               syslog(LOG_ERR, "trace command from unknown router, %s",
-                      (*afswitch[from->sa_family].af_format)(from, buf,
-                                                             sizeof(buf)));
-               return NULL;
-       }
+       struct sockaddr_in from;
+       int fromlen, cc;
+       union pkt_buf inbuf;
 
-       if ((ifp->int_flags & 
-               (IFF_BROADCAST|IFF_POINTOPOINT|IFF_REMOTE)) == 0) {
-               syslog(LOG_ERR,
-                      "trace command from router %s, with bad flags %x",
-                      (*afswitch[from->sa_family].af_format)(from, buf,
-                                                             sizeof(buf)),
-                      ifp->int_flags);
-               return NULL;
-       }
 
-       if ((ifp->int_flags & IFF_PASSIVE) != 0) {
-               syslog(LOG_ERR,
-                      "trace command from %s on an active interface",
-                      (*afswitch[from->sa_family].af_format)(from, buf,
-                                                             sizeof(buf)));
-               return NULL;
-       }
+       for (;;) {
+               fromlen = sizeof(from);
+               cc = recvfrom(sock, &inbuf, sizeof(inbuf), 0,
+                             (struct sockaddr*)&from, &fromlen);
+               if (cc <= 0) {
+                       if (cc < 0 && errno != EWOULDBLOCK)
+                               LOGERR("recvfrom(rip)");
+                       break;
+               }
+               if (fromlen != sizeof(struct sockaddr_in))
+                       logbad(1,"impossible recvfrom(rip) fromlen=%d",
+                              fromlen);
 
-       return ifp;
+               input(&from,
+                     (ifp != 0) ? ifp : iflookup(from.sin_addr.s_addr),
+                     &inbuf.rip, cc);
+       }
 }
 
 
-/*
- * Process a newly received packet.
+/* Process a RIP packet
  */
-void
-rip_input(from, rip, size)
-       struct sockaddr *from;
-       register struct rip *rip;
-       int size;
+static void
+input(struct sockaddr_in *from,                /* received from this IP address */
+      struct interface *ifp,
+      struct rip *rip,
+      int size)
 {
-       register struct rt_entry *rt;
-       register struct netinfo *n;
-       register struct interface *ifp;
-       struct sockaddr dst, gateway, netmask;
-       int count, changes = 0;
-       register struct afswitch *afp;
-       static struct sockaddr badfrom;
-       char buf1[256], buf2[256];
-
-       ifp = 0;
-       TRACE_INPUT(ifp, from, (char *)rip, size);
-       if (from->sa_family >= af_max ||
-           (afp = &afswitch[from->sa_family])->af_hash == NULL) {
-               syslog(LOG_INFO,
-        "\"from\" address in unsupported address family (%d), cmd %d\n",
-                   from->sa_family, rip->rip_cmd);
+#      define FROM_NADDR from->sin_addr.s_addr
+       static naddr use_auth, bad_len, bad_mask;
+       static naddr unk_router, bad_router, bad_nhop;
+
+       struct rt_entry *rt;
+       struct netinfo *n, *lim;
+       struct interface *ifp1;
+       naddr gate, mask, v1_mask, dst, ddst_h;
+       int i;
+
+
+       if (ifp != 0)
+               ifp->int_state |= IS_ACTIVE;
+
+       trace_rip("Recv", "from", from, ifp, rip, size);
+
+       if (rip->rip_vers == 0) {
+               if (from->sin_addr.s_addr != bad_router)
+                       msglog("RIP version 0, cmd %d, packet received"
+                              " from %s",
+                              rip->rip_cmd, naddr_ntoa(FROM_NADDR));
+               bad_router = from->sin_addr.s_addr;
                return;
        }
-       if (rip->rip_vers == 0) {
-               syslog(LOG_ERR,
-                   "RIP version 0 packet received from %s! (cmd %d)",
-                   (*afswitch[from->sa_family].af_format)(from, buf1,
-                                                          sizeof(buf1)),
-                   rip->rip_cmd);
+       if (size > MAXPACKETSIZE) {
+               if (from->sin_addr.s_addr != bad_router)
+                       msglog("packet at least %d bytes too long received"
+                              " from %s",
+                              size-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR));
+               bad_router = from->sin_addr.s_addr;
                return;
        }
 
-       switch (rip->rip_cmd) {
+       n = rip->rip_nets;
+       lim = (struct netinfo *)((char*)rip + size);
 
+       /* Notice authentication.
+        * As required by section 4.2 in RFC 1723, discard authenticated
+        * RIPv2 messages, but only if configured for that silliness.
+        *
+        * RIPv2 authentication is lame, since snooping on the wire makes
+        * its simple passwords evident.  Also, why authenticate queries?
+        * Why should a RIPv2 implementation with authentication disabled
+        * not be able to listen to RIPv2 packets with authenication, while
+        * RIPv1 systems will listen?  Crazy!
+        */
+       if (!auth_ok
+           && rip->rip_vers >= RIPv2
+           && n < lim && n->n_family == RIP_AF_AUTH) {
+               if (from->sin_addr.s_addr != use_auth)
+                       msglog("RIPv2 message with authentication"
+                              " from %s discarded",
+                              naddr_ntoa(FROM_NADDR));
+               use_auth = from->sin_addr.s_addr;
+               trace_pkt("discard authenticated RIPv2 message\n");
+               return;
+       }
+
+       switch (rip->rip_cmd) {
        case RIPCMD_REQUEST:
-               n = rip->rip_nets;
-               count = size - ((char *)n - (char *)rip);
-               if (count < sizeof (struct netinfo))
-                       return;
-               for (; count > 0; n++) {
-                       if (count < sizeof (struct netinfo))
-                               break;
-                       count -= sizeof (struct netinfo);
-
-                       n->rip_metric = ntohl(n->rip_metric);
-                       n->rip_family = ntohs(n->rip_family);
-                       /* 
-                        * A single entry with sa_family == AF_UNSPEC and
-                        * metric ``infinity'' means ``all routes''.
+               /* did the request come from a router?
+                */
+               if (from->sin_port == htons(RIP_PORT)) {
+                       /* yes, ignore it if RIP is off so that it does not
+                        * depend on us.
+                        */
+                       if (rip_sock < 0) {
+                               trace_pkt("ignore request while RIP off\n");
+                               return;
+                       }
+
+                       /* Ignore the request if we talking to ourself
+                        * (and not a remote gateway).
+                        */
+                       if (ifwithaddr(FROM_NADDR, 0, 0) != 0) {
+                               trace_pkt("discard our own RIP request\n");
+                               return;
+                       }
+               }
+
+               /* According to RFC 1723, we should ignore unathenticated
+                * queries.  That is too silly to bother with.  Sheesh!
+                * Are forwarding tables supposed to be secret?  When
+                * a bad guy can infer them with test traffic?
+                * Maybe on firewalls you'd care, but not enough to
+                * give up the diagnostic facilities of remote probing.
+                */
+
+               if (n >= lim
+                   || size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
+                       if (from->sin_addr.s_addr != bad_len)
+                               msglog("request of bad length (%d) from %s",
+                                      size, naddr_ntoa(FROM_NADDR));
+                       bad_len = from->sin_addr.s_addr;
+               }
+               for (; n < lim; n++) {
+                       n->n_metric = ntohl(n->n_metric);
+
+                       /* A single entry with family RIP_AF_UNSPEC and
+                        * metric HOPCNT_INFINITY means "all routes".
                         * We respond to routers only if we are acting
                         * as a supplier, or to anyone other than a router
-                        * (eg, query).
+                        * (i.e. a query).
+                        *
+                        * Answer a query from a stray program with all
+                        * we know. Filter the answer to a query from a
+                        * router in the about same way broadcasts are
+                        * filtered.
+                        *
+                        * Only answer a router if we are a supplier
+                        * to keep an unwary host that is just starting
+                        * from picking us an a router.
                         */
-                       if (n->rip_family == AF_UNSPEC &&
-                           n->rip_metric == HOPCNT_INFINITY && count == 0) {
-                               if (supplier || (*afp->af_portmatch)(from) == 0)
-                                       supply(from, 0, 0, 0);
+                       if (n->n_family == RIP_AF_UNSPEC
+                           && n->n_metric == HOPCNT_INFINITY
+                           && n == rip->rip_nets
+                           && n+1 == lim) {
+                               if (from->sin_port != htons(RIP_PORT)) {
+                                       /* query from `rtquery` or similar
+                                        */
+                                       supply(from, ifp,
+                                              OUT_QUERY, 0, rip->rip_vers);
+                               } else if (supplier) {
+                                       /* a router trying to prime its
+                                        * tables.
+                                        */
+                                       supply(from, ifp,
+                                              OUT_UNICAST, 0, rip->rip_vers);
+                               }
+                               return;
+                       }
+
+                       if (n->n_family != RIP_AF_INET) {
+                               if (from->sin_addr.s_addr != bad_router)
+                                       msglog("request from %s"
+                                              " for unsupported (af %d) %s",
+                                              naddr_ntoa(FROM_NADDR),
+                                              ntohs(n->n_family),
+                                              naddr_ntoa(n->n_dst));
+                               bad_router = from->sin_addr.s_addr;
                                return;
                        }
-                       if (n->rip_family < af_max &&
-                           afswitch[n->rip_family].af_hash) {
-                               if (!(*afswitch[n->rip_family].af_get)(
-                                       DESTINATION, n, &dst))
-                                       return;
-                               rt = rtlookup(&dst);
+
+                       dst = n->n_dst;
+                       if (!check_dst(dst)) {
+                               if (from->sin_addr.s_addr != bad_router)
+                                       msglog("bad queried destination"
+                                              " %s from %s",
+                                              naddr_ntoa(dst),
+                                              naddr_ntoa(FROM_NADDR));
+                               bad_router = from->sin_addr.s_addr;
+                               return;
+                       }
+
+                       if (rip->rip_vers == RIPv1
+                           || 0 == (mask = ntohl(n->n_mask))
+                           || 0 != (ntohl(dst) & ~mask))
+                               mask = ripv1_mask_host(dst,ifp);
+
+                       rt = rtget(dst, mask);
+                       if (!rt && dst != RIP_DEFAULT)
+                               rt = rtfind(n->n_dst);
+
+                       n->n_tag = 0;
+                       n->n_nhop = 0;
+                       if (rip->rip_vers == RIPv1) {
+                               n->n_mask = 0;
+                       } else {
+                               n->n_mask = mask;
+                       }
+                       if (rt == 0) {
+                               n->n_metric = HOPCNT_INFINITY;
+                       } else {
+                               n->n_metric = rt->rt_metric+1;
+                               n->n_metric += (ifp!=0) ? ifp->int_metric : 1;
+                               if (n->n_metric > HOPCNT_INFINITY)
+                                       n->n_metric = HOPCNT_INFINITY;
+                               if (rip->rip_vers != RIPv1) {
+                                       n->n_tag = rt->rt_tag;
+                                       if (ifp != 0
+                                           && on_net(rt->rt_gate,
+                                                     ifp->int_net,
+                                                     ifp->int_mask)
+                                           && rt->rt_gate != ifp->int_addr)
+                                               n->n_nhop = rt->rt_gate;
+                               }
                        }
-                       else
-                               rt = 0;
-#define min(a, b) (a < b ? a : b)
-                       n->rip_metric = rt == 0 ? HOPCNT_INFINITY :
-                               min(rt->rt_metric + 1, HOPCNT_INFINITY);
-                       n->rip_metric = htonl(n->rip_metric);
+                       HTONL(n->n_metric);
                }
+               /* Answer about specific routes.
+                * Only answer a router if we are a supplier
+                * to keep an unwary host that is just starting
+                * from picking us an a router.
+                */
                rip->rip_cmd = RIPCMD_RESPONSE;
-               memcpy(packet, rip, size);
-               (*afp->af_output)(s, 0, from, size);
+               rip->rip_res1 = 0;
+               if (rip->rip_vers != RIPv1)
+                       rip->rip_vers = RIPv2;
+               if (from->sin_port != htons(RIP_PORT)) {
+                       /* query */
+                       (void)output(OUT_QUERY, from, ifp, rip, size);
+               } else if (supplier) {
+                       (void)output(OUT_UNICAST, from, ifp, rip, size);
+               }
                return;
 
        case RIPCMD_TRACEON:
        case RIPCMD_TRACEOFF:
                /* verify message came from a privileged port */
-#ifdef TRACING
-               if ((*afp->af_portcheck)(from) == 0)
+               if (ntohs(from->sin_port) > IPPORT_RESERVED) {
+                       msglog("trace command from untrusted port on %s",
+                              naddr_ntoa(FROM_NADDR));
                        return;
-
-               if ((ifp = rip_verify(from)) == NULL)
+               }
+               if (ifp == 0) {
+                       msglog("trace command from unknown router %s",
+                              naddr_ntoa(FROM_NADDR));
                        return;
-
-               ((char *)rip)[size] = '\0';
-               if (rip->rip_cmd == RIPCMD_TRACEON)
-                       traceon(rip->rip_tracefile);
-               else
-                       traceoff();
-#endif
+               }
+               if (rip->rip_cmd == RIPCMD_TRACEON) {
+                       rip->rip_tracefile[size-4] = '\0';
+                       trace_on((char*)rip->rip_tracefile, 0);
+               } else {
+                       trace_off("tracing turned off by %s\n",
+                                 naddr_ntoa(FROM_NADDR));
+               }
                return;
 
        case RIPCMD_RESPONSE:
+               if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
+                       if (from->sin_addr.s_addr != bad_len)
+                               msglog("response of bad length (%d) from %s",
+                                      size, naddr_ntoa(FROM_NADDR));
+                       bad_len = from->sin_addr.s_addr;
+               }
+
                /* verify message came from a router */
-               if ((*afp->af_portmatch)(from) == 0)
+               if (from->sin_port != ntohs(RIP_PORT)) {
+                       trace_pkt("discard RIP response from unknown port\n");
                        return;
-               (*afp->af_canon)(from);
-               /* are we talking to ourselves? */
-               ifp = if_ifwithaddr(from);
-               if (ifp) {
-                       if (ifp->int_flags & IFF_PASSIVE) {
-                               syslog(LOG_ERR,
-                                 "bogus input (from passive interface, %s)",
-                                 (*afswitch[from->sa_family].af_format)(from,
-                                                        buf1, sizeof(buf1)));
-                               return;
+               }
+
+               if (rip_sock < 0) {
+                       trace_pkt("discard response while RIP off\n");
+                       return;
+               }
+
+               /* Are we talking to ourself or a remote gateway?
+                */
+               ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
+               if (ifp1) {
+                       if (ifp1->int_state & IS_REMOTE) {
+                               if (ifp1->int_state & IS_PASSIVE) {
+                                       msglog("bogus input from %s on"
+                                              " supposedly passive %s",
+                                              naddr_ntoa(FROM_NADDR),
+                                              ifp1->int_name);
+                               } else {
+                                       ifp1->int_act_time = now.tv_sec;
+                                       if (if_ok(ifp1, "remote "))
+                                               addrouteforif(ifp1);
+                               }
+                       } else {
+                               trace_pkt("discard our own RIP response\n");
                        }
-                       rt = rtfind(from);
-                       if (rt == 0 || (((rt->rt_state & RTS_INTERFACE) == 0) &&
-                           rt->rt_metric >= ifp->int_metric))
-                               addrouteforif(ifp);
-                       else
-                               rt->rt_timer = 0;
                        return;
                }
-               /*
-                * Update timer for interface on which the packet arrived.
-                * If from other end of a point-to-point link that isn't
-                * in the routing tables, (re-)add the route.
+
+               /* Check the router from which message originated. We accept
+                * routing packets from routers directly connected via
+                * broadcast or point-to-point networks, and from
+                * those listed in /etc/gateways.
+                */
+               if (!ifp) {
+                       if (from->sin_addr.s_addr != unk_router)
+                               msglog("discard packet from unknown router %s"
+                                      " or via unidentified interface",
+                                      naddr_ntoa(FROM_NADDR));
+                       unk_router = from->sin_addr.s_addr;
+                       return;
+               }
+               if (ifp->int_state & IS_PASSIVE) {
+                       trace_act("discard packet from %s"
+                                 " via passive interface %s\n",
+                                 naddr_ntoa(FROM_NADDR),
+                                 ifp->int_name);
+                       return;
+               }
+
+               /* Check required version
+                */
+               if (((ifp->int_state & IS_NO_RIPV1_IN)
+                    && rip->rip_vers == RIPv1)
+                   || ((ifp->int_state & IS_NO_RIPV2_IN)
+                       && rip->rip_vers != RIPv1)) {
+                       trace_pkt("discard RIPv%d response\n",
+                                 rip->rip_vers);
+                       return;
+               }
+
+               /* Ignore routes via dead interface.
                 */
-               if ((rt = rtfind(from)) &&
-                   (rt->rt_state & (RTS_INTERFACE | RTS_REMOTE)))
-                       rt->rt_timer = 0;
-               else if ((ifp = if_ifwithdstaddr(from)) &&
-                   (rt == 0 || rt->rt_metric >= ifp->int_metric))
-                       addrouteforif(ifp);
-
-               if ((ifp = rip_verify(from)) == NULL)
+               if (ifp->int_state & IS_BROKE) {
+                       trace_pkt("discard response via broken interface %s\n",
+                                 ifp->int_name);
                        return;
+               }
+
+               /* Authenticate the packet if we have a secret.
+                */
+               if (ifp->int_passwd[0] != '\0') {
+                       if (n >= lim
+                           || n->n_family != RIP_AF_AUTH
+                           || ((struct netauth*)n)->a_type != RIP_AUTH_PW) {
+                               if (from->sin_addr.s_addr != use_auth)
+                                       msglog("missing password from %s",
+                                              naddr_ntoa(FROM_NADDR));
+                               use_auth = from->sin_addr.s_addr;
+                               return;
+
+                       } else if (0 != bcmp(((struct netauth*)n)->au.au_pw,
+                                            ifp->int_passwd,
+                                            sizeof(ifp->int_passwd))) {
+                               if (from->sin_addr.s_addr != use_auth)
+                                       msglog("bad password from %s",
+                                              naddr_ntoa(FROM_NADDR));
+                               use_auth = from->sin_addr.s_addr;
+                               return;
+                       }
+               }
 
-               size -= 4 * sizeof (char);
-               n = rip->rip_nets;
-               for (; size > 0; size -= sizeof (struct netinfo), n++) {
-                       if (size < sizeof (struct netinfo))
-                               break;
-                       n->rip_metric = ntohl(n->rip_metric);
-                       n->rip_family = ntohs(n->rip_family);
-                       if (!(*afswitch[n->rip_family].af_get)(DESTINATION, n,
-                                                              &dst))
+               for (; n < lim; n++) {
+                       if (n->n_family == RIP_AF_AUTH)
                                continue;
-                       if (!(*afswitch[n->rip_family].af_get)(NETMASK,
-                                                              n, &netmask))
-                               memset(&netmask, 0, sizeof(netmask));
-                       if (!(*afswitch[n->rip_family].af_get)(GATEWAY,
-                                                              n, &gateway))
-                               memcpy(&gateway, from, sizeof(gateway));
-                       if (dst.sa_family >= af_max ||
-                           (afp = &afswitch[dst.sa_family])->af_hash == NULL) {
-                               syslog(LOG_INFO,
-               "route in unsupported address family (%d), from %s (af %d)\n",
-                                  dst.sa_family,
-                                  (*afswitch[from->sa_family].af_format)(from,
-                                                         buf1, sizeof(buf1)),
-                                  from->sa_family);
+
+                       NTOHL(n->n_metric);
+                       dst = n->n_dst;
+                       if (n->n_family != RIP_AF_INET
+                           && (n->n_family != RIP_AF_UNSPEC
+                               || dst != RIP_DEFAULT)) {
+                               if (from->sin_addr.s_addr != bad_router)
+                                       msglog("route from %s to unsupported"
+                                              " address family %d,"
+                                              " destination %s",
+                                              naddr_ntoa(FROM_NADDR),
+                                              n->n_family,
+                                              naddr_ntoa(dst));
+                               bad_router = from->sin_addr.s_addr;
                                continue;
                        }
-                       if (((*afp->af_checkhost)(&dst)) == 0) {
-                               syslog(LOG_DEBUG,
-                                  "bad host %s in route from %s (af %d)\n",
-                                  (*afswitch[dst.sa_family].af_format)(
-                                       &dst, buf1, sizeof(buf1)),
-                                  (*afswitch[from->sa_family].af_format)(from,
-                                       buf2, sizeof(buf2)),
-                                  from->sa_family);
-                               continue;
+                       if (!check_dst(dst)) {
+                               if (from->sin_addr.s_addr != bad_router)
+                                       msglog("bad destination %s from %s",
+                                              naddr_ntoa(dst),
+                                              naddr_ntoa(FROM_NADDR));
+                               bad_router = from->sin_addr.s_addr;
+                               return;
                        }
-                       if (n->rip_metric == 0 ||
-                           (unsigned) n->rip_metric > HOPCNT_INFINITY) {
-                               if (memcmp(from, &badfrom,
-                                          sizeof(badfrom)) != 0) {
-                                       syslog(LOG_ERR,
-                                           "bad metric (%d) from %s\n",
-                                           n->rip_metric,
-                                 (*afswitch[from->sa_family].af_format)(from,
-                                               buf1, sizeof(buf1)));
-                                       badfrom = *from;
-                               }
-                               continue;
+                       if (n->n_metric == 0
+                           || n->n_metric > HOPCNT_INFINITY) {
+                               if (from->sin_addr.s_addr != bad_router)
+                                       msglog("bad metric %d from %s"
+                                              " for destination %s",
+                                              n->n_metric,
+                                              naddr_ntoa(FROM_NADDR),
+                                              naddr_ntoa(dst));
+                               bad_router = from->sin_addr.s_addr;
+                               return;
                        }
-                       /*
-                        * Adjust metric according to incoming interface.
+
+                       /* Notice the next-hop.
                         */
-                       if ((unsigned) n->rip_metric < HOPCNT_INFINITY)
-                               n->rip_metric += ifp->int_metric;
-                       if ((unsigned) n->rip_metric > HOPCNT_INFINITY)
-                               n->rip_metric = HOPCNT_INFINITY;
-                       rt = rtlookup(&dst);
-                       if (rt == 0 ||
-                           (rt->rt_state & (RTS_INTERNAL|RTS_INTERFACE)) ==
-                           (RTS_INTERNAL|RTS_INTERFACE)) {
-                               /*
-                                * If we're hearing a logical network route
-                                * back from a peer to which we sent it,
-                                * ignore it.
-                                */
-                               if (rt && rt->rt_state & RTS_SUBNET &&
-                                   (*afp->af_sendroute)(rt, from))
-                                       continue;
-                               if ((unsigned)n->rip_metric < HOPCNT_INFINITY) {
-                                   /*
-                                    * Look for an equivalent route that
-                                    * includes this one before adding
-                                    * this route.
-                                    */
-                                   rt = rtfind(&dst);
-                                   if (rt && equal(&gateway, &rt->rt_router))
-                                           continue;
-                                   rtadd(&dst, &gateway, &netmask,
-                                         n->rip_metric, 0);
-                                   changes++;
+                       gate = from->sin_addr.s_addr;
+                       if (n->n_nhop != 0) {
+                               if (rip->rip_vers == RIPv2) {
+                                       n->n_nhop = 0;
+                               } else {
+                                   /* Use it only if it is valid. */
+                                   if (on_net(n->n_nhop,
+                                              ifp->int_net, ifp->int_mask)
+                                       && check_dst(n->n_nhop)) {
+                                           gate = n->n_nhop;
+                                   } else {
+                                       if (bad_nhop != from->sin_addr.s_addr)
+                                               msglog("router %s to %s has"
+                                                      " bad next hop %s",
+                                                      naddr_ntoa(FROM_NADDR),
+                                                      naddr_ntoa(dst),
+                                                      naddr_ntoa(n->n_nhop));
+                                       bad_nhop = from->sin_addr.s_addr;
+                                       n->n_nhop = 0;
+                                   }
+                               }
+                       }
+
+                       if (rip->rip_vers == RIPv1
+                           || 0 == (mask = ntohl(n->n_mask))) {
+                               mask = ripv1_mask_host(dst,ifp);
+                       } else if ((ntohl(dst) & ~mask) != 0) {
+                               if (bad_mask != from->sin_addr.s_addr) {
+                                       msglog("router %s sent bad netmask"
+                                              " %#x with %s",
+                                              naddr_ntoa(FROM_NADDR),
+                                              mask,
+                                              naddr_ntoa(dst));
+                                       bad_mask = from->sin_addr.s_addr;
                                }
                                continue;
                        }
+                       if (rip->rip_vers == RIPv1)
+                               n->n_tag = 0;
+
+                       /* Adjust metric according to incoming interface..
+                        */
+                       n->n_metric += ifp->int_metric;
+                       if (n->n_metric > HOPCNT_INFINITY)
+                               n->n_metric = HOPCNT_INFINITY;
+
+                       /* Recognize and ignore a default route we faked
+                        * which is being sent back to us by a machine with
+                        * broken split-horizon.
+                        * Be a little more paranoid than that, and reject
+                        * default routes with the same metric we advertised.
+                        */
+                       if (ifp->int_d_metric != 0
+                           && dst == RIP_DEFAULT
+                           && n->n_metric >= ifp->int_d_metric)
+                               continue;
 
-                       /*
-                        * Update if from gateway and different,
-                        * shorter, or equivalent but old route
-                        * is getting stale.
+                       /* We can receive aggregated RIPv2 routes that must
+                        * be broken down before they are transmitted by
+                        * RIPv1 via an interface on a subnet.
+                        * We might also receive the same routes aggregated
+                        * via other RIPv2 interfaces.
+                        * This could cause duplicate routes to be sent on
+                        * the RIPv1 interfaces.  "Longest matching variable
+                        * length netmasks" lets RIPv2 listeners understand,
+                        * but breaking down the aggregated routes for RIPv1
+                        * listeners can produce duplicate routes.
+                        *
+                        * Breaking down aggregated routes here bloats
+                        * the daemon table, but does not hurt the kernel
+                        * table, since routes are always aggregated for
+                        * the kernel.
+                        *
+                        * Notice that this does not break down network
+                        * routes corresponding to subnets.  This is part
+                        * of the defense against RS_NET_SYN.
                         */
-                       if (equal(&gateway, &rt->rt_router)) {
-                               if (n->rip_metric != rt->rt_metric) {
-                                       rtchange(rt, &gateway,
-                                                &netmask, n->rip_metric);
-                                       changes++;
-                                       rt->rt_timer = 0;
-                                       if (rt->rt_metric >= HOPCNT_INFINITY)
-                                               rt->rt_timer =
-                                                   GARBAGE_TIME - EXPIRE_TIME;
-                               } else if (rt->rt_metric < HOPCNT_INFINITY)
-                                       rt->rt_timer = 0;
-                       } else if ((unsigned) n->rip_metric < rt->rt_metric ||
-                           (rt->rt_metric == n->rip_metric &&
-                           rt->rt_timer > (EXPIRE_TIME/2) &&
-                           (unsigned) n->rip_metric < HOPCNT_INFINITY)) {
-                               rtchange(rt, &gateway, &netmask, n->rip_metric);
-                               changes++;
-                               rt->rt_timer = 0;
+                       if (have_ripv1_out
+                           && (v1_mask = ripv1_mask_net(dst,0)) > mask
+                           && (((rt = rtget(dst,mask)) == 0
+                                || !(rt->rt_state & RS_NET_SYN)))) {
+                               ddst_h = v1_mask & -v1_mask;
+                               i = (v1_mask & ~mask)/ddst_h;
+                               if (i >= 511) {
+                                       /* Punt if we would have to generate
+                                        * an unreasonable number of routes.
+                                        */
+#ifdef DEBUG
+                                       msglog("accept %s from %s as 1"
+                                              " instead of %d routes",
+                                              addrname(dst,mask,0),
+                                              naddr_ntoa(FROM_NADDR),
+                                              i+1);
+#endif
+                                       i = 0;
+                               } else {
+                                       mask = v1_mask;
+                               }
+                       } else {
+                               i = 0;
+                       }
+
+                       for (;;) {
+                               input_route(ifp, FROM_NADDR,
+                                           dst, mask, gate, n);
+                               if (i-- == 0)
+                                       break;
+                               dst = htonl(ntohl(dst) + ddst_h);
                        }
                }
                break;
        }
+}
+
 
-       /*
-        * If changes have occurred, and if we have not sent a broadcast
-        * recently, send a dynamic update.  This update is sent only
-        * on interfaces other than the one on which we received notice
-        * of the change.  If we are within MIN_WAITTIME of a full update,
-        * don't bother sending; if we just sent a dynamic update
-        * and set a timer (nextbcast), delay until that time.
-        * If we just sent a full update, delay the dynamic update.
-        * Set a timer for a randomized value to suppress additional
-        * dynamic updates until it expires; if we delayed sending
-        * the current changes, set needupdate.
+/* Process a single input route.
+ */
+static void
+input_route(struct interface *ifp,
+           naddr from,
+           naddr dst,
+           naddr mask,
+           naddr gate,
+           struct netinfo *n)
+{
+       int i;
+       struct rt_entry *rt;
+       struct rt_spare *rts, *rts0;
+       struct interface *ifp1;
+       time_t new_time;
+
+
+       /* See if the other guy is telling us to send our packets to him.
+        * Sometimes network routes arrive over a point-to-point link for
+        * the network containing the address(es) of the link.
+        *
+        * If our interface is broken, switch to using the other guy.
         */
-       if (changes && supplier &&
-          now.tv_sec - lastfullupdate.tv_sec < SUPPLY_INTERVAL-MAX_WAITTIME) {
-               u_long delay;
-
-               if (now.tv_sec - lastbcast.tv_sec >= MIN_WAITTIME &&
-                   timercmp(&nextbcast, &now, <)) {
-                       if (traceactions)
-                               fprintf(ftrace, "send dynamic update\n");
-                       toall(supply, RTS_CHANGED, ifp);
-                       lastbcast = now;
-                       needupdate = 0;
-                       nextbcast.tv_sec = 0;
-               } else {
-                       needupdate++;
-                       if (traceactions)
-                               fprintf(ftrace, "delay dynamic update\n");
-               }
-#define RANDOMDELAY()  (MIN_WAITTIME * 1000000 + \
-               (u_long)random() % ((MAX_WAITTIME - MIN_WAITTIME) * 1000000))
-
-               if (nextbcast.tv_sec == 0) {
-                       delay = RANDOMDELAY();
-                       if (traceactions)
-                               fprintf(ftrace,
-                                   "inhibit dynamic update for %d usec\n",
-                                   delay);
-                       nextbcast.tv_sec = delay / 1000000;
-                       nextbcast.tv_usec = delay % 1000000;
-                       timeradd(&nextbcast, &now, &nextbcast);
-                       /*
-                        * If the next possibly dynamic update
-                        * is within MIN_WAITTIME of the next full update,
-                        * force the delay past the full update,
-                        * or we might send a dynamic update just before
-                        * the full update.
+       ifp1 = ifwithaddr(dst, 1, 1);
+       if (ifp1 != 0
+           && !(ifp1->int_state & IS_BROKE))
+               return;
+
+       /* Look for the route in our table.
+        */
+       rt = rtget(dst, mask);
+
+       /* Consider adding the route if we do not already have it.
+        */
+       if (rt == 0) {
+               /* Ignore unknown routes being poisoned.
+                */
+               if (n->n_metric == HOPCNT_INFINITY)
+                       return;
+
+               /* Ignore the route if it points to us */
+               if (n->n_nhop != 0
+                   && 0 != ifwithaddr(n->n_nhop, 1, 0))
+                       return;
+
+               /* If something has not gone crazy and tried to fill
+                * our memory, accept the new route.
+                */
+               if (total_routes < MAX_ROUTES)
+                       rtadd(dst, mask, gate, from, n->n_metric,
+                             n->n_tag, 0, ifp);
+               return;
+       }
+
+       /* We already know about the route.  Consider this update.
+        *
+        * If (rt->rt_state & RS_NET_SYN), then this route
+        * is the same as a network route we have inferred
+        * for subnets we know, in order to tell RIPv1 routers
+        * about the subnets.
+        *
+        * It is impossible to tell if the route is coming
+        * from a distant RIPv2 router with the standard
+        * netmask because that router knows about the entire
+        * network, or if it is a round-about echo of a
+        * synthetic, RIPv1 network route of our own.
+        * The worst is that both kinds of routes might be
+        * received, and the bad one might have the smaller
+        * metric.  Partly solve this problem by faking the
+        * RIPv1 route with a metric that reflects the most
+        * distant part of the subnet.  Also never
+        * aggregate into such a route.  Also keep it
+        * around as long as the interface exists.
+        */
+
+       rts0 = rt->rt_spares;
+       for (rts = rts0, i = NUM_SPARES; i != 0; i--, rts++) {
+               if (rts->rts_router == from)
+                       break;
+               /* Note the worst slot to reuse,
+                * other than the current slot.
+                */
+               if (rts0 == rt->rt_spares
+                   || BETTER_LINK(rt, rts0, rts))
+                       rts0 = rts;
+       }
+       if (i != 0) {
+               /* Found the router
+                */
+               int old_metric = rts->rts_metric;
+
+               /* Keep poisoned routes around only long enough to pass
+                * the poison on.  Get a new timestamp for good routes.
+                */
+               new_time =((old_metric == HOPCNT_INFINITY)
+                          ? rts->rts_time
+                          : now.tv_sec);
+
+               /* If this is an update for the router we currently prefer,
+                * then note it.
+                */
+               if (i == NUM_SPARES) {
+                       rtchange(rt,rt->rt_state, gate,rt->rt_router,
+                                n->n_metric, n->n_tag, ifp, new_time, 0);
+                       /* If the route got worse, check for something better.
                         */
-                       if (nextbcast.tv_sec > lastfullupdate.tv_sec +
-                           SUPPLY_INTERVAL - MIN_WAITTIME)
-                               nextbcast.tv_sec = lastfullupdate.tv_sec +
-                                   SUPPLY_INTERVAL + 1;
+                       if (n->n_metric > old_metric)
+                               rtswitch(rt, 0);
+                       return;
+               }
+
+               /* This is an update for a spare route.
+                * Finished if the route is unchanged.
+                */
+               if (rts->rts_gate == gate
+                   && old_metric == n->n_metric
+                   && rts->rts_tag == n->n_tag) {
+                       rts->rts_time = new_time;
+                       return;
                }
+
+       } else {
+               /* The update is for a route we know about,
+                * but not from a familiar router.
+                *
+                * Ignore the route if it points to us.
+                */
+               if (n->n_nhop != 0
+                   && 0 != ifwithaddr(n->n_nhop, 1, 0))
+                       return;
+
+               rts = rts0;
+
+               /* Save the route as a spare only if it has
+                * a better metric than our worst spare.
+                * This also ignores poisoned routes (those
+                * received with metric HOPCNT_INFINITY).
+                */
+               if (n->n_metric >= rts->rts_metric)
+                       return;
+
+               new_time = now.tv_sec;
        }
+
+       trace_upslot(rt, rts, gate, from, ifp, n->n_metric,n->n_tag, new_time);
+
+       rts->rts_gate = gate;
+       rts->rts_router = from;
+       rts->rts_metric = n->n_metric;
+       rts->rts_tag = n->n_tag;
+       rts->rts_time = new_time;
+       rts->rts_ifp = ifp;
+
+       /* try to switch to a better route */
+       rtswitch(rt, rts);
 }
diff --git a/sbin/routed/interface.h b/sbin/routed/interface.h
deleted file mode 100644 (file)
index 09653f9..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*     $OpenBSD: interface.h,v 1.2 1996/06/23 14:32:28 deraadt Exp $   */
-/*     $NetBSD: interface.h,v 1.8 1995/06/20 22:27:52 christos Exp $   */
-
-/*
- * Copyright (c) 1983, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *     @(#)interface.h 8.1 (Berkeley) 6/5/93
- */
-
-/*
- * Routing table management daemon.
- */
-
-/*
- * An ``interface'' is similar to an ifnet structure,
- * except it doesn't contain q'ing info, and it also
- * handles ``logical'' interfaces (remote gateways
- * that we want to keep polling even if they go down).
- * The list of interfaces which we maintain is used
- * in supplying the gratuitous routing table updates.
- */
-struct interface {
-       struct  interface *int_next;
-       struct  sockaddr int_addr;              /* address on this host */
-       union {
-               struct  sockaddr intu_broadaddr;
-               struct  sockaddr intu_dstaddr;
-       } int_intu;
-#define        int_broadaddr   int_intu.intu_broadaddr /* broadcast address */
-#define        int_dstaddr     int_intu.intu_dstaddr   /* other end of p-to-p link */
-       int     int_metric;                     /* init's routing entry */
-       int     int_flags;                      /* see below */
-       /* START INTERNET SPECIFIC */
-       u_long  int_net;                        /* network # */
-       u_long  int_netmask;                    /* net mask for addr */
-       u_long  int_subnet;                     /* subnet # */
-       u_long  int_subnetmask;                 /* subnet mask for addr */
-       /* END INTERNET SPECIFIC */
-       struct  ifdebug int_input, int_output;  /* packet tracing stuff */
-       int     int_ipackets;                   /* input packets received */
-       int     int_opackets;                   /* output packets sent */
-       char    *int_name;                      /* from kernel if structure */
-       u_short int_transitions;                /* times gone up-down */
-};
-
-/*
- * 0x1 to 0x10 are reused from the kernel's ifnet definitions,
- * the others agree with the RTS_ flags defined elsewhere.
- */
-#define        IFF_UP          0x1             /* interface is up */
-#define        IFF_BROADCAST   0x2             /* broadcast address valid */
-#define        IFF_DEBUG       0x4             /* turn on debugging */
-#define        IFF_LOOPBACK    0x8             /* software loopback net */
-#define        IFF_POINTOPOINT 0x10            /* interface is point-to-point link */
-
-#define        IFF_SUBNET      0x100000        /* interface on subnetted network */
-#define        IFF_PASSIVE     0x200000        /* can't tell if up/down */
-#define        IFF_INTERFACE   0x400000        /* hardware interface */
-#define        IFF_REMOTE      0x800000        /* interface isn't on this machine */
-
-struct interface *if_ifwithaddr __P((struct sockaddr *));
-struct interface *if_ifwithdstaddr __P((struct sockaddr *));
-struct interface *if_ifwithnet __P((struct sockaddr *));
-struct interface *if_iflookup __P((struct sockaddr *));
index 567efa9..55faf5d 100644 (file)
@@ -1,5 +1,4 @@
-/*     $OpenBSD: main.c,v 1.2 1996/06/23 14:32:29 deraadt Exp $        */
-/*     $NetBSD: main.c,v 1.13 1995/06/20 22:27:53 christos Exp $       */
+/*     $OpenBSD: main.c,v 1.3 1996/09/05 14:31:32 mickey Exp $ */
 
 /*
  * Copyright (c) 1983, 1988, 1993
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static char copyright[] =
+char copyright[] =
 "@(#) Copyright (c) 1983, 1988, 1993\n\
        The Regents of the University of California.  All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-#if 0
+#if !defined(lint)
 static char sccsid[] = "@(#)main.c     8.1 (Berkeley) 6/5/93";
 #else
-static char rcsid[] = "$OpenBSD: main.c,v 1.2 1996/06/23 14:32:29 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: main.c,v 1.3 1996/09/05 14:31:32 mickey Exp $";
 #endif
-#endif /* not lint */
 
-/*
- * Routing Table Management Daemon
- */
 #include "defs.h"
-#include <sys/ioctl.h>
+#include "pathnames.h"
+#ifdef sgi
+#include "math.h"
+#endif
+#include <signal.h>
+#include <fcntl.h>
 #include <sys/file.h>
 
-#include <net/if.h>
+pid_t  mypid;
 
-#include <errno.h>
-#include <signal.h>
-#include <syslog.h>
-#include "pathnames.h"
+naddr  myaddr;                         /* system address */
+char   myname[MAXHOSTNAMELEN+1];
 
-int    supplier = -1;          /* process should supply updates */
-int    gateway = 0;            /* 1 if we are a gateway to parts beyond */
-int    debug = 0;
-int    bufspace = 127*1024;    /* max. input buffer size to request */
-struct rip *msg = (struct rip *)packet;
+int    supplier;                       /* supply or broadcast updates */
+int    supplier_set;
+int    ipforwarding = 1;               /* kernel forwarding on */
 
-int getsocket __P((int, int, struct sockaddr_in *));
-void process __P((int));
+int    default_gateway;                /* 1=advertise default */
+int    background = 1;
+int    ridhosts;                       /* 1=reduce host routes */
+int    mhome;                          /* 1=want multi-homed host route */
+int    advertise_mhome;                /* 1=must continue adverising it */
+int    auth_ok = 1;                    /* 1=ignore auth if we do not care */
+
+struct timeval epoch;                  /* when started */
+struct timeval clk, prev_clk;
+struct timeval now;                    /* current idea of time */
+time_t now_stale;
+time_t now_expire;
+time_t now_garbage;
+
+struct timeval next_bcast;             /* next general broadcast */
+struct timeval no_flash = {EPOCH+SUPPLY_INTERVAL};  /* inhibit flash update */
+
+fd_set fdbits;
+int    sock_max;
+int    rip_sock = -1;                  /* RIP socket */
+struct interface *rip_sock_mcast;      /* current multicast interface */
+int    rt_sock;                        /* routing socket */
+int    rt_sock_seqno;
+
+
+static  int get_rip_sock(naddr, int);
+static void timevalsub(struct timeval *, struct timeval *, struct timeval *);
 
 int
-main(argc, argv)
-       int argc;
-       char *argv[];
+main(int argc,
+     char *argv[])
 {
-       int n, nfd, tflags = 0;
-       struct timeval *tvp, waittime;
-       struct itimerval itval;
-       register struct rip *query = msg;
+       int n, mib[4], off;
+       size_t len;
+       char *p, *q;
+       struct timeval wtime, t2;
+       time_t dt;
        fd_set ibits;
-       sigset_t sigset, osigset;
-       
-       argv0 = argv;
-#if BSD >= 43
+       naddr p_addr, p_mask;
+       struct interface *ifp;
+       struct parm parm;
+       char *tracename = 0;
+
+
        openlog("routed", LOG_PID | LOG_ODELAY, LOG_DAEMON);
-       setlogmask(LOG_UPTO(LOG_WARNING));
+       ftrace = stdout;
+
+       gettimeofday(&clk, 0);
+       prev_clk = clk;
+       epoch = clk;
+       epoch.tv_sec -= EPOCH;
+       now.tv_sec = EPOCH;
+       now_stale = EPOCH - STALE_TIME;
+       now_expire = EPOCH - EXPIRE_TIME;
+       now_garbage = EPOCH - GARBAGE_TIME;
+       wtime.tv_sec = 0;
+
+       (void)gethostname(myname, sizeof(myname)-1);
+       (void)gethost(myname, &myaddr);
+
+       while ((n = getopt(argc, argv, "sqdghmpAtT:F:P:")) != EOF) {
+               switch (n) {
+               case 's':
+                       supplier = 1;
+                       supplier_set = 1;
+                       break;
+
+               case 'q':
+                       supplier = 0;
+                       supplier_set = 1;
+                       break;
+
+               case 'd':
+                       background = 0;
+                       break;
+
+               case 'g':
+                       bzero(&parm, sizeof(parm));
+                       parm.parm_d_metric = 1;
+                       p = check_parms(&parm);
+                       if (p != 0)
+                               msglog("bad -g: %s", p);
+                       else
+                               default_gateway = 1;
+                       break;
+
+               case 'h':               /* suppress extra host routes */
+                       ridhosts = 1;
+                       break;
+
+               case 'm':               /* advertise host route */
+                       mhome = 1;      /* on multi-homed hosts */
+                       break;
+
+               case 'A':
+                       /* Ignore authentication if we do not care.
+                        * Crazy as it is, that is what RFC 1723 requires.
+                        */
+                       auth_ok = 0;
+                       break;
+
+               case 't':
+                       new_tracelevel++;
+                       break;
+
+               case 'T':
+                       tracename = optarg;
+                       break;
+
+               case 'F':               /* minimal routes for SLIP */
+                       n = HOPCNT_INFINITY-2;
+                       p = strchr(optarg,',');
+                       if (p && *p != '\0') {
+                               n = (int)strtoul(p+1, &q, 0);
+                               if (*q == '\0'
+                                   && n <= HOPCNT_INFINITY-1
+                                   && n >= 1)
+                                       *p = '\0';
+                       }
+                       if (!getnet(optarg, &p_addr, &p_mask)) {
+                               msglog("bad network; \"-F %s\"",
+                                      optarg);
+                               break;
+                       }
+                       bzero(&parm, sizeof(parm));
+                       parm.parm_addr_h = ntohl(p_addr);
+                       parm.parm_mask = p_mask;
+                       parm.parm_d_metric = n;
+                       p = check_parms(&parm);
+                       if (p != 0)
+                               msglog("bad -F: %s", p);
+                       break;
+
+               case 'P':
+                       /* handle arbirary, (usually) per-interface
+                        * parameters.
+                        */
+                       p = parse_parms(optarg);
+                       if (p != 0)
+                               msglog("bad \"%s\" in \"%s\"",
+                                      p, optarg);
+                       break;
+
+               default:
+                       goto usage;
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       if (tracename == 0 && argc >= 1) {
+               tracename = *argv++;
+               argc--;
+       }
+       if (argc != 0) {
+usage:
+               logbad(0, "usage: routed [-sqdghmpAt] [-T /tracefile]"
+                      " [-F net[,metric]] [-P parms]");
+       }
+       if (geteuid() != 0)
+               logbad(0, "requires UID 0");
+
+       mib[0] = CTL_NET;
+       mib[1] = PF_INET;
+       mib[2] = IPPROTO_IP;
+       mib[3] = IPCTL_FORWARDING;
+       len = sizeof(ipforwarding);
+       if (sysctl(mib, 4, &ipforwarding, &len, 0, 0) < 0)
+               LOGERR("sysctl(IPCTL_FORWARDING)");
+
+       if (!ipforwarding) {
+               if (supplier)
+                       msglog("-s incompatible with ipforwarding=0");
+               if (default_gateway) {
+                       msglog("-g incompatible with ipforwarding=0");
+                       default_gateway = 0;
+               }
+               supplier = 0;
+               supplier_set = 1;
+       }
+       if (default_gateway) {
+               if (supplier_set && !supplier) {
+                       msglog("-g and -q incompatible");
+               } else {
+                       supplier = 1;
+                       supplier_set = 1;
+               }
+       }
+
+
+       /* get into the background */
+       if (background) {
+#ifdef sgi
+               if (0 > _daemonize(_DF_NOCHDIR,
+                                  new_tracelevel == 0 ? -1 : STDOUT_FILENO,
+                                  new_tracelevel == 0 ? -1 : STDERR_FILENO,
+                                  -1))
+                       BADERR(0, "_daemonize()");
 #else
-       openlog("routed", LOG_PID);
-#define LOG_UPTO(x) (x)
-#define setlogmask(x) (x)
+               if (daemon(1, 1) < 0)
+                       BADERR(0,"daemon()");
 #endif
-       sp = getservbyname("router", "udp");
-       if (sp == NULL) {
-               fprintf(stderr, "routed: router/udp: unknown service\n");
-               exit(1);
        }
-       addr.sin_family = AF_INET;
-       addr.sin_port = sp->s_port;
-       r = socket(AF_ROUTE, SOCK_RAW, 0);
-       /* later, get smart about lookingforinterfaces */
-       if (r)
-               shutdown(r, 0); /* for now, don't want reponses */
-       else {
-               fprintf(stderr, "routed: no routing socket\n");
-               exit(1);
+
+       mypid = getpid();
+       srandom((int)(clk.tv_sec ^ clk.tv_usec ^ mypid));
+
+       /* prepare socket connected to the kernel.
+        */
+       rt_sock = socket(AF_ROUTE, SOCK_RAW, 0);
+       if (rt_sock < 0)
+               BADERR(1,"rt_sock = socket()");
+       if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1)
+               logbad(1, "fcntl(rt_sock) O_NONBLOCK: %s", strerror(errno));
+       off = 0;
+       if (setsockopt(rt_sock, SOL_SOCKET,SO_USELOOPBACK,
+                      &off,sizeof(off)) < 0)
+               LOGERR("setsockopt(SO_USELOOPBACK,0)");
+
+       fix_select();
+
+
+       if (background && new_tracelevel == 0)
+               ftrace = 0;
+       if (tracename != 0) {
+               trace_on(tracename, 1);
+               if (new_tracelevel == 0)        /* use stdout if file is bad */
+                       new_tracelevel = 1;
        }
-       s = getsocket(AF_INET, SOCK_DGRAM, &addr);
-       if (s < 0)
-               exit(1);
-       argv++, argc--;
-       while (argc > 0 && **argv == '-') {
-               if (strcmp(*argv, "-s") == 0) {
-                       supplier = 1;
-                       argv++, argc--;
+       set_tracelevel();
+
+       /* initialize radix tree */
+       rtinit();
+
+       /* Pick a random part of the second for our output to minimize
+        * collisions.
+        *
+        * Start broadcasting after hearing from other routers, and
+        * at a random time so a bunch of systems do not get synchronized
+        * after a power failure.
+        */
+       intvl_random(&next_bcast, EPOCH+MIN_WAITTIME, EPOCH+SUPPLY_INTERVAL);
+       age_timer.tv_usec = next_bcast.tv_usec;
+       age_timer.tv_sec = EPOCH+MIN_WAITTIME;
+       rdisc_timer = next_bcast;
+       ifinit_timer.tv_usec = next_bcast.tv_usec;
+
+       signal(SIGALRM, sigalrm);
+       signal(SIGHUP, sigterm);
+       signal(SIGTERM, sigterm);
+       signal(SIGINT, sigterm);
+       signal(SIGUSR1, sigtrace_on);
+       signal(SIGUSR2, sigtrace_off);
+
+       /* Collect an initial view of the world by checking the interface
+        * configuration and the kludge file.
+        */
+       gwkludge();
+       ifinit();
+       flush_kern();
+
+       /* Ask for routes */
+       rip_query();
+       if (!supplier)
+               rdisc_sol();
+
+       /* Loop forever, listening and broadcasting.
+        */
+       for (;;) {
+               prev_clk = clk;
+               gettimeofday(&clk, 0);
+               timevalsub(&t2, &clk, &prev_clk);
+               if (t2.tv_sec < 0
+                   || t2.tv_sec > wtime.tv_sec + 5) {
+                       /* Deal with time changes before other housekeeping to
+                        * keep everything straight.
+                        */
+                       dt = t2.tv_sec;
+                       if (dt > 0)
+                               dt -= wtime.tv_sec;
+                       trace_act("time changed by %d sec\n", dt);
+                       epoch.tv_sec += dt;
+               }
+               timevalsub(&now, &clk, &epoch);
+               now_stale = now.tv_sec - STALE_TIME;
+               now_expire = now.tv_sec - EXPIRE_TIME;
+               now_garbage = now.tv_sec - GARBAGE_TIME;
+
+               /* deal with interrupts that should affect tracing */
+               set_tracelevel();
+
+               if (stopint != 0) {
+                       if (supplier) {
+                               rip_bcast(0);
+                               rdisc_adv();
+                       }
+                       trace_off("exiting with signal %d\n", stopint);
+                       exit(stopint | 128);
+               }
+
+               /* look for new or dead interfaces */
+               timevalsub(&wtime, &ifinit_timer, &now);
+               if (wtime.tv_sec <= 0) {
+                       wtime.tv_sec = 0;
+                       ifinit();
+                       rip_query();
                        continue;
                }
-               if (strcmp(*argv, "-q") == 0) {
-                       supplier = 0;
-                       argv++, argc--;
+
+               /* If it is time, then broadcast our routes.
+                */
+               if (supplier || advertise_mhome) {
+                       timevalsub(&t2, &next_bcast, &now);
+                       if (t2.tv_sec <= 0) {
+                               /* Synchronize the aging and broadcast
+                                * timers to minimize awakenings
+                                */
+                               age(0);
+
+                               rip_bcast(0);
+
+                               /* It is desirable to send routing updates
+                                * regularly.  So schedule the next update
+                                * 30 seconds after the previous one was
+                                * secheduled, instead of 30 seconds after
+                                * the previous update was finished.
+                                * Even if we just started after discovering
+                                * a 2nd interface or were otherwise delayed,
+                                * pick a 30-second aniversary of the
+                                * original broadcast time.
+                                */
+                               n = 1 + (0-t2.tv_sec)/SUPPLY_INTERVAL;
+                               next_bcast.tv_sec += n*SUPPLY_INTERVAL;
+
+                               continue;
+                       }
+
+                       if (timercmp(&t2, &wtime, <))
+                               wtime = t2;
+               }
+
+               /* If we need a flash update, either do it now or
+                * set the delay to end when it is time.
+                *
+                * If we are within MIN_WAITTIME seconds of a full update,
+                * do not bother.
+                */
+               if (need_flash
+                   && supplier
+                   && no_flash.tv_sec+MIN_WAITTIME < next_bcast.tv_sec) {
+                       /* accurate to the millisecond */
+                       if (!timercmp(&no_flash, &now, >))
+                               rip_bcast(1);
+                       timevalsub(&t2, &no_flash, &now);
+                       if (timercmp(&t2, &wtime, <))
+                               wtime = t2;
+               }
+
+               /* trigger the main aging timer.
+                */
+               timevalsub(&t2, &age_timer, &now);
+               if (t2.tv_sec <= 0) {
+                       age(0);
                        continue;
                }
-               if (strcmp(*argv, "-t") == 0) {
-                       tflags++;
-                       setlogmask(LOG_UPTO(LOG_DEBUG));
-                       argv++, argc--;
+               if (timercmp(&t2, &wtime, <))
+                       wtime = t2;
+
+               /* update the kernel routing table
+                */
+               timevalsub(&t2, &need_kern, &now);
+               if (t2.tv_sec <= 0) {
+                       age(0);
                        continue;
                }
-               if (strcmp(*argv, "-d") == 0) {
-                       debug++;
-                       setlogmask(LOG_UPTO(LOG_DEBUG));
-                       argv++, argc--;
+               if (timercmp(&t2, &wtime, <))
+                       wtime = t2;
+
+               /* take care of router discovery,
+                * but do it to the millisecond
+                */
+               if (!timercmp(&rdisc_timer, &now, >)) {
+                       rdisc_age(0);
                        continue;
                }
-               if (strcmp(*argv, "-g") == 0) {
-                       gateway = 1;
-                       argv++, argc--;
+               timevalsub(&t2, &rdisc_timer, &now);
+               if (timercmp(&t2, &wtime, <))
+                       wtime = t2;
+
+
+               /* wait for input or a timer to expire.
+                */
+               trace_flush();
+               ibits = fdbits;
+               n = select(sock_max, &ibits, 0, 0, &wtime);
+               if (n <= 0) {
+                       if (n < 0 && errno != EINTR && errno != EAGAIN)
+                               BADERR(1,"select");
                        continue;
                }
-               fprintf(stderr,
-                       "usage: routed [ -s ] [ -q ] [ -t ] [ -g ]\n");
-               exit(1);
+
+               if (FD_ISSET(rt_sock, &ibits)) {
+                       read_rt();
+                       n--;
+               }
+               if (rdisc_sock >= 0 && FD_ISSET(rdisc_sock, &ibits)) {
+                       read_d();
+                       n--;
+               }
+               if (rip_sock >= 0 && FD_ISSET(rip_sock, &ibits)) {
+                       read_rip(rip_sock, 0);
+                       n--;
+               }
+
+               for (ifp = ifnet; n > 0 && 0 != ifp; ifp = ifp->int_next) {
+                       if (ifp->int_rip_sock >= 0
+                           && FD_ISSET(ifp->int_rip_sock, &ibits)) {
+                               read_rip(ifp->int_rip_sock, ifp);
+                               n--;
+                       }
+               }
        }
+}
 
-       if (debug == 0 && tflags == 0)
-               daemon(0, 0);
-       /*
-        * Any extra argument is considered
-        * a tracing log file.
-        */
-       if (argc > 0)
-               traceon(*argv);
-       while (tflags-- > 0)
-               bumploglevel();
-
-       (void) gettimeofday(&now, NULL);
-       /*
-        * Collect an initial view of the world by
-        * checking the interface configuration and the gateway kludge
-        * file.  Then, send a request packet on all
-        * directly connected networks to find out what
-        * everyone else thinks.
+
+/* ARGSUSED */
+void
+sigalrm(int sig)
+{
+       /* Historically, SIGALRM would cause the daemon to check for
+        * new and broken interfaces.
         */
-       rtinit();
-       ifinit();
-       gwkludge();
-       if (gateway > 0)
-               rtdefault();
-       if (supplier < 0)
-               supplier = 0;
-       query->rip_cmd = RIPCMD_REQUEST;
-       query->rip_vers = RIP_VERSION_1;
-       if (sizeof(query->rip_nets[0].rip_family) > 1)  /* XXX */
-               query->rip_nets[0].rip_family = htons((u_short)AF_UNSPEC);
-       else
-               query->rip_nets[0].rip_family = AF_UNSPEC;
-       query->rip_nets[0].rip_metric = htonl((u_long)HOPCNT_INFINITY);
-       toall(sndmsg, 0, NULL);
-       signal(SIGALRM, timer);
-       signal(SIGHUP, hup);
-       signal(SIGTERM, hup);
-       signal(SIGINT, rtdeleteall);
-       signal(SIGUSR1, sigtrace);
-       signal(SIGUSR2, sigtrace);
-       itval.it_interval.tv_sec = TIMER_RATE;
-       itval.it_value.tv_sec = TIMER_RATE;
-       itval.it_interval.tv_usec = 0;
-       itval.it_value.tv_usec = 0;
-       srandom(getpid());
-       if (setitimer(ITIMER_REAL, &itval, NULL) < 0)
-               syslog(LOG_ERR, "setitimer: %m\n");
-
-       FD_ZERO(&ibits);
-       nfd = s + 1;                    /* 1 + max(fd's) */
-       for (;;) {
-               FD_SET(s, &ibits);
-               /*
-                * If we need a dynamic update that was held off,
-                * needupdate will be set, and nextbcast is the time
-                * by which we want select to return.  Compute time
-                * until dynamic update should be sent, and select only
-                * until then.  If we have already passed nextbcast,
-                * just poll.
-                */
-               if (needupdate) {
-                       timersub(&nextbcast, &now, &waittime);
-                       if (waittime.tv_sec < 0) {
-                               waittime.tv_sec = 0;
-                               waittime.tv_usec = 0;
-                       }
-                       if (traceactions)
-                               fprintf(ftrace,
-                                "select until dynamic update %d/%d sec/usec\n",
-                                   waittime.tv_sec, waittime.tv_usec);
-                       tvp = &waittime;
-               } else
-                       tvp = NULL;
-               n = select(nfd, &ibits, 0, 0, tvp);
-               if (n <= 0) {
-                       /*
-                        * Need delayed dynamic update if select returned
-                        * nothing and we timed out.  Otherwise, ignore
-                        * errors (e.g. EINTR).
-                        */
-                       if (n < 0) {
-                               if (errno == EINTR)
-                                       continue;
-                               syslog(LOG_ERR, "select: %m");
+       ifinit_timer.tv_sec = now.tv_sec;
+       trace_act("SIGALRM\n");
+}
+
+
+/* watch for fatal signals */
+void
+sigterm(int sig)
+{
+       stopint = sig;
+       (void)signal(sig, SIG_DFL);     /* catch it only once */
+}
+
+
+void
+fix_select(void)
+{
+       struct interface *ifp;
+
+
+       FD_ZERO(&fdbits);
+       sock_max = 0;
+
+       FD_SET(rt_sock, &fdbits);
+       if (sock_max <= rt_sock)
+               sock_max = rt_sock+1;
+       if (rip_sock >= 0) {
+               FD_SET(rip_sock, &fdbits);
+               if (sock_max <= rip_sock)
+                       sock_max = rip_sock+1;
+       }
+       for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
+               if (ifp->int_rip_sock >= 0) {
+                       FD_SET(ifp->int_rip_sock, &fdbits);
+                       if (sock_max <= ifp->int_rip_sock)
+                               sock_max = ifp->int_rip_sock+1;
+               }
+       }
+       if (rdisc_sock >= 0) {
+               FD_SET(rdisc_sock, &fdbits);
+               if (sock_max <= rdisc_sock)
+                       sock_max = rdisc_sock+1;
+       }
+}
+
+
+void
+fix_sock(int sock,
+        char *name)
+{
+       int on;
+#define MIN_SOCKBUF (4*1024)
+       static int rbuf;
+
+       if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
+               logbad(1, "fcntl(%s) O_NONBLOCK: %s",
+                      name, strerror(errno));
+       on = 1;
+       if (setsockopt(sock, SOL_SOCKET,SO_BROADCAST,
+                      &on,sizeof(on)) < 0)
+               msglog("setsockopt(%s,SO_BROADCAST): %s",
+                      name, strerror(errno));
+       if (rbuf >= MIN_SOCKBUF) {
+               if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+                              &rbuf, sizeof(rbuf)) < 0)
+                       msglog("setsockopt(%s,SO_RCVBUF=%d): %s",
+                              name, rbuf, strerror(errno));
+       } else {
+               for (rbuf = 60*1024; ; rbuf -= 4096) {
+                       if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+                                      &rbuf, sizeof(rbuf)) == 0) {
+                               trace_act("RCVBUF=%d\n", rbuf);
+                               break;
                        }
-                       sigemptyset(&sigset);
-                       sigaddset(&sigset, SIGALRM);
-                       sigprocmask(SIG_BLOCK, &sigset, &osigset);
-                       if (n == 0 && needupdate) {
-                               if (traceactions)
-                                       fprintf(ftrace,
-                                           "send delayed dynamic update\n");
-                               (void) gettimeofday(&now, NULL);
-                               toall(supply, RTS_CHANGED, NULL);
-                               lastbcast = now;
-                               needupdate = 0;
-                               nextbcast.tv_sec = 0;
+                       if (rbuf < MIN_SOCKBUF) {
+                               msglog("setsockopt(%s,SO_RCVBUF = %d): %s",
+                                      name, rbuf, strerror(errno));
+                               break;
                        }
-                       sigprocmask(SIG_SETMASK, &osigset, NULL);
-                       continue;
                }
-               (void) gettimeofday(&now, NULL);
-               sigemptyset(&sigset);
-               sigaddset(&sigset, SIGALRM);
-               sigprocmask(SIG_BLOCK, &sigset, &osigset);
-#ifdef doesntwork
-/*
-printf("s %d, ibits %x index %d, mod %d, sh %x, or %x &ibits %x\n",
-       s,
-       ibits.fds_bits[0],
-       (s)/(sizeof(fd_mask) * 8),
-       ((s) % (sizeof(fd_mask) * 8)),
-       (1 << ((s) % (sizeof(fd_mask) * 8))),
-       ibits.fds_bits[(s)/(sizeof(fd_mask) * 8)] & (1 << ((s) % (sizeof(fd_mask) * 8))),
-       &ibits
-       );
-*/
-               if (FD_ISSET(s, &ibits))
-#else
-               if (ibits.fds_bits[s/32] & (1 << s))
+       }
+}
+
+
+/* get a rip socket
+ */
+static int                             /* <0 or file descriptor */
+get_rip_sock(naddr addr,
+            int serious)               /* 1=failure to bind is serious */
+{
+       struct sockaddr_in sin;
+       unsigned char ttl;
+       int s;
+
+
+       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+               BADERR(1,"rip_sock = socket()");
+
+       bzero(&sin,sizeof(sin));
+#ifdef _HAVE_SIN_LEN
+       sin.sin_len = sizeof(sin);
 #endif
-                       process(s);
-               /* handle ICMP redirects */
-               sigprocmask(SIG_SETMASK, &osigset, NULL);
+       sin.sin_family = AF_INET;
+       sin.sin_port = htons(RIP_PORT);
+       sin.sin_addr.s_addr = addr;
+       if (bind(s, (struct sockaddr *)&sin,sizeof(sin)) < 0) {
+               if (serious)
+                       BADERR(errno != EADDRINUSE, "bind(rip_sock)");
+               return -1;
        }
+       fix_sock(s,"rip_sock");
+
+       ttl = 1;
+       if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
+                      &ttl, sizeof(ttl)) < 0)
+               DBGERR(1,"rip_sock setsockopt(IP_MULTICAST_TTL)");
+
+       return s;
 }
 
+
+/* turn off main RIP socket */
 void
-process(fd)
-       int fd;
+rip_off(void)
 {
-       struct sockaddr from;
-       int fromlen, cc;
-       union {
-               char    buf[MAXPACKETSIZE+1];
-               struct  rip rip;
-       } inbuf;
+       struct interface *ifp;
+       register naddr addr;
 
-       for (;;) {
-               fromlen = sizeof (from);
-               cc = recvfrom(fd, &inbuf, sizeof (inbuf), 0, &from, &fromlen);
-               if (cc <= 0) {
-                       if (cc < 0 && errno != EWOULDBLOCK)
-                               perror("recvfrom");
-                       break;
+
+       if (rip_sock >= 0 && !mhome) {
+               trace_act("turn off RIP\n");
+
+               (void)close(rip_sock);
+               rip_sock = -1;
+
+               /* get non-broadcast sockets to listen to queries.
+                */
+               for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
+                       if (ifp->int_rip_sock < 0
+                           && !(ifp->int_state & IS_ALIAS)) {
+                               addr = ((ifp->int_if_flags & IFF_POINTOPOINT)
+                                       ? ifp->int_dstaddr
+                                       : ifp->int_addr);
+                               ifp->int_rip_sock = get_rip_sock(addr, 0);
+                       }
                }
-               if (fromlen != sizeof (struct sockaddr_in))
-                       break;
-               rip_input(&from, &inbuf.rip, cc);
+
+               fix_select();
+
+               age(0);
        }
 }
 
-int
-getsocket(domain, type, sin)
-       int domain, type;
-       struct sockaddr_in *sin;
+
+/* turn on RIP multicast input via an interface
+ */
+static void
+rip_mcast_on(struct interface *ifp)
 {
-       int sock, on = 1;
+       struct ip_mreq m;
 
-       if ((sock = socket(domain, type, 0)) < 0) {
-               perror("socket");
-               syslog(LOG_ERR, "socket: %m");
-               return (-1);
+       if (!IS_RIP_IN_OFF(ifp->int_state)
+           && (ifp->int_if_flags & IFF_MULTICAST)
+#ifdef MCAST_PPP_BUG
+           && !(ifp->int_if_flags & IFF_POINTOPOINT)
+#endif
+           && !(ifp->int_state & IS_ALIAS)) {
+               m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP);
+               m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT)
+                                         ? ifp->int_dstaddr
+                                         : ifp->int_addr);
+               if (setsockopt(rip_sock,IPPROTO_IP, IP_ADD_MEMBERSHIP,
+                              &m, sizeof(m)) < 0)
+                       LOGERR("setsockopt(IP_ADD_MEMBERSHIP RIP)");
        }
-#ifdef SO_BROADCAST
-       if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
-               syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
-               close(sock);
-               return (-1);
+}
+
+
+/* Prepare socket used for RIP.
+ */
+void
+rip_on(struct interface *ifp)
+{
+       /* If the main RIP socket is already alive, only start receiving
+        * multicasts for this interface.
+        */
+       if (rip_sock >= 0) {
+               if (ifp != 0)
+                       rip_mcast_on(ifp);
+               return;
        }
-#endif
-#ifdef SO_RCVBUF
-       for (on = bufspace; ; on -= 1024) {
-               if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
-                   &on, sizeof (on)) == 0)
-                       break;
-               if (on <= 8*1024) {
-                       syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
-                       break;
+
+       /* If the main RIP socket is off, and it makes sense to turn it on,
+        * turn it on for all of the interfaces.
+        */
+       if (rip_interfaces > 0 && !rdisc_ok) {
+               trace_act("turn on RIP\n");
+
+               /* Close all of the query sockets so that we can open
+                * the main socket.  SO_REUSEPORT is not a solution,
+                * since that would let two daemons bind to the broadcast
+                * socket.
+                */
+               for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
+                       if (ifp->int_rip_sock >= 0) {
+                               (void)close(ifp->int_rip_sock);
+                               ifp->int_rip_sock = -1;
+                       }
+               }
+
+               rip_sock = get_rip_sock(INADDR_ANY, 1);
+               rip_sock_mcast = 0;
+
+               /* Do not advertise anything until we have heard something
+                */
+               if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME)
+                       next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME;
+
+               for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
+                       if (!IS_RIP_IN_OFF(ifp->int_state))
+                               ifp->int_state &= ~IS_RIP_QUERIED;
+                       rip_mcast_on(ifp);
                }
+
+               ifinit_timer.tv_sec = now.tv_sec;
+
+               fix_select();
+
+       } else if (ifp != 0
+                  && ifp->int_rip_sock < 0
+                  && !(ifp->int_state & IS_ALIAS)) {
+               /* RIP is off, so ensure there are sockets on which
+                * to listen for queries.
+                */
+               ifp->int_rip_sock = get_rip_sock(ifp->int_addr, 0);
+
+               fix_select();
        }
-       if (traceactions)
-               fprintf(ftrace, "recv buf %d\n", on);
-#endif
-       if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0) {
-               perror("bind");
-               syslog(LOG_ERR, "bind: %m");
-               close(sock);
-               return (-1);
+}
+
+
+/* die if malloc(3) fails
+ */
+void *
+rtmalloc(size_t size,
+        char *msg)
+{
+       void *p = malloc(size);
+       if (p == 0)
+               logbad(1,"malloc() failed in %s", msg);
+       return p;
+}
+
+
+/* get a random instant in an interval
+ */
+void
+intvl_random(struct timeval *tp,       /* put value here */
+            u_long lo,                 /* value is after this second */
+            u_long hi)                 /* and before this */
+{
+       tp->tv_sec = (time_t)(hi == lo
+                             ? lo
+                             : (lo + random() % ((hi - lo))));
+       tp->tv_usec = random() % 1000000;
+}
+
+
+void
+timevaladd(struct timeval *t1,
+          struct timeval *t2)
+{
+
+       t1->tv_sec += t2->tv_sec;
+       if ((t1->tv_usec += t2->tv_usec) > 1000000) {
+               t1->tv_sec++;
+               t1->tv_usec -= 1000000;
        }
-       if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
-               syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
-       return (sock);
+}
+
+
+/* t1 = t2 - t3
+ */
+static void
+timevalsub(struct timeval *t1,
+          struct timeval *t2,
+          struct timeval *t3)
+{
+       t1->tv_sec = t2->tv_sec - t3->tv_sec;
+       if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) {
+               t1->tv_sec--;
+               t1->tv_usec += 1000000;
+       }
+}
+
+
+void
+msglog(char *p, ...)
+{
+       va_list args;
+
+       trace_flush();
+
+       va_start(args, p);
+       vsyslog(LOG_ERR, p, args);
+
+       if (ftrace != 0) {
+               if (ftrace == stdout)
+                       (void)fputs("routed: ", ftrace);
+               (void)vfprintf(ftrace, p, args);
+               (void)fputc('\n', ftrace);
+       }
+}
+
+
+void
+logbad(int dump, char *p, ...)
+{
+       va_list args;
+
+       trace_flush();
+
+       va_start(args, p);
+       vsyslog(LOG_ERR, p, args);
+
+       (void)fputs("routed: ", stderr);
+       (void)vfprintf(stderr, p, args);
+       (void)fputs("; giving up\n",stderr);
+       (void)fflush(stderr);
+
+       if (dump)
+               abort();
+       exit(1);
 }
index 9e74959..c1ad2fc 100644 (file)
@@ -1,5 +1,4 @@
-/*     $OpenBSD: output.c,v 1.2 1996/06/23 14:32:29 deraadt Exp $      */
-/*     $NetBSD: output.c,v 1.9 1995/06/20 22:27:54 christos Exp $      */
+/*     $OpenBSD: output.c,v 1.3 1996/09/05 14:31:36 mickey Exp $       */
 
 /*
  * Copyright (c) 1983, 1988, 1993
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-#if 0
+#if !defined(lint)
 static char sccsid[] = "@(#)output.c   8.1 (Berkeley) 6/5/93";
 #else
-static char rcsid[] = "$OpenBSD: output.c,v 1.2 1996/06/23 14:32:29 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: output.c,v 1.3 1996/09/05 14:31:36 mickey Exp $";
 #endif
-#endif /* not lint */
 
-/*
- * Routing Table Management Daemon
- */
 #include "defs.h"
 
-/*
- * Apply the function "f" to all non-passive
- * interfaces.  If the interface supports the
- * use of broadcasting use it, otherwise address
- * the output to the known router.
+
+int update_seqno;
+
+
+/* walk the tree of routes with this for output
  */
-void
-toall(f, rtstate, skipif)
-       void (*f) __P((struct sockaddr *, int, struct interface *, int));
-       int rtstate;
-       struct interface *skipif;
+struct {
+       struct sockaddr_in to;
+       naddr   to_mask;
+       naddr   to_net;
+       naddr   to_std_mask;
+       naddr   to_std_net;
+       struct interface *ifp;          /* usually output interface */
+       struct ws_buf {                 /* info for each buffer */
+           struct rip  *buf;
+           struct netinfo *n;
+           struct netinfo *base;
+           struct netinfo *lim;
+           enum output_type type;
+       } v12, v2;
+       char    metric;                 /* adjust metrics by interface */
+       int     npackets;
+       int     gen_limit;
+       u_int   state;
+#define            WS_ST_FLASH     0x001       /* send only changed routes */
+#define            WS_ST_RIP2_SAFE 0x002       /* send RIPv2 safe for RIPv1 */
+#define            WS_ST_RIP2_ALL  0x004       /* send full featured RIPv2 */
+#define            WS_ST_AG        0x008       /* ok to aggregate subnets */
+#define            WS_ST_SUPER_AG  0x010       /* ok to aggregate networks */
+#define            WS_ST_SUB_AG    0x020       /* aggregate subnets in odd case */
+#define            WS_ST_QUERY     0x040       /* responding to a query */
+#define            WS_ST_TO_ON_NET 0x080       /* sending onto one of our nets */
+#define            WS_ST_DEFAULT   0x100       /* faking a default */
+#define            WS_ST_PM_RDISC  0x200       /* poor-man's router discovery */
+} ws;
+
+/* A buffer for what can be heard by both RIPv1 and RIPv2 listeners */
+union pkt_buf ripv12_buf;
+
+/* Another for only RIPv2 listeners */
+union pkt_buf rip_v2_buf;
+
+
+
+/* Send the contents of the global buffer via the non-multicast socket
+ */
+int                                    /* <0 on failure */
+output(enum output_type type,
+       struct sockaddr_in *dst,                /* send to here */
+       struct interface *ifp,
+       struct rip *buf,
+       int size)                       /* this many bytes */
 {
-       register struct interface *ifp;
-       register struct sockaddr *dst;
-       register int flags;
-       extern struct interface *ifnet;
+       struct sockaddr_in sin;
+       int flags;
+       char *msg;
+       int res;
+       naddr tgt_mcast;
+       int soc;
+       int serrno;
 
-       for (ifp = ifnet; ifp; ifp = ifp->int_next) {
-               if (ifp->int_flags & IFF_PASSIVE || ifp == skipif)
-                       continue;
-               dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
-                     ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
-                     &ifp->int_addr;
-               flags = ifp->int_flags & IFF_INTERFACE ? MSG_DONTROUTE : 0;
-               (*f)(dst, flags, ifp, rtstate);
+       sin = *dst;
+       if (sin.sin_port == 0)
+               sin.sin_port = htons(RIP_PORT);
+#ifdef _HAVE_SIN_LEN
+       if (sin.sin_len == 0)
+               sin.sin_len = sizeof(sin);
+#endif
+
+       soc = rip_sock;
+       flags = 0;
+
+       switch (type) {
+       case OUT_QUERY:
+               msg = "Answer Query";
+               if (soc < 0)
+                       soc = ifp->int_rip_sock;
+               break;
+       case OUT_UNICAST:
+               msg = "Send";
+               if (soc < 0)
+                       soc = ifp->int_rip_sock;
+               flags = MSG_DONTROUTE;
+               break;
+       case OUT_BROADCAST:
+               if (ifp->int_if_flags & IFF_POINTOPOINT) {
+                       msg = "Send";
+               } else {
+                       msg = "Send bcast";
+               }
+               flags = MSG_DONTROUTE;
+               break;
+       case OUT_MULTICAST:
+               if (ifp->int_if_flags & IFF_POINTOPOINT) {
+                       msg = "Send pt-to-pt";
+               } else if (ifp->int_state & IS_DUP) {
+                       trace_act("abort multicast output via %s"
+                                 " with duplicate address\n",
+                                 ifp->int_name);
+                       return 0;
+               } else {
+                       msg = "Send mcast";
+                       if (rip_sock_mcast != ifp) {
+#ifdef MCAST_PPP_BUG
+                               /* Do not specifiy the primary interface
+                                * explicitly if we have the multicast
+                                * point-to-point kernel bug, since the
+                                * kernel will do the wrong thing if the
+                                * local address of a point-to-point link
+                                * is the same as the address of an ordinary
+                                * interface.
+                                */
+                               if (ifp->int_addr == myaddr) {
+                                       tgt_mcast = 0;
+                               } else
+#endif
+                               tgt_mcast = ifp->int_addr;
+                               if (0 > setsockopt(rip_sock,
+                                                  IPPROTO_IP, IP_MULTICAST_IF,
+                                                  &tgt_mcast,
+                                                  sizeof(tgt_mcast))) {
+                                       serrno = errno;
+                                       LOGERR("setsockopt(rip_sock,"
+                                              "IP_MULTICAST_IF)");
+                                       errno = serrno;
+                                       ifp = 0;
+                                       return -1;
+                               }
+                               rip_sock_mcast = ifp;
+                       }
+                       sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP);
+               }
+
+       case NO_OUT_MULTICAST:
+       case NO_OUT_RIPV2:
+               break;
+       }
+
+       trace_rip(msg, "to", &sin, ifp, buf, size);
+
+       res = sendto(soc, buf, size, flags,
+                    (struct sockaddr *)&sin, sizeof(sin));
+       if (res < 0
+           && (ifp == 0 || !(ifp->int_state & IS_BROKE))) {
+               serrno = errno;
+               msglog("%s sendto(%s%s%s.%d): %s", msg,
+                      ifp != 0 ? ifp->int_name : "",
+                      ifp != 0 ? ", " : "",
+                      inet_ntoa(sin.sin_addr),
+                      ntohs(sin.sin_port),
+                      strerror(errno));
+               errno = serrno;
        }
+
+       return res;
 }
 
-/*
- * Output a preformed packet.
+
+/* install authentication if appropriate
  */
-/*ARGSUSED*/
-void
-sndmsg(dst, flags, ifp, rtstate)
-       struct sockaddr *dst;
-       int flags;
-       struct interface *ifp;
-       int rtstate;
+static void
+set_auth(struct ws_buf *w)
+{
+       if (ws.ifp != 0
+           && ws.ifp->int_passwd[0] != '\0'
+           && (ws.state & WS_ST_RIP2_SAFE)) {
+               w->n->n_family = RIP_AF_AUTH;
+               ((struct netauth*)w->n)->a_type = RIP_AUTH_PW;
+               bcopy(ws.ifp->int_passwd, ((struct netauth*)w->n)->au.au_pw,
+                     sizeof(((struct netauth*)w->n)->au.au_pw));
+               w->n++;
+       }
+}
+
+
+/* Send the buffer
+ */
+static void
+supply_write(struct ws_buf *wb)
 {
+       /* Output multicast only if legal.
+        * If we would multcast and it would be illegal, then discard the
+        * packet.
+        */
+       switch (wb->type) {
+       case NO_OUT_MULTICAST:
+               trace_pkt("skip multicast to %s because impossible\n",
+                         naddr_ntoa(ws.to.sin_addr.s_addr));
+               break;
+       case NO_OUT_RIPV2:
+               break;
+       default:
+               if (output(wb->type, &ws.to, ws.ifp, wb->buf,
+                          ((char *)wb->n - (char*)wb->buf)) < 0
+                   && ws.ifp != 0)
+                       if_sick(ws.ifp);
+               ws.npackets++;
+               break;
+       }
 
-       (*afswitch[dst->sa_family].af_output)(s, flags,
-               dst, sizeof (struct rip));
-       TRACE_OUTPUT(ifp, dst, sizeof (struct rip));
+       bzero(wb->n = wb->base, sizeof(*wb->n)*NETS_LEN);
+       if (wb->buf->rip_vers == RIPv2)
+               set_auth(wb);
 }
 
-/*
- * Supply dst with the contents of the routing tables.
+
+/* put an entry into the packet
+ */
+static void
+supply_out(struct ag_info *ag)
+{
+       int i;
+       naddr mask, v1_mask, s_mask, dst_h, ddst_h;
+       struct ws_buf *wb;
+
+
+       /* Skip this route if doing a flash update and it and the routes
+        * it aggregates have not changed recently.
+        */
+       if (ag->ag_seqno < update_seqno
+           && (ws.state & WS_ST_FLASH))
+               return;
+
+       /* Skip this route if required by split-horizon.
+        */
+       if (ag->ag_state & AGS_SPLIT_HZ)
+               return;
+
+       dst_h = ag->ag_dst_h;
+       mask = ag->ag_mask;
+       v1_mask = ripv1_mask_host(htonl(dst_h),
+                                 (ws.state & WS_ST_TO_ON_NET) ? ws.ifp : 0);
+       s_mask = std_mask(htonl(dst_h));
+       i = 0;
+
+       /* If we are sending RIPv2 packets that cannot (or must not) be
+        * heard by RIPv1 listeners, do not worry about sub- or supernets.
+        * Subnets (from other networks) can only be sent via multicast.
+        * A pair of subnet routes might have been promoted so that they
+        * are legal to send by RIPv1.
+        * If RIPv1 is off, use the multicast buffer, unless this is the
+        * fake default route and it is acting as a poor-man's router-
+        * discovery mechanism.
+        */
+       if (((ws.state & WS_ST_RIP2_ALL)
+            && (dst_h != RIP_DEFAULT || !(ws.state & WS_ST_PM_RDISC)))
+           || ((ag->ag_state & AGS_RIPV2) && v1_mask != mask)) {
+               /* use the RIPv2-only buffer */
+               wb = &ws.v2;
+
+       } else {
+               /* use the RIPv1-or-RIPv2 buffer */
+               wb = &ws.v12;
+
+               /* Convert supernet route into corresponding set of network
+                * routes for RIPv1, but leave non-contiguous netmasks
+                * to ag_check().
+                */
+               if (v1_mask > mask
+                   && mask + (mask & -mask) == 0) {
+                       ddst_h = v1_mask & -v1_mask;
+                       i = (v1_mask & ~mask)/ddst_h;
+
+                       if (i > ws.gen_limit) {
+                               /* Punt if we would have to generate an
+                                * unreasonable number of routes.
+                                */
+#ifdef DEBUG
+                               msglog("sending %s to %s as 1 instead"
+                                      " of %d routes",
+                                      addrname(htonl(dst_h),mask,1),
+                                      naddr_ntoa(ws.to.sin_addr.s_addr),
+                                      i+1);
+#endif
+                               i = 0;
+
+                       } else {
+                               mask = v1_mask;
+                               ws.gen_limit -= i;
+                       }
+               }
+       }
+
+       do {
+               wb->n->n_family = RIP_AF_INET;
+               wb->n->n_dst = htonl(dst_h);
+               /* If the route is from router-discovery or we are
+                * shutting down, admit only a bad metric.
+                */
+               wb->n->n_metric = ((stopint || ag->ag_metric < 1)
+                                  ? HOPCNT_INFINITY
+                                  : ag->ag_metric);
+               HTONL(wb->n->n_metric);
+               if (wb->buf->rip_vers == RIPv2) {
+                       if (ag->ag_nhop != 0
+                           && (ws.state & WS_ST_RIP2_SAFE)
+                           && ((ws.state & WS_ST_QUERY)
+                               || (ag->ag_nhop != ws.ifp->int_addr
+                                   && on_net(ag->ag_nhop,
+                                             ws.ifp->int_net,
+                                             ws.ifp->int_mask))))
+                               wb->n->n_nhop = ag->ag_nhop;
+                       if ((ws.state & WS_ST_RIP2_ALL)
+                           || mask != s_mask)
+                               wb->n->n_mask = htonl(mask);
+                       wb->n->n_tag = ag->ag_tag;
+               }
+               dst_h += ddst_h;
+
+               if (++wb->n >= wb->lim)
+                       supply_write(wb);
+       } while (i-- != 0);
+}
+
+
+/* supply one route from the table
+ */
+/* ARGSUSED */
+static int
+walk_supply(struct radix_node *rn,
+           void *w)
+{
+#define RT ((struct rt_entry *)rn)
+       u_short ags;
+       char metric, pref;
+       naddr dst, nhop;
+
+
+       /* Do not advertise the loopback interface
+        * or external remote interfaces
+        */
+       if ((RT->rt_state & RS_IF)
+           && RT->rt_ifp != 0
+           && ((RT->rt_ifp->int_if_flags & IFF_LOOPBACK)
+               || (RT->rt_ifp->int_state & IS_EXTERNAL))
+           && !(RT->rt_state & RS_MHOME))
+               return 0;
+
+       /* If being quiet about our ability to forward, then
+        * do not say anything unless responding to a query.
+        */
+       if (!supplier && !(ws.state & WS_ST_QUERY))
+               return 0;
+
+       dst = RT->rt_dst;
+
+       /* do not collide with the fake default route */
+       if (dst == RIP_DEFAULT
+           && (ws.state & WS_ST_DEFAULT))
+               return 0;
+
+       if (RT->rt_state & RS_NET_SYN) {
+               if (RT->rt_state & RS_NET_INT) {
+                       /* Do not send manual synthetic network routes
+                        * into the subnet.
+                        */
+                       if (on_net(ws.to.sin_addr.s_addr,
+                                  ntohl(dst), RT->rt_mask))
+                               return 0;
+
+               } else {
+                       /* Do not send automatic synthetic network routes
+                        * if they are not needed becaus no RIPv1 listeners
+                        * can hear them.
+                        */
+                       if (ws.state & WS_ST_RIP2_ALL)
+                               return 0;
+
+                       /* Do not send automatic synthetic network routes to
+                        * the real subnet.
+                        */
+                       if (on_net(ws.to.sin_addr.s_addr,
+                                  ntohl(dst), RT->rt_mask))
+                               return 0;
+               }
+               nhop = 0;
+
+       } else {
+               /* Advertise the next hop if this is not a route for one
+                * of our interfaces and the next hop is on the same
+                * network as the target.
+                */
+               if (!(RT->rt_state & RS_IF)
+                   && RT->rt_gate != myaddr
+                   && RT->rt_gate != loopaddr)
+                       nhop = RT->rt_gate;
+               else
+                       nhop = 0;
+       }
+
+       metric = RT->rt_metric;
+       ags = 0;
+
+       if (RT->rt_state & RS_MHOME) {
+               /* retain host route of multi-homed servers */
+               ;
+
+       } else if (RT_ISHOST(RT)) {
+               /* We should always aggregate the host routes
+                * for the local end of our point-to-point links.
+                * If we are suppressing host routes in general, then do so.
+                * Avoid advertising host routes onto their own network,
+                * where they should be handled by proxy-ARP.
+                */
+               if ((RT->rt_state & RS_LOCAL)
+                   || ridhosts
+                   || (ws.state & WS_ST_SUPER_AG)
+                   || on_net(dst, ws.to_net, ws.to_mask))
+                       ags |= AGS_SUPPRESS;
+
+               if (ws.state & WS_ST_SUPER_AG)
+                       ags |= AGS_PROMOTE;
+
+       } else if (ws.state & WS_ST_AG) {
+               /* Aggregate network routes, if we are allowed.
+                */
+               ags |= AGS_SUPPRESS;
+
+               /* Generate supernets if allowed.
+                * If we can be heard by RIPv1 systems, we will
+                * later convert back to ordinary nets.
+                * This unifies dealing with received supernets.
+                */
+               if ((RT->rt_state & RS_SUBNET)
+                   || (ws.state & WS_ST_SUPER_AG))
+                       ags |= AGS_PROMOTE;
+
+       }
+
+       /* Do not send RIPv1 advertisements of subnets to other
+        * networks. If possible, multicast them by RIPv2.
+        */
+       if ((RT->rt_state & RS_SUBNET)
+           && !(ws.state & WS_ST_RIP2_ALL)
+           && !on_net(dst, ws.to_std_net, ws.to_std_mask)) {
+               ags |= AGS_RIPV2 | AGS_PROMOTE;
+               if (ws.state & WS_ST_SUB_AG)
+                       ags |= AGS_SUPPRESS;
+       }
+
+       /* Do not send a route back to where it came from, except in
+        * response to a query.  This is "split-horizon".  That means not
+        * advertising back to the same network and so via the same interface.
+        *
+        * We want to suppress routes that might have been fragmented
+        * from this route by a RIPv1 router and sent back to us, and so we
+        * cannot forget this route here.  Let the split-horizon route
+        * aggregate (suppress) the fragmented routes and then itself be
+        * forgotten.
+        *
+        * Include the routes for both ends of point-to-point interfaces
+        * since the other side presumably knows them as well as we do.
+        */
+       if (RT->rt_ifp == ws.ifp && ws.ifp != 0
+           && !(ws.state & WS_ST_QUERY)
+           && (ws.state & WS_ST_TO_ON_NET)
+           && (!(RT->rt_state & RS_IF)
+               || ws.ifp->int_if_flags & IFF_POINTOPOINT)) {
+               /* Poison-reverse the route instead of only not advertising it
+                * it is recently changed from some other route.
+                * In almost all cases, if there is no spare for the route
+                * then it is either old or a brand new route, and if it
+                * is brand new, there is no need for poison-reverse.
+                */
+               metric = HOPCNT_INFINITY;
+               if (RT->rt_poison_time < now_expire
+                   || RT->rt_spares[1].rts_gate ==0) {
+                       ags |= AGS_SPLIT_HZ;
+                       ags &= ~(AGS_PROMOTE | AGS_SUPPRESS);
+               }
+       }
+
+       /* Adjust the outgoing metric by the cost of the link.
+        */
+       pref = metric + ws.metric;
+       if (pref < HOPCNT_INFINITY) {
+               /* Keep track of the best metric with which the
+                * route has been advertised recently.
+                */
+               if (RT->rt_poison_metric >= metric
+                   || RT->rt_poison_time < now_expire) {
+                       RT->rt_poison_time = now.tv_sec;
+                       RT->rt_poison_metric = metric;
+               }
+               metric = pref;
+
+       } else {
+               /* Do not advertise stable routes that will be ignored,
+                * unless they are being held down and poisoned.  If the
+                * route recently was advertised with a metric that would
+                * have been less than infinity through this interface, we
+                * need to continue to advertise it in order to poison it.
+                */
+               pref = RT->rt_poison_metric + ws.metric;
+               if (pref >= HOPCNT_INFINITY
+                   || RT->rt_poison_time < now_garbage )
+                       return 0;
+
+               metric = HOPCNT_INFINITY;
+       }
+
+       ag_check(dst, RT->rt_mask, 0, nhop, metric, pref,
+                RT->rt_seqno, RT->rt_tag, ags, supply_out);
+       return 0;
+#undef RT
+}
+
+
+/* Supply dst with the contents of the routing tables.
  * If this won't fit in one packet, chop it up into several.
  */
 void
-supply(dst, flags, ifp, rtstate)
-       struct sockaddr *dst;
-       int flags;
-       struct interface *ifp;
-       int rtstate;
+supply(struct sockaddr_in *dst,
+       struct interface *ifp,          /* output interface */
+       enum output_type type,
+       int flash,                      /* 1=flash update */
+       int vers)                       /* RIP version */
 {
-       register struct rt_entry *rt;
-       register struct netinfo *n = msg->rip_nets;
-       register struct rthash *rh;
-       struct rthash *base = hosthash;
-       int doinghost = 1, size;
-       void (*output) __P((int, int, struct sockaddr *, int)) =
-               afswitch[dst->sa_family].af_output;
-       int (*sendroute) __P((struct rt_entry *, struct sockaddr *)) =
-               afswitch[dst->sa_family].af_sendroute;
-       int npackets = 0;
-
-       msg->rip_cmd = RIPCMD_RESPONSE;
-       msg->rip_vers = RIP_VERSION_1;
-       memset(msg->rip_res1, 0, sizeof(msg->rip_res1));
-again:
-       for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
-       for (rt = rh->cqh_first; rt != (void *) rh; rt = rt->rt_entry.cqe_next) {
-               /*
-                * Don't resend the information on the network
-                * from which it was received (unless sending
-                * in response to a query).
+       static int init = 1;
+       struct rt_entry *rt;
+
+
+       ws.state = 0;
+       ws.gen_limit = 1024;
+
+       ws.to = *dst;
+       ws.to_std_mask = std_mask(ws.to.sin_addr.s_addr);
+       ws.to_std_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_std_mask;
+
+       if (ifp != 0) {
+               ws.to_mask = ifp->int_mask;
+               ws.to_net = ifp->int_net;
+               if (on_net(ws.to.sin_addr.s_addr, ws.to_net, ws.to_mask))
+                       ws.state |= WS_ST_TO_ON_NET;
+
+       } else {
+               ws.to_mask = ripv1_mask_net(ws.to.sin_addr.s_addr, 0);
+               ws.to_net = ntohl(ws.to.sin_addr.s_addr) & ws.to_mask;
+               rt = rtfind(dst->sin_addr.s_addr);
+               if (rt)
+                       ifp = rt->rt_ifp;
+       }
+
+       ws.npackets = 0;
+       if (flash)
+               ws.state |= WS_ST_FLASH;
+       if (type == OUT_QUERY)
+               ws.state |= WS_ST_QUERY;
+
+       if ((ws.ifp = ifp) == 0) {
+               ws.metric = 1;
+       } else {
+               /* Adjust the advertised metric by the outgoing interface
+                * metric.
+                */
+               ws.metric = ifp->int_metric+1;
+       }
+
+       if (init) {
+               init = 0;
+
+               bzero(&ripv12_buf, sizeof(ripv12_buf));
+               ripv12_buf.rip.rip_cmd = RIPCMD_RESPONSE;
+               ws.v12.buf = &ripv12_buf.rip;
+               ws.v12.base = &ws.v12.buf->rip_nets[0];
+               ws.v12.lim = ws.v12.base + NETS_LEN;
+
+               bzero(&rip_v2_buf, sizeof(rip_v2_buf));
+               rip_v2_buf.rip.rip_cmd = RIPCMD_RESPONSE;
+               rip_v2_buf.rip.rip_vers = RIPv2;
+               ws.v2.buf = &rip_v2_buf.rip;
+               ws.v2.base = &ws.v2.buf->rip_nets[0];
+               ws.v2.lim = ws.v2.base + NETS_LEN;
+       }
+       ripv12_buf.rip.rip_vers = vers;
+
+       ws.v12.n = ws.v12.base;
+       set_auth(&ws.v12);
+       ws.v2.n = ws.v2.base;
+       set_auth(&ws.v2);
+
+       switch (type) {
+       case OUT_BROADCAST:
+               ws.v2.type = ((ws.ifp != 0
+                              && (ws.ifp->int_if_flags & IFF_MULTICAST))
+                             ? OUT_MULTICAST
+                             : NO_OUT_MULTICAST);
+               ws.v12.type = OUT_BROADCAST;
+               break;
+       case OUT_MULTICAST:
+               ws.v2.type = ((ws.ifp != 0
+                              && (ws.ifp->int_if_flags & IFF_MULTICAST))
+                             ? OUT_MULTICAST
+                             : NO_OUT_MULTICAST);
+               ws.v12.type = OUT_BROADCAST;
+               break;
+       case OUT_UNICAST:
+       case OUT_QUERY:
+               ws.v2.type = (vers == RIPv2) ? type : NO_OUT_RIPV2;
+               ws.v12.type = type;
+               break;
+       default:
+               ws.v2.type = type;
+               ws.v12.type = type;
+               break;
+       }
+
+       if (vers == RIPv2) {
+               /* if asked to send RIPv2, send at least that which can
+                * be safely heard by RIPv1 listeners.
+                */
+               ws.state |= WS_ST_RIP2_SAFE;
+
+               /* full RIPv2 only if cannot be heard by RIPv1 listeners */
+               if (type != OUT_BROADCAST)
+                       ws.state |= WS_ST_RIP2_ALL;
+               if (!(ws.state & WS_ST_TO_ON_NET)) {
+                       ws.state |= (WS_ST_AG | WS_ST_SUPER_AG);
+               } else if (ws.ifp == 0 || !(ws.ifp->int_state & IS_NO_AG)) {
+                       ws.state |= WS_ST_AG;
+                       if (type != OUT_BROADCAST
+                           && (ws.ifp == 0
+                               || !(ws.ifp->int_state & IS_NO_SUPER_AG)))
+                               ws.state |= WS_ST_SUPER_AG;
+               }
+
+       } else if (ws.ifp == 0 || !(ws.ifp->int_state & IS_NO_AG)) {
+               ws.state |= WS_ST_SUB_AG;
+       }
+
+       if (supplier) {
+               /*  Fake a default route if asked, and if there is not
+                * a better, real default route.
                 */
-               if (ifp && rt->rt_ifp == ifp &&
-                   (rt->rt_state & RTS_INTERFACE) == 0)
+               if (ifp->int_d_metric != 0
+                   && (0 == (rt = rtget(RIP_DEFAULT, 0))
+                       || rt->rt_metric+ws.metric >= ifp->int_d_metric)) {
+                       ws.state |= WS_ST_DEFAULT;
+                       ag_check(0, 0, 0, 0,
+                                ifp->int_d_metric,ifp->int_d_metric,
+                                0, 0, 0, supply_out);
+               }
+               if ((ws.state & WS_ST_RIP2_ALL)
+                   && (ifp->int_state & IS_PM_RDISC)) {
+                       ws.state |= WS_ST_PM_RDISC;
+                       ripv12_buf.rip.rip_vers = RIPv1;
+               }
+       }
+
+       (void)rn_walktree(rhead, walk_supply, 0);
+       ag_flush(0,0,supply_out);
+
+       /* Flush the packet buffers, provided they are not empty and
+        * do not contain only the password.
+        */
+       if (ws.v12.n != ws.v12.base
+           && (ws.v12.n > ws.v12.base+1
+               || ws.v12.n->n_family != RIP_AF_AUTH))
+               supply_write(&ws.v12);
+       if (ws.v2.n != ws.v2.base
+           && (ws.v2.n > ws.v2.base+1
+               || ws.v2.n->n_family != RIP_AF_AUTH))
+               supply_write(&ws.v2);
+
+       /* If we sent nothing and this is an answer to a query, send
+        * an empty buffer.
+        */
+       if (ws.npackets == 0
+           && (ws.state & WS_ST_QUERY))
+               supply_write(&ws.v12);
+}
+
+
+/* send all of the routing table or just do a flash update
+ */
+void
+rip_bcast(int flash)
+{
+#ifdef _HAVE_SIN_LEN
+       static struct sockaddr_in dst = {sizeof(dst), AF_INET};
+#else
+       static struct sockaddr_in dst = {AF_INET};
+#endif
+       struct interface *ifp;
+       enum output_type type;
+       int vers;
+       struct timeval rtime;
+
+
+       need_flash = 0;
+       intvl_random(&rtime, MIN_WAITTIME, MAX_WAITTIME);
+       no_flash = rtime;
+       timevaladd(&no_flash, &now);
+
+       if (rip_sock < 0)
+               return;
+
+       trace_act("send %s and inhibit dynamic updates for %.3f sec\n",
+                 flash ? "dynamic update" : "all routes",
+                 rtime.tv_sec + ((float)rtime.tv_usec)/1000000.0);
+
+       for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
+               /* skip interfaces not doing RIP, those already queried,
+                * and aliases.  Do try broken interfaces to see
+                * if they have healed.
+                */
+               if (0 != (ifp->int_state & (IS_PASSIVE | IS_ALIAS)))
                        continue;
-               if (rt->rt_state & RTS_EXTERNAL)
+
+               /* skip turned off interfaces */
+               if (!iff_alive(ifp->int_if_flags))
                        continue;
-               /*
-                * For dynamic updates, limit update to routes
-                * with the specified state.
+
+               /* default to RIPv1 output */
+               if (ifp->int_state & IS_NO_RIPV1_OUT) {
+                       /* Say nothing if this interface is turned off */
+                       if (ifp->int_state & IS_NO_RIPV2_OUT)
+                               continue;
+                       vers = RIPv2;
+               } else {
+                       vers = RIPv1;
+               }
+
+               if (ifp->int_if_flags & IFF_BROADCAST) {
+                       /* ordinary, hardware interface */
+                       dst.sin_addr.s_addr = ifp->int_brdaddr;
+                       /* if RIPv1 is not turned off, then broadcast so
+                        * that RIPv1 listeners can hear.
+                        */
+                       if (vers == RIPv2
+                           && (ifp->int_state & IS_NO_RIPV1_OUT)) {
+                               type = OUT_MULTICAST;
+                       } else {
+                               type = OUT_BROADCAST;
+                       }
+
+               } else if (ifp->int_if_flags & IFF_POINTOPOINT) {
+                       /* point-to-point hardware interface */
+                       dst.sin_addr.s_addr = ifp->int_dstaddr;
+                       type = OUT_UNICAST;
+
+               } else {
+                       /* remote interface */
+                       dst.sin_addr.s_addr = ifp->int_addr;
+                       type = OUT_UNICAST;
+               }
+
+               supply(&dst, ifp, type, flash, vers);
+       }
+
+       update_seqno++;                 /* all routes are up to date */
+}
+
+
+/* Ask for routes
+ * Do it only once to an interface, and not even after the interface
+ * was broken and recovered.
+ */
+void
+rip_query(void)
+{
+#ifdef _HAVE_SIN_LEN
+       static struct sockaddr_in dst = {sizeof(dst), AF_INET};
+#else
+       static struct sockaddr_in dst = {AF_INET};
+#endif
+       struct interface *ifp;
+       struct rip buf;
+       enum output_type type;
+
+
+       if (rip_sock < 0)
+               return;
+
+       bzero(&buf, sizeof(buf));
+
+       for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+               /* skip interfaces not doing RIP, those already queried,
+                * and aliases.  Do try broken interfaces to see
+                * if they have healed.
                 */
-               if (rtstate && (rt->rt_state & rtstate) == 0)
+               if (0 != (ifp->int_state & (IS_RIP_QUERIED
+                                           | IS_PASSIVE | IS_ALIAS)))
                        continue;
-               /*
-                * Limit the spread of subnet information
-                * to those who are interested.
-                */
-               if (doinghost == 0 && rt->rt_state & RTS_SUBNET) {
-                       if (rt->rt_dst.sa_family != dst->sa_family)
-                               continue;
-                       if ((*sendroute)(rt, dst) == 0)
+
+               /* skip turned off interfaces */
+               if (!iff_alive(ifp->int_if_flags))
+                       continue;
+
+               /* default to RIPv1 output */
+               if (ifp->int_state & IS_NO_RIPV2_OUT) {
+                       /* Say nothing if this interface is turned off */
+                       if (ifp->int_state & IS_NO_RIPV1_OUT)
                                continue;
+                       buf.rip_vers = RIPv1;
+               } else {
+                       buf.rip_vers = RIPv2;
                }
-               size = (char *)n - packet;
-               if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
-                       TRACE_OUTPUT(ifp, dst, size);
-                       (*output)(s, flags, dst, size);
-                       /*
-                        * If only sending to ourselves,
-                        * one packet is enough to monitor interface.
+
+               buf.rip_cmd = RIPCMD_REQUEST;
+               buf.rip_nets[0].n_family = RIP_AF_UNSPEC;
+               buf.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY);
+
+               if (ifp->int_if_flags & IFF_BROADCAST) {
+                       /* ordinary, hardware interface */
+                       dst.sin_addr.s_addr = ifp->int_brdaddr;
+                       /* if RIPv1 is not turned off, then broadcast so
+                        * that RIPv1 listeners can hear.
                         */
-                       if (ifp && (ifp->int_flags &
-                          (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0)
-                               return;
-                       n = msg->rip_nets;
-                       npackets++;
+                       if (buf.rip_vers == RIPv2
+                           && (ifp->int_state & IS_NO_RIPV1_OUT)) {
+                               type = OUT_MULTICAST;
+                       } else {
+                               type = OUT_BROADCAST;
+                       }
+
+               } else if (ifp->int_if_flags & IFF_POINTOPOINT) {
+                       /* point-to-point hardware interface */
+                       dst.sin_addr.s_addr = ifp->int_dstaddr;
+                       type = OUT_UNICAST;
+
+               } else {
+                       /* remote interface */
+                       dst.sin_addr.s_addr = ifp->int_addr;
+                       type = OUT_UNICAST;
                }
-               (*afswitch[rt->rt_dst.sa_family].af_put)(n, &rt->rt_dst);
-               n->rip_metric = htonl(rt->rt_metric);
-               n++;
-       }
-       if (doinghost) {
-               doinghost = 0;
-               base = nethash;
-               goto again;
-       }
-       if (n != msg->rip_nets || (npackets == 0 && rtstate == 0)) {
-               size = (char *)n - packet;
-               TRACE_OUTPUT(ifp, dst, size);
-               (*output)(s, flags, dst, size);
+
+               ifp->int_state |= IS_RIP_QUERIED;
+               if (output(type, &dst, ifp, &buf, sizeof(buf)) < 0)
+                       if_sick(ifp);
        }
 }
index 2a540c6..561927f 100644 (file)
@@ -1,5 +1,4 @@
-/*     $OpenBSD: pathnames.h,v 1.2 1996/06/23 14:32:30 deraadt Exp $   */
-/*     $NetBSD: pathnames.h,v 1.6 1995/03/18 15:00:37 cgd Exp $        */
+/*     $OpenBSD: pathnames.h,v 1.3 1996/09/05 14:31:38 mickey Exp $    */
 
 /*
  * Copyright (c) 1989, 1993
  * SUCH DAMAGE.
  *
  *     @(#)pathnames.h 8.1 (Berkeley) 6/5/93
+ *
  */
 
 #include <paths.h>
 
 #define        _PATH_GATEWAYS  "/etc/gateways"
+
+/* All remotely requested trace files must either start with this prefix
+ * or be the same as the tracefile specified when the daemon was started.
+ * If this is a directory, routed will create log files in it.  That
+ * might be a security problem.
+ */
+#define _PATH_TRACE    "/tmp/routed.log"
index 8be7cfd..460d955 100644 (file)
@@ -1,5 +1,4 @@
-.\"    $OpenBSD: routed.8,v 1.4 1996/06/23 14:32:31 deraadt Exp $
-.\"    $NetBSD: routed.8,v 1.7 1996/02/06 20:34:28 scottr Exp $
+.\"    $OpenBSD: routed.8,v 1.5 1996/09/05 14:31:41 mickey Exp $
 .\"
 .\" Copyright (c) 1983, 1991, 1993
 .\"    The Regents of the University of California.  All rights reserved.
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"    @(#)routed.8    8.2 (Berkeley) 12/11/93
+.\"     @(#)routed.8   8.2 (Berkeley) 12/11/93
 .\"
-.Dd December 11, 1993
+.Dd June 1, 1996
 .Dt ROUTED 8
-.Os BSD 4.2
+.Os BSD 4.4
 .Sh NAME
 .Nm routed
-.Nd network routing daemon
+.Nd network RIP and router discovery routing daemon
 .Sh SYNOPSIS
-.Nm routed
-.Op Fl d
-.Op Fl g
-.Op Fl q
-.Op Fl s
-.Op Fl t
-.Op Ar logfile
+.Nm
+.Op Fl sqdghmpAt
+.Op Fl T Ar tracefile
+.Oo
+.Fl F
+.Ar net Ns Op /mask Ns Op ,metric
+.Oc
+.OP Fl P Ar parms
 .Sh DESCRIPTION
 .Nm Routed
-is invoked at boot time to manage the network routing tables.
-The routing daemon uses a variant of the Xerox NS Routing
-Information Protocol in maintaining up to date kernel routing
-table entries.
-It used a generalized protocol capable of use with multiple
-address types, but is currently used only for Internet routing
-within a cluster of networks.
-.Pp
-In normal operation
-.Nm routed
-listens on the
+is a dameon invoked at boot time to manage the network
+routing tables.
+It uses Routing Information Protocol, RIPv1 (RFC\ 1058),
+RIPv2 (RFC\ 1723),
+and Internet Router Discovery Protocol (RFC 1256)
+to maintain the kernel routing table.
+The RIPv1 protocol is based on the reference 4.3BSD daemon.
+.Pp
+It listens on the
 .Xr udp 4
 socket for the
 .Xr route 8
 service (see
 .Xr services 5 )
-for routing information packets.  If the host is an
-internetwork router, it periodically supplies copies
-of its routing tables to any directly connected hosts
-and networks.
+for Routing Information Protocol packets.
+It also sends and receives multicast Router Discovery ICMP messages.
+If the host is a router,
+.Nm
+periodically supplies copies
+of its routing tables to any directly connected hosts and networks.
+It also advertise or solicits default routes using Router Discovery
+ICMP messages.
 .Pp
-When
-.Nm routed
-is started, it uses the
-.Dv SIOCGIFCONF
-.Xr ioctl 2
-to find those
+When started (or when a network interface is later turned on),
+.Nm
+uses an AF_ROUTE address family facility to find those
 directly connected interfaces configured into the
-system and marked ``up'' (the software loopback interface
-is ignored).  If multiple interfaces
-are present, it is assumed that the host will forward packets
-between networks.
-.Nm Routed
-then transmits a 
-.Em request
-packet on each interface (using a broadcast packet if
-the interface supports it) and enters a loop, listening
-for
+system and marked "up".
+It adds necessary routes for the interfaces
+to the kernel routing table.
+Soon after being first started, and provided there is at least one
+interface on which RIP has not been disabled,
+.Nm
+deletes all pre-existing
+non-static routes in kernel table.
+Static routes in the kernel table are preserved and
+included in RIP responses if they have a valid RIP metric
+(see
+.Xr route 8 ).
+.Pp
+If more than one interface is present (not counting the loopback interface),
+it is assumed that the host should forward packets among the
+connected networks.
+After transmitting a RIP
 .Em request
 and
-.Em response
-packets from other hosts.
+Router Discovery Advertisements or Solicitations on a new interface,
+the daemon enters a loop, listening for
+RIP request and response and Router Discover packets from other hosts.
 .Pp
 When a
 .Em request
-packet is received, 
-.Nm routed
+packet is received,
+.Nm
 formulates a reply based on the information maintained in its
-internal tables.  The
+internal tables.
+The
 .Em response
 packet generated contains a list of known routes, each marked
-with a ``hop count'' metric (a count of 16, or greater, is
-considered ``infinite'').  The metric associated with each
-route returned provides a metric
-.Em relative to the sender .
+with a "hop count" metric (a count of 16 or greater is
+considered "infinite").
+Advertised metrics reflect the metric associated with interface
+(see
+.Xr ifconfig 8 ),
+so setting the metric on an interface
+is an effective way to steer traffic.
 .Pp
-.Em Response
-packets received by
-.Nm routed
-are used to update the routing tables if one of the following
-conditions is satisfied:
-.Bl -enum
-.It
-No routing table entry exists for the destination network
-or host, and the metric indicates the destination is ``reachable''
-(i.e. the hop count is not infinite).
-.It
-The source host of the packet is the same as the router in the
-existing routing table entry.  That is, updated information is
-being received from the very internetwork router through which
-packets for the destination are being routed.
-.It
-The existing entry in the routing table has not been updated for
-some time (defined to be 90 seconds) and the route is at least
-as cost effective as the current route.
-.It
-The new route describes a shorter route to the destination than
-the one currently stored in the routing tables; the metric of
-the new route is compared against the one stored in the table
-to decide this.
-.El
+Responses do not contain routes with a first hop on the requesting
+network to implement in part
+.Em split-horizon .
+Requests from query programs
+such as
+.Xr rtquery 8
+are answered with the complete table.
+.Pp
+The routing table maintained by the daemon
+includes space for several gateways for each destination
+to speed recovery from a failing router.
+RIP
+.Em response
+packets received are used to update the routing tables provided they are
+from one of the several currently recognized gateways or
+advertise a better metric than at least one of the existing
+gateways.
 .Pp
 When an update is applied,
-.Nm routed
-records the change in its internal tables and updates the kernel
-routing table.
-The change is reflected in the next
+.Nm
+records the change in its own tables and updates the kernel routing table
+if the best route to the destination changes.
+The change in the kernel routing tableis reflected in the next batch of
 .Em response
-packet sent.
+packets sent.
+If the next response is not scheduled for a while, a
+.Em flash update
+response containing only recently changed routes is sent.
 .Pp
 In addition to processing incoming packets,
-.Nm routed
+.Nm
 also periodically checks the routing table entries.
 If an entry has not been updated for 3 minutes, the entry's metric
-is set to infinity and marked for deletion.  Deletions are delayed
-an additional 60 seconds to insure the invalidation is propagated
-throughout the local internet.
+is set to infinity and marked for deletion.
+Deletions are delayed until the route has been advertised with
+an infinite metric to insure the invalidation
+is propagated throughout the local internet.
+This is a form of
+.Em poison reverse .
+.Pp
+Routes in the kernel table that are added or changed as a result
+of ICMP Redirect messages are deleted after a while to minimize
+.Em black-holes .
+When a TCP connection suffers a timeout,
+the kernel tells
+.Nm routed ,
+which deletes all redirected routes
+through the gateway involved, advances the age of all RIP routes through
+the gateway to allow an alternate to be chosen, and advances of the
+age of any relevant Router Discovery Protocol default routes.
 .Pp
 Hosts acting as internetwork routers gratuitously supply their
 routing tables every 30 seconds to all directly connected hosts
 and networks.
-The response is sent to the broadcast address on nets capable of that function,
+These RIP responses are sent to the broadcast address on nets that support
+broadcasting,
 to the destination address on point-to-point links, and to the router's
 own address on other networks.
-The normal routing tables are bypassed when sending gratuitous responses.
-The reception of responses on each network is used to determine that the
-network and interface are functioning correctly.
-If no response is received on an interface, another route may be chosen
-to route around the interface, or the route may be dropped if no alternative
-is available.
+If RIPv2 is enabled, multicast packets are sent on interfaces that
+support multicasting.
+.Pp
+If no response is received on a remote interface, if there are errors
+while sending responses,
+or if there are more errors than input or output (see
+.Xr netstat 8 ),
+then the cable or some other part of the interface is assumed to be
+disconnected or broken, and routes are adjusted appropriately.
+.Pp
+The
+.Em Internet Router Discovery Protocol
+is handled similarly.
+When the daemon is supplying RIP routes, it also listens for
+Router Discovery Solicitations and sends Advertisements.
+When it is quiet and only listening to other RIP routers, it
+sends Solicitations and listens for Advertisements.
+If it receives
+a good Advertisement, it stops listening for broadcast or multicast
+RIP responses.
+It tracks several advertising routers to speed recovery when the
+currently chosen router dies.
+If all discovered routers disappear,
+the daemon resumes listening to RIP responses.
+.Pp
+While using Router Discovery (which happens by default when
+the system has a single network interface and a Router Discover Advertisement
+is received), there is a single default route and a variable number of
+redirected host routes in the kernel table.
+.Pp
+The Router Discover standard requires that advertisements
+have a default "lifetime" of 30 minutes.  That means should
+something happen, a client can be without a good route for
+30 minutes.  It is a good idea to reduce the default to 45
+seconds using
+.Fl P Cm rdisc_interval=45
+on the command line or
+.Cm rdisc_interval=45
+in the
+.Pa /etc/gateways
+file.
+.Pp
+While using Router Discovery (which happens by default when
+the system has a single network interface and a Router Discover Advertisement
+is received), there is a single default route and a variable number of
+redirected host routes in the kernel table.
+.Pp
+See the
+.Cm pm_rdisc
+facility described below to support "legacy" systems
+that can handle neither RIPv2 nor Router Discovery.
+.Pp
+By default, neither Router Discovery advertisements nor solicications
+are sent over point to point links (e.g. PPP).
+
 .Pp
 Options supported by
 .Nm routed :
 .Bl -tag -width Ds
+.It Fl s
+this option forces
+.Nm
+to supply routing information.
+This is the default if multiple network interfaces are present on which
+RIP or Router Discovery have not been disabled, and if the kernel switch
+ipforwarding=1.
+.It Fl q
+is the opposite of the
+.Fl s
+option.
 .It Fl d
-Enable additional debugging information to be logged,
-such as bad packets received.
+Do not run in the background.
+This option is meant for interactive use.
 .It Fl g
 This flag is used on internetwork routers to offer a route
-to the ``default'' destination.
+to the "default" destination.
+It is equivalent to
+.Fl F
+.Cm 0/0,1
+and is present mostly for historical reasons.
+A better choice is
+.Fl P Cm pm_rdisc
+on the command line or
+.CM pm_rdisc in the
+.Pa /etc/gateways
+file.
+since a larger metric
+will be used, reducing the spread of the potentially dangerous
+default route.
 This is typically used on a gateway to the Internet,
 or on a gateway that uses another routing protocol whose routes
 are not reported to other local routers.
-.It Fl s
-Supplying this
-option forces 
-.Nm routed
-to supply routing information whether it is acting as an internetwork
-router or not.
-This is the default if multiple network interfaces are present,
-or if a point-to-point link is in use.
-.It Fl q
-This
-is the opposite of the
-.Fl s
-option.
+Notice that because a metric of 1 is used, this feature is
+dangerous.  It is more commonly accidently used to create chaos with routing
+loop than to solve problems.
+.It Fl h
+This causes host or point-to-point routes to not be advertised,
+provided there is a network route going the same direction.
+That is a limited kind of aggregation.
+This option is useful on gateways to ethernets that have other gateway
+machines connected with point-to-point links such as SLIP.
+.It Fl m
+This causes the machine to advertise a host or point-to-point route to
+its primary interface.
+It is useful on multi-homed machines such as NFS servers.
+This option should not be used except when the cost of
+the host routes it generates is justified by the popularity of
+the server.
+It is effective only when the machine is supplying
+routing information, because there is more than one interface.
+The
+.Fl m
+option overrides the
+.Fl q
+option to the limited extent of advertising the host route.
+.It Fl A
+do not ignore RIPv2 authentication if we do not care about RIPv2
+authentication.
+This option is required for conformance with RFC 1723.
+However, it makes no sense and breaks using RIP as a discovery protocol
+to ignore all RIPv2 packets that carry authentication when this machine
+does not care about authentication.
+.It Fl T Ar tracefile
+increases the debugging level to at least 1 and
+causes debugging information to be appended to the trace file.
 .It Fl t
-If the
-.Fl t
-option is specified, all packets sent or received are
-printed on the standard output.  In addition,
-.Nm routed
-will not divorce itself from the controlling terminal
-so that interrupts from the keyboard will kill the process.
+increases the debugging level, which causes more information to be logged
+on the tracefile specified with
+.Fl T
+or standard out.
+The debugging level can be increased or decreased
+with the
+.Em SIGUSR1
+or
+.Em SIGUSR2
+signals or with the
+.Cm rtquery
+command.
+.It Fl F Ar net[/mask][,metric]
+minimize routes in transmissions via interfaces with addresses that match
+.Em net/mask ,
+and synthesizes a default route to this machine with the
+.Em metric .
+The intent is to reduce RIP traffic on slow, point-to-point links
+such as PPP links by replacing many large UDP packets of RIP information
+with a single, small packet containing a "fake" default route.
+If
+.Em metric
+is absent, a value of 14 is assumed to limit
+the spread of the "fake" default route.
+
+This is a dangerous feature that when used carelessly can cause routing
+loops.
+Notice also that more than one interface can match the specified network
+number and mask.
+See also
+.Fl g .
+.It Fl P Ar parms
+is equivalent to adding the parameter
+line
+.Em parms
+to the
+.Pa /etc/gateways
+file.
 .El
 .Pp
 Any other argument supplied is interpreted as the name
-of file in which 
-.Nm routed Ns \'s
-actions should be logged.  This log contains information
-about any changes to the routing tables and, if not tracing all packets,
-a history of recent messages sent and received which are related to
-the changed route.
-.Pp
-In addition to the facilities described above, 
-.Nm routed
-supports the notion of ``distant''
+of a file in which the actions of
+.Nm
+should be logged.
+It is better to use
+.Fl T
+instead of
+appending the name of the trace file to the command.
+.Pp
+.Nm
+also supports the notion of
+"distant"
 .Em passive
-and 
+or
 .Em active
-gateways.  When 
-.Nm routed
-is started up, it reads the file
+gateways.
+When
+.Nm
+is started, it reads the file
 .Pa /etc/gateways
-to find gateways which may not be located using
-only information from the
-.Dv SIOGIFCONF
-.Xr ioctl 2 .
+to find such distant gateways which may not be located using
+only information from a routing socket, to discover if some
+of the local gateways are
+.Em passive ,
+and to obtain other parameters.
 Gateways specified in this manner should be marked passive
 if they are not expected to exchange routing information,
 while gateways marked active
-should be willing to exchange routing information (i.e.
-they should have a
-.Nm routed
-process running on the machine).
-Routes through passive gateways are installed in the
-kernel's routing tables once upon startup.
-Such routes are not included in
-any routing information transmitted.
-Active gateways are treated equally to network
-interfaces.  Routing information is distributed
-to the gateway and if no routing information is
-received for a period of time, the associated
-route is deleted.
+should be willing to exchange RIP packets.
+Routes through
+.Em passive
+gateways are installed in the
+kernel's routing tables once upon startup and are not included in
+transmitted RIP responses.
+.Pp
+Distant active gateways are treated like network interfaces.
+RIP responses are sent
+to the distant
+.Em active
+gateway.
+If no responses are received, the associated route is deleted from
+the kernel table and RIP responses advertised via other interfaces.
+If the distant gateway resumes sending RIP responses, the associated
+route is restored.
+.Pp
+Such gateways can be useful on media that do not support broadcasts
+or multicasts but otherwise act like classic shared media like
+Ethernets such as some ATM networks.
+One can list all RIP routers reachable on the ATM network in
+.Pa /etc/gateways
+with a series of
+"host" lines.
+.Pp
 Gateways marked
 .Em external
 are also passive, but are not placed in the kernel
 routing table nor are they included in routing updates.
-The function of external entries is to inform
-.Nm routed
+The function of external entries is to indicate
 that another routing process
-will install such a route, and that alternate routes to that destination
-should not be installed.
+will install such a route if ncessary,
+and that alternate routes to that destination should not be installed
+by
+.Nm routed .
 Such entries are only required when both routers may learn of routes
 to the same destination.
 .Pp
-The 
-.Pa /etc/gateways
-file is composed of a series of lines, each in
-the following format:
+The
+.Em /etc/gateways
+file is comprised of a series of lines, each in
+one of the following formats or consist of parameters described below:
+.Pp
 .Bd -ragged
-.Pf < Cm net No \&|
-.Cm host Ns >
-.Ar name1
+.Cm net
+.Ar Nname[/mask]
 .Cm gateway
-.Ar name2
+.Ar Gname
 .Cm metric
 .Ar value
 .Pf < Cm passive No \&|
 .Cm active No \&|
-.Cm external Ns >
+.Cm extern Ns >
 .Ed
-.Pp
-The 
-.Cm net
-or
+.Bd -ragged
 .Cm host
-keyword indicates if the route is to a network or specific host.
+.Ar Hname
+.Cm gateway
+.Ar Gname
+.Cm metric
+.Ar value
+.Pf < Cm passive No \&|
+.Cm active No \&|
+.Cm extern Ns >
+.Ed
 .Pp
-.Ar Name1
-is the name of the destination network or host.  This may be a
-symbolic name located in
+.Ar Nname
+or
+.Ar Hname
+is the name of the destination network or host.
+It may be a symbolic network name or an Internet address
+specified in "dot" notation (see
+.Xr inet 3 ).
+(If it is a name, then it must either be defined in
 .Pa /etc/networks
 or
-.Pa /etc/hosts
-(or, if started after
+.Pa /etc/hosts ,
+or
 .Xr named 8 ,
-known to the name server), 
-or an Internet address specified in ``dot'' notation; see
-.Xr inet 3 .
+must have been started before
+.Xr routed Ns .)
+.Pp
+.Ar mask
+is an optional number between 1 and 32 indicating the netmask associated
+with
+.Ar Nname .
 .Pp
-.Ar Name2
-is the name or address of the gateway to which messages should
+.Ar Gname
+is the name or address of the gateway to which RIP responses should
 be forwarded.
 .Pp
 .Ar Value
-is a metric indicating the hop count to the destination host
-or network.
+is the hop count to the destination host or network.
+.Ar " host hname "
+is equivalent to
+.Ar " net  nname/32 ".
 .Pp
 One of the keywords
 .Cm passive ,
 .Cm active
 or
 .Cm external
-indicates if the gateway should be treated as 
-.Em passive
+must be present to indicate whether the gateway should be treated as
+.Cm passive
 or
-.Em active
+.Cm active
 (as described above),
 or whether the gateway is
-.Em external
-to the scope of the
+.Cm external
+to the scope of the RIP protocol.
+.Pp
+Lines that start with neither "net" nor "host" must consist of one
+or more of the following parameter settings, separated by commas or
+blanks:
+.Bl -tag -width Ds
+.It Cm if Ns \&= Ns Ar ifname
+indicates that the other parameters on the line apply to the interface
+name
+.Ar ifname .
+.It Cm subnet Ns \&= Ns Ar nname[/mask][,metric]
+advertises a route to network
+.AR nname
+with mask
+.AR mask
+and the supplied metric (default 1).
+This is useful for filling "holes" in CIDR allocations.
+This parameter must appear by itself on a line.
+.Pp
+Do not use this feature unless necessary.  It is dangerous.
+.It Cm passwd Ns \&= Ns Ar XXX
+specifies a RIPv2 password that will be included on all RIPv2
+responses sent and checked on all RIPv2 responses received.
+The password must not contain any blanks, tab characters, commas
+or '#' characters.
+.It Cm no_ag
+turns off aggregation of subnets in RIPv1 and RIPv2 responses.
+.It Cm no_super_ag
+turns off aggregation of networks into supernets in RIPv2 responses.
+.It Cm passive
+is equivalent
+.Cm no_rip Cm no_rdisc .
+.It Cm no_rip
+disables all RIP processing on the specified interface.
+If no interfaces are allowed to process RIP packets,
+.Nm
+acts purely as a router discovery daemon.
+.Cm No_rip
+is equivalent to
+.Cm no_ripv1_in no_ripv2_in no_ripv1_out no_ripv2_out .
+
+Note that turning off RIP without explicitly turning on router
+discovery advertisements with
+.Cm rdisc_adv
+or
+.Fl s
+causes
 .Nm routed
-protocol.
-.Pp
-Internetwork routers that are directly attached to the Arpanet or Milnet
-should use the Exterior Gateway Protocol
-.Pq Tn EGP
-to gather routing information
-rather then using a static routing table of passive gateways.
-.Tn EGP
-is required in order to provide routes for local networks to the rest
-of the Internet system.
+to act as a client router discovery daemon, not adveritising.
+.It Cm no_ripv1_in
+causes RIPv1 received responses to be ignored.
+.It Cm no_ripv2_in
+causes RIPv2 received responses to be ignored.
+.It Cm ripv2_out
+turns off RIPv1 output and causes RIPv2 advertisements to be
+multicast when possible.
+.It Cm no_rdisc
+disables the Internet Router Discovery Protocol.
+.It Cm no_solicit
+disables the tranmission of Router Discovery Solicitations.
+.It Cm send_solicit
+specifies that Router Discovery solicitations should be sent,
+even on point-to-point links,
+which by default only listen to Router Discovery messages.
+.It Cm no_rdisc_adv
+disables the transmission of Router Discovery Advertisements
+.It Cm rdisc_adv
+specifies that Router Discovery advertisements should be sent,
+even on point-to-point links,
+which by default only listen to Router Discovery messages
+.It Cm bcast_rdisc
+specifies that Router Discovery packets should be broadcast instead of
+multicast.
+.It Cm rdisc_pref Ns \&= Ns Ar N
+sets the preference in Router Discovery Advertisements to the integer
+.Ar N .
+.It Cm rdisc_interval Ns \&= Ns Ar N
+sets the nominal interval with which Router Discovery Advertisements
+are transmitted to N seconds and their lifetime to 3*N.
+.It Cm fake_default Ns \&= Ns Ar metric
+has an identical effect to
+.Fl F Ar net[/mask][,metric]
+with the network and mask coming from the sepcified interface.
+.It Cm pm_rdisc
+is similar to
+.Cm fake_default .
+When RIPv2 routes are multicast, so that RIPv1 listeners cannot
+receive them, this feature causes a RIPv1 default route to be
+broadcast to RIPv1 listeners.
+Unless modified with
+.Cm fake_default ,
+the default route is broadcast with a metric of 14.
+That serves as a "poor man's router discovery" protocol.
+.El
+.Pp
+Note that the netmask associated with point-to-point links (such as SLIP
+or PPP, with the IFF_POINTOPOINT flag) is used by
+.Nm routed
+to infer the netmask used by the remote system when RIPv1 is used.
+.Pp
 .Sh FILES
 .Bl -tag -width /etc/gateways -compact
 .It Pa /etc/gateways
 for distant gateways
 .El
 .Sh SEE ALSO
+.Xr gated 8 ,
 .Xr udp 4 ,
 .Xr icmp 4 ,
-.Xr XNSrouted 8 ,
-.Xr htable 8
+.Xr htable 8 ,
+.Xr rtquery 8 .
 .Rs
 .%T Internet Transport Protocols
 .%R XSIS 028112
 .%Q Xerox System Integration Standard
 .Re
 .Sh BUGS
-The kernel's routing tables may not correspond to those of
-.Nm routed
-when redirects change or add routes.
-.Nm Routed
-should note any redirects received by reading
-the
-.Tn ICMP
-packets received via a raw socket.
-.Pp
-.Nm Routed
-should incorporate other routing protocols,
-such as Xerox
-.Tn \&NS
-.Pq Xr XNSrouted 8
-and
-.Tn EGP .
-Using separate processes for each requires configuration options
-to avoid redundant or competing routes.
-.Pp
-.Nm Routed
-should listen to intelligent interfaces, such as an
-.Tn IMP ,
-to gather more information.
 It does not always detect unidirectional failures in network interfaces
 (e.g., when the output side fails).
 .Sh HISTORY
diff --git a/sbin/routed/startup.c b/sbin/routed/startup.c
deleted file mode 100644 (file)
index 4129ec4..0000000
+++ /dev/null
@@ -1,531 +0,0 @@
-/*     $OpenBSD: startup.c,v 1.2 1996/06/23 14:32:31 deraadt Exp $     */
-/*     $NetBSD: startup.c,v 1.14 1995/06/20 22:27:56 christos Exp $    */
-
-/*
- * Copyright (c) 1983, 1988, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)startup.c  8.1 (Berkeley) 6/5/93";
-#else
-/*###40 [cc] warning: `rcsid' defined but not used%%%*/
-static char rcsid[] = "$OpenBSD: startup.c,v 1.2 1996/06/23 14:32:31 deraadt Exp $";
-#endif
-#endif /* not lint */
-
-/*
- * Routing Table Management Daemon
- */
-#include "defs.h"
-#include <sys/ioctl.h>
-#include <sys/sysctl.h>
-#include <net/if.h>
-#include <net/if_dl.h>
-#include <syslog.h>
-#include "pathnames.h"
-
-struct interface *ifnet;
-struct interface **ifnext = &ifnet;
-int    lookforinterfaces = 1;
-int    externalinterfaces = 0;         /* # of remote and local interfaces */
-int    foundloopback;                  /* valid flag for loopaddr */
-struct sockaddr loopaddr;              /* our address on loopback */
-
-void add_ptopt_localrt __P((struct interface *));
-int getnetorhostname __P((char *, char *, struct sockaddr_in *));
-int gethostnameornumber __P((char *, struct sockaddr_in *));
-
-void
-quit(s)
-       char *s;
-{
-       extern int errno;
-       int sverrno = errno;
-
-       (void) fprintf(stderr, "route: ");
-       if (s)
-               (void) fprintf(stderr, "%s: ", s);
-       (void) fprintf(stderr, "%s\n", strerror(sverrno));
-       exit(1);
-       /* NOTREACHED */
-}
-
-struct rt_addrinfo info;
-/* Sleazy use of local variables throughout file, warning!!!! */
-#define netmask        info.rti_info[RTAX_NETMASK]
-#define ifaaddr        info.rti_info[RTAX_IFA]
-#define brdaddr        info.rti_info[RTAX_BRD]
-
-#define ROUNDUP(a) \
-       ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
-
-void
-rt_xaddrs(cp, cplim, rtinfo)
-       register caddr_t cp, cplim;
-       register struct rt_addrinfo *rtinfo;
-{
-       register struct sockaddr *sa;
-       register int i;
-
-       memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
-       for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
-               if ((rtinfo->rti_addrs & (1 << i)) == 0)
-                       continue;
-               rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
-               ADVANCE(cp, sa);
-       }
-}
-
-/*
- * Find the network interfaces which have configured themselves.
- * If the interface is present but not yet up (for example an
- * ARPANET IMP), set the lookforinterfaces flag so we'll
- * come back later and look again.
- */
-void
-ifinit()
-{
-       struct interface ifs, *ifp;
-       size_t needed;
-       int mib[6], no_ipaddr = 0, flags = 0;
-       char *buf, *cplim, *cp;
-       register struct if_msghdr *ifm;
-       register struct ifa_msghdr *ifam;
-       struct sockaddr_dl *sdl = NULL;
-        struct sockaddr_in *sin;
-       u_long i;
-
-        mib[0] = CTL_NET;
-        mib[1] = PF_ROUTE;
-        mib[2] = 0;
-        mib[3] = AF_INET;
-        mib[4] = NET_RT_IFLIST;
-        mib[5] = 0;
-        if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
-                quit("route-sysctl-estimate");
-       if ((buf = malloc(needed)) == NULL)
-               quit("malloc");
-        if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
-               quit("actual retrieval of interface table");
-       lookforinterfaces = 0;
-       cplim = buf + needed;
-       for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) {
-               ifm = (struct if_msghdr *)cp;
-               if (ifm->ifm_type == RTM_IFINFO) {
-                       memset(&ifs, 0, sizeof(ifs));
-                       ifs.int_flags = flags = (0xffff & ifm->ifm_flags) | IFF_INTERFACE;
-                       if ((flags & IFF_UP) == 0 || no_ipaddr)
-                               lookforinterfaces = 1;
-                       sdl = (struct sockaddr_dl *) (ifm + 1);
-                       sdl->sdl_data[sdl->sdl_nlen] = 0;
-                       no_ipaddr = 1;
-                       continue;
-               }
-               if (ifm->ifm_type != RTM_NEWADDR)
-                       quit("ifinit: out of sync");
-               if ((flags & IFF_UP) == 0) {
-                       lookforinterfaces = 1;
-                       continue;
-               }
-               ifam = (struct ifa_msghdr *)ifm;
-               info.rti_addrs = ifam->ifam_addrs;
-               rt_xaddrs((char *)(ifam + 1), cp + ifam->ifam_msglen, &info);
-               if (ifaaddr == 0) {
-                       syslog(LOG_ERR, "%s: (get addr)", sdl->sdl_data);
-                       continue;
-               }
-               ifs.int_addr = *ifaaddr;
-               if (ifs.int_addr.sa_family != AF_INET)
-                       continue;
-               no_ipaddr = 0;
-               if (ifs.int_flags & IFF_POINTOPOINT) {
-                       if (brdaddr == 0) {
-                               syslog(LOG_ERR, "%s: (get dstaddr)",
-                                       sdl->sdl_data);
-                               continue;
-                       }
-                       if (brdaddr->sa_family == AF_UNSPEC) {
-                               lookforinterfaces = 1;
-                               continue;
-                       }
-                       ifs.int_dstaddr = *brdaddr;
-               }
-               /*
-                * already known to us?
-                * This allows multiple point-to-point links
-                * to share a source address (possibly with one
-                * other link), but assumes that there will not be
-                * multiple links with the same destination address.
-                */
-               if (ifs.int_flags & IFF_POINTOPOINT) {
-                       if (if_ifwithdstaddr(&ifs.int_dstaddr))
-                               continue;
-               } else if (if_ifwithaddr(&ifs.int_addr))
-                       continue;
-               if (ifs.int_flags & IFF_LOOPBACK) {
-                       ifs.int_flags |= IFF_PASSIVE;
-                       foundloopback = 1;
-                       loopaddr = ifs.int_addr;
-                       for (ifp = ifnet; ifp; ifp = ifp->int_next)
-                           if (ifp->int_flags & IFF_POINTOPOINT)
-                               add_ptopt_localrt(ifp);
-               }
-               if (ifs.int_flags & IFF_BROADCAST) {
-                       if (brdaddr == 0) {
-                               syslog(LOG_ERR, "%s: (get broadaddr)",
-                                       sdl->sdl_data);
-                               continue;
-                       }
-                       ifs.int_dstaddr = *brdaddr;
-               }
-               /*
-                * Use a minimum metric of one;
-                * treat the interface metric (default 0)
-                * as an increment to the hop count of one.
-                */
-               ifs.int_metric = ifam->ifam_metric + 1;
-               if (netmask == 0) {
-                               syslog(LOG_ERR, "%s: (get netmask)",
-                                       sdl->sdl_data);
-                               continue;
-               }
-               sin = (struct sockaddr_in *)netmask;
-               ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr);
-               sin = (struct sockaddr_in *)&ifs.int_addr;
-               i = ntohl(sin->sin_addr.s_addr);
-               if (IN_CLASSA(i))
-                       ifs.int_netmask = IN_CLASSA_NET;
-               else if (IN_CLASSB(i))
-                       ifs.int_netmask = IN_CLASSB_NET;
-               else
-                       ifs.int_netmask = IN_CLASSC_NET;
-               ifs.int_net = i & ifs.int_netmask;
-               ifs.int_subnet = i & ifs.int_subnetmask;
-               if (ifs.int_subnetmask != ifs.int_netmask)
-                       ifs.int_flags |= IFF_SUBNET;
-               ifp = (struct interface *)
-                       malloc(sdl->sdl_nlen + 1 + sizeof(ifs));
-               if (ifp == 0) {
-                       printf("routed: out of memory\n");
-                       lookforinterfaces = 1;
-                       break;
-               }
-               *ifp = ifs;
-               /*
-                * Count the # of directly connected networks
-                * and point to point links which aren't looped
-                * back to ourself.  This is used below to
-                * decide if we should be a routing ``supplier''.
-                */
-               if ((ifs.int_flags & IFF_LOOPBACK) == 0 &&
-                   ((ifs.int_flags & IFF_POINTOPOINT) == 0 ||
-                   if_ifwithaddr(&ifs.int_dstaddr) == 0))
-                       externalinterfaces++;
-               /*
-                * If we have a point-to-point link, we want to act
-                * as a supplier even if it's our only interface,
-                * as that's the only way our peer on the other end
-                * can tell that the link is up.
-                */
-               if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0)
-                       supplier = 1;
-               ifp->int_name = (char *)(ifp + 1);
-               strcpy(ifp->int_name, sdl->sdl_data);
-               *ifnext = ifp;
-               ifnext = &ifp->int_next;
-               traceinit(ifp);
-               addrouteforif(ifp);
-       }
-       if (externalinterfaces > 1 && supplier < 0)
-               supplier = 1;
-       free(buf);
-}
-
-/*
- * Add route for interface if not currently installed.
- * Create route to other end if a point-to-point link,
- * otherwise a route to this (sub)network.
- * INTERNET SPECIFIC.
- */
-void
-addrouteforif(ifp)
-       register struct interface *ifp;
-{
-       struct sockaddr_in net;
-       struct sockaddr *dst;
-       int state;
-       register struct rt_entry *rt;
-       struct sockaddr mask;
-
-       memset(&mask, 0, sizeof(mask));
-       if (ifp->int_flags & IFF_POINTOPOINT)
-               dst = &ifp->int_dstaddr;
-       else {
-               memset(&net, 0, sizeof (net));
-               net.sin_family = AF_INET;
-               net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY);
-               dst = (struct sockaddr *)&net;
-       }
-       rt = rtfind(dst);
-       if (rt &&
-           (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE)
-               return;
-       if (rt)
-               rtdelete(rt);
-       /*
-        * If interface on subnetted network,
-        * install route to network as well.
-        * This is meant for external viewers.
-        */
-       if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) {
-               struct in_addr subnet;
-
-               subnet = net.sin_addr;
-               net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
-               rt = rtfind(dst);
-               if (rt == 0)
-                       rtadd(dst, &ifp->int_addr, &mask, ifp->int_metric,
-                           ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) |
-                           RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET));
-               else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) == 
-                   (RTS_INTERNAL|RTS_SUBNET) &&
-                   ifp->int_metric < rt->rt_metric)
-                       rtchange(rt, &rt->rt_router, &mask, ifp->int_metric);
-               net.sin_addr = subnet;
-       }
-       if (ifp->int_transitions++ > 0)
-               syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
-       state = ifp->int_flags &
-           (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET);
-       if (ifp->int_flags & IFF_POINTOPOINT &&
-           (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) &
-           ifp->int_netmask) != ifp->int_net)
-               state &= ~RTS_SUBNET;
-       if (ifp->int_flags & IFF_LOOPBACK)
-               state |= RTS_EXTERNAL;
-       rtadd(dst, &ifp->int_addr, &mask, ifp->int_metric, state);
-       if (ifp->int_flags & IFF_POINTOPOINT && foundloopback)
-               add_ptopt_localrt(ifp);
-}
-
-/*
- * Add route to local end of point-to-point using loopback.
- * If a route to this network is being sent to neighbors on other nets,
- * mark this route as subnet so we don't have to propagate it too.
- */
-void
-add_ptopt_localrt(ifp)
-       register struct interface *ifp;
-{
-       struct rt_entry *rt;
-       struct sockaddr *dst;
-       struct sockaddr_in net;
-       int state;
-       struct sockaddr mask;
-
-       memset(&mask, 0, sizeof(mask));
-       state = RTS_INTERFACE | RTS_PASSIVE;
-
-       /* look for route to logical network */
-       memset(&net, 0, sizeof (net));
-       net.sin_family = AF_INET;
-       net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
-       dst = (struct sockaddr *)&net;
-       rt = rtfind(dst);
-       if (rt && rt->rt_state & RTS_INTERNAL)
-               state |= RTS_SUBNET;
-
-       dst = &ifp->int_addr;
-       if ((rt = rtfind(dst)) != NULL) {
-               if (rt && rt->rt_state & RTS_INTERFACE)
-                       return;
-               rtdelete(rt);
-       }
-       rtadd(dst, &loopaddr, &mask, 1, state);
-}
-
-/*
- * As a concession to the ARPANET we read a list of gateways
- * from /etc/gateways and add them to our tables.  This file
- * exists at each ARPANET gateway and indicates a set of ``remote''
- * gateways (i.e. a gateway which we can't immediately determine
- * if it's present or not as we can do for those directly connected
- * at the hardware level).  If a gateway is marked ``passive''
- * in the file, then we assume it doesn't have a routing process
- * of our design and simply assume it's always present.  Those
- * not marked passive are treated as if they were directly
- * connected -- they're added into the interface list so we'll
- * send them routing updates.
- *
- * PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP.
- */
-void
-gwkludge()
-{
-       struct sockaddr_in dst, gate;
-       FILE *fp;
-       char *type, *dname, *gname, *qual, buf[BUFSIZ];
-       struct interface *ifp;
-       int metric, n;
-       struct rt_entry route;
-       struct sockaddr mask;
-       memset(&mask, 0, sizeof(mask));
-
-
-       fp = fopen(_PATH_GATEWAYS, "r");
-       if (fp == NULL)
-               return;
-       qual = buf;
-       dname = buf + 64;
-       gname = buf + ((BUFSIZ - 64) / 3);
-       type = buf + (((BUFSIZ - 64) * 2) / 3);
-       memset(&dst, 0, sizeof (dst));
-       memset(&gate, 0, sizeof (gate));
-       memset(&route, 0, sizeof(route));
-/* format: {net | host} XX gateway XX metric DD [passive | external]\n */
-#define        readentry(fp) \
-       fscanf((fp), "%s %s gateway %s metric %d %s\n", \
-               type, dname, gname, &metric, qual)
-       for (;;) {
-               if ((n = readentry(fp)) == EOF)
-                       break;
-               if (!getnetorhostname(type, dname, &dst))
-                       continue;
-               if (!gethostnameornumber(gname, &gate))
-                       continue;
-               if (metric == 0)                        /* XXX */
-                       metric = 1;
-               if (strcmp(qual, "passive") == 0) {
-                       /*
-                        * Passive entries aren't placed in our tables,
-                        * only the kernel's, so we don't copy all of the
-                        * external routing information within a net.
-                        * Internal machines should use the default
-                        * route to a suitable gateway (like us).
-                        */
-                       route.rt_dst = *(struct sockaddr *) &dst;
-                       route.rt_router = *(struct sockaddr *) &gate;
-                       route.rt_flags = RTF_UP;
-                       if (strcmp(type, "host") == 0)
-                               route.rt_flags |= RTF_HOST;
-                       if (metric)
-                               route.rt_flags |= RTF_GATEWAY;
-                       (void) rtioctl(ADD, &route.rt_rt);
-                       continue;
-               }
-               if (strcmp(qual, "external") == 0) {
-                       /*
-                        * Entries marked external are handled
-                        * by other means, e.g. EGP,
-                        * and are placed in our tables only
-                        * to prevent overriding them
-                        * with something else.
-                        */
-                       rtadd((struct sockaddr *)&dst,
-                           (struct sockaddr *)&gate, &mask, metric,
-                           RTS_EXTERNAL|RTS_PASSIVE);
-                       continue;
-               }
-               /* assume no duplicate entries */
-               externalinterfaces++;
-               ifp = (struct interface *)malloc(sizeof (*ifp));
-               memset(ifp, 0, sizeof (*ifp));
-               ifp->int_flags = IFF_REMOTE;
-               /* can't identify broadcast capability */
-               ifp->int_net = inet_netof_subnet(dst.sin_addr);
-               if (strcmp(type, "host") == 0) {
-                       ifp->int_flags |= IFF_POINTOPOINT;
-                       ifp->int_dstaddr = *((struct sockaddr *)&dst);
-               }
-               ifp->int_addr = *((struct sockaddr *)&gate);
-               ifp->int_metric = metric;
-               ifp->int_next = ifnet;
-               ifnet = ifp;
-               addrouteforif(ifp);
-       }
-       fclose(fp);
-}
-
-int
-getnetorhostname(type, name, sin)
-       char *type, *name;
-       struct sockaddr_in *sin;
-{
-
-       if (strcmp(type, "net") == 0) {
-               struct netent *np = getnetbyname(name);
-               int n;
-
-               if (np == 0)
-                       n = inet_network(name);
-               else {
-                       if (np->n_addrtype != AF_INET)
-                               return (0);
-                       n = np->n_net;
-                       /*
-                        * getnetbyname returns right-adjusted value.
-                        */
-                       if (n < 128)
-                               n <<= IN_CLASSA_NSHIFT;
-                       else if (n < 65536)
-                               n <<= IN_CLASSB_NSHIFT;
-                       else
-                               n <<= IN_CLASSC_NSHIFT;
-               }
-               sin->sin_family = AF_INET;
-               sin->sin_addr = inet_makeaddr(n, INADDR_ANY);
-               return (1);
-       }
-       if (strcmp(type, "host") == 0)
-               return (gethostnameornumber(name, sin));
-       return (0);
-}
-
-int
-gethostnameornumber(name, sin)
-       char *name;
-       struct sockaddr_in *sin;
-{
-       struct hostent *hp;
-
-       if (inet_aton(name, &sin->sin_addr) == 0) {
-               hp = gethostbyname(name);
-               if (hp == 0)
-                       return (0);
-               memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
-               sin->sin_family = hp->h_addrtype;
-       } else
-               sin->sin_family = AF_INET;
-       return (1);
-}
diff --git a/sbin/routed/table.h b/sbin/routed/table.h
deleted file mode 100644 (file)
index 6b64b8a..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*     $OpenBSD: table.h,v 1.2 1996/06/23 14:32:32 deraadt Exp $       */
-/*     $NetBSD: table.h,v 1.7 1995/06/20 22:27:58 christos Exp $       */
-
-/*
- * Copyright (c) 1983, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *     @(#)table.h     8.1 (Berkeley) 6/5/93
- */
-
-/*
- * Routing table management daemon.
- */
-#include <sys/queue.h>
-/*
- * Routing table structure; differs a bit from kernel tables.
- *
- * Note: the union below must agree in the first 4 members
- * so the ioctl's will work.
- */
-#ifdef RTM_ADD
-#define rtentry ortentry
-#endif
-
-struct rt_entry {
-       CIRCLEQ_ENTRY(rt_entry) rt_entry;
-       union {
-               struct  rtentry rtu_rt;
-               struct rtuentry {
-                       u_long  rtu_hash;
-                       struct  sockaddr rtu_dst;
-                       struct  sockaddr rtu_router;
-                       struct  sockaddr rtu_netmask;
-                       short   rtu_rtflags; /* used by rtioctl */
-                       short   rtu_wasted[5];
-                       int     rtu_flags;
-                       int     rtu_state;
-                       int     rtu_timer;
-                       int     rtu_metric;
-                       int     rtu_ifmetric;
-                       struct  interface *rtu_ifp;
-               } rtu_entry;
-       } rt_rtu;
-};
-
-#define        rt_rt           rt_rtu.rtu_entry                /* pass to ioctl */
-#define        rt_hash         rt_rtu.rtu_entry.rtu_hash       /* for net or host */
-#define        rt_dst          rt_rtu.rtu_entry.rtu_dst        /* match value */
-#define        rt_router       rt_rtu.rtu_entry.rtu_router     /* who to forward to */
-#define        rt_netmask      rt_rtu.rtu_entry.rtu_netmask    /* mask for the route */
-#define        rt_flags        rt_rtu.rtu_entry.rtu_flags      /* kernel flags */
-#define        rt_timer        rt_rtu.rtu_entry.rtu_timer      /* for invalidation */
-#define        rt_state        rt_rtu.rtu_entry.rtu_state      /* see below */
-#define        rt_metric       rt_rtu.rtu_entry.rtu_metric     /* cost of route */
-#define        rt_ifmetric     rt_rtu.rtu_entry.rtu_ifmetric   /* cost of route if */
-#define        rt_ifp          rt_rtu.rtu_entry.rtu_ifp        /* interface to take */
-
-#define        ROUTEHASHSIZ    32              /* must be a power of 2 */
-#define        ROUTEHASHMASK   (ROUTEHASHSIZ - 1)
-
-/*
- * "State" of routing table entry.
- */
-#define        RTS_CHANGED     0x1             /* route has been altered recently */
-#define        RTS_EXTERNAL    0x2             /* extern info, not installed or sent */
-#define        RTS_INTERNAL    0x4             /* internal route, not installed */
-#define        RTS_PASSIVE     IFF_PASSIVE     /* don't time out route */
-#define        RTS_INTERFACE   IFF_INTERFACE   /* route is for network interface */
-#define        RTS_REMOTE      IFF_REMOTE      /* route is for ``remote'' entity */
-#define        RTS_SUBNET      IFF_SUBNET      /* route is for network subnet */
-
-/*
- * Flags are same as kernel, with this addition for af_rtflags:
- */
-#define        RTF_SUBNET      0x80000         /* pseudo: route to subnet */
-
-CIRCLEQ_HEAD(rthash, rt_entry);
-
-struct rthash nethash[ROUTEHASHSIZ];
-struct rthash hosthash[ROUTEHASHSIZ];
-
-struct rt_entry *rtlookup __P((struct sockaddr *));
-struct rt_entry *rtfind __P((struct sockaddr *));
-struct rthash *rthead __P((struct sockaddr *, u_int *, int *));
-void rtadd __P((struct sockaddr *, struct sockaddr *, struct sockaddr *,
-               int, int ));
-void rtchange __P((struct rt_entry *, struct sockaddr *, struct sockaddr *,
-                  int));
-void rtdelete __P((struct rt_entry *));
-void rtdeleteall __P((int));
-void rtdefault __P((void));
-void rtinit __P((void));
-int rtioctl __P((int, struct rtuentry *));
diff --git a/sbin/routed/tables.c b/sbin/routed/tables.c
deleted file mode 100644 (file)
index aae9e18..0000000
+++ /dev/null
@@ -1,496 +0,0 @@
-/*     $OpenBSD: tables.c,v 1.2 1996/06/23 14:32:33 deraadt Exp $      */
-/*     $NetBSD: tables.c,v 1.15 1995/06/20 22:27:59 christos Exp $     */
-
-/*
- * Copyright (c) 1983, 1988, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)tables.c   8.1 (Berkeley) 6/5/93";
-#else
-static char rcsid[] = "$OpenBSD: tables.c,v 1.2 1996/06/23 14:32:33 deraadt Exp $";
-#endif
-#endif /* not lint */
-
-/*
- * Routing Table Management Daemon
- */
-#include "defs.h"
-#include <sys/ioctl.h>
-#include <syslog.h>
-#include <errno.h>
-#include <search.h>
-
-#ifndef DEBUG
-#define        DEBUG   0
-#endif
-
-#ifdef RTM_ADD
-#define FIXLEN(s) {if ((s)->sa_len == 0) (s)->sa_len = sizeof *(s);}
-#else
-#define FIXLEN(s) { }
-#endif
-
-int    install = !DEBUG;               /* if 1 call kernel */
-
-/*
- * Lookup dst in the tables for an exact match.
- */
-struct rt_entry *
-rtlookup(dst)
-       struct sockaddr *dst;
-{
-       register struct rt_entry *rt;
-       register struct rthash *rh;
-       register u_int hash;
-       struct afhash h;
-       int doinghost = 1;
-
-       if (dst->sa_family >= af_max)
-               return (0);
-       (*afswitch[dst->sa_family].af_hash)(dst, &h);
-       hash = h.afh_hosthash;
-       rh = &hosthash[hash & ROUTEHASHMASK];
-again:
-       for (rt = rh->cqh_first; rt != (void *)rh; rt = rt->rt_entry.cqe_next) {
-               if (rt->rt_hash != hash)
-                       continue;
-               if (equal(&rt->rt_dst, dst))
-                       return (rt);
-       }
-       if (doinghost) {
-               doinghost = 0;
-               hash = h.afh_nethash;
-               rh = &nethash[hash & ROUTEHASHMASK];
-               goto again;
-       }
-       return (0);
-}
-
-struct sockaddr wildcard;      /* zero valued cookie for wildcard searches */
-
-/*
- * Find a route to dst as the kernel would.
- */
-struct rt_entry *
-rtfind(dst)
-       struct sockaddr *dst;
-{
-       register struct rt_entry *rt;
-       register struct rthash *rh;
-       register u_int hash;
-       struct afhash h;
-       int af = dst->sa_family;
-       int doinghost = 1,
-               (*match) __P((struct sockaddr *, struct sockaddr *)) = NULL;
-
-       if (af >= af_max)
-               return (0);
-       (*afswitch[af].af_hash)(dst, &h);
-       hash = h.afh_hosthash;
-       rh = &hosthash[hash & ROUTEHASHMASK];
-
-again:
-       for (rt = rh->cqh_first; rt != (void *)rh; rt = rt->rt_entry.cqe_next) {
-               if (rt->rt_hash != hash)
-                       continue;
-               if (doinghost) {
-                       if (equal(&rt->rt_dst, dst))
-                               return (rt);
-               } else {
-                       if (rt->rt_dst.sa_family == af && match &&
-                           (*match)(&rt->rt_dst, dst))
-                               return (rt);
-               }
-       }
-       if (doinghost) {
-               doinghost = 0;
-               hash = h.afh_nethash;
-               rh = &nethash[hash & ROUTEHASHMASK];
-               match = afswitch[af].af_netmatch;
-               goto again;
-       }
-#ifdef notyet
-       /*
-        * Check for wildcard gateway, by convention network 0.
-        */
-       if (dst != &wildcard) {
-               dst = &wildcard, hash = 0;
-               goto again;
-       }
-#endif
-       return (0);
-}
-
-struct rthash *
-rthead(dst, hashp, flagsp)
-       struct sockaddr *dst;
-       u_int *hashp;
-       int   *flagsp;
-{
-       struct afhash h;
-       int af = dst->sa_family;
-
-       if (af >= af_max)
-               return NULL;
-
-       (*afswitch[af].af_hash)(dst, &h);
-
-       *flagsp = (*afswitch[af].af_rtflags)(dst);
-
-       if (*flagsp & RTF_HOST) {
-               *hashp = h.afh_hosthash;
-               return &hosthash[*hashp & ROUTEHASHMASK];
-       } else {
-               *hashp = h.afh_nethash;
-               return &nethash[*hashp & ROUTEHASHMASK];
-       }
-}
-
-void
-rtadd(dst, gate, netmask, metric, state)
-       struct sockaddr *dst, *gate, *netmask;
-       int metric, state;
-{
-       register struct rt_entry *rt;
-       struct rthash *rh;
-       int flags;
-       u_int hash;
-       char buf1[256], buf2[256];
-
-       /*
-        * Subnet flag isn't visible to kernel, move to state.  XXX
-        */
-       FIXLEN(dst);
-       FIXLEN(gate);
-
-       rh = rthead(dst, &hash, &flags);
-
-       if (rh == NULL) {
-               syslog(LOG_ERR, "rtadd: Internal error finding route\n");
-               return;
-       }
-
-       if (flags & RTF_SUBNET) {
-               state |= RTS_SUBNET;
-               flags &= ~RTF_SUBNET;
-       }
-
-       rt = (struct rt_entry *)malloc(sizeof (*rt));
-       if (rt == 0)
-               return;
-       rt->rt_hash = hash;
-       rt->rt_dst = *dst;
-       rt->rt_router = *gate;
-       rt->rt_netmask = *netmask;
-       rt->rt_timer = 0;
-       rt->rt_flags = RTF_UP | flags;
-       rt->rt_state = state | RTS_CHANGED;
-       rt->rt_ifp = if_ifwithdstaddr(&rt->rt_dst);
-       if (rt->rt_ifp == 0)
-               rt->rt_ifp = if_ifwithnet(&rt->rt_router);
-       if ((state & RTS_INTERFACE) == 0)
-               rt->rt_flags |= RTF_GATEWAY;
-       rt->rt_metric = metric;
-       CIRCLEQ_INSERT_HEAD(rh, rt, rt_entry);
-       TRACE_ACTION("ADD", rt);
-       /*
-        * If the ioctl fails because the gateway is unreachable
-        * from this host, discard the entry.  This should only
-        * occur because of an incorrect entry in /etc/gateways.
-        */
-       if ((rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
-           rtioctl(ADD, &rt->rt_rt) < 0) {
-               if (errno != EEXIST && gate->sa_family < af_max)
-                       syslog(LOG_ERR,
-                       "adding route to net/host %s through gateway %s: %m\n",
-                          (*afswitch[dst->sa_family].af_format)(dst, buf1,
-                                                            sizeof(buf1)),
-                          (*afswitch[gate->sa_family].af_format)(gate, buf2,
-                                                             sizeof(buf2)));
-               perror("ADD ROUTE");
-               if (errno == ENETUNREACH) {
-                       TRACE_ACTION("DELETE", rt);
-                       CIRCLEQ_REMOVE(rh, rt, rt_entry);
-                       free((char *)rt);
-               }
-       }
-}
-
-void
-rtchange(rt, gate, netmask, metric)
-       struct rt_entry *rt;
-       struct sockaddr *gate;
-       struct sockaddr *netmask;
-       short metric;
-{
-       int add = 0, delete = 0, newgateway = 0;
-       struct rtuentry oldroute;
-
-       FIXLEN(gate);
-       FIXLEN(netmask);
-       FIXLEN(&(rt->rt_router));
-       FIXLEN(&(rt->rt_dst));
-       if (!equal(&rt->rt_router, gate)) {
-               newgateway++;
-               TRACE_ACTION("CHANGE FROM ", rt);
-       } else if (metric != rt->rt_metric)
-               TRACE_NEWMETRIC(rt, metric);
-       if ((rt->rt_state & RTS_INTERNAL) == 0) {
-               /*
-                * If changing to different router, we need to add
-                * new route and delete old one if in the kernel.
-                * If the router is the same, we need to delete
-                * the route if has become unreachable, or re-add
-                * it if it had been unreachable.
-                */
-               if (newgateway) {
-                       add++;
-                       if (rt->rt_metric != HOPCNT_INFINITY)
-                               delete++;
-               } else if (metric == HOPCNT_INFINITY)
-                       delete++;
-               else if (rt->rt_metric == HOPCNT_INFINITY)
-                       add++;
-       }
-       if (delete)
-               oldroute = rt->rt_rt;
-       if ((rt->rt_state & RTS_INTERFACE) && delete) {
-               rt->rt_state &= ~RTS_INTERFACE;
-               rt->rt_flags |= RTF_GATEWAY;
-               if (metric > rt->rt_metric && delete)
-                       syslog(LOG_ERR, "%s route to interface %s (timed out)",
-                           add? "changing" : "deleting",
-                           rt->rt_ifp ? rt->rt_ifp->int_name : "?");
-       }
-       if (add) {
-               rt->rt_router = *gate;
-               rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
-               if (rt->rt_ifp == 0)
-                       rt->rt_ifp = if_ifwithnet(&rt->rt_router);
-       }
-       rt->rt_netmask = *netmask;
-       rt->rt_metric = metric;
-       rt->rt_state |= RTS_CHANGED;
-       if (newgateway)
-               TRACE_ACTION("CHANGE TO   ", rt);
-#ifndef RTM_ADD
-       if (add && rtioctl(ADD, &rt->rt_rt) < 0)
-               perror("ADD ROUTE");
-       if (delete && rtioctl(DELETE, &oldroute) < 0)
-               perror("DELETE ROUTE");
-#else
-       if (delete && !add) {
-               if (rtioctl(DELETE, &oldroute) < 0)
-                       perror("DELETE ROUTE");
-       } else if (!delete && add) {
-               if (rtioctl(ADD, &rt->rt_rt) < 0)
-                       perror("ADD ROUTE");
-       } else if (delete && add) {
-               if (rtioctl(CHANGE, &rt->rt_rt) < 0)
-                       perror("CHANGE ROUTE");
-       }
-#endif
-}
-
-void
-rtdelete(rt)
-       struct rt_entry *rt;
-{
-       u_int hash;
-       int flags;
-       struct rthash *rh = rthead(&rt->rt_dst, &hash, &flags);
-
-       if (rh == NULL) {
-               syslog(LOG_ERR, "rtdelete: Internal error finding route\n");
-               return;
-       }
-
-       TRACE_ACTION("DELETE", rt);
-       FIXLEN(&(rt->rt_router));
-       FIXLEN(&(rt->rt_dst));
-       if (rt->rt_metric < HOPCNT_INFINITY) {
-           if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE)
-               syslog(LOG_ERR,
-                   "deleting route to interface %s? (timed out?)",
-                   rt->rt_ifp->int_name);
-           if ((rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
-                                           rtioctl(DELETE, &rt->rt_rt) < 0)
-                   perror("rtdelete");
-       }
-       CIRCLEQ_REMOVE(rh, rt, rt_entry);
-       free((char *)rt);
-}
-
-void
-rtdeleteall(sig)
-       int sig;
-{
-       register struct rthash *rh;
-       register struct rt_entry *rt;
-       struct rthash *base = hosthash;
-       int doinghost = 1;
-
-again:
-       for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
-               rt = rh->cqh_first;
-               for (; rt != (void *)rh; rt = rt->rt_entry.cqe_next) {
-                       if (rt->rt_state & RTS_INTERFACE ||
-                           rt->rt_metric >= HOPCNT_INFINITY)
-                               continue;
-                       TRACE_ACTION("DELETE", rt);
-                       if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 &&
-                           rtioctl(DELETE, &rt->rt_rt) < 0)
-                               perror("rtdeleteall");
-               }
-       }
-       if (doinghost) {
-               doinghost = 0;
-               base = nethash;
-               goto again;
-       }
-       exit(sig);
-}
-
-/*
- * If we have an interface to the wide, wide world,
- * add an entry for an Internet default route (wildcard) to the internal
- * tables and advertise it.  This route is not added to the kernel routes,
- * but this entry prevents us from listening to other people's defaults
- * and installing them in the kernel here.
- */
-void
-rtdefault()
-{
-       extern struct sockaddr inet_default;
-
-       rtadd(&inet_default, &inet_default, &inet_default, 1,
-               RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
-}
-
-void
-rtinit()
-{
-       register struct rthash *rh;
-
-       for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
-               CIRCLEQ_INIT(rh);
-       for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
-               CIRCLEQ_INIT(rh);
-}
-
-int
-rtioctl(action, ort)
-       int action;
-       struct rtuentry *ort;
-{
-#ifndef RTM_ADD
-       if (install == 0)
-               return (errno = 0);
-       ort->rtu_rtflags = ort->rtu_flags;
-       switch (action) {
-
-       case ADD:
-               return (ioctl(s, SIOCADDRT, (char *)ort));
-
-       case DELETE:
-               return (ioctl(s, SIOCDELRT, (char *)ort));
-
-       default:
-               return (-1);
-       }
-#else /* RTM_ADD */
-       struct {
-               struct rt_msghdr w_rtm;
-               struct sockaddr_in w_dst;
-               struct sockaddr w_gate;
-               struct sockaddr_in w_netmask;
-       } w;
-#define rtm w.w_rtm
-
-       memset(&w, 0, sizeof(w));
-       rtm.rtm_msglen = sizeof(w);
-       rtm.rtm_version = RTM_VERSION;
-       rtm.rtm_type = (action == ADD ? RTM_ADD :
-                               (action == DELETE ? RTM_DELETE : RTM_CHANGE));
-#undef rt_dst
-       rtm.rtm_flags = ort->rtu_flags;
-       rtm.rtm_seq = ++seqno;
-       rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
-       memcpy(&w.w_dst, &ort->rtu_dst, sizeof(w.w_dst));
-       memcpy(&w.w_gate, &ort->rtu_router, sizeof(w.w_gate));
-       memcpy(&w.w_netmask, &ort->rtu_netmask, sizeof(w.w_netmask));
-       w.w_dst.sin_family = AF_INET;
-       w.w_dst.sin_len = sizeof(w.w_dst);
-       w.w_gate.sa_family = AF_INET;
-       w.w_gate.sa_len = sizeof(w.w_gate);
-       if (rtm.rtm_flags & RTF_HOST) {
-               rtm.rtm_msglen -= sizeof(w.w_netmask);
-       } else {
-               register char *cp;
-               int len;
-
-               rtm.rtm_addrs |= RTA_NETMASK;
-               /*
-                * Check if we had a version 2 rip packet that sets the
-                * netmask, and otherwise set it to the default for
-                * the destination of the interface.
-                */
-               if (w.w_netmask.sin_family == AF_UNSPEC) {
-                       w.w_netmask.sin_addr.s_addr =
-                           inet_maskof(w.w_dst.sin_addr.s_addr);
-               }
-
-               for (cp = (char *)(1 + &w.w_netmask.sin_addr);
-                                   --cp > (char *) &w.w_netmask; )
-                       if (*cp)
-                               break;
-               len = cp - (char *)&w.w_netmask;
-               if (len) {
-                       len++;
-                       w.w_netmask.sin_len = len;
-                       len = 1 + ((len - 1) | (sizeof(long) - 1));
-               } else 
-                       len = sizeof(long);
-               rtm.rtm_msglen -= (sizeof(w.w_netmask) - len);
-       }
-#if 0
-       fprintf(stderr, "%s ", action == ADD ? "add" : (action == DELETE ? "delete" : "change"));
-       fprintf(stderr, "dst = %s, ", inet_ntoa(w.w_dst.sin_addr));
-       fprintf(stderr, "gate = %s, ", inet_ntoa(((struct sockaddr_in *) &w.w_gate)->sin_addr));
-       fprintf(stderr, "mask = %s\n", inet_ntoa(w.w_netmask.sin_addr));
-#endif
-       errno = 0;
-       return (install ? write(r, (char *)&w, rtm.rtm_msglen) : (errno = 0));
-#endif  /* RTM_ADD */
-}
diff --git a/sbin/routed/timer.c b/sbin/routed/timer.c
deleted file mode 100644 (file)
index 2430836..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/*     $OpenBSD: timer.c,v 1.2 1996/06/23 14:32:33 deraadt Exp $       */
-/*     $NetBSD: timer.c,v 1.8 1995/06/20 22:28:02 christos Exp $       */
-
-/*
- * Copyright (c) 1983, 1988, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)timer.c    8.1 (Berkeley) 6/5/93";
-#else
-static char rcsid[] = "$OpenBSD: timer.c,v 1.2 1996/06/23 14:32:33 deraadt Exp $";
-#endif
-#endif /* not lint */
-
-/*
- * Routing Table Management Daemon
- */
-#include "defs.h"
-
-int    faketime;
-
-/*
- * Timer routine.  Performs routing information supply
- * duties and manages timers on routing table entries.
- * Management of the RTS_CHANGED bit assumes that we broadcast
- * each time called.
- */
-void
-timer(sig)
-       int sig;
-{
-       register struct rthash *rh;
-       register struct rt_entry *rt;
-       struct rthash *base = hosthash;
-       int doinghost = 1, timetobroadcast;
-
-       (void) gettimeofday(&now, NULL);
-       faketime += TIMER_RATE;
-       if (lookforinterfaces && (faketime % CHECK_INTERVAL) == 0)
-               ifinit();
-       timetobroadcast = supplier && (faketime % SUPPLY_INTERVAL) == 0;
-again:
-       for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
-               rt = rh->cqh_first;
-               for (; rt != (void *)rh; rt = rt->rt_entry.cqe_next) {
-                       /*
-                        * We don't advance time on a routing entry for
-                        * a passive gateway, or any interface if we're
-                        * not acting as supplier.
-                        */
-                       if (!(rt->rt_state & RTS_PASSIVE) &&
-                           (supplier || !(rt->rt_state & RTS_INTERFACE)))
-                               rt->rt_timer += TIMER_RATE;
-                       if (rt->rt_timer >= GARBAGE_TIME) {
-                               rt = rt->rt_entry.cqe_prev;
-                               rtdelete(rt->rt_entry.cqe_next);
-                               continue;
-                       }
-                       if (rt->rt_timer >= EXPIRE_TIME &&
-                           rt->rt_metric < HOPCNT_INFINITY)
-                               rtchange(rt, &rt->rt_router, 
-                                        &rt->rt_netmask, HOPCNT_INFINITY);
-                       rt->rt_state &= ~RTS_CHANGED;
-               }
-       }
-       if (doinghost) {
-               doinghost = 0;
-               base = nethash;
-               goto again;
-       }
-       if (timetobroadcast) {
-               toall(supply, 0, NULL);
-               lastbcast = now;
-               lastfullupdate = now;
-               needupdate = 0;         /* cancel any pending dynamic update */
-               nextbcast.tv_sec = 0;
-       }
-}
-
-/*
- * On hangup, let everyone know we're going away.
- */
-void
-hup(sig)
-       int sig;
-{
-       register struct rthash *rh;
-       register struct rt_entry *rt;
-       struct rthash *base = hosthash;
-       int doinghost = 1;
-
-       if (supplier) {
-again:
-               for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
-                       rt = rh->cqh_first;
-                       for (; rt != (void *)rh; rt = rt->rt_entry.cqe_next)
-                               rt->rt_metric = HOPCNT_INFINITY;
-               }
-               if (doinghost) {
-                       doinghost = 0;
-                       base = nethash;
-                       goto again;
-               }
-               toall(supply, 0, NULL);
-       }
-       exit(1);
-}
index c419182..3d59264 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: trace.c,v 1.2 1996/06/23 14:32:34 deraadt Exp $       */
+/*     $OpenBSD: trace.c,v 1.3 1996/09/05 14:31:52 mickey Exp $        */
 /*     $NetBSD: trace.c,v 1.13 1995/06/20 22:28:03 christos Exp $      */
 
 /*
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-#if 0
+#if !defined(lint)
 static char sccsid[] = "@(#)trace.c    8.1 (Berkeley) 6/5/93";
 #else
-static char rcsid[] = "$OpenBSD: trace.c,v 1.2 1996/06/23 14:32:34 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: trace.c,v 1.3 1996/09/05 14:31:52 mickey Exp $";
 #endif
-#endif /* not lint */
 
-/*
- * Routing Table Management Daemon
- */
 #define        RIPCMDS
 #include "defs.h"
+#include "pathnames.h"
 #include <sys/stat.h>
-#include <signal.h>
+#include <sys/signal.h>
 #include <fcntl.h>
-#include "pathnames.h"
 
-#define        NRECORDS        50              /* size of circular trace buffer */
-#ifdef DEBUG
-FILE   *ftrace = stdout;
-int    traceactions = 0;
+
+#ifdef sgi
+/* use *stat64 for files on large filesystems */
+#define stat   stat64
 #endif
-static struct timeval lastlog;
-static char *savetracename;
 
-static int iftraceinit __P((struct interface *, struct ifdebug *));
-void dumpif __P((FILE *, struct interface *));
-void dumptrace __P((FILE *, char *, struct ifdebug *));
+#define        NRECORDS        50              /* size of circular trace buffer */
 
-void
-traceinit(ifp)
-       register struct interface *ifp;
+u_int  tracelevel, new_tracelevel;
+FILE   *ftrace = stdout;               /* output trace file */
+static char *tracelevel_pat = "%s\n";
+
+char savetracename[MAXPATHLEN+1];
+
+
+/* convert IP address to a string, but not into a single buffer
+ */
+char *
+naddr_ntoa(naddr a)
 {
-       if (iftraceinit(ifp, &ifp->int_input) &&
-           iftraceinit(ifp, &ifp->int_output))
-               return;
-       tracehistory = 0;
-       fprintf(stderr, "traceinit: can't init %s\n", ifp->int_name);
+#define NUM_BUFS 4
+       static int bufno;
+       static struct {
+           char    str[16];            /* xxx.xxx.xxx.xxx\0 */
+       } bufs[NUM_BUFS];
+       char *s;
+       struct in_addr addr;
+
+       addr.s_addr = a;
+       s = strcpy(bufs[bufno].str, inet_ntoa(addr));
+       bufno = (bufno+1) % NUM_BUFS;
+       return s;
+#undef NUM_BUFS
 }
 
-static int
-iftraceinit(ifp, ifd)
-       struct interface *ifp;
-       register struct ifdebug *ifd;
+
+char *
+saddr_ntoa(struct sockaddr *sa)
 {
-       register struct iftrace *t;
-
-       ifd->ifd_records =
-         (struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace));
-       if (ifd->ifd_records == 0)
-               return (0);
-       ifd->ifd_front = ifd->ifd_records;
-       ifd->ifd_count = 0;
-       for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
-               t->ift_size = 0;
-               t->ift_packet = 0;
-       }
-       ifd->ifd_if = ifp;
-       return (1);
+       return (sa == 0) ? "?" : naddr_ntoa(S_ADDR(sa));
+}
+
+
+static char *
+ts(time_t secs) {
+       static char s[20];
+
+       secs += epoch.tv_sec;
+#ifdef sgi
+       (void)cftime(s, "%T", &secs);
+#else
+       bcopy(ctime(&secs)+11, s, 8);
+       s[8] = '\0';
+#endif
+       return s;
 }
 
+
+/* On each event, display a time stamp.
+ * This assumes that 'now' is update once for each event, and
+ * that at least now.tv_usec changes.
+ */
 void
-traceon(file)
-       char *file;
+lastlog(void)
 {
-       struct stat stbuf;
+       static struct timeval last;
 
-       if (ftrace != NULL)
-               return;
-       if (stat(file, &stbuf) >= 0 && !S_ISREG(stbuf.st_mode))
-               return;
-       savetracename = file;
-       (void) gettimeofday(&now, NULL);
-       ftrace = fopen(file, "a");
-       if (ftrace == NULL)
-               return;
-       dup2(fileno(ftrace), 1);
-       dup2(fileno(ftrace), 2);
-       traceactions = 1;
-       fprintf(ftrace, "Tracing enabled %s\n", ctime((time_t *)&now.tv_sec));
+       if (last.tv_sec != now.tv_sec
+           || last.tv_usec != now.tv_usec) {
+               (void)fprintf(ftrace, "-- %s --\n", ts(now.tv_sec));
+               last = now;
+       }
 }
 
-void
-traceoff()
+
+static void
+tmsg(char *p, ...)
 {
-       if (!traceactions)
-               return;
-       if (ftrace != NULL) {
-               int fd = open(_PATH_DEVNULL, O_RDWR);
+       va_list args;
 
-               fprintf(ftrace, "Tracing disabled %s\n",
-                   ctime((time_t *)&now.tv_sec));
+       if (ftrace != 0) {
+               lastlog();
+               va_start(args, p);
+               vfprintf(ftrace, p, args);
                fflush(ftrace);
-               (void) dup2(fd, 1);
-               (void) dup2(fd, 2);
-               (void) close(fd);
+       }
+}
+
+
+static void
+trace_close(void)
+{
+       int fd;
+
+
+       fflush(stdout);
+       fflush(stderr);
+
+       if (ftrace != 0
+           && savetracename[0] != '\0') {
+               fd = open(_PATH_DEVNULL, O_RDWR);
+               (void)dup2(fd, STDOUT_FILENO);
+               (void)dup2(fd, STDERR_FILENO);
+               (void)close(fd);
                fclose(ftrace);
-               ftrace = NULL;
+               ftrace = 0;
        }
-       traceactions = 0;
-       tracehistory = 0;
-       tracepackets = 0;
-       tracecontents = 0;
 }
 
+
 void
-sigtrace(s)
-       int s;
+trace_flush(void)
 {
-
-       if (s == SIGUSR2)
-               traceoff();
-       else if (ftrace == NULL && savetracename)
-               traceon(savetracename);
-       else
-               bumploglevel();
+       if (ftrace != 0) {
+               fflush(ftrace);
+               if (ferror(ftrace))
+                       trace_off("tracing off: ", strerror(ferror(ftrace)));
+       }
 }
 
-/*
- * Move to next higher level of tracing when -t option processed or
- * SIGUSR1 is received.  Successive levels are:
- *     traceactions
- *     traceactions + tracepackets
- *     traceactions + tracehistory (packets and contents after change)
- *     traceactions + tracepackets + tracecontents
- */
+
 void
-bumploglevel()
+trace_off(char *p, ...)
 {
+       va_list args;
 
-       (void) gettimeofday(&now, NULL);
-       if (traceactions == 0) {
-               traceactions++;
-               if (ftrace)
-                       fprintf(ftrace, "Tracing actions started %s\n",
-                           ctime((time_t *)&now.tv_sec));
-       } else if (tracepackets == 0) {
-               tracepackets++;
-               tracehistory = 0;
-               tracecontents = 0;
-               if (ftrace)
-                       fprintf(ftrace, "Tracing packets started %s\n",
-                           ctime((time_t *)&now.tv_sec));
-       } else if (tracehistory == 0) {
-               tracehistory++;
-               if (ftrace)
-                       fprintf(ftrace, "Tracing history started %s\n",
-                           ctime((time_t *)&now.tv_sec));
-       } else {
-               tracepackets++;
-               tracecontents++;
-               tracehistory = 0;
-               if (ftrace)
-                       fprintf(ftrace, "Tracing packet contents started %s\n",
-                           ctime((time_t *)&now.tv_sec));
-       }
-       if (ftrace)
+
+       if (ftrace != 0) {
+               lastlog();
+               va_start(args, p);
+               vfprintf(ftrace, p, args);
                fflush(ftrace);
+       }
+       trace_close();
+
+       new_tracelevel = tracelevel = 0;
 }
 
+
 void
-trace(ifd, who, p, len, m)
-       register struct ifdebug *ifd;
-       struct sockaddr *who;
-       char *p;
-       int len, m;
+trace_on(char *filename,
+        int trusted)
 {
-       register struct iftrace *t;
+       struct stat stbuf;
+       FILE *n_ftrace;
+
+
+       /* Given a null filename when tracing is already on, increase the
+        * debugging level and re-open the file in case it has been unlinked.
+        */
+       if (filename[0] == '\0') {
+               if (tracelevel != 0) {
+                       new_tracelevel++;
+                       tracelevel_pat = "trace command: %s\n";
+               } else if (savetracename[0] == '\0') {
+                       msglog("missing trace file name");
+                       return;
+               }
+               filename = savetracename;
 
-       if (ifd->ifd_records == 0)
-               return;
-       t = ifd->ifd_front++;
-       if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
-               ifd->ifd_front = ifd->ifd_records;
-       if (ifd->ifd_count < NRECORDS)
-               ifd->ifd_count++;
-       if (t->ift_size > 0 && t->ift_size < len && t->ift_packet) {
-               free(t->ift_packet);
-               t->ift_packet = 0;
+       } else if (stat(filename, &stbuf) >= 0) {
+               if (!trusted) {
+                       msglog("trace file \"%s\" already exists");
+                       return;
+               }
+               if ((stbuf.st_mode & S_IFMT) != S_IFREG) {
+                       msglog("wrong type (%#x) of trace file \"%s\"",
+                              stbuf.st_mode, filename);
+                       return;
+               }
+
+               if (!trusted
+                   && strcmp(filename, savetracename)
+                   && strncmp(filename, _PATH_TRACE, sizeof(_PATH_TRACE)-1)) {
+                       msglog("wrong directory for trace file: \"%s\"",
+                              filename);
+                       return;
+               }
        }
-       t->ift_stamp = now;
-       t->ift_who = *who;
-       if (len > 0 && t->ift_packet == 0) {
-               t->ift_packet = malloc(len);
-               if (t->ift_packet == 0)
-                       len = 0;
+
+       n_ftrace = fopen(filename, "a");
+       if (n_ftrace == 0) {
+               msglog("failed to open trace file \"%s\" %s",
+                      filename, strerror(errno));
+               return;
        }
-       if (len > 0)
-               memcpy(t->ift_packet, p, len);
-       t->ift_size = len;
-       t->ift_metric = m;
+
+       tmsg("switch to trace file %s\n", filename);
+       trace_close();
+       if (filename != savetracename)
+               strncpy(savetracename, filename, sizeof(savetracename)-1);
+       ftrace = n_ftrace;
+
+       fflush(stdout);
+       fflush(stderr);
+       dup2(fileno(ftrace), STDOUT_FILENO);
+       dup2(fileno(ftrace), STDERR_FILENO);
+
+       if (new_tracelevel == 0)
+               new_tracelevel = 1;
+       set_tracelevel();
 }
 
+
+/* ARGSUSED */
 void
-traceaction(fd, action, rt)
-       FILE *fd;
-       char *action;
-       struct rt_entry *rt;
+sigtrace_on(int s)
 {
-       struct sockaddr_in *dst, *gate, *netmask;
-       static struct bits {
-               int     t_bits;
-               char    *t_name;
-       } flagbits[] = {
-               { RTF_UP,       "UP" },
-               { RTF_GATEWAY,  "GATEWAY" },
-               { RTF_HOST,     "HOST" },
-               { 0 }
-       }, statebits[] = {
-               { RTS_PASSIVE,  "PASSIVE" },
-               { RTS_REMOTE,   "REMOTE" },
-               { RTS_INTERFACE,"INTERFACE" },
-               { RTS_CHANGED,  "CHANGED" },
-               { RTS_INTERNAL, "INTERNAL" },
-               { RTS_EXTERNAL, "EXTERNAL" },
-               { RTS_SUBNET,   "SUBNET" },
-               { 0 }
+       new_tracelevel++;
+       tracelevel_pat = "SIGUSR1: %s\n";
+}
+
+
+/* ARGSUSED */
+void
+sigtrace_off(int s)
+{
+       new_tracelevel--;
+       tracelevel_pat = "SIGUSR2: %s\n";
+}
+
+
+/* Move to next higher level of tracing when -t option processed or
+ * SIGUSR1 is received.  Successive levels are:
+ *     actions
+ *     actions + packets
+ *     actions + packets + contents
+ */
+void
+set_tracelevel(void)
+{
+       static char *off_msgs[MAX_TRACELEVEL] = {
+               "Tracing actions stopped",
+               "Tracing packets stopped",
+               "Tracing packet contents stopped",
+               "Tracing kernel changes stopped",
+       };
+       static char *on_msgs[MAX_TRACELEVEL] = {
+               "Tracing actions started",
+               "Tracing packets started",
+               "Tracing packet contents started",
+               "Tracing kernel changes started",
        };
-       register struct bits *p;
-       register int first;
-       char *cp;
 
-       if (fd == NULL)
-               return;
-       if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
-               fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
-               lastlog = now;
+
+       if (new_tracelevel > MAX_TRACELEVEL) {
+               new_tracelevel = MAX_TRACELEVEL;
+               if (new_tracelevel == tracelevel) {
+                       tmsg(tracelevel_pat, on_msgs[tracelevel-1]);
+                       return;
+               }
+       }
+       while (new_tracelevel != tracelevel) {
+               if (new_tracelevel < tracelevel) {
+                       if (--tracelevel == 0)
+                               trace_off(tracelevel_pat, off_msgs[0]);
+                       else
+                               tmsg(tracelevel_pat, off_msgs[tracelevel]);
+               } else {
+                       if (ftrace == 0) {
+                               if (savetracename[0] != '\0')
+                                       trace_on(savetracename, 1);
+                               else
+                                       ftrace = stdout;
+                       }
+                       tmsg(tracelevel_pat, on_msgs[tracelevel++]);
+               }
        }
-       fprintf(fd, "%s ", action);
-       dst = (struct sockaddr_in *)&rt->rt_dst;
-       gate = (struct sockaddr_in *)&rt->rt_router;
-       netmask = (struct sockaddr_in *)&rt->rt_netmask;
-       fprintf(fd, "dst %s, ", inet_ntoa(dst->sin_addr));
-       fprintf(fd, "router %s, ", inet_ntoa(gate->sin_addr));
-       fprintf(fd, " netmask %s, metric %d, flags",
-               inet_ntoa(netmask->sin_addr), rt->rt_metric);
-       cp = " %s";
-       for (first = 1, p = flagbits; p->t_bits > 0; p++) {
-               if ((rt->rt_flags & p->t_bits) == 0)
-                       continue;
-               fprintf(fd, cp, p->t_name);
-               if (first) {
-                       cp = "|%s";
-                       first = 0;
+       tracelevel_pat = "%s\n";
+}
+
+
+/* display an address
+ */
+char *
+addrname(naddr addr,                   /* in network byte order */
+        naddr  mask,
+        int    force)                  /* 0=show mask if nonstandard, */
+{                                      /*      1=always show mask, 2=never */
+#define NUM_BUFS 4
+       static int bufno;
+       static struct {
+           char    str[15+20];
+       } bufs[NUM_BUFS];
+       char *s, *sp;
+       naddr dmask;
+       int i;
+
+       s = strcpy(bufs[bufno].str, naddr_ntoa(addr));
+       bufno = (bufno+1) % NUM_BUFS;
+
+       if (force == 1 || (force == 0 && mask != std_mask(addr))) {
+               sp = &s[strlen(s)];
+
+               dmask = mask & -mask;
+               if (mask + dmask == 0) {
+                       for (i = 0; i != 32 && ((1<<i) & mask) == 0; i++)
+                               continue;
+                       (void)sprintf(sp, "/%d", 32-i);
+
+               } else {
+                       (void)sprintf(sp, " (mask %#x)", (u_int)mask);
                }
        }
-       fprintf(fd, " state");
-       cp = " %s";
-       for (first = 1, p = statebits; p->t_bits > 0; p++) {
-               if ((rt->rt_state & p->t_bits) == 0)
-                       continue;
-               fprintf(fd, cp, p->t_name);
-               if (first) {
-                       cp = "|%s";
-                       first = 0;
+
+       return s;
+#undef NUM_BUFS
+}
+
+
+/* display a bit-field
+ */
+struct bits {
+       int     bits_mask;
+       int     bits_clear;
+       char    *bits_name;
+};
+
+static struct bits if_bits[] = {
+       { IFF_LOOPBACK,         0,              "LOOPBACK" },
+       { IFF_POINTOPOINT,      0,              "PT-TO-PT" },
+       { 0,                    0,              0}
+};
+
+static struct bits is_bits[] = {
+       { IS_SUBNET,            0,              "" },
+       { IS_REMOTE,            0,              "REMOTE" },
+       { IS_PASSIVE,           (IS_NO_RDISC
+                                | IS_BCAST_RDISC
+                                | IS_NO_RIP
+                                | IS_NO_SUPER_AG
+                                | IS_PM_RDISC
+                                | IS_NO_AG),   "PASSIVE" },
+       { IS_EXTERNAL,          0,              "EXTERNAL" },
+       { IS_CHECKED,           0,              "" },
+       { IS_ALL_HOSTS,         0,              "" },
+       { IS_ALL_ROUTERS,       0,              "" },
+       { IS_RIP_QUERIED,       0,              "" },
+       { IS_BROKE,             IS_SICK,        "BROKEN" },
+       { IS_SICK,              0,              "SICK" },
+       { IS_ACTIVE,            0,              "ACTIVE" },
+       { IS_NEED_NET_SYN,      0,              "" },
+       { IS_NO_AG,             IS_NO_SUPER_AG, "NO_AG" },
+       { IS_NO_SUPER_AG,       0,              "NO_SUPER_AG" },
+       { (IS_NO_RIPV1_IN
+          | IS_NO_RIPV2_IN
+          | IS_NO_RIPV1_OUT
+          | IS_NO_RIPV2_OUT),  0,              "NO_RIP" },
+       { (IS_NO_RIPV1_IN
+          | IS_NO_RIPV1_OUT),  0,              "RIPV2" },
+       { IS_NO_RIPV1_IN,       0,              "NO_RIPV1_IN" },
+       { IS_NO_RIPV2_IN,       0,              "NO_RIPV2_IN" },
+       { IS_NO_RIPV1_OUT,      0,              "NO_RIPV1_OUT" },
+       { IS_NO_RIPV2_OUT,      0,              "NO_RIPV2_OUT" },
+       { (IS_NO_ADV_IN
+          | IS_NO_SOL_OUT
+          | IS_NO_ADV_OUT),    IS_BCAST_RDISC, "NO_RDISC" },
+       { IS_NO_SOL_OUT,        0,              "NO_SOLICIT" },
+       { IS_SOL_OUT,           0,              "SEND_SOLICIT" },
+       { IS_NO_ADV_OUT,        IS_BCAST_RDISC, "NO_RDISC_ADV" },
+       { IS_ADV_OUT,           0,              "RDISC_ADV" },
+       { IS_BCAST_RDISC,       0,              "BCAST_RDISC" },
+       { IS_PM_RDISC,          0,              "PM_RDISC" },
+       { 0,                    0,              "%#x"}
+};
+
+static struct bits rs_bits[] = {
+       { RS_IF,                0,              "IF" },
+       { RS_NET_INT,           RS_NET_SYN,     "NET_INT" },
+       { RS_NET_SYN,           0,              "NET_SYN" },
+       { RS_SUBNET,            0,              "" },
+       { RS_LOCAL,             0,              "LOCAL" },
+       { RS_MHOME,             0,              "MHOME" },
+       { RS_STATIC,            0,              "STATIC" },
+       { RS_RDISC,             0,              "RDISC" },
+       { 0,                    0,              "%#x"}
+};
+
+
+static void
+trace_bits(struct bits *tbl,
+          u_int field,
+          int force)
+{
+       int b;
+       char c;
+
+       if (force) {
+               (void)putc('<', ftrace);
+               c = 0;
+       } else {
+               c = '<';
+       }
+
+       while (field != 0
+              && (b = tbl->bits_mask) != 0) {
+               if ((b & field) == b) {
+                       if (tbl->bits_name[0] != '\0') {
+                               if (c)
+                                       (void)putc(c, ftrace);
+                               (void)fprintf(ftrace, "%s", tbl->bits_name);
+                               c = '|';
+                       }
+                       if (0 == (field &= ~(b | tbl->bits_clear)))
+                               break;
                }
+               tbl++;
+       }
+       if (field != 0 && tbl->bits_name != 0) {
+               if (c)
+                       (void)putc(c, ftrace);
+               (void)fprintf(ftrace, tbl->bits_name, field);
+               c = '|';
        }
-       fprintf(fd, " timer %d\n", rt->rt_timer);
-       if (tracehistory && !tracepackets &&
-           (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
-               dumpif(fd, rt->rt_ifp);
-       fflush(fd);
-       if (ferror(fd))
-               traceoff();
+
+       if (c != '<' || force)
+               (void)fputs("> ", ftrace);
+}
+
+
+static char *
+trace_pair(naddr dst,
+          naddr mask,
+          char *gate)
+{
+       static char buf[3*4+3+1+2+3     /* "xxx.xxx.xxx.xxx/xx-->" */
+                       +3*4+3+1];      /* "xxx.xxx.xxx.xxx" */
+       int i;
+
+       i = sprintf(buf, "%-16s-->", addrname(dst, mask, 0));
+       (void)sprintf(&buf[i], "%-*s", 15+20-MAX(20,i), gate);
+       return buf;
 }
 
+
 void
-tracenewmetric(fd, rt, newmetric)
-       FILE *fd;
-       struct rt_entry *rt;
-       int newmetric;
+trace_if(char *act,
+         struct interface *ifp)
 {
-       struct sockaddr_in *dst, *gate;
+       if (!TRACEACTIONS || ftrace == 0)
+               return;
 
-       if (fd == NULL)
+       lastlog();
+       (void)fprintf(ftrace, "%s interface %-4s ", act, ifp->int_name);
+       (void)fprintf(ftrace, "%-15s-->%-15s ",
+                     naddr_ntoa(ifp->int_addr),
+                     addrname(htonl((ifp->int_if_flags & IFF_POINTOPOINT)
+                                    ? ifp->int_dstaddr
+                                    : ifp->int_net),
+                              ifp->int_mask, 1));
+       if (ifp->int_metric != 0)
+               (void)fprintf(ftrace, "metric=%d ", ifp->int_metric);
+       trace_bits(if_bits, ifp->int_if_flags, 0);
+       trace_bits(is_bits, ifp->int_state, 0);
+       (void)fputc('\n',ftrace);
+}
+
+
+void
+trace_upslot(struct rt_entry *rt,
+            struct rt_spare *rts,
+            naddr      gate,
+            naddr      router,
+            struct interface *ifp,
+            int        metric,
+            u_short    tag,
+            time_t     new_time)
+{
+       if (!TRACEACTIONS || ftrace == 0)
+               return;
+       if (rts->rts_gate == gate
+           && rts->rts_router == router
+           && rts->rts_metric == metric
+           && rts->rts_tag == tag)
                return;
-       if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
-               fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
-               lastlog = now;
+
+       lastlog();
+       if (rts->rts_gate != RIP_DEFAULT) {
+               (void)fprintf(ftrace, "Chg #%d %-35s ",
+                             rts - rt->rt_spares,
+                             trace_pair(rt->rt_dst, rt->rt_mask,
+                                        naddr_ntoa(rts->rts_gate)));
+               if (rts->rts_gate != rts->rts_gate)
+                       (void)fprintf(ftrace, "router=%s ",
+                                     naddr_ntoa(rts->rts_gate));
+               if (rts->rts_tag != 0)
+                       (void)fprintf(ftrace, "tag=%#x ", ntohs(rts->rts_tag));
+               (void)fprintf(ftrace, "metric=%-2d ", rts->rts_metric);
+               if (rts->rts_ifp != 0)
+                       (void)fprintf(ftrace, "%s ",
+                                     rts->rts_ifp->int_name);
+               (void)fprintf(ftrace, "%s\n", ts(rts->rts_time));
+
+               (void)fprintf(ftrace, "       %19s%-16s ",
+                             "",
+                             gate != rts->rts_gate ? naddr_ntoa(gate) : "");
+               if (gate != router)
+                       (void)fprintf(ftrace,"router=%s ",naddr_ntoa(router));
+               if (tag != rts->rts_tag)
+                       (void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
+               if (metric != rts->rts_metric)
+                       (void)fprintf(ftrace, "metric=%-2d ", metric);
+               if (ifp != rts->rts_ifp && ifp != 0 )
+                       (void)fprintf(ftrace, "%s ", ifp->int_name);
+               (void)fprintf(ftrace, "%s\n",
+                             new_time != rts->rts_time ? ts(new_time) : "");
+
+       } else {
+               (void)fprintf(ftrace, "Add #%d %-35s ",
+                             rts - rt->rt_spares,
+                             trace_pair(rt->rt_dst, rt->rt_mask,
+                                        naddr_ntoa(gate)));
+               if (gate != router)
+                       (void)fprintf(ftrace, "router=%s ", naddr_ntoa(gate));
+               if (tag != 0)
+                       (void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
+               (void)fprintf(ftrace, "metric=%-2d ", metric);
+               if (ifp != 0)
+                       (void)fprintf(ftrace, "%s ", ifp->int_name);
+               (void)fprintf(ftrace, "%s\n", ts(new_time));
        }
-       dst = (struct sockaddr_in *)&rt->rt_dst;
-       gate = (struct sockaddr_in *)&rt->rt_router;
-       fprintf(fd, "CHANGE metric dst %s, ", inet_ntoa(dst->sin_addr));
-       fprintf(fd, "router %s, from %d to %d\n",
-            inet_ntoa(gate->sin_addr), rt->rt_metric, newmetric);
-       fflush(fd);
-       if (ferror(fd))
-               traceoff();
 }
 
+
+/* talk about a change made to the kernel table
+ */
 void
-dumpif(fd, ifp)
-       FILE *fd;
-       register struct interface *ifp;
+trace_kernel(char *p, ...)
 {
-       if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
-               fprintf(fd, "*** Packet history for interface %s ***\n",
-                       ifp->int_name);
-#ifdef notneeded
-               dumptrace(fd, "to", &ifp->int_output);
-#endif
-               dumptrace(fd, "from", &ifp->int_input);
-               fprintf(fd, "*** end packet history ***\n");
-       }
+       va_list args;
+
+       if (!TRACEKERNEL || ftrace == 0)
+               return;
+
+       lastlog();
+       va_start(args, p);
+       vfprintf(ftrace, p, args);
 }
 
+
+/* display a message if tracing actions
+ */
 void
-dumptrace(fd, dir, ifd)
-       FILE *fd;
-       char *dir;
-       register struct ifdebug *ifd;
+trace_act(char *p, ...)
 {
-       register struct iftrace *t;
-       char *cp = !strcmp(dir, "to") ? "Output" : "Input";
+       va_list args;
 
-       if (ifd->ifd_front == ifd->ifd_records &&
-           ifd->ifd_front->ift_size == 0) {
-               fprintf(fd, "%s: no packets.\n", cp);
-               fflush(fd);
+       if (!TRACEACTIONS || ftrace == 0)
                return;
-       }
-       fprintf(fd, "%s trace:\n", cp);
-       t = ifd->ifd_front - ifd->ifd_count;
-       if (t < ifd->ifd_records)
-               t += NRECORDS;
-       for ( ; ifd->ifd_count; ifd->ifd_count--, t++) {
-               if (t >= ifd->ifd_records + NRECORDS)
-                       t = ifd->ifd_records;
-               if (t->ift_size == 0)
-                       continue;
-               dumppacket(fd, dir, (struct sockaddr_in *)&t->ift_who,
-                   t->ift_packet, t->ift_size, &t->ift_stamp);
-       }
+
+       lastlog();
+       va_start(args, p);
+       vfprintf(ftrace, p, args);
 }
 
+
+/* display a message if tracing packets
+ */
 void
-dumppacket(fd, dir, who, cp, size, stamp)
-       FILE *fd;
-       struct sockaddr_in *who;                /* should be sockaddr */
-       char *dir, *cp;
-       register int size;
-       struct timeval *stamp;
+trace_pkt(char *p, ...)
 {
-       register struct rip *msg = (struct rip *)cp;
-       register struct netinfo *n;
+       va_list args;
 
-       if (fd == NULL)
+       if (!TRACEPACKETS || ftrace == 0)
                return;
-       if (msg->rip_cmd && msg->rip_cmd < RIPCMD_MAX)
-               fprintf(fd, "%s %s %s.%d %.19s:\n", ripcmds[msg->rip_cmd],
-                   dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port),
-                   ctime((time_t *)&stamp->tv_sec));
-       else {
-               fprintf(fd, "Bad cmd 0x%x %s %s.%d %.19s\n", msg->rip_cmd,
-                   dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port),
-                   ctime((time_t *)&stamp->tv_sec));
-               fprintf(fd, "size=%d cp=%lx packet=%lx\n", size,
-                       (u_long) cp, (u_long) packet);
-               fflush(fd);
+
+       lastlog();
+       va_start(args, p);
+       vfprintf(ftrace, p, args);
+}
+
+
+void
+trace_change(struct rt_entry *rt,
+            u_int      state,
+            naddr      gate,           /* forward packets here */
+            naddr      router,         /* on the authority of this router */
+            int        metric,
+            u_short    tag,
+            struct interface *ifp,
+            time_t     new_time,
+            char       *label)
+{
+       if (ftrace == 0)
                return;
-       }
-       if (tracepackets && tracecontents == 0) {
-               fflush(fd);
+
+       if (rt->rt_metric == metric
+           && rt->rt_gate == gate
+           && rt->rt_router == router
+           && rt->rt_state == state
+           && rt->rt_tag == tag)
+               return;
+
+       lastlog();
+       (void)fprintf(ftrace, "%s %-35s metric=%-2d ",
+                     label,
+                     trace_pair(rt->rt_dst, rt->rt_mask,
+                                naddr_ntoa(rt->rt_gate)),
+                     rt->rt_metric);
+       if (rt->rt_router != rt->rt_gate)
+               (void)fprintf(ftrace, "router=%s ",
+                             naddr_ntoa(rt->rt_router));
+       if (rt->rt_tag != 0)
+               (void)fprintf(ftrace, "tag=%#x ", ntohs(rt->rt_tag));
+       trace_bits(rs_bits, rt->rt_state, rt->rt_state != state);
+       (void)fprintf(ftrace, "%s ",
+                     rt->rt_ifp == 0 ? "?" : rt->rt_ifp->int_name);
+       (void)fprintf(ftrace, "%s\n",
+                     AGE_RT(rt->rt_state, rt->rt_ifp) ? ts(rt->rt_time) : "");
+
+       (void)fprintf(ftrace, "%*s %19s%-16s ",
+                     strlen(label), "", "",
+                     rt->rt_gate != gate ? naddr_ntoa(gate) : "");
+       if (rt->rt_metric != metric)
+               (void)fprintf(ftrace, "metric=%-2d ", metric);
+       if (router != gate)
+               (void)fprintf(ftrace, "router=%s ", naddr_ntoa(router));
+       if (rt->rt_tag != tag)
+               (void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
+       if (rt->rt_state != state)
+               trace_bits(rs_bits, state, 1);
+       if (rt->rt_ifp != ifp)
+               (void)fprintf(ftrace, "%s ",
+                             ifp != 0 ? ifp->int_name : "?");
+       (void)fprintf(ftrace, "%s\n",
+                     ((rt->rt_time == new_time || !AGE_RT(rt->rt_state, ifp))
+                      ? "" : ts(new_time)));
+}
+
+
+void
+trace_add_del(char * action, struct rt_entry *rt)
+{
+       u_int state = rt->rt_state;
+
+       if (ftrace == 0)
+               return;
+
+       lastlog();
+       (void)fprintf(ftrace, "%s    %-35s metric=%-2d ",
+                     action,
+                     trace_pair(rt->rt_dst, rt->rt_mask,
+                                naddr_ntoa(rt->rt_gate)),
+                     rt->rt_metric);
+       if (rt->rt_router != rt->rt_gate)
+               (void)fprintf(ftrace, "router=%s ",
+                             naddr_ntoa(rt->rt_router));
+       if (rt->rt_tag != 0)
+               (void)fprintf(ftrace, "tag=%#x ", ntohs(rt->rt_tag));
+       trace_bits(rs_bits, state, 0);
+       (void)fprintf(ftrace, "%s ",
+                     rt->rt_ifp != 0 ? rt->rt_ifp->int_name : "?");
+       (void)fprintf(ftrace, "%s\n", ts(rt->rt_time));
+}
+
+
+void
+trace_rip(char *dir1, char *dir2,
+         struct sockaddr_in *who,
+         struct interface *ifp,
+         struct rip *msg,
+         int size)                     /* total size of message */
+{
+       struct netinfo *n, *lim;
+       struct netauth *a;
+       int i;
+
+       if (!TRACEPACKETS || ftrace == 0)
+               return;
+
+       lastlog();
+       if (msg->rip_cmd >= RIPCMD_MAX
+           || msg->rip_vers == 0) {
+               (void)fprintf(ftrace, "%s bad RIPv%d cmd=%d %s"
+                             " %s.%d size=%d\n",
+                             dir1, msg->rip_vers, msg->rip_cmd, dir2,
+                             naddr_ntoa(who->sin_addr.s_addr),
+                             ntohs(who->sin_port),
+                             size);
                return;
        }
-       switch (msg->rip_cmd) {
 
+       (void)fprintf(ftrace, "%s RIPv%d %s %s %s.%d%s%s\n",
+                     dir1, msg->rip_vers, ripcmds[msg->rip_cmd], dir2,
+                     naddr_ntoa(who->sin_addr.s_addr), ntohs(who->sin_port),
+                     ifp ? " via " : "", ifp ? ifp->int_name : "");
+       if (!TRACECONTENTS)
+               return;
+
+       switch (msg->rip_cmd) {
        case RIPCMD_REQUEST:
        case RIPCMD_RESPONSE:
-               size -= 4 * sizeof (char);
                n = msg->rip_nets;
-               for (; size > 0; n++, size -= sizeof (struct netinfo)) {
-                       if (size < sizeof (struct netinfo)) {
-                               fprintf(fd, "(truncated record, len %d)\n",
-                                   size);
-                               break;
+               lim = (struct netinfo *)((char*)msg + size);
+               for (; n < lim; n++) {
+                       if (n->n_family == RIP_AF_UNSPEC
+                           && ntohl(n->n_metric) == HOPCNT_INFINITY
+                           && n+1 == lim
+                           && n == msg->rip_nets
+                           && msg->rip_cmd == RIPCMD_REQUEST) {
+                               (void)fputs("\tQUERY ", ftrace);
+                               if (n->n_dst != 0)
+                                       (void)fprintf(ftrace, "%s ",
+                                                     naddr_ntoa(n->n_dst));
+                               if (n->n_mask != 0)
+                                       (void)fprintf(ftrace, "mask=%#x ",
+                                                     (u_int)ntohl(n->n_mask));
+                               if (n->n_nhop != 0)
+                                       (void)fprintf(ftrace, " nhop=%s ",
+                                                     naddr_ntoa(n->n_nhop));
+                               if (n->n_tag != 0)
+                                       (void)fprintf(ftrace, "tag=%#x",
+                                                     ntohs(n->n_tag));
+                               (void)fputc('\n',ftrace);
+                               continue;
                        }
-                       switch (n->rip_family) {
-
-                       case AF_INET:
-                               {
-                                       struct sockaddr_in sa;
-                                       sa.sin_addr.s_addr = n->rip_dst;
-                                       fprintf(fd, "\tdst %s",
-                                               inet_ntoa(sa.sin_addr));
-                                       if (msg->rip_vers > RIP_VERSION_1) {
-                                               fprintf(fd, ", mask 0x%.8x",
-                                                       n->rip_netmask);
-                                               sa.sin_addr.s_addr =
-                                                       n->rip_router;
-                                               fprintf(fd, ", router %s",
-                                                       inet_ntoa(sa.sin_addr));
-                                       }
-                               }
-                               break;
 
-                       default:
-                               fprintf(fd, "\taf %d?", n->rip_family);
-                               break;
+                       if (n->n_family == RIP_AF_AUTH) {
+                               a = (struct netauth*)n;
+                               (void)fprintf(ftrace,
+                                             "\tAuthentication type %d: ",
+                                             ntohs(a->a_type));
+                               for (i = 0;
+                                    i < sizeof(a->au.au_pw);
+                                    i++)
+                                       (void)fprintf(ftrace, "%02x ",
+                                                     a->au.au_pw[i]);
+                               (void)fputc('\n',ftrace);
+                               continue;
+                       }
+
+                       if (n->n_family != RIP_AF_INET) {
+                               (void)fprintf(ftrace,
+                                             "\t(af %d) %-18s mask=%#x",
+                                             ntohs(n->n_family),
+                                             naddr_ntoa(n->n_dst),
+                                             (u_int)ntohl(n->n_mask));
+                       } else if (msg->rip_vers == RIPv1) {
+                               (void)fprintf(ftrace, "\t%-18s ",
+                                             addrname(n->n_dst,
+                                                      ntohl(n->n_mask),
+                                                      n->n_mask==0 ? 2 : 1));
+                       } else {
+                               (void)fprintf(ftrace, "\t%-18s ",
+                                             addrname(n->n_dst,
+                                                      ntohl(n->n_mask),
+                                                      n->n_mask==0 ? 2 : 0));
                        }
-                       fprintf(fd, ", metric %d\n", ntohl(n->rip_metric));
+                       (void)fprintf(ftrace, "metric=%-2d ",
+                                     (u_int)ntohl(n->n_metric));
+                       if (n->n_nhop != 0)
+                               (void)fprintf(ftrace, " nhop=%s ",
+                                             naddr_ntoa(n->n_nhop));
+                       if (n->n_tag != 0)
+                               (void)fprintf(ftrace, "tag=%#x",
+                                             ntohs(n->n_tag));
+                       (void)fputc('\n',ftrace);
                }
+               if (size != (char *)n - (char *)msg)
+                       (void)fprintf(ftrace, "truncated record, len %d\n",
+                               size);
                break;
 
        case RIPCMD_TRACEON:
-               fprintf(fd, "\tfile=%*s\n", size, msg->rip_tracefile);
+               fprintf(ftrace, "\tfile=%*s\n", size-4, msg->rip_tracefile);
                break;
 
        case RIPCMD_TRACEOFF:
                break;
        }
-       fflush(fd);
-       if (ferror(fd))
-               traceoff();
 }
diff --git a/sbin/routed/trace.h b/sbin/routed/trace.h
deleted file mode 100644 (file)
index c8c4beb..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*     $OpenBSD: trace.h,v 1.2 1996/06/23 14:32:35 deraadt Exp $       */
-/*     $NetBSD: trace.h,v 1.8 1995/06/20 22:28:04 christos Exp $       */
-
-/*
- * Copyright (c) 1983, 1988, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *     @(#)trace.h     8.1 (Berkeley) 6/5/93
- */
-
-/*
- * Routing table management daemon.
- */
-
-/*
- * Trace record format.
- */
-struct iftrace {
-       struct  timeval ift_stamp;      /* time stamp */
-       struct  sockaddr ift_who;       /* from/to */
-       char    *ift_packet;            /* pointer to packet */
-       short   ift_size;               /* size of packet */
-       short   ift_metric;             /* metric on associated metric */
-};
-
-/*
- * Per interface packet tracing buffers.  An incoming and
- * outgoing circular buffer of packets is maintained, per
- * interface, for debugging.  Buffers are dumped whenever
- * an interface is marked down.
- */
-struct ifdebug {
-       struct  iftrace *ifd_records;   /* array of trace records */
-       struct  iftrace *ifd_front;     /* next empty trace record */
-       int     ifd_count;              /* number of unprinted records */
-       struct  interface *ifd_if;      /* for locating stuff */
-};
-
-/*
- * Packet tracing stuff.
- */
-int    tracepackets;           /* watch packets as they go by */
-int    tracecontents;          /* watch packet contents as they go by */
-int    traceactions;           /* on/off */
-int    tracehistory;           /* on/off */
-FILE   *ftrace;                /* output trace file */
-
-#define        TRACE_ACTION(action, route) { \
-         if (traceactions) \
-               traceaction(ftrace, action, route); \
-       }
-#define        TRACE_NEWMETRIC(route, newmetric) { \
-         if (traceactions) \
-               tracenewmetric(ftrace, route, newmetric); \
-       }
-#define        TRACE_INPUT(ifp, src, pack, size) { \
-         if (tracehistory) { \
-               ifp = if_iflookup(src); \
-               if (ifp) \
-                       trace(&ifp->int_input, src, pack, size, \
-                           ntohl(ifp->int_metric)); \
-         } \
-         if (tracepackets) \
-               dumppacket(ftrace, "from", (struct sockaddr_in *)src, pack, \
-                   size, &now); \
-       }
-#define        TRACE_OUTPUT(ifp, dst, size) { \
-         if (tracehistory && ifp) \
-               trace(&ifp->int_output, dst, packet, size, ifp->int_metric); \
-         if (tracepackets) \
-               dumppacket(ftrace, "to", (struct sockaddr_in *)dst, packet, \
-                   size, &now); \
-       }
-
-/* trace.c */
-void traceinit __P((struct interface *));
-void traceon __P((char *));
-void traceoff __P((void));
-void sigtrace __P((int));
-void bumploglevel __P((void));
-void trace __P((struct ifdebug *, struct sockaddr *, char *, int, int ));
-void traceaction __P((FILE *, char *, struct rt_entry *));
-void tracenewmetric __P((FILE *, struct rt_entry *, int));
-void dumpif __P((FILE *, struct interface *));
-void dumptrace __P((FILE *, char *, struct ifdebug *));
-void dumppacket __P((FILE *, char *, struct sockaddr_in *, char *, int, struct timeval *));
-