-# $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>
+++ /dev/null
-/* $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;
-}
+++ /dev/null
-/* $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 */
-/* $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);
-/* $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);
}
+++ /dev/null
-/* $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);
- }
-}
-/* $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);
}
+++ /dev/null
-/* $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 *));
-/* $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);
}
-/* $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);
}
}
-/* $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"
-.\" $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
+++ /dev/null
-/* $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);
-}
+++ /dev/null
-/* $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 *));
+++ /dev/null
-/* $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 */
-}
+++ /dev/null
-/* $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);
-}
-/* $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();
}
+++ /dev/null
-/* $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 *));
-