summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
Diffstat (limited to 'sbin')
-rw-r--r--sbin/routed/Makefile18
-rw-r--r--sbin/routed/af.c254
-rw-r--r--sbin/routed/af.h85
-rw-r--r--sbin/routed/defs.h593
-rw-r--r--sbin/routed/if.c1140
-rw-r--r--sbin/routed/inet.c260
-rw-r--r--sbin/routed/input.c918
-rw-r--r--sbin/routed/interface.h93
-rw-r--r--sbin/routed/main.c988
-rw-r--r--sbin/routed/output.c920
-rw-r--r--sbin/routed/pathnames.h11
-rw-r--r--sbin/routed/routed.8679
-rw-r--r--sbin/routed/startup.c531
-rw-r--r--sbin/routed/table.h121
-rw-r--r--sbin/routed/tables.c496
-rw-r--r--sbin/routed/timer.c137
-rw-r--r--sbin/routed/trace.c1004
-rw-r--r--sbin/routed/trace.h115
18 files changed, 4897 insertions, 3466 deletions
diff --git a/sbin/routed/Makefile b/sbin/routed/Makefile
index 930e279d502..35ebc319e4b 100644
--- a/sbin/routed/Makefile
+++ b/sbin/routed/Makefile
@@ -1,13 +1,15 @@
-# $OpenBSD: Makefile,v 1.3 1996/06/23 14:32:24 deraadt Exp $
-# $NetBSD: Makefile,v 1.14 1995/06/20 22:25:51 christos Exp $
-
-# disable an undesirable feature
-#CFLAGS=-DTRACING
+# $OpenBSD: Makefile,v 1.4 1996/09/05 14:31:10 mickey Exp $
+# @(#)Makefile 8.1 (Berkeley) 6/19/93
PROG= routed
-SRCS= af.c if.c input.c main.c output.c startup.c tables.c timer.c \
- trace.c inet.c
+SRCS= if.c input.c main.c output.c parms.c radix.c rdisc.c table.c trace.c
MAN= routed.8
-#SUBDIR= query trace
+CFLAGS+=-D_ROUTED -D'min(a,b)=(a < b ? a : b)' -D'log=syslog'
+CFLAGS+=-D'panic(s)={log(LOG_ERR,s); exit(1);}'
+SUBDIR= rtquery
+DPADD= ${LIBCOMPAT}
+LDADD= -lcompat
+
+.PATH: ${.CURDIR}/../../sys/net
.include <bsd.prog.mk>
diff --git a/sbin/routed/af.c b/sbin/routed/af.c
deleted file mode 100644
index e58ea8d459e..00000000000
--- a/sbin/routed/af.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/* $OpenBSD: af.c,v 1.2 1996/06/23 14:32:24 deraadt Exp $ */
-/* $NetBSD: af.c,v 1.12 1995/07/24 13:03:25 ws Exp $ */
-
-/*
- * Copyright (c) 1983, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)af.c 8.1 (Berkeley) 6/5/93";
-#else
-static char rcsid[] = "$OpenBSD: af.c,v 1.2 1996/06/23 14:32:24 deraadt Exp $";
-#endif
-#endif /* not lint */
-
-#include "defs.h"
-
-/*
- * Address family support routines
- */
-static void inet_canon __P((struct sockaddr *));
-static int inet_checkhost __P((struct sockaddr *));
-static char *inet_format __P((struct sockaddr *, char *buf, size_t sz));
-static void inet_hash __P((struct sockaddr *, struct afhash *));
-static int inet_netmatch __P((struct sockaddr *, struct sockaddr *));
-static int inet_portcheck __P((struct sockaddr *));
-static int inet_portmatch __P((struct sockaddr *));
-static void inet_output __P((int, int, struct sockaddr *, int));
-static int inet_get __P((int, void *, struct sockaddr *));
-static void inet_put __P((void *, struct sockaddr *));
-
-#define NIL { 0 }
-#define INET \
- { inet_hash, inet_netmatch, inet_output, \
- inet_portmatch, inet_portcheck, inet_checkhost, \
- inet_rtflags, inet_sendroute, inet_canon, \
- inet_format, inet_get, inet_put \
- }
-
-struct afswitch afswitch[AF_MAX] = {
- NIL, /* 0- unused */
- NIL, /* 1- Unix domain, unused */
- INET, /* Internet */
-};
-
-int af_max = sizeof(afswitch) / sizeof(afswitch[0]);
-
-struct sockaddr_in inet_default = {
-#ifdef RTM_ADD
- sizeof (inet_default),
-#endif
- AF_INET, INADDR_ANY };
-
-static void
-inet_hash(sa, hp)
- struct sockaddr *sa;
- struct afhash *hp;
-{
- struct sockaddr_in *sin = (struct sockaddr_in *) sa;
- register u_long n;
-
- n = inet_netof_subnet(sin->sin_addr);
- if (n)
- while ((n & 0xff) == 0)
- n >>= 8;
- hp->afh_nethash = n;
- hp->afh_hosthash = ntohl(sin->sin_addr.s_addr);
- hp->afh_hosthash &= 0x7fffffff;
-}
-
-static int
-inet_netmatch(sa1, sa2)
- struct sockaddr *sa1, *sa2;
-{
- struct sockaddr_in *sin1 = (struct sockaddr_in *) sa1;
- struct sockaddr_in *sin2 = (struct sockaddr_in *) sa2;
-
- return (inet_netof_subnet(sin1->sin_addr) ==
- inet_netof_subnet(sin2->sin_addr));
-}
-
-/*
- * Verify the message is from the right port.
- */
-static int
-inet_portmatch(sa)
- struct sockaddr *sa;
-{
- struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-
- return (sin->sin_port == sp->s_port);
-}
-
-/*
- * Verify the message is from a "trusted" port.
- */
-static int
-inet_portcheck(sa)
- struct sockaddr *sa;
-{
- struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-
- return (ntohs(sin->sin_port) <= IPPORT_RESERVED);
-}
-
-/*
- * Internet output routine.
- */
-static void
-inet_output(s, flags, sa, size)
- int s, flags;
- struct sockaddr *sa;
- int size;
-{
- struct sockaddr_in *sin = (struct sockaddr_in *) sa;
- struct sockaddr_in dst;
-
- dst = *sin;
- sin = &dst;
- if (sin->sin_port == 0)
- sin->sin_port = sp->s_port;
- if (sin->sin_len == 0)
- sin->sin_len = sizeof (*sin);
- if (sendto(s, packet, size, flags,
- (struct sockaddr *)sin, sizeof (*sin)) < 0)
- perror("sendto");
-}
-
-/*
- * Return 1 if the address is believed
- * for an Internet host -- THIS IS A KLUDGE.
- */
-static int
-inet_checkhost(sa)
- struct sockaddr *sa;
-{
- struct sockaddr_in *sin = (struct sockaddr_in *) sa;
- u_long i = ntohl(sin->sin_addr.s_addr);
-
-#ifndef IN_EXPERIMENTAL
-#define IN_EXPERIMENTAL(i) (((long) (i) & 0xe0000000) == 0xe0000000)
-#endif
-
- if (IN_EXPERIMENTAL(i) || sin->sin_port != 0)
- return (0);
- if (i != 0 && (i & 0xff000000) == 0)
- return (0);
- for (i = 0; i < sizeof(sin->sin_zero)/sizeof(sin->sin_zero[0]); i++)
- if (sin->sin_zero[i])
- return (0);
- return (1);
-}
-
-static void
-inet_canon(sa)
- struct sockaddr *sa;
-{
- struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-
- sin->sin_port = 0;
- sin->sin_len = sizeof(*sin);
-}
-
-static char *
-inet_format(sa, buf, sz)
- struct sockaddr *sa;
- char *buf; size_t sz;
-{
- struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-
- strncpy(buf, inet_ntoa(sin->sin_addr), sz);
- buf[sz - 1] = '\0';
- return buf;
-}
-
-static int
-inet_get(what, pck, sa)
- int what;
- void *pck;
- struct sockaddr *sa;
-{
- struct sockaddr_in *sin = (struct sockaddr_in *) sa;
- struct netinfo *n = pck;
- /* XXX: Internet only */
- memset(sin, 0, sizeof(*sin));
- switch (what) {
- case DESTINATION:
- sin->sin_addr.s_addr = n->rip_dst;
- break;
- case NETMASK:
- if (n->rip_netmask == 0)
- return 0;
- sin->sin_addr.s_addr = n->rip_netmask;
- break;
- case GATEWAY:
- if (n->rip_router == 0)
- return 0;
- sin->sin_addr.s_addr = n->rip_router;
- break;
- default:
- abort();
- break;
- }
-
- sin->sin_family = n->rip_family;
-#if BSD >= 198810
- sin->sin_len = sizeof(*sin);
-#endif
- return 1;
-}
-
-static void
-inet_put(pck, sa)
- void *pck;
- struct sockaddr *sa;
-{
- struct netinfo *n = pck;
- struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-#if BSD >= 198810
- n->rip_family = htons(sin->sin_family);
-#else
- n->rip_family = sin->sin_family;
-#endif
- n->rip_dst = sin->sin_addr.s_addr;
-}
diff --git a/sbin/routed/af.h b/sbin/routed/af.h
deleted file mode 100644
index b80a54f3e5a..00000000000
--- a/sbin/routed/af.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* $OpenBSD: af.h,v 1.2 1996/06/23 14:32:25 deraadt Exp $ */
-/* $NetBSD: af.h,v 1.8 1995/06/20 22:26:45 christos Exp $ */
-
-/*
- * Copyright (c) 1983, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)af.h 8.1 (Berkeley) 6/5/93
- */
-
-/*
- * Routing table management daemon.
- */
-
-/*
- * Structure returned by af_hash routines.
- */
-struct afhash {
- u_int afh_hosthash; /* host based hash */
- u_int afh_nethash; /* network based hash */
-};
-
-/*
- * Per address family routines.
- */
-struct afswitch {
- /* returns keys based on address */
- void (*af_hash) __P((struct sockaddr *, struct afhash *));
- /* verifies net # matching */
- int (*af_netmatch) __P((struct sockaddr *, struct sockaddr *));
- /* interprets address for sending */
- void (*af_output) __P((int, int, struct sockaddr *, int));
- /* packet from some other router? */
- int (*af_portmatch) __P((struct sockaddr *));
- /* packet from privileged peer? */
- int (*af_portcheck) __P((struct sockaddr *));
- /* tells if address is valid */
- int (*af_checkhost) __P((struct sockaddr *));
- /* get flags for route (host or net) */
- int (*af_rtflags) __P((struct sockaddr *));
- /* check bounds of subnet broadcast */
- int (*af_sendroute) __P((struct rt_entry *, struct sockaddr *));
- /* canonicalize address for compares */
- void (*af_canon) __P((struct sockaddr *));
- /* convert address to string */
- char *(*af_format) __P((struct sockaddr *, char *, size_t));
- /* get address from packet */
-#define DESTINATION 0
-#define GATEWAY 1
-#define NETMASK 2
- int (*af_get) __P((int, void *, struct sockaddr *));
- /* put address to packet */
- void (*af_put) __P((void *, struct sockaddr *));
-};
-
-extern struct afswitch afswitch[]; /* table proper */
-extern int af_max; /* number of entries in table */
diff --git a/sbin/routed/defs.h b/sbin/routed/defs.h
index b363a4653d5..6e61b27674a 100644
--- a/sbin/routed/defs.h
+++ b/sbin/routed/defs.h
@@ -1,5 +1,4 @@
-/* $OpenBSD: defs.h,v 1.2 1996/06/23 14:32:26 deraadt Exp $ */
-/* $NetBSD: defs.h,v 1.11 1995/06/20 22:26:57 christos Exp $ */
+/* $OpenBSD: defs.h,v 1.3 1996/09/05 14:31:18 mickey Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@@ -34,106 +33,514 @@
* 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);
diff --git a/sbin/routed/if.c b/sbin/routed/if.c
index 7bf0084319e..946c797ee93 100644
--- a/sbin/routed/if.c
+++ b/sbin/routed/if.c
@@ -1,5 +1,4 @@
-/* $OpenBSD: if.c,v 1.2 1996/06/23 14:32:26 deraadt Exp $ */
-/* $NetBSD: if.c,v 1.8 1995/06/20 22:27:21 christos Exp $ */
+/* $OpenBSD: if.c,v 1.3 1996/09/05 14:31:21 mickey Exp $ */
/*
* Copyright (c) 1983, 1993
@@ -34,122 +33,1101 @@
* SUCH DAMAGE.
*/
-#ifndef lint
-#if 0
+#if !defined(lint)
static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93";
#else
-static char rcsid[] = "$OpenBSD: if.c,v 1.2 1996/06/23 14:32:26 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: if.c,v 1.3 1996/09/05 14:31:21 mickey Exp $";
#endif
-#endif /* not lint */
-/*
- * Routing Table Management Daemon
- */
#include "defs.h"
+#include "pathnames.h"
-extern struct interface *ifnet;
+struct interface *ifnet; /* all interfaces */
+int tot_interfaces; /* # of remote and local interfaces */
+int rip_interfaces; /* # of interfaces doing RIP */
+int foundloopback; /* valid flag for loopaddr */
+naddr loopaddr; /* our address on loopback */
-/*
- * Find the interface with address addr.
+struct timeval ifinit_timer;
+
+int have_ripv1_out; /* have a RIPv1 interface */
+int have_ripv1_in;
+
+
+/* Find the interface with an address
*/
struct interface *
-if_ifwithaddr(addr)
- struct sockaddr *addr;
+ifwithaddr(naddr addr,
+ int bcast, /* notice IFF_BROADCAST address */
+ int remote) /* include IS_REMOTE interfaces */
{
- register struct interface *ifp;
+ struct interface *ifp, *possible = 0;
-#define same(a1, a2) \
- (memcmp((a1)->sa_data, (a2)->sa_data, 14) == 0)
for (ifp = ifnet; ifp; ifp = ifp->int_next) {
- if (ifp->int_flags & IFF_REMOTE)
- continue;
- if (ifp->int_addr.sa_family != addr->sa_family)
- continue;
- if (same(&ifp->int_addr, addr))
- break;
- if ((ifp->int_flags & IFF_BROADCAST) &&
- same(&ifp->int_broadaddr, addr))
- break;
+ if (ifp->int_addr == addr
+ || ((ifp->int_if_flags & IFF_BROADCAST)
+ && ifp->int_brdaddr == addr
+ && bcast)) {
+ if ((ifp->int_state & IS_REMOTE) && !remote)
+ continue;
+
+ if (!(ifp->int_state & IS_BROKE)
+ && !(ifp->int_state & IS_PASSIVE))
+ return ifp;
+
+ possible = ifp;
+ }
}
- return (ifp);
+
+ return possible;
}
-/*
- * Find the point-to-point interface with destination address addr.
+
+/* find the interface with a name
*/
struct interface *
-if_ifwithdstaddr(addr)
- struct sockaddr *addr;
+ifwithname(char *name, /* "ec0" or whatever */
+ naddr addr) /* 0 or network address */
{
- register struct interface *ifp;
+ struct interface *ifp;
- for (ifp = ifnet; ifp; ifp = ifp->int_next) {
- if ((ifp->int_flags & IFF_POINTOPOINT) == 0)
- continue;
- if (same(&ifp->int_dstaddr, addr))
- break;
+
+ for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
+ if (!strcmp(ifp->int_name, name)
+ && (ifp->int_addr == addr
+ || (addr == 0 && !(ifp->int_state & IS_ALIAS))))
+ return ifp;
}
- return (ifp);
+ return 0;
}
-/*
- * Find the interface on the network
- * of the specified address.
- */
+
struct interface *
-if_ifwithnet(addr)
- register struct sockaddr *addr;
+ifwithindex(u_short index)
{
- register struct interface *ifp;
- register int af = addr->sa_family;
- register int (*netmatch) __P((struct sockaddr *, struct sockaddr *));
+ struct interface *ifp;
- if (af >= af_max)
- return (0);
- netmatch = afswitch[af].af_netmatch;
- for (ifp = ifnet; ifp; ifp = ifp->int_next) {
- if (ifp->int_flags & IFF_REMOTE)
- continue;
- if (af != ifp->int_addr.sa_family)
- continue;
- if ((*netmatch)(addr, &ifp->int_addr))
- break;
+
+ for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
+ if (ifp->int_index == index)
+ return ifp;
}
- return (ifp);
+ return 0;
}
-/*
- * Find an interface from which the specified address
+
+/* Find an interface from which the specified address
* should have come from. Used for figuring out which
* interface a packet came in on -- for tracing.
*/
struct interface *
-if_iflookup(addr)
- struct sockaddr *addr;
+iflookup(naddr addr)
{
- register struct interface *ifp, *maybe;
- register int af = addr->sa_family;
- register int (*netmatch) __P((struct sockaddr *, struct sockaddr *));
+ struct interface *ifp, *maybe;
- if (af >= af_max)
- return (0);
maybe = 0;
- netmatch = afswitch[af].af_netmatch;
for (ifp = ifnet; ifp; ifp = ifp->int_next) {
- if (ifp->int_addr.sa_family != af)
+ if (ifp->int_if_flags & IFF_POINTOPOINT) {
+ if (ifp->int_dstaddr == addr)
+ /* finished with a match */
+ return ifp;
+
+ } else {
+ /* finished with an exact match */
+ if (ifp->int_addr == addr)
+ return ifp;
+ if ((ifp->int_if_flags & IFF_BROADCAST)
+ && ifp->int_brdaddr == addr)
+ return ifp;
+
+ /* Look for the longest approximate match.
+ */
+ if (on_net(addr, ifp->int_net, ifp->int_mask)
+ && (maybe == 0
+ || ifp->int_mask > maybe->int_mask))
+ maybe = ifp;
+ }
+ }
+
+ return maybe;
+}
+
+
+/* Return the classical netmask for an IP address.
+ */
+naddr
+std_mask(naddr addr) /* in network order */
+{
+ NTOHL(addr); /* was a host, not a network */
+
+ if (addr == 0) /* default route has mask 0 */
+ return 0;
+ if (IN_CLASSA(addr))
+ return IN_CLASSA_NET;
+ if (IN_CLASSB(addr))
+ return IN_CLASSB_NET;
+ return IN_CLASSC_NET;
+}
+
+
+/* Find the netmask that would be inferred by RIPv1 listeners
+ * on the given interface for a given network.
+ * If no interface is specified, look for the best fitting interface.
+ */
+naddr
+ripv1_mask_net(naddr addr, /* in network byte order */
+ struct interface *ifp) /* as seen on this interface */
+{
+ naddr mask = 0;
+
+ if (addr == 0) /* default always has 0 mask */
+ return mask;
+
+ if (ifp != 0) {
+ /* If the target network is that of the associated interface
+ * on which it arrived, then use the netmask of the interface.
+ */
+ if (on_net(addr, ifp->int_net, ifp->int_std_mask))
+ mask = ifp->int_ripv1_mask;
+
+ } else {
+ /* Examine all interfaces, and if it the target seems
+ * to have the same network number of an interface, use the
+ * netmask of that interface. If there is more than one
+ * such interface, prefer the interface with the longest
+ * match.
+ */
+ for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
+ if (on_net(addr, ifp->int_std_net, ifp->int_std_mask)
+ && ifp->int_ripv1_mask > mask)
+ mask = ifp->int_ripv1_mask;
+ }
+ }
+
+ /* Otherwise, make the classic A/B/C guess.
+ */
+ if (mask == 0)
+ mask = std_mask(addr);
+
+ return mask;
+}
+
+
+naddr
+ripv1_mask_host(naddr addr, /* in network byte order */
+ struct interface *ifp) /* as seen on this interface */
+{
+ naddr mask = ripv1_mask_net(addr, ifp);
+
+
+ /* If the computed netmask does not mask the address,
+ * then assume it is a host address
+ */
+ if ((ntohl(addr) & ~mask) != 0)
+ mask = HOST_MASK;
+ return mask;
+}
+
+
+/* See if a IP address looks reasonable as a destination
+ */
+int /* 0=bad */
+check_dst(naddr addr)
+{
+ NTOHL(addr);
+
+ if (IN_CLASSA(addr)) {
+ if (addr == 0)
+ return 1; /* default */
+
+ addr >>= IN_CLASSA_NSHIFT;
+ return (addr != 0 && addr != IN_LOOPBACKNET);
+ }
+
+ return (IN_CLASSB(addr) || IN_CLASSC(addr));
+}
+
+
+/* Delete an interface.
+ */
+static void
+ifdel(struct interface *ifp)
+{
+ struct ip_mreq m;
+ struct interface *ifp1;
+
+
+ trace_if("Del", ifp);
+
+ ifp->int_state |= IS_BROKE;
+
+ /* unlink the interface
+ */
+ if (rip_sock_mcast == ifp)
+ rip_sock_mcast = 0;
+ if (ifp->int_next != 0)
+ ifp->int_next->int_prev = ifp->int_prev;
+ if (ifp->int_prev != 0)
+ ifp->int_prev->int_next = ifp->int_next;
+ else
+ ifnet = ifp->int_next;
+
+ if (!(ifp->int_state & IS_ALIAS)) {
+ /* delete aliases
+ */
+ for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) {
+ if (ifp1 != ifp
+ && !strcmp(ifp->int_name, ifp1->int_name))
+ ifdel(ifp1);
+ }
+
+ if ((ifp->int_if_flags & IFF_MULTICAST)
+#ifdef MCAST_PPP_BUG
+ && !(ifp->int_if_flags & IFF_POINTOPOINT)
+#endif
+ && rip_sock >= 0) {
+ m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP);
+ m.imr_interface.s_addr = ((ifp->int_if_flags
+ & IFF_POINTOPOINT)
+ ? ifp->int_dstaddr
+ : ifp->int_addr);
+ if (setsockopt(rip_sock,IPPROTO_IP,IP_DROP_MEMBERSHIP,
+ &m, sizeof(m)) < 0
+ && errno != EADDRNOTAVAIL
+ && !TRACEACTIONS)
+ LOGERR("setsockopt(IP_DROP_MEMBERSHIP RIP)");
+ }
+ if (ifp->int_rip_sock >= 0) {
+ (void)close(ifp->int_rip_sock);
+ ifp->int_rip_sock = -1;
+ fix_select();
+ }
+
+ tot_interfaces--;
+ if (!IS_RIP_OFF(ifp->int_state))
+ rip_interfaces--;
+
+ /* Zap all routes associated with this interface.
+ * Assume routes just using gateways beyond this interface will
+ * timeout naturally, and have probably already died.
+ */
+ (void)rn_walktree(rhead, walk_bad, 0);
+
+ set_rdisc_mg(ifp, 0);
+ if_bad_rdisc(ifp);
+ }
+
+ free(ifp);
+}
+
+
+/* Mark an interface ill.
+ */
+void
+if_sick(struct interface *ifp)
+{
+ if (0 == (ifp->int_state & (IS_SICK | IS_BROKE))) {
+ ifp->int_state |= IS_SICK;
+ trace_if("Chg", ifp);
+
+ LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL);
+ }
+}
+
+
+/* Mark an interface dead.
+ */
+void
+if_bad(struct interface *ifp)
+{
+ struct interface *ifp1;
+
+
+ if (ifp->int_state & IS_BROKE)
+ return;
+
+ LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL);
+
+ ifp->int_state |= (IS_BROKE | IS_SICK);
+ ifp->int_state &= ~(IS_RIP_QUERIED | IS_ACTIVE);
+ ifp->int_data.ts = 0;
+
+ trace_if("Chg", ifp);
+
+ if (!(ifp->int_state & IS_ALIAS)) {
+ for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) {
+ if (ifp1 != ifp
+ && !strcmp(ifp->int_name, ifp1->int_name))
+ if_bad(ifp1);
+ }
+ (void)rn_walktree(rhead, walk_bad, 0);
+ if_bad_rdisc(ifp);
+ }
+}
+
+
+/* Mark an interface alive
+ */
+int /* 1=it was dead */
+if_ok(struct interface *ifp,
+ char *type)
+{
+ struct interface *ifp1;
+
+
+ if (!(ifp->int_state & IS_BROKE)) {
+ if (ifp->int_state & IS_SICK) {
+ trace_act("%sinterface %s to %s working better\n",
+ type,
+ ifp->int_name, naddr_ntoa(ifp->int_addr));
+ ifp->int_state &= ~IS_SICK;
+ }
+ return 0;
+ }
+
+ msglog("%sinterface %s to %s restored",
+ type, ifp->int_name, naddr_ntoa(ifp->int_addr));
+ ifp->int_state &= ~(IS_BROKE | IS_SICK);
+ ifp->int_data.ts = 0;
+
+ if (!(ifp->int_state & IS_ALIAS)) {
+ for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) {
+ if (ifp1 != ifp
+ && !strcmp(ifp->int_name, ifp1->int_name))
+ if_ok(ifp1, type);
+ }
+ if_ok_rdisc(ifp);
+ }
+ return 1;
+}
+
+
+/* disassemble routing message
+ */
+void
+rt_xaddrs(struct rt_addrinfo *info,
+ struct sockaddr *sa,
+ struct sockaddr *lim,
+ int addrs)
+{
+ int i;
+#ifdef _HAVE_SA_LEN
+ static struct sockaddr sa_zero;
+#endif
+#ifdef sgi
+#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) \
+ : sizeof(__uint64_t))
+#else
+#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \
+ : sizeof(long))
+#endif
+
+
+ bzero(info, sizeof(*info));
+ info->rti_addrs = addrs;
+ for (i = 0; i < RTAX_MAX && sa < lim; i++) {
+ if ((addrs & (1 << i)) == 0)
continue;
- if (same(&ifp->int_addr, addr))
- break;
- if ((ifp->int_flags & IFF_BROADCAST) &&
- same(&ifp->int_broadaddr, addr))
- break;
- if ((ifp->int_flags & IFF_POINTOPOINT) &&
- same(&ifp->int_dstaddr, addr))
+#ifdef _HAVE_SA_LEN
+ info->rti_info[i] = (sa->sa_len != 0) ? sa : &sa_zero;
+ sa = (struct sockaddr *)((char*)(sa)
+ + ROUNDUP(sa->sa_len));
+#else
+ info->rti_info[i] = sa;
+ sa = (struct sockaddr *)((char*)(sa)
+ + ROUNDUP(_FAKE_SA_LEN_DST(sa)));
+#endif
+ }
+}
+
+
+/* Find the network interfaces which have configured themselves.
+ * This must be done regularly, if only for extra addresses
+ * that come and go on interfaces.
+ */
+void
+ifinit(void)
+{
+ static char *sysctl_buf;
+ static size_t sysctl_buf_size = 0;
+ uint complaints = 0;
+ static u_int prev_complaints = 0;
+# define COMP_NOT_INET 0x001
+# define COMP_WIERD 0x002
+# define COMP_NOADDR 0x004
+# define COMP_NODST 0x008
+# define COMP_NOBADR 0x010
+# define COMP_NOMASK 0x020
+# define COMP_DUP 0x040
+# define COMP_BAD_METRIC 0x080
+# define COMP_NETMASK 0x100
+
+ struct interface ifs, ifs0, *ifp, *ifp1;
+ struct rt_entry *rt;
+ size_t needed;
+ int mib[6];
+ struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam, *ifam_lim, *ifam2;
+ struct sockaddr_dl *sdl;
+ int in, ierr, out, oerr;
+ struct intnet *intnetp;
+ struct rt_addrinfo info;
+#ifdef SIOCGIFMETRIC
+ struct ifreq ifr;
+#endif
+
+
+ ifinit_timer.tv_sec = now.tv_sec + (supplier
+ ? CHECK_ACT_INTERVAL
+ : CHECK_QUIET_INTERVAL);
+
+ /* mark all interfaces so we can get rid of thost that disappear */
+ for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next)
+ ifp->int_state &= ~(IS_CHECKED | IS_DUP);
+
+ /* Fetch the interface list, without too many system calls
+ * since we do it repeatedly.
+ */
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET;
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0;
+ for (;;) {
+ if ((needed = sysctl_buf_size) != 0) {
+ if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0)
+ break;
+ if (errno != ENOMEM && errno != EFAULT)
+ BADERR(1, "ifinit: get interface table");
+ free(sysctl_buf);
+ needed = 0;
+ }
+ if (sysctl(mib, 6, 0, &needed, 0, 0) < 0)
+ BADERR(1,"ifinit: route-sysctl-estimate");
+ sysctl_buf = rtmalloc(sysctl_buf_size = needed, "ifinit");
+ }
+
+ ifam_lim = (struct ifa_msghdr *)(sysctl_buf + needed);
+ for (ifam = (struct ifa_msghdr *)sysctl_buf;
+ ifam < ifam_lim;
+ ifam = ifam2) {
+
+ ifam2 = (struct ifa_msghdr*)((char*)ifam + ifam->ifam_msglen);
+
+ if (ifam->ifam_type == RTM_IFINFO) {
+ ifm = (struct if_msghdr *)ifam;
+ /* make prototype structure for the IP aliases
+ */
+ bzero(&ifs0, sizeof(ifs0));
+ ifs0.int_rip_sock = -1;
+ ifs0.int_index = ifm->ifm_index;
+ ifs0.int_if_flags = ifm->ifm_flags;
+ ifs0.int_state = IS_CHECKED;
+ ifs0.int_act_time = now.tv_sec;
+ ifs0.int_data.ts = now.tv_sec;
+ ifs0.int_data.ipackets = ifm->ifm_data.ifi_ipackets;
+ ifs0.int_data.ierrors = ifm->ifm_data.ifi_ierrors;
+ ifs0.int_data.opackets = ifm->ifm_data.ifi_opackets;
+ ifs0.int_data.oerrors = ifm->ifm_data.ifi_oerrors;
+#ifdef sgi
+ ifs0.int_data.odrops = ifm->ifm_data.ifi_odrops;
+#endif
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ sdl->sdl_data[sdl->sdl_nlen] = 0;
+ continue;
+ }
+ if (ifam->ifam_type != RTM_NEWADDR) {
+ logbad(1,"ifinit: out of sync");
+ continue;
+ }
+
+ rt_xaddrs(&info, (struct sockaddr *)(ifam+1),
+ (struct sockaddr *)ifam2,
+ ifam->ifam_addrs);
+
+ if (INFO_IFA(&info) == 0) {
+ if (iff_alive(ifs.int_if_flags)) {
+ if (!(prev_complaints & COMP_NOADDR))
+ msglog("%s has a bad address",
+ sdl->sdl_data);
+ complaints |= COMP_NOADDR;
+ }
+ continue;
+ }
+ if (INFO_IFA(&info)->sa_family != AF_INET) {
+ if (iff_alive(ifs.int_if_flags)) {
+ if (!(prev_complaints & COMP_NOT_INET))
+ trace_act("%s: not AF_INET\n",
+ sdl->sdl_data);
+ complaints |= COMP_NOT_INET;
+ }
+ continue;
+ }
+
+ bcopy(&ifs0, &ifs, sizeof(ifs0));
+ ifs0.int_state |= IS_ALIAS; /* next will be an alias */
+
+ ifs.int_addr = S_ADDR(INFO_IFA(&info));
+
+ if (ifs.int_if_flags & IFF_BROADCAST) {
+ if (INFO_MASK(&info) == 0) {
+ if (iff_alive(ifs.int_if_flags)) {
+ if (!(prev_complaints & COMP_NOMASK))
+ msglog("%s has no netmask",
+ sdl->sdl_data);
+ complaints |= COMP_NOMASK;
+ }
+ continue;
+ }
+ ifs.int_dstaddr = ifs.int_addr;
+ ifs.int_mask = ntohl(S_ADDR(INFO_MASK(&info)));
+ ifs.int_ripv1_mask = ifs.int_mask;
+ ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask;
+ ifs.int_std_mask = std_mask(ifs.int_addr);
+ if (ifs.int_mask != ifs.int_std_mask)
+ ifs.int_state |= IS_SUBNET;
+
+ if (INFO_BRD(&info) == 0) {
+ if (iff_alive(ifs.int_if_flags)) {
+ if (!(prev_complaints & COMP_NOBADR))
+ msglog("%s has no"
+ " broadcast address",
+ sdl->sdl_data);
+ complaints |= COMP_NOBADR;
+ }
+ continue;
+ }
+ ifs.int_brdaddr = S_ADDR(INFO_BRD(&info));
+
+ } else if (ifs.int_if_flags & IFF_POINTOPOINT) {
+ if (INFO_BRD(&info) == 0
+ || INFO_BRD(&info)->sa_family != AF_INET) {
+ if (iff_alive(ifs.int_if_flags)) {
+ if (!(prev_complaints & COMP_NODST))
+ msglog("%s has a bad"
+ " destination address",
+ sdl->sdl_data);
+ complaints |= COMP_NODST;
+ }
+ continue;
+ }
+ ifs.int_dstaddr = S_ADDR(INFO_BRD(&info));
+ ifs.int_mask = HOST_MASK;
+ ifs.int_ripv1_mask = ntohl(S_ADDR(INFO_MASK(&info)));
+ ifs.int_net = ntohl(ifs.int_dstaddr);
+ ifs.int_std_mask = std_mask(ifs.int_dstaddr);
+
+ } else if (ifs.int_if_flags & IFF_LOOPBACK) {
+ ifs.int_state |= IS_PASSIVE | IS_NO_RIP;
+ ifs.int_dstaddr = ifs.int_addr;
+ ifs.int_mask = HOST_MASK;
+ ifs.int_ripv1_mask = HOST_MASK;
+ ifs.int_net = ntohl(ifs.int_dstaddr);
+ ifs.int_std_mask = std_mask(ifs.int_dstaddr);
+ if (!foundloopback) {
+ foundloopback = 1;
+ loopaddr = ifs.int_addr;
+ }
+
+ } else {
+ if (!(prev_complaints & COMP_WIERD))
+ trace_act("%s is neither broadcast"
+ " nor point-to-point nor loopback",
+ sdl->sdl_data);
+ complaints |= COMP_WIERD;
+ continue;
+ }
+ ifs.int_std_net = ifs.int_net & ifs.int_std_mask;
+ ifs.int_std_addr = htonl(ifs.int_std_net);
+
+ /* Use a minimum metric of one. Treat the interface metric
+ * (default 0) as an increment to the hop count of one.
+ *
+ * The metric obtained from the routing socket dump of
+ * interface addresses is wrong. It is not set by the
+ * SIOCSIFMETRIC ioctl.
+ */
+#ifdef SIOCGIFMETRIC
+ strncpy(ifr.ifr_name, sdl->sdl_data, sizeof(ifr.ifr_name));
+ if (ioctl(rt_sock, SIOCGIFMETRIC, &ifr) < 0) {
+ DBGERR(1, "ioctl(SIOCGIFMETRIC)");
+ ifs.int_metric = 0;
+ } else {
+ ifs.int_metric = ifr.ifr_metric;
+ }
+#else
+ ifs.int_metric = ifam->ifam_metric;
+#endif
+ if (ifs.int_metric > HOPCNT_INFINITY) {
+ ifs.int_metric = 0;
+ if (!(prev_complaints & COMP_BAD_METRIC)
+ && iff_alive(ifs.int_if_flags)) {
+ complaints |= COMP_BAD_METRIC;
+ msglog("%s has a metric of %d",
+ sdl->sdl_data, ifs.int_metric);
+ }
+ }
+
+ /* See if this is a familiar interface.
+ * If so, stop worrying about it if it is the same.
+ * Start it over if it now is to somewhere else, as happens
+ * frequently with PPP and SLIP.
+ */
+ ifp = ifwithname(sdl->sdl_data, ((ifs.int_state & IS_ALIAS)
+ ? ifs.int_addr
+ : 0));
+ if (ifp != 0) {
+ ifp->int_state |= IS_CHECKED;
+
+ if (0 != ((ifp->int_if_flags ^ ifs.int_if_flags)
+ & (IFF_BROADCAST
+ | IFF_LOOPBACK
+ | IFF_POINTOPOINT
+ | IFF_MULTICAST))
+ || 0 != ((ifp->int_state ^ ifs.int_state)
+ & IS_ALIAS)
+ || ifp->int_addr != ifs.int_addr
+ || ifp->int_brdaddr != ifs.int_brdaddr
+ || ifp->int_dstaddr != ifs.int_dstaddr
+ || ifp->int_mask != ifs.int_mask
+ || ifp->int_metric != ifs.int_metric) {
+ /* Forget old information about
+ * a changed interface.
+ */
+ trace_act("interface %s has changed\n",
+ ifp->int_name);
+ ifdel(ifp);
+ ifp = 0;
+ }
+ }
+
+ if (ifp != 0) {
+ /* The primary representative of an alias worries
+ * about how things are working.
+ */
+ if (ifp->int_state & IS_ALIAS)
+ continue;
+
+ /* note interfaces that have been turned off
+ */
+ if (!iff_alive(ifs.int_if_flags)) {
+ if (iff_alive(ifp->int_if_flags)) {
+ msglog("interface %s to %s turned off",
+ ifp->int_name,
+ naddr_ntoa(ifp->int_addr));
+ if_bad(ifp);
+ ifp->int_if_flags &= ~IFF_UP_RUNNING;
+ }
+ continue;
+ }
+ /* or that were off and are now ok */
+ if (!iff_alive(ifp->int_if_flags)) {
+ ifp->int_if_flags |= IFF_UP_RUNNING;
+ (void)if_ok(ifp, "");
+ }
+
+ /* If it has been long enough,
+ * see if the interface is broken.
+ */
+ if (now.tv_sec < ifp->int_data.ts+CHECK_BAD_INTERVAL)
+ continue;
+
+ in = ifs.int_data.ipackets - ifp->int_data.ipackets;
+ ierr = ifs.int_data.ierrors - ifp->int_data.ierrors;
+ out = ifs.int_data.opackets - ifp->int_data.opackets;
+ oerr = ifs.int_data.oerrors - ifp->int_data.oerrors;
+#ifdef sgi
+ /* Through at least IRIX 6.2, PPP and SLIP
+ * count packets dropped by the filters.
+ * But FDDI rings stuck non-operational count
+ * dropped packets as they wait for improvement.
+ */
+ if (!(ifp->int_if_flags & IFF_POINTOPOINT))
+ oerr += (ifs.int_data.odrops
+ - ifp->int_data.odrops);
+#endif
+ /* If the interface just awoke, restart the counters.
+ */
+ if (ifp->int_data.ts == 0) {
+ ifp->int_data = ifs.int_data;
+ continue;
+ }
+ ifp->int_data = ifs.int_data;
+
+ /* Withhold judgement when the short error
+ * counters wrap or the interface is reset.
+ */
+ if (ierr < 0 || in < 0 || oerr < 0 || out < 0) {
+ LIM_SEC(ifinit_timer,
+ now.tv_sec+CHECK_BAD_INTERVAL);
+ continue;
+ }
+
+ /* Withhold judgement when there is no traffic
+ */
+ if (in == 0 && out == 0 && ierr == 0 && oerr == 0)
+ continue;
+
+ /* It is bad if input or output is not working.
+ * Require presistent problems before marking it dead.
+ */
+ if ((in <= ierr && ierr > 0)
+ || (out <= oerr && oerr > 0)) {
+ if (!(ifp->int_state & IS_SICK)) {
+ trace_act("interface %s to %s"
+ " sick: in=%d ierr=%d"
+ " out=%d oerr=%d\n",
+ ifp->int_name,
+ naddr_ntoa(ifp->int_addr),
+ in, ierr, out, oerr);
+ if_sick(ifp);
+ continue;
+ }
+ if (!(ifp->int_state & IS_BROKE)) {
+ msglog("interface %s to %s bad:"
+ " in=%d ierr=%d out=%d oerr=%d",
+ ifp->int_name,
+ naddr_ntoa(ifp->int_addr),
+ in, ierr, out, oerr);
+ if_bad(ifp);
+ }
+ continue;
+ }
+
+ /* otherwise, it is active and healthy
+ */
+ ifp->int_act_time = now.tv_sec;
+ (void)if_ok(ifp, "");
+ continue;
+ }
+
+ /* This is a new interface.
+ * If it is dead, forget it.
+ */
+ if (!iff_alive(ifs.int_if_flags))
+ continue;
+
+ /* See if it duplicates an existing interface.
+ */
+ for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
+ if (ifp->int_mask != ifs.int_mask)
+ continue;
+ if (((ifp->int_addr != ifs.int_addr
+ && ifs.int_mask != HOST_MASK)
+ || (ifp->int_dstaddr != ifs.int_dstaddr
+ && ifs.int_mask == HOST_MASK)))
+ continue;
+ if (!iff_alive(ifp->int_if_flags))
+ continue;
+ /* Let one of our real interfaces be marked
+ * passive.
+ */
+ if ((ifp->int_state & IS_PASSIVE)
+ && !(ifp->int_state & IS_EXTERNAL))
+ continue;
+
+ /* It does duplicate an existing interface,
+ * so complain about it, mark the other one
+ * duplicated, and for get this one.
+ */
+ if (!(prev_complaints & COMP_DUP)) {
+ complaints |= COMP_DUP;
+ msglog("%s is duplicated by %s at %s",
+ sdl->sdl_data, ifp->int_name,
+ naddr_ntoa(ifp->int_addr));
+ }
+ ifp->int_state |= IS_DUP;
break;
- if (maybe == 0 && (*netmatch)(addr, &ifp->int_addr))
- maybe = ifp;
+ }
+ if (ifp != 0)
+ continue;
+
+ /* It is new and ok. So make it real
+ */
+ strncpy(ifs.int_name, sdl->sdl_data,
+ MIN(sizeof(ifs.int_name)-1, sdl->sdl_nlen));
+ get_parms(&ifs);
+
+ /* Add it to the list of interfaces
+ */
+ ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit");
+ bcopy(&ifs, ifp, sizeof(*ifp));
+ if (ifnet != 0) {
+ ifp->int_next = ifnet;
+ ifnet->int_prev = ifp;
+ }
+ ifnet = ifp;
+ trace_if("Add", ifp);
+
+ /* Notice likely bad netmask.
+ */
+ if (!(prev_complaints & COMP_NETMASK)
+ && !(ifp->int_if_flags & IFF_POINTOPOINT)) {
+ for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) {
+ if (ifp1->int_mask == ifp->int_mask)
+ continue;
+ if (ifp1->int_if_flags & IFF_POINTOPOINT)
+ continue;
+ if (on_net(ifp->int_addr,
+ ifp1->int_net, ifp1->int_mask)
+ || on_net(ifp1->int_addr,
+ ifp->int_net, ifp->int_mask)) {
+ msglog("possible netmask problem"
+ " betwen %s:%s and %s:%s",
+ ifp->int_name,
+ addrname(htonl(ifp->int_net),
+ ifp->int_mask, 1),
+ ifp1->int_name,
+ addrname(htonl(ifp1->int_net),
+ ifp1->int_mask, 1));
+ complaints |= COMP_NETMASK;
+ }
+ }
+ }
+
+ /* Count the # of directly connected networks.
+ */
+ if (!(ifp->int_state & IS_ALIAS)) {
+ if (!(ifp->int_if_flags & IFF_LOOPBACK))
+ tot_interfaces++;
+ if (!IS_RIP_OFF(ifp->int_state))
+ rip_interfaces++;
+ }
+
+ if_ok_rdisc(ifp);
+ rip_on(ifp);
+ }
+
+ /* If we are multi-homed and have at least one interface
+ * listening to RIP, then output by default.
+ */
+ if (!supplier_set && rip_interfaces > 1)
+ set_supplier();
+
+ /* If we are multi-homed, optionally advertise a route to
+ * our main address.
+ */
+ if (advertise_mhome
+ || (tot_interfaces > 1
+ && mhome
+ && (ifp = ifwithaddr(myaddr, 0, 0)) != 0
+ && foundloopback)) {
+ advertise_mhome = 1;
+ rt = rtget(myaddr, HOST_MASK);
+ if (rt != 0) {
+ if (rt->rt_ifp != ifp
+ || rt->rt_router != loopaddr) {
+ rtdelete(rt);
+ rt = 0;
+ } else {
+ rtchange(rt, rt->rt_state | RS_MHOME,
+ loopaddr, loopaddr,
+ 0, 0, ifp, rt->rt_time, 0);
+ }
+ }
+ if (rt == 0)
+ rtadd(myaddr, HOST_MASK, loopaddr, loopaddr,
+ 0, 0, RS_MHOME, ifp);
+ }
+
+ for (ifp = ifnet; ifp != 0; ifp = ifp1) {
+ ifp1 = ifp->int_next; /* because we may delete it */
+
+ /* Forget any interfaces that have disappeared.
+ */
+ if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) {
+ trace_act("interface %s has disappeared\n",
+ ifp->int_name);
+ ifdel(ifp);
+ continue;
+ }
+
+ if ((ifp->int_state & IS_BROKE)
+ && !(ifp->int_state & IS_PASSIVE))
+ LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL);
+
+ /* If we ever have a RIPv1 interface, assume we always will.
+ * It might come back if it ever goes away.
+ */
+ if (!(ifp->int_if_flags & IFF_LOOPBACK)) {
+ if (!(ifp->int_state & IS_NO_RIPV1_OUT))
+ have_ripv1_out = 1;
+ if (!(ifp->int_state & IS_NO_RIPV1_IN))
+ have_ripv1_in = 1;
+ }
+ }
+
+ for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
+ /* Ensure there is always a network route for interfaces,
+ * after any dead interfaces have been deleted, which
+ * might affect routes for point-to-point links.
+ */
+ addrouteforif(ifp);
+
+ /* Add routes to the local end of point-to-point interfaces
+ * using loopback.
+ */
+ if ((ifp->int_if_flags & IFF_POINTOPOINT)
+ && !(ifp->int_state & IS_REMOTE)
+ && foundloopback) {
+ /* Delete any routes to the network address through
+ * foreign routers. Remove even static routes.
+ */
+ del_static(ifp->int_addr, HOST_MASK, 0);
+ rt = rtget(ifp->int_addr, HOST_MASK);
+ if (rt != 0 && rt->rt_router != loopaddr) {
+ rtdelete(rt);
+ rt = 0;
+ }
+ if (rt != 0) {
+ if (!(rt->rt_state & RS_LOCAL)
+ || rt->rt_metric > ifp->int_metric) {
+ ifp1 = ifp;
+ } else {
+ ifp1 = rt->rt_ifp;
+ }
+ rtchange(rt,((rt->rt_state & ~RS_NET_SYN)
+ | (RS_IF|RS_LOCAL)),
+ loopaddr, loopaddr,
+ 0, 0, ifp1, rt->rt_time, 0);
+ } else {
+ rtadd(ifp->int_addr, HOST_MASK,
+ loopaddr, loopaddr,
+ 0, 0, (RS_IF | RS_LOCAL), ifp);
+ }
+ }
+ }
+
+ /* add the authority routes */
+ for (intnetp = intnets; intnetp!=0; intnetp = intnetp->intnet_next) {
+ rt = rtget(intnetp->intnet_addr, intnetp->intnet_mask);
+ if (rt != 0
+ && !(rt->rt_state & RS_NO_NET_SYN)
+ && !(rt->rt_state & RS_NET_INT)) {
+ rtdelete(rt);
+ rt = 0;
+ }
+ if (rt == 0)
+ rtadd(intnetp->intnet_addr, intnetp->intnet_mask,
+ loopaddr, loopaddr, intnetp->intnet_metric-1,
+ 0, RS_NET_SYN | RS_NET_INT, 0);
+ }
+
+ prev_complaints = complaints;
+}
+
+
+static void
+check_net_syn(struct interface *ifp)
+{
+ struct rt_entry *rt;
+
+
+ /* Turn on the need to automatically synthesize a network route
+ * for this interface only if we are running RIPv1 on some other
+ * interface that is on a different class-A,B,or C network.
+ */
+ if (have_ripv1_out || have_ripv1_in) {
+ ifp->int_state |= IS_NEED_NET_SYN;
+ rt = rtget(ifp->int_std_addr, ifp->int_std_mask);
+ if (rt != 0
+ && 0 == (rt->rt_state & RS_NO_NET_SYN)
+ && (!(rt->rt_state & RS_NET_SYN)
+ || rt->rt_metric > ifp->int_metric)) {
+ rtdelete(rt);
+ rt = 0;
+ }
+ if (rt == 0)
+ rtadd(ifp->int_std_addr, ifp->int_std_mask,
+ ifp->int_addr, ifp->int_addr,
+ ifp->int_metric, 0, RS_NET_SYN, ifp);
+
+ } else {
+ ifp->int_state &= ~IS_NEED_NET_SYN;
+
+ rt = rtget(ifp->int_std_addr,
+ ifp->int_std_mask);
+ if (rt != 0
+ && (rt->rt_state & RS_NET_SYN)
+ && rt->rt_ifp == ifp)
+ rtbad_sub(rt);
+ }
+}
+
+
+/* Add route for interface if not currently installed.
+ * Create route to other end if a point-to-point link,
+ * otherwise a route to this (sub)network.
+ */
+void
+addrouteforif(struct interface *ifp)
+{
+ struct rt_entry *rt;
+ naddr dst, gate;
+
+
+ /* skip sick interfaces
+ */
+ if (ifp->int_state & IS_BROKE)
+ return;
+
+ /* If the interface on a subnet, then install a RIPv1 route to
+ * the network as well (unless it is sick).
+ */
+ if (ifp->int_state & IS_SUBNET)
+ check_net_syn(ifp);
+
+ if (ifp->int_state & IS_REMOTE) {
+ dst = ifp->int_addr;
+ gate = ifp->int_dstaddr;
+ /* If we are going to send packets to the gateway,
+ * it must be reachable using our physical interfaces
+ */
+ if (!(ifp->int_state && IS_EXTERNAL)
+ && !rtfind(ifp->int_dstaddr)
+ && ifp->int_transitions == 0) {
+ msglog("unreachable gateway %s in "
+ _PATH_GATEWAYS" entry %s",
+ naddr_ntoa(gate), ifp->int_name);
+ return;
+ }
+
+ } else {
+ dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT
+ | IFF_LOOPBACK))
+ ? ifp->int_dstaddr
+ : htonl(ifp->int_net));
+ gate = ifp->int_addr;
+ }
+
+ /* We are finished if the correct main interface route exists.
+ * The right route must be for the right interface, not synthesized
+ * from a subnet, be a "gateway" or not as appropriate, and so forth.
+ */
+ del_static(dst, ifp->int_mask, 0);
+ rt = rtget(dst, ifp->int_mask);
+ if (rt != 0) {
+ if ((rt->rt_ifp != ifp
+ || rt->rt_router != ifp->int_addr)
+ && (!(ifp->int_state & IS_DUP)
+ || rt->rt_ifp == 0
+ || (rt->rt_ifp->int_state & IS_BROKE))) {
+ rtdelete(rt);
+ rt = 0;
+ } else {
+ rtchange(rt, ((rt->rt_state | RS_IF)
+ & ~(RS_NET_SYN | RS_LOCAL)),
+ ifp->int_addr, ifp->int_addr,
+ ifp->int_metric, 0, ifp, now.tv_sec, 0);
+ }
+ }
+ if (rt == 0) {
+ if (ifp->int_transitions++ > 0)
+ trace_act("re-install interface %s\n",
+ ifp->int_name);
+
+ rtadd(dst, ifp->int_mask, gate, gate,
+ ifp->int_metric, 0, RS_IF, ifp);
}
- if (ifp == 0)
- ifp = maybe;
- return (ifp);
}
diff --git a/sbin/routed/inet.c b/sbin/routed/inet.c
deleted file mode 100644
index bbb5d1a7b62..00000000000
--- a/sbin/routed/inet.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/* $OpenBSD: inet.c,v 1.2 1996/06/23 14:32:27 deraadt Exp $ */
-/* $NetBSD: inet.c,v 1.9 1995/06/20 22:27:40 christos Exp $ */
-
-/*
- * Copyright (c) 1983, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)inet.c 8.2 (Berkeley) 8/14/93";
-#else
-static char rcsid[] = "$OpenBSD: inet.c,v 1.2 1996/06/23 14:32:27 deraadt Exp $";
-#endif
-#endif /* not lint */
-
-/*
- * Temporarily, copy these routines from the kernel,
- * as we need to know about subnets.
- */
-#include "defs.h"
-
-extern struct interface *ifnet;
-
-/*
- * Formulate an Internet address from network + host.
- */
-struct in_addr
-inet_makeaddr(net, host)
- u_long net, host;
-{
- register struct interface *ifp;
- register u_long mask;
- u_long addr;
-
- if (IN_CLASSA(net))
- mask = IN_CLASSA_HOST;
- else if (IN_CLASSB(net))
- mask = IN_CLASSB_HOST;
- else
- mask = IN_CLASSC_HOST;
- for (ifp = ifnet; ifp; ifp = ifp->int_next)
- if ((ifp->int_netmask & net) == ifp->int_net) {
- mask = ~ifp->int_subnetmask;
- break;
- }
- addr = net | (host & mask);
- addr = htonl(addr);
- return (*(struct in_addr *)&addr);
-}
-
-/*
- * Return the network number from an internet address.
- */
-u_long
-inet_netof_subnet(in)
- struct in_addr in;
-{
- register u_long i = ntohl(in.s_addr);
- register u_long net;
- register struct interface *ifp;
-
- if (IN_CLASSA(i))
- net = i & IN_CLASSA_NET;
- else if (IN_CLASSB(i))
- net = i & IN_CLASSB_NET;
- else
- net = i & IN_CLASSC_NET;
-
- /*
- * Check whether network is a subnet;
- * if so, return subnet number.
- */
- for (ifp = ifnet; ifp; ifp = ifp->int_next)
- if ((ifp->int_netmask & net) == ifp->int_net)
- return (i & ifp->int_subnetmask);
- return (net);
-}
-
-#ifdef notdef
-/*
- * Return the host portion of an internet address.
- * XXX THIS FUNCTION UNUSED.
- */
-u_long
-inet_lnaof_subnet(in)
- struct in_addr in;
-{
- register u_long i = ntohl(in.s_addr);
- register u_long net, host;
- register struct interface *ifp;
-
- if (IN_CLASSA(i)) {
- net = i & IN_CLASSA_NET;
- host = i & IN_CLASSA_HOST;
- } else if (IN_CLASSB(i)) {
- net = i & IN_CLASSB_NET;
- host = i & IN_CLASSB_HOST;
- } else {
- net = i & IN_CLASSC_NET;
- host = i & IN_CLASSC_HOST;
- }
-
- /*
- * Check whether network is a subnet;
- * if so, use the modified interpretation of `host'.
- */
- for (ifp = ifnet; ifp; ifp = ifp->int_next)
- if ((ifp->int_netmask & net) == ifp->int_net)
- return (host &~ ifp->int_subnetmask);
- return (host);
-}
-#endif
-
-/*
- * Return the netmask pertaining to an internet address.
- */
-int
-inet_maskof(inaddr)
- u_long inaddr;
-{
- register u_long i = ntohl(inaddr);
- register u_long mask;
- register struct interface *ifp;
-
- if (i == 0) {
- mask = 0;
- } else if (IN_CLASSA(i)) {
- mask = IN_CLASSA_NET;
- } else if (IN_CLASSB(i)) {
- mask = IN_CLASSB_NET;
- } else
- mask = IN_CLASSC_NET;
-
- /*
- * Check whether network is a subnet;
- * if so, use the modified interpretation of `host'.
- */
- for (ifp = ifnet; ifp; ifp = ifp->int_next)
- if ((ifp->int_netmask & i) == ifp->int_net)
- mask = ifp->int_subnetmask;
- return (htonl(mask));
-}
-
-/*
- * Return RTF_HOST if the address is
- * for an Internet host, RTF_SUBNET for a subnet,
- * 0 for a network.
- */
-int
-inet_rtflags(sa)
- struct sockaddr *sa;
-{
- struct sockaddr_in *sin = (struct sockaddr_in *) sa;
- register u_long i = ntohl(sin->sin_addr.s_addr);
- register u_long net, host;
- register struct interface *ifp;
-
- if (IN_CLASSA(i)) {
- net = i & IN_CLASSA_NET;
- host = i & IN_CLASSA_HOST;
- } else if (IN_CLASSB(i)) {
- net = i & IN_CLASSB_NET;
- host = i & IN_CLASSB_HOST;
- } else {
- net = i & IN_CLASSC_NET;
- host = i & IN_CLASSC_HOST;
- }
-
- /*
- * Check whether this network is subnetted;
- * if so, check whether this is a subnet or a host.
- */
- for (ifp = ifnet; ifp; ifp = ifp->int_next)
- if (net == ifp->int_net) {
- if (host &~ ifp->int_subnetmask)
- return (RTF_HOST);
- else if (ifp->int_subnetmask != ifp->int_netmask)
- return (RTF_SUBNET);
- else
- return (0); /* network */
- }
- if (host == 0)
- return (0); /* network */
- else
- return (RTF_HOST);
-}
-
-/*
- * Return true if a route to subnet/host of route rt should be sent to dst.
- * Send it only if dst is on the same logical network if not "internal",
- * otherwise only if the route is the "internal" route for the logical net.
- */
-int
-inet_sendroute(rt, sa)
- struct rt_entry *rt;
- struct sockaddr *sa;
-{
- struct sockaddr_in *dst = (struct sockaddr_in *) sa;
- register u_long r =
- ntohl(((struct sockaddr_in *)&rt->rt_dst)->sin_addr.s_addr);
- register u_long d = ntohl(dst->sin_addr.s_addr);
-
- if (IN_CLASSA(r)) {
- if ((r & IN_CLASSA_NET) == (d & IN_CLASSA_NET)) {
- if ((r & IN_CLASSA_HOST) == 0)
- return ((rt->rt_state & RTS_INTERNAL) == 0);
- return (1);
- }
- if (r & IN_CLASSA_HOST)
- return (0);
- return ((rt->rt_state & RTS_INTERNAL) != 0);
- } else if (IN_CLASSB(r)) {
- if ((r & IN_CLASSB_NET) == (d & IN_CLASSB_NET)) {
- if ((r & IN_CLASSB_HOST) == 0)
- return ((rt->rt_state & RTS_INTERNAL) == 0);
- return (1);
- }
- if (r & IN_CLASSB_HOST)
- return (0);
- return ((rt->rt_state & RTS_INTERNAL) != 0);
- } else {
- if ((r & IN_CLASSC_NET) == (d & IN_CLASSC_NET)) {
- if ((r & IN_CLASSC_HOST) == 0)
- return ((rt->rt_state & RTS_INTERNAL) == 0);
- return (1);
- }
- if (r & IN_CLASSC_HOST)
- return (0);
- return ((rt->rt_state & RTS_INTERNAL) != 0);
- }
-}
diff --git a/sbin/routed/input.c b/sbin/routed/input.c
index 941725028d0..c17e4fd2a36 100644
--- a/sbin/routed/input.c
+++ b/sbin/routed/input.c
@@ -1,5 +1,4 @@
-/* $OpenBSD: input.c,v 1.3 1996/06/23 14:32:27 deraadt Exp $ */
-/* $NetBSD: input.c,v 1.16 1995/07/13 23:20:10 christos Exp $ */
+/* $OpenBSD: input.c,v 1.4 1996/09/05 14:31:27 mickey Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@@ -34,365 +33,698 @@
* SUCH DAMAGE.
*/
-#ifndef lint
-#if 0
+#if !defined(lint)
static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93";
#else
-static char rcsid[] = "$OpenBSD: input.c,v 1.3 1996/06/23 14:32:27 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: input.c,v 1.4 1996/09/05 14:31:27 mickey Exp $";
#endif
-#endif /* not lint */
-/*
- * Routing Table Management Daemon
- */
#include "defs.h"
-#include <syslog.h>
+static void input(struct sockaddr_in *, struct interface*, struct rip *, int);
+static void input_route(struct interface *, naddr,
+ naddr, naddr, naddr, struct netinfo *);
-/*
- * "Authenticate" router from which message originated.
- * We accept routing packets from routers directly connected
- * via broadcast or point-to-point networks,
- * and from those listed in /etc/gateways.
+
+/* process RIP input
*/
-static struct interface *
-rip_verify(from)
- struct sockaddr *from;
+void
+read_rip(int sock,
+ struct interface *ifp)
{
- struct interface *ifp;
- char buf[256];
-
- if ((ifp = if_iflookup(from)) == 0) {
- syslog(LOG_ERR, "trace command from unknown router, %s",
- (*afswitch[from->sa_family].af_format)(from, buf,
- sizeof(buf)));
- return NULL;
- }
+ struct sockaddr_in from;
+ int fromlen, cc;
+ union pkt_buf inbuf;
- if ((ifp->int_flags &
- (IFF_BROADCAST|IFF_POINTOPOINT|IFF_REMOTE)) == 0) {
- syslog(LOG_ERR,
- "trace command from router %s, with bad flags %x",
- (*afswitch[from->sa_family].af_format)(from, buf,
- sizeof(buf)),
- ifp->int_flags);
- return NULL;
- }
- if ((ifp->int_flags & IFF_PASSIVE) != 0) {
- syslog(LOG_ERR,
- "trace command from %s on an active interface",
- (*afswitch[from->sa_family].af_format)(from, buf,
- sizeof(buf)));
- return NULL;
- }
+ for (;;) {
+ fromlen = sizeof(from);
+ cc = recvfrom(sock, &inbuf, sizeof(inbuf), 0,
+ (struct sockaddr*)&from, &fromlen);
+ if (cc <= 0) {
+ if (cc < 0 && errno != EWOULDBLOCK)
+ LOGERR("recvfrom(rip)");
+ break;
+ }
+ if (fromlen != sizeof(struct sockaddr_in))
+ logbad(1,"impossible recvfrom(rip) fromlen=%d",
+ fromlen);
- return ifp;
+ input(&from,
+ (ifp != 0) ? ifp : iflookup(from.sin_addr.s_addr),
+ &inbuf.rip, cc);
+ }
}
-/*
- * Process a newly received packet.
+/* Process a RIP packet
*/
-void
-rip_input(from, rip, size)
- struct sockaddr *from;
- register struct rip *rip;
- int size;
+static void
+input(struct sockaddr_in *from, /* received from this IP address */
+ struct interface *ifp,
+ struct rip *rip,
+ int size)
{
- register struct rt_entry *rt;
- register struct netinfo *n;
- register struct interface *ifp;
- struct sockaddr dst, gateway, netmask;
- int count, changes = 0;
- register struct afswitch *afp;
- static struct sockaddr badfrom;
- char buf1[256], buf2[256];
-
- ifp = 0;
- TRACE_INPUT(ifp, from, (char *)rip, size);
- if (from->sa_family >= af_max ||
- (afp = &afswitch[from->sa_family])->af_hash == NULL) {
- syslog(LOG_INFO,
- "\"from\" address in unsupported address family (%d), cmd %d\n",
- from->sa_family, rip->rip_cmd);
+# define FROM_NADDR from->sin_addr.s_addr
+ static naddr use_auth, bad_len, bad_mask;
+ static naddr unk_router, bad_router, bad_nhop;
+
+ struct rt_entry *rt;
+ struct netinfo *n, *lim;
+ struct interface *ifp1;
+ naddr gate, mask, v1_mask, dst, ddst_h;
+ int i;
+
+
+ if (ifp != 0)
+ ifp->int_state |= IS_ACTIVE;
+
+ trace_rip("Recv", "from", from, ifp, rip, size);
+
+ if (rip->rip_vers == 0) {
+ if (from->sin_addr.s_addr != bad_router)
+ msglog("RIP version 0, cmd %d, packet received"
+ " from %s",
+ rip->rip_cmd, naddr_ntoa(FROM_NADDR));
+ bad_router = from->sin_addr.s_addr;
return;
}
- if (rip->rip_vers == 0) {
- syslog(LOG_ERR,
- "RIP version 0 packet received from %s! (cmd %d)",
- (*afswitch[from->sa_family].af_format)(from, buf1,
- sizeof(buf1)),
- rip->rip_cmd);
+ if (size > MAXPACKETSIZE) {
+ if (from->sin_addr.s_addr != bad_router)
+ msglog("packet at least %d bytes too long received"
+ " from %s",
+ size-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR));
+ bad_router = from->sin_addr.s_addr;
return;
}
- switch (rip->rip_cmd) {
+ n = rip->rip_nets;
+ lim = (struct netinfo *)((char*)rip + size);
+ /* Notice authentication.
+ * As required by section 4.2 in RFC 1723, discard authenticated
+ * RIPv2 messages, but only if configured for that silliness.
+ *
+ * RIPv2 authentication is lame, since snooping on the wire makes
+ * its simple passwords evident. Also, why authenticate queries?
+ * Why should a RIPv2 implementation with authentication disabled
+ * not be able to listen to RIPv2 packets with authenication, while
+ * RIPv1 systems will listen? Crazy!
+ */
+ if (!auth_ok
+ && rip->rip_vers >= RIPv2
+ && n < lim && n->n_family == RIP_AF_AUTH) {
+ if (from->sin_addr.s_addr != use_auth)
+ msglog("RIPv2 message with authentication"
+ " from %s discarded",
+ naddr_ntoa(FROM_NADDR));
+ use_auth = from->sin_addr.s_addr;
+ trace_pkt("discard authenticated RIPv2 message\n");
+ return;
+ }
+
+ switch (rip->rip_cmd) {
case RIPCMD_REQUEST:
- n = rip->rip_nets;
- count = size - ((char *)n - (char *)rip);
- if (count < sizeof (struct netinfo))
- return;
- for (; count > 0; n++) {
- if (count < sizeof (struct netinfo))
- break;
- count -= sizeof (struct netinfo);
-
- n->rip_metric = ntohl(n->rip_metric);
- n->rip_family = ntohs(n->rip_family);
- /*
- * A single entry with sa_family == AF_UNSPEC and
- * metric ``infinity'' means ``all routes''.
+ /* did the request come from a router?
+ */
+ if (from->sin_port == htons(RIP_PORT)) {
+ /* yes, ignore it if RIP is off so that it does not
+ * depend on us.
+ */
+ if (rip_sock < 0) {
+ trace_pkt("ignore request while RIP off\n");
+ return;
+ }
+
+ /* Ignore the request if we talking to ourself
+ * (and not a remote gateway).
+ */
+ if (ifwithaddr(FROM_NADDR, 0, 0) != 0) {
+ trace_pkt("discard our own RIP request\n");
+ return;
+ }
+ }
+
+ /* According to RFC 1723, we should ignore unathenticated
+ * queries. That is too silly to bother with. Sheesh!
+ * Are forwarding tables supposed to be secret? When
+ * a bad guy can infer them with test traffic?
+ * Maybe on firewalls you'd care, but not enough to
+ * give up the diagnostic facilities of remote probing.
+ */
+
+ if (n >= lim
+ || size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
+ if (from->sin_addr.s_addr != bad_len)
+ msglog("request of bad length (%d) from %s",
+ size, naddr_ntoa(FROM_NADDR));
+ bad_len = from->sin_addr.s_addr;
+ }
+ for (; n < lim; n++) {
+ n->n_metric = ntohl(n->n_metric);
+
+ /* A single entry with family RIP_AF_UNSPEC and
+ * metric HOPCNT_INFINITY means "all routes".
* We respond to routers only if we are acting
* as a supplier, or to anyone other than a router
- * (eg, query).
+ * (i.e. a query).
+ *
+ * Answer a query from a stray program with all
+ * we know. Filter the answer to a query from a
+ * router in the about same way broadcasts are
+ * filtered.
+ *
+ * Only answer a router if we are a supplier
+ * to keep an unwary host that is just starting
+ * from picking us an a router.
*/
- if (n->rip_family == AF_UNSPEC &&
- n->rip_metric == HOPCNT_INFINITY && count == 0) {
- if (supplier || (*afp->af_portmatch)(from) == 0)
- supply(from, 0, 0, 0);
+ if (n->n_family == RIP_AF_UNSPEC
+ && n->n_metric == HOPCNT_INFINITY
+ && n == rip->rip_nets
+ && n+1 == lim) {
+ if (from->sin_port != htons(RIP_PORT)) {
+ /* query from `rtquery` or similar
+ */
+ supply(from, ifp,
+ OUT_QUERY, 0, rip->rip_vers);
+ } else if (supplier) {
+ /* a router trying to prime its
+ * tables.
+ */
+ supply(from, ifp,
+ OUT_UNICAST, 0, rip->rip_vers);
+ }
+ return;
+ }
+
+ if (n->n_family != RIP_AF_INET) {
+ if (from->sin_addr.s_addr != bad_router)
+ msglog("request from %s"
+ " for unsupported (af %d) %s",
+ naddr_ntoa(FROM_NADDR),
+ ntohs(n->n_family),
+ naddr_ntoa(n->n_dst));
+ bad_router = from->sin_addr.s_addr;
return;
}
- if (n->rip_family < af_max &&
- afswitch[n->rip_family].af_hash) {
- if (!(*afswitch[n->rip_family].af_get)(
- DESTINATION, n, &dst))
- return;
- rt = rtlookup(&dst);
+
+ dst = n->n_dst;
+ if (!check_dst(dst)) {
+ if (from->sin_addr.s_addr != bad_router)
+ msglog("bad queried destination"
+ " %s from %s",
+ naddr_ntoa(dst),
+ naddr_ntoa(FROM_NADDR));
+ bad_router = from->sin_addr.s_addr;
+ return;
+ }
+
+ if (rip->rip_vers == RIPv1
+ || 0 == (mask = ntohl(n->n_mask))
+ || 0 != (ntohl(dst) & ~mask))
+ mask = ripv1_mask_host(dst,ifp);
+
+ rt = rtget(dst, mask);
+ if (!rt && dst != RIP_DEFAULT)
+ rt = rtfind(n->n_dst);
+
+ n->n_tag = 0;
+ n->n_nhop = 0;
+ if (rip->rip_vers == RIPv1) {
+ n->n_mask = 0;
+ } else {
+ n->n_mask = mask;
+ }
+ if (rt == 0) {
+ n->n_metric = HOPCNT_INFINITY;
+ } else {
+ n->n_metric = rt->rt_metric+1;
+ n->n_metric += (ifp!=0) ? ifp->int_metric : 1;
+ if (n->n_metric > HOPCNT_INFINITY)
+ n->n_metric = HOPCNT_INFINITY;
+ if (rip->rip_vers != RIPv1) {
+ n->n_tag = rt->rt_tag;
+ if (ifp != 0
+ && on_net(rt->rt_gate,
+ ifp->int_net,
+ ifp->int_mask)
+ && rt->rt_gate != ifp->int_addr)
+ n->n_nhop = rt->rt_gate;
+ }
}
- else
- rt = 0;
-#define min(a, b) (a < b ? a : b)
- n->rip_metric = rt == 0 ? HOPCNT_INFINITY :
- min(rt->rt_metric + 1, HOPCNT_INFINITY);
- n->rip_metric = htonl(n->rip_metric);
+ HTONL(n->n_metric);
}
+ /* Answer about specific routes.
+ * Only answer a router if we are a supplier
+ * to keep an unwary host that is just starting
+ * from picking us an a router.
+ */
rip->rip_cmd = RIPCMD_RESPONSE;
- memcpy(packet, rip, size);
- (*afp->af_output)(s, 0, from, size);
+ rip->rip_res1 = 0;
+ if (rip->rip_vers != RIPv1)
+ rip->rip_vers = RIPv2;
+ if (from->sin_port != htons(RIP_PORT)) {
+ /* query */
+ (void)output(OUT_QUERY, from, ifp, rip, size);
+ } else if (supplier) {
+ (void)output(OUT_UNICAST, from, ifp, rip, size);
+ }
return;
case RIPCMD_TRACEON:
case RIPCMD_TRACEOFF:
/* verify message came from a privileged port */
-#ifdef TRACING
- if ((*afp->af_portcheck)(from) == 0)
+ if (ntohs(from->sin_port) > IPPORT_RESERVED) {
+ msglog("trace command from untrusted port on %s",
+ naddr_ntoa(FROM_NADDR));
return;
-
- if ((ifp = rip_verify(from)) == NULL)
+ }
+ if (ifp == 0) {
+ msglog("trace command from unknown router %s",
+ naddr_ntoa(FROM_NADDR));
return;
-
- ((char *)rip)[size] = '\0';
- if (rip->rip_cmd == RIPCMD_TRACEON)
- traceon(rip->rip_tracefile);
- else
- traceoff();
-#endif
+ }
+ if (rip->rip_cmd == RIPCMD_TRACEON) {
+ rip->rip_tracefile[size-4] = '\0';
+ trace_on((char*)rip->rip_tracefile, 0);
+ } else {
+ trace_off("tracing turned off by %s\n",
+ naddr_ntoa(FROM_NADDR));
+ }
return;
case RIPCMD_RESPONSE:
+ if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
+ if (from->sin_addr.s_addr != bad_len)
+ msglog("response of bad length (%d) from %s",
+ size, naddr_ntoa(FROM_NADDR));
+ bad_len = from->sin_addr.s_addr;
+ }
+
/* verify message came from a router */
- if ((*afp->af_portmatch)(from) == 0)
+ if (from->sin_port != ntohs(RIP_PORT)) {
+ trace_pkt("discard RIP response from unknown port\n");
return;
- (*afp->af_canon)(from);
- /* are we talking to ourselves? */
- ifp = if_ifwithaddr(from);
- if (ifp) {
- if (ifp->int_flags & IFF_PASSIVE) {
- syslog(LOG_ERR,
- "bogus input (from passive interface, %s)",
- (*afswitch[from->sa_family].af_format)(from,
- buf1, sizeof(buf1)));
- return;
+ }
+
+ if (rip_sock < 0) {
+ trace_pkt("discard response while RIP off\n");
+ return;
+ }
+
+ /* Are we talking to ourself or a remote gateway?
+ */
+ ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
+ if (ifp1) {
+ if (ifp1->int_state & IS_REMOTE) {
+ if (ifp1->int_state & IS_PASSIVE) {
+ msglog("bogus input from %s on"
+ " supposedly passive %s",
+ naddr_ntoa(FROM_NADDR),
+ ifp1->int_name);
+ } else {
+ ifp1->int_act_time = now.tv_sec;
+ if (if_ok(ifp1, "remote "))
+ addrouteforif(ifp1);
+ }
+ } else {
+ trace_pkt("discard our own RIP response\n");
}
- rt = rtfind(from);
- if (rt == 0 || (((rt->rt_state & RTS_INTERFACE) == 0) &&
- rt->rt_metric >= ifp->int_metric))
- addrouteforif(ifp);
- else
- rt->rt_timer = 0;
return;
}
- /*
- * Update timer for interface on which the packet arrived.
- * If from other end of a point-to-point link that isn't
- * in the routing tables, (re-)add the route.
+
+ /* Check the router from which message originated. We accept
+ * routing packets from routers directly connected via
+ * broadcast or point-to-point networks, and from
+ * those listed in /etc/gateways.
+ */
+ if (!ifp) {
+ if (from->sin_addr.s_addr != unk_router)
+ msglog("discard packet from unknown router %s"
+ " or via unidentified interface",
+ naddr_ntoa(FROM_NADDR));
+ unk_router = from->sin_addr.s_addr;
+ return;
+ }
+ if (ifp->int_state & IS_PASSIVE) {
+ trace_act("discard packet from %s"
+ " via passive interface %s\n",
+ naddr_ntoa(FROM_NADDR),
+ ifp->int_name);
+ return;
+ }
+
+ /* Check required version
+ */
+ if (((ifp->int_state & IS_NO_RIPV1_IN)
+ && rip->rip_vers == RIPv1)
+ || ((ifp->int_state & IS_NO_RIPV2_IN)
+ && rip->rip_vers != RIPv1)) {
+ trace_pkt("discard RIPv%d response\n",
+ rip->rip_vers);
+ return;
+ }
+
+ /* Ignore routes via dead interface.
*/
- if ((rt = rtfind(from)) &&
- (rt->rt_state & (RTS_INTERFACE | RTS_REMOTE)))
- rt->rt_timer = 0;
- else if ((ifp = if_ifwithdstaddr(from)) &&
- (rt == 0 || rt->rt_metric >= ifp->int_metric))
- addrouteforif(ifp);
-
- if ((ifp = rip_verify(from)) == NULL)
+ if (ifp->int_state & IS_BROKE) {
+ trace_pkt("discard response via broken interface %s\n",
+ ifp->int_name);
return;
+ }
+
+ /* Authenticate the packet if we have a secret.
+ */
+ if (ifp->int_passwd[0] != '\0') {
+ if (n >= lim
+ || n->n_family != RIP_AF_AUTH
+ || ((struct netauth*)n)->a_type != RIP_AUTH_PW) {
+ if (from->sin_addr.s_addr != use_auth)
+ msglog("missing password from %s",
+ naddr_ntoa(FROM_NADDR));
+ use_auth = from->sin_addr.s_addr;
+ return;
+
+ } else if (0 != bcmp(((struct netauth*)n)->au.au_pw,
+ ifp->int_passwd,
+ sizeof(ifp->int_passwd))) {
+ if (from->sin_addr.s_addr != use_auth)
+ msglog("bad password from %s",
+ naddr_ntoa(FROM_NADDR));
+ use_auth = from->sin_addr.s_addr;
+ return;
+ }
+ }
- size -= 4 * sizeof (char);
- n = rip->rip_nets;
- for (; size > 0; size -= sizeof (struct netinfo), n++) {
- if (size < sizeof (struct netinfo))
- break;
- n->rip_metric = ntohl(n->rip_metric);
- n->rip_family = ntohs(n->rip_family);
- if (!(*afswitch[n->rip_family].af_get)(DESTINATION, n,
- &dst))
+ for (; n < lim; n++) {
+ if (n->n_family == RIP_AF_AUTH)
continue;
- if (!(*afswitch[n->rip_family].af_get)(NETMASK,
- n, &netmask))
- memset(&netmask, 0, sizeof(netmask));
- if (!(*afswitch[n->rip_family].af_get)(GATEWAY,
- n, &gateway))
- memcpy(&gateway, from, sizeof(gateway));
- if (dst.sa_family >= af_max ||
- (afp = &afswitch[dst.sa_family])->af_hash == NULL) {
- syslog(LOG_INFO,
- "route in unsupported address family (%d), from %s (af %d)\n",
- dst.sa_family,
- (*afswitch[from->sa_family].af_format)(from,
- buf1, sizeof(buf1)),
- from->sa_family);
+
+ NTOHL(n->n_metric);
+ dst = n->n_dst;
+ if (n->n_family != RIP_AF_INET
+ && (n->n_family != RIP_AF_UNSPEC
+ || dst != RIP_DEFAULT)) {
+ if (from->sin_addr.s_addr != bad_router)
+ msglog("route from %s to unsupported"
+ " address family %d,"
+ " destination %s",
+ naddr_ntoa(FROM_NADDR),
+ n->n_family,
+ naddr_ntoa(dst));
+ bad_router = from->sin_addr.s_addr;
continue;
}
- if (((*afp->af_checkhost)(&dst)) == 0) {
- syslog(LOG_DEBUG,
- "bad host %s in route from %s (af %d)\n",
- (*afswitch[dst.sa_family].af_format)(
- &dst, buf1, sizeof(buf1)),
- (*afswitch[from->sa_family].af_format)(from,
- buf2, sizeof(buf2)),
- from->sa_family);
- continue;
+ if (!check_dst(dst)) {
+ if (from->sin_addr.s_addr != bad_router)
+ msglog("bad destination %s from %s",
+ naddr_ntoa(dst),
+ naddr_ntoa(FROM_NADDR));
+ bad_router = from->sin_addr.s_addr;
+ return;
}
- if (n->rip_metric == 0 ||
- (unsigned) n->rip_metric > HOPCNT_INFINITY) {
- if (memcmp(from, &badfrom,
- sizeof(badfrom)) != 0) {
- syslog(LOG_ERR,
- "bad metric (%d) from %s\n",
- n->rip_metric,
- (*afswitch[from->sa_family].af_format)(from,
- buf1, sizeof(buf1)));
- badfrom = *from;
- }
- continue;
+ if (n->n_metric == 0
+ || n->n_metric > HOPCNT_INFINITY) {
+ if (from->sin_addr.s_addr != bad_router)
+ msglog("bad metric %d from %s"
+ " for destination %s",
+ n->n_metric,
+ naddr_ntoa(FROM_NADDR),
+ naddr_ntoa(dst));
+ bad_router = from->sin_addr.s_addr;
+ return;
}
- /*
- * Adjust metric according to incoming interface.
+
+ /* Notice the next-hop.
*/
- if ((unsigned) n->rip_metric < HOPCNT_INFINITY)
- n->rip_metric += ifp->int_metric;
- if ((unsigned) n->rip_metric > HOPCNT_INFINITY)
- n->rip_metric = HOPCNT_INFINITY;
- rt = rtlookup(&dst);
- if (rt == 0 ||
- (rt->rt_state & (RTS_INTERNAL|RTS_INTERFACE)) ==
- (RTS_INTERNAL|RTS_INTERFACE)) {
- /*
- * If we're hearing a logical network route
- * back from a peer to which we sent it,
- * ignore it.
- */
- if (rt && rt->rt_state & RTS_SUBNET &&
- (*afp->af_sendroute)(rt, from))
- continue;
- if ((unsigned)n->rip_metric < HOPCNT_INFINITY) {
- /*
- * Look for an equivalent route that
- * includes this one before adding
- * this route.
- */
- rt = rtfind(&dst);
- if (rt && equal(&gateway, &rt->rt_router))
- continue;
- rtadd(&dst, &gateway, &netmask,
- n->rip_metric, 0);
- changes++;
+ gate = from->sin_addr.s_addr;
+ if (n->n_nhop != 0) {
+ if (rip->rip_vers == RIPv2) {
+ n->n_nhop = 0;
+ } else {
+ /* Use it only if it is valid. */
+ if (on_net(n->n_nhop,
+ ifp->int_net, ifp->int_mask)
+ && check_dst(n->n_nhop)) {
+ gate = n->n_nhop;
+ } else {
+ if (bad_nhop != from->sin_addr.s_addr)
+ msglog("router %s to %s has"
+ " bad next hop %s",
+ naddr_ntoa(FROM_NADDR),
+ naddr_ntoa(dst),
+ naddr_ntoa(n->n_nhop));
+ bad_nhop = from->sin_addr.s_addr;
+ n->n_nhop = 0;
+ }
+ }
+ }
+
+ if (rip->rip_vers == RIPv1
+ || 0 == (mask = ntohl(n->n_mask))) {
+ mask = ripv1_mask_host(dst,ifp);
+ } else if ((ntohl(dst) & ~mask) != 0) {
+ if (bad_mask != from->sin_addr.s_addr) {
+ msglog("router %s sent bad netmask"
+ " %#x with %s",
+ naddr_ntoa(FROM_NADDR),
+ mask,
+ naddr_ntoa(dst));
+ bad_mask = from->sin_addr.s_addr;
}
continue;
}
+ if (rip->rip_vers == RIPv1)
+ n->n_tag = 0;
+
+ /* Adjust metric according to incoming interface..
+ */
+ n->n_metric += ifp->int_metric;
+ if (n->n_metric > HOPCNT_INFINITY)
+ n->n_metric = HOPCNT_INFINITY;
+
+ /* Recognize and ignore a default route we faked
+ * which is being sent back to us by a machine with
+ * broken split-horizon.
+ * Be a little more paranoid than that, and reject
+ * default routes with the same metric we advertised.
+ */
+ if (ifp->int_d_metric != 0
+ && dst == RIP_DEFAULT
+ && n->n_metric >= ifp->int_d_metric)
+ continue;
- /*
- * Update if from gateway and different,
- * shorter, or equivalent but old route
- * is getting stale.
+ /* We can receive aggregated RIPv2 routes that must
+ * be broken down before they are transmitted by
+ * RIPv1 via an interface on a subnet.
+ * We might also receive the same routes aggregated
+ * via other RIPv2 interfaces.
+ * This could cause duplicate routes to be sent on
+ * the RIPv1 interfaces. "Longest matching variable
+ * length netmasks" lets RIPv2 listeners understand,
+ * but breaking down the aggregated routes for RIPv1
+ * listeners can produce duplicate routes.
+ *
+ * Breaking down aggregated routes here bloats
+ * the daemon table, but does not hurt the kernel
+ * table, since routes are always aggregated for
+ * the kernel.
+ *
+ * Notice that this does not break down network
+ * routes corresponding to subnets. This is part
+ * of the defense against RS_NET_SYN.
*/
- if (equal(&gateway, &rt->rt_router)) {
- if (n->rip_metric != rt->rt_metric) {
- rtchange(rt, &gateway,
- &netmask, n->rip_metric);
- changes++;
- rt->rt_timer = 0;
- if (rt->rt_metric >= HOPCNT_INFINITY)
- rt->rt_timer =
- GARBAGE_TIME - EXPIRE_TIME;
- } else if (rt->rt_metric < HOPCNT_INFINITY)
- rt->rt_timer = 0;
- } else if ((unsigned) n->rip_metric < rt->rt_metric ||
- (rt->rt_metric == n->rip_metric &&
- rt->rt_timer > (EXPIRE_TIME/2) &&
- (unsigned) n->rip_metric < HOPCNT_INFINITY)) {
- rtchange(rt, &gateway, &netmask, n->rip_metric);
- changes++;
- rt->rt_timer = 0;
+ if (have_ripv1_out
+ && (v1_mask = ripv1_mask_net(dst,0)) > mask
+ && (((rt = rtget(dst,mask)) == 0
+ || !(rt->rt_state & RS_NET_SYN)))) {
+ ddst_h = v1_mask & -v1_mask;
+ i = (v1_mask & ~mask)/ddst_h;
+ if (i >= 511) {
+ /* Punt if we would have to generate
+ * an unreasonable number of routes.
+ */
+#ifdef DEBUG
+ msglog("accept %s from %s as 1"
+ " instead of %d routes",
+ addrname(dst,mask,0),
+ naddr_ntoa(FROM_NADDR),
+ i+1);
+#endif
+ i = 0;
+ } else {
+ mask = v1_mask;
+ }
+ } else {
+ i = 0;
+ }
+
+ for (;;) {
+ input_route(ifp, FROM_NADDR,
+ dst, mask, gate, n);
+ if (i-- == 0)
+ break;
+ dst = htonl(ntohl(dst) + ddst_h);
}
}
break;
}
+}
+
- /*
- * If changes have occurred, and if we have not sent a broadcast
- * recently, send a dynamic update. This update is sent only
- * on interfaces other than the one on which we received notice
- * of the change. If we are within MIN_WAITTIME of a full update,
- * don't bother sending; if we just sent a dynamic update
- * and set a timer (nextbcast), delay until that time.
- * If we just sent a full update, delay the dynamic update.
- * Set a timer for a randomized value to suppress additional
- * dynamic updates until it expires; if we delayed sending
- * the current changes, set needupdate.
+/* Process a single input route.
+ */
+static void
+input_route(struct interface *ifp,
+ naddr from,
+ naddr dst,
+ naddr mask,
+ naddr gate,
+ struct netinfo *n)
+{
+ int i;
+ struct rt_entry *rt;
+ struct rt_spare *rts, *rts0;
+ struct interface *ifp1;
+ time_t new_time;
+
+
+ /* See if the other guy is telling us to send our packets to him.
+ * Sometimes network routes arrive over a point-to-point link for
+ * the network containing the address(es) of the link.
+ *
+ * If our interface is broken, switch to using the other guy.
*/
- if (changes && supplier &&
- now.tv_sec - lastfullupdate.tv_sec < SUPPLY_INTERVAL-MAX_WAITTIME) {
- u_long delay;
-
- if (now.tv_sec - lastbcast.tv_sec >= MIN_WAITTIME &&
- timercmp(&nextbcast, &now, <)) {
- if (traceactions)
- fprintf(ftrace, "send dynamic update\n");
- toall(supply, RTS_CHANGED, ifp);
- lastbcast = now;
- needupdate = 0;
- nextbcast.tv_sec = 0;
- } else {
- needupdate++;
- if (traceactions)
- fprintf(ftrace, "delay dynamic update\n");
- }
-#define RANDOMDELAY() (MIN_WAITTIME * 1000000 + \
- (u_long)random() % ((MAX_WAITTIME - MIN_WAITTIME) * 1000000))
-
- if (nextbcast.tv_sec == 0) {
- delay = RANDOMDELAY();
- if (traceactions)
- fprintf(ftrace,
- "inhibit dynamic update for %d usec\n",
- delay);
- nextbcast.tv_sec = delay / 1000000;
- nextbcast.tv_usec = delay % 1000000;
- timeradd(&nextbcast, &now, &nextbcast);
- /*
- * If the next possibly dynamic update
- * is within MIN_WAITTIME of the next full update,
- * force the delay past the full update,
- * or we might send a dynamic update just before
- * the full update.
+ ifp1 = ifwithaddr(dst, 1, 1);
+ if (ifp1 != 0
+ && !(ifp1->int_state & IS_BROKE))
+ return;
+
+ /* Look for the route in our table.
+ */
+ rt = rtget(dst, mask);
+
+ /* Consider adding the route if we do not already have it.
+ */
+ if (rt == 0) {
+ /* Ignore unknown routes being poisoned.
+ */
+ if (n->n_metric == HOPCNT_INFINITY)
+ return;
+
+ /* Ignore the route if it points to us */
+ if (n->n_nhop != 0
+ && 0 != ifwithaddr(n->n_nhop, 1, 0))
+ return;
+
+ /* If something has not gone crazy and tried to fill
+ * our memory, accept the new route.
+ */
+ if (total_routes < MAX_ROUTES)
+ rtadd(dst, mask, gate, from, n->n_metric,
+ n->n_tag, 0, ifp);
+ return;
+ }
+
+ /* We already know about the route. Consider this update.
+ *
+ * If (rt->rt_state & RS_NET_SYN), then this route
+ * is the same as a network route we have inferred
+ * for subnets we know, in order to tell RIPv1 routers
+ * about the subnets.
+ *
+ * It is impossible to tell if the route is coming
+ * from a distant RIPv2 router with the standard
+ * netmask because that router knows about the entire
+ * network, or if it is a round-about echo of a
+ * synthetic, RIPv1 network route of our own.
+ * The worst is that both kinds of routes might be
+ * received, and the bad one might have the smaller
+ * metric. Partly solve this problem by faking the
+ * RIPv1 route with a metric that reflects the most
+ * distant part of the subnet. Also never
+ * aggregate into such a route. Also keep it
+ * around as long as the interface exists.
+ */
+
+ rts0 = rt->rt_spares;
+ for (rts = rts0, i = NUM_SPARES; i != 0; i--, rts++) {
+ if (rts->rts_router == from)
+ break;
+ /* Note the worst slot to reuse,
+ * other than the current slot.
+ */
+ if (rts0 == rt->rt_spares
+ || BETTER_LINK(rt, rts0, rts))
+ rts0 = rts;
+ }
+ if (i != 0) {
+ /* Found the router
+ */
+ int old_metric = rts->rts_metric;
+
+ /* Keep poisoned routes around only long enough to pass
+ * the poison on. Get a new timestamp for good routes.
+ */
+ new_time =((old_metric == HOPCNT_INFINITY)
+ ? rts->rts_time
+ : now.tv_sec);
+
+ /* If this is an update for the router we currently prefer,
+ * then note it.
+ */
+ if (i == NUM_SPARES) {
+ rtchange(rt,rt->rt_state, gate,rt->rt_router,
+ n->n_metric, n->n_tag, ifp, new_time, 0);
+ /* If the route got worse, check for something better.
*/
- if (nextbcast.tv_sec > lastfullupdate.tv_sec +
- SUPPLY_INTERVAL - MIN_WAITTIME)
- nextbcast.tv_sec = lastfullupdate.tv_sec +
- SUPPLY_INTERVAL + 1;
+ if (n->n_metric > old_metric)
+ rtswitch(rt, 0);
+ return;
+ }
+
+ /* This is an update for a spare route.
+ * Finished if the route is unchanged.
+ */
+ if (rts->rts_gate == gate
+ && old_metric == n->n_metric
+ && rts->rts_tag == n->n_tag) {
+ rts->rts_time = new_time;
+ return;
}
+
+ } else {
+ /* The update is for a route we know about,
+ * but not from a familiar router.
+ *
+ * Ignore the route if it points to us.
+ */
+ if (n->n_nhop != 0
+ && 0 != ifwithaddr(n->n_nhop, 1, 0))
+ return;
+
+ rts = rts0;
+
+ /* Save the route as a spare only if it has
+ * a better metric than our worst spare.
+ * This also ignores poisoned routes (those
+ * received with metric HOPCNT_INFINITY).
+ */
+ if (n->n_metric >= rts->rts_metric)
+ return;
+
+ new_time = now.tv_sec;
}
+
+ trace_upslot(rt, rts, gate, from, ifp, n->n_metric,n->n_tag, new_time);
+
+ rts->rts_gate = gate;
+ rts->rts_router = from;
+ rts->rts_metric = n->n_metric;
+ rts->rts_tag = n->n_tag;
+ rts->rts_time = new_time;
+ rts->rts_ifp = ifp;
+
+ /* try to switch to a better route */
+ rtswitch(rt, rts);
}
diff --git a/sbin/routed/interface.h b/sbin/routed/interface.h
deleted file mode 100644
index 09653f93127..00000000000
--- a/sbin/routed/interface.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* $OpenBSD: interface.h,v 1.2 1996/06/23 14:32:28 deraadt Exp $ */
-/* $NetBSD: interface.h,v 1.8 1995/06/20 22:27:52 christos Exp $ */
-
-/*
- * Copyright (c) 1983, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)interface.h 8.1 (Berkeley) 6/5/93
- */
-
-/*
- * Routing table management daemon.
- */
-
-/*
- * An ``interface'' is similar to an ifnet structure,
- * except it doesn't contain q'ing info, and it also
- * handles ``logical'' interfaces (remote gateways
- * that we want to keep polling even if they go down).
- * The list of interfaces which we maintain is used
- * in supplying the gratuitous routing table updates.
- */
-struct interface {
- struct interface *int_next;
- struct sockaddr int_addr; /* address on this host */
- union {
- struct sockaddr intu_broadaddr;
- struct sockaddr intu_dstaddr;
- } int_intu;
-#define int_broadaddr int_intu.intu_broadaddr /* broadcast address */
-#define int_dstaddr int_intu.intu_dstaddr /* other end of p-to-p link */
- int int_metric; /* init's routing entry */
- int int_flags; /* see below */
- /* START INTERNET SPECIFIC */
- u_long int_net; /* network # */
- u_long int_netmask; /* net mask for addr */
- u_long int_subnet; /* subnet # */
- u_long int_subnetmask; /* subnet mask for addr */
- /* END INTERNET SPECIFIC */
- struct ifdebug int_input, int_output; /* packet tracing stuff */
- int int_ipackets; /* input packets received */
- int int_opackets; /* output packets sent */
- char *int_name; /* from kernel if structure */
- u_short int_transitions; /* times gone up-down */
-};
-
-/*
- * 0x1 to 0x10 are reused from the kernel's ifnet definitions,
- * the others agree with the RTS_ flags defined elsewhere.
- */
-#define IFF_UP 0x1 /* interface is up */
-#define IFF_BROADCAST 0x2 /* broadcast address valid */
-#define IFF_DEBUG 0x4 /* turn on debugging */
-#define IFF_LOOPBACK 0x8 /* software loopback net */
-#define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */
-
-#define IFF_SUBNET 0x100000 /* interface on subnetted network */
-#define IFF_PASSIVE 0x200000 /* can't tell if up/down */
-#define IFF_INTERFACE 0x400000 /* hardware interface */
-#define IFF_REMOTE 0x800000 /* interface isn't on this machine */
-
-struct interface *if_ifwithaddr __P((struct sockaddr *));
-struct interface *if_ifwithdstaddr __P((struct sockaddr *));
-struct interface *if_ifwithnet __P((struct sockaddr *));
-struct interface *if_iflookup __P((struct sockaddr *));
diff --git a/sbin/routed/main.c b/sbin/routed/main.c
index 567efa90faa..55faf5d70dc 100644
--- a/sbin/routed/main.c
+++ b/sbin/routed/main.c
@@ -1,5 +1,4 @@
-/* $OpenBSD: main.c,v 1.2 1996/06/23 14:32:29 deraadt Exp $ */
-/* $NetBSD: main.c,v 1.13 1995/06/20 22:27:53 christos Exp $ */
+/* $OpenBSD: main.c,v 1.3 1996/09/05 14:31:32 mickey Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@@ -34,307 +33,796 @@
* 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);
}
diff --git a/sbin/routed/output.c b/sbin/routed/output.c
index 9e74959367f..c1ad2fc6a12 100644
--- a/sbin/routed/output.c
+++ b/sbin/routed/output.c
@@ -1,5 +1,4 @@
-/* $OpenBSD: output.c,v 1.2 1996/06/23 14:32:29 deraadt Exp $ */
-/* $NetBSD: output.c,v 1.9 1995/06/20 22:27:54 christos Exp $ */
+/* $OpenBSD: output.c,v 1.3 1996/09/05 14:31:36 mickey Exp $ */
/*
* Copyright (c) 1983, 1988, 1993
@@ -34,144 +33,843 @@
* 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);
}
}
diff --git a/sbin/routed/pathnames.h b/sbin/routed/pathnames.h
index 2a540c60383..561927f35a4 100644
--- a/sbin/routed/pathnames.h
+++ b/sbin/routed/pathnames.h
@@ -1,5 +1,4 @@
-/* $OpenBSD: pathnames.h,v 1.2 1996/06/23 14:32:30 deraadt Exp $ */
-/* $NetBSD: pathnames.h,v 1.6 1995/03/18 15:00:37 cgd Exp $ */
+/* $OpenBSD: pathnames.h,v 1.3 1996/09/05 14:31:38 mickey Exp $ */
/*
* Copyright (c) 1989, 1993
@@ -34,8 +33,16 @@
* 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"
diff --git a/sbin/routed/routed.8 b/sbin/routed/routed.8
index 8be7cfd7d57..460d955e56e 100644
--- a/sbin/routed/routed.8
+++ b/sbin/routed/routed.8
@@ -1,5 +1,4 @@
-.\" $OpenBSD: routed.8,v 1.4 1996/06/23 14:32:31 deraadt Exp $
-.\" $NetBSD: routed.8,v 1.7 1996/02/06 20:34:28 scottr Exp $
+.\" $OpenBSD: routed.8,v 1.5 1996/09/05 14:31:41 mickey Exp $
.\"
.\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -32,326 +31,570 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)routed.8 8.2 (Berkeley) 12/11/93
+.\" @(#)routed.8 8.2 (Berkeley) 12/11/93
.\"
-.Dd December 11, 1993
+.Dd June 1, 1996
.Dt ROUTED 8
-.Os BSD 4.2
+.Os BSD 4.4
.Sh NAME
.Nm routed
-.Nd network routing daemon
+.Nd network RIP and router discovery routing daemon
.Sh SYNOPSIS
-.Nm routed
-.Op Fl d
-.Op Fl g
-.Op Fl q
-.Op Fl s
-.Op Fl t
-.Op Ar logfile
+.Nm
+.Op Fl sqdghmpAt
+.Op Fl T Ar tracefile
+.Oo
+.Fl F
+.Ar net Ns Op /mask Ns Op ,metric
+.Oc
+.OP Fl P Ar parms
.Sh DESCRIPTION
.Nm Routed
-is invoked at boot time to manage the network routing tables.
-The routing daemon uses a variant of the Xerox NS Routing
-Information Protocol in maintaining up to date kernel routing
-table entries.
-It used a generalized protocol capable of use with multiple
-address types, but is currently used only for Internet routing
-within a cluster of networks.
-.Pp
-In normal operation
-.Nm routed
-listens on the
+is a dameon invoked at boot time to manage the network
+routing tables.
+It uses Routing Information Protocol, RIPv1 (RFC\ 1058),
+RIPv2 (RFC\ 1723),
+and Internet Router Discovery Protocol (RFC 1256)
+to maintain the kernel routing table.
+The RIPv1 protocol is based on the reference 4.3BSD daemon.
+.Pp
+It listens on the
.Xr udp 4
socket for the
.Xr route 8
service (see
.Xr services 5 )
-for routing information packets. If the host is an
-internetwork router, it periodically supplies copies
-of its routing tables to any directly connected hosts
-and networks.
+for Routing Information Protocol packets.
+It also sends and receives multicast Router Discovery ICMP messages.
+If the host is a router,
+.Nm
+periodically supplies copies
+of its routing tables to any directly connected hosts and networks.
+It also advertise or solicits default routes using Router Discovery
+ICMP messages.
.Pp
-When
-.Nm routed
-is started, it uses the
-.Dv SIOCGIFCONF
-.Xr ioctl 2
-to find those
+When started (or when a network interface is later turned on),
+.Nm
+uses an AF_ROUTE address family facility to find those
directly connected interfaces configured into the
-system and marked ``up'' (the software loopback interface
-is ignored). If multiple interfaces
-are present, it is assumed that the host will forward packets
-between networks.
-.Nm Routed
-then transmits a
-.Em request
-packet on each interface (using a broadcast packet if
-the interface supports it) and enters a loop, listening
-for
+system and marked "up".
+It adds necessary routes for the interfaces
+to the kernel routing table.
+Soon after being first started, and provided there is at least one
+interface on which RIP has not been disabled,
+.Nm
+deletes all pre-existing
+non-static routes in kernel table.
+Static routes in the kernel table are preserved and
+included in RIP responses if they have a valid RIP metric
+(see
+.Xr route 8 ).
+.Pp
+If more than one interface is present (not counting the loopback interface),
+it is assumed that the host should forward packets among the
+connected networks.
+After transmitting a RIP
.Em request
and
-.Em response
-packets from other hosts.
+Router Discovery Advertisements or Solicitations on a new interface,
+the daemon enters a loop, listening for
+RIP request and response and Router Discover packets from other hosts.
.Pp
When a
.Em request
-packet is received,
-.Nm routed
+packet is received,
+.Nm
formulates a reply based on the information maintained in its
-internal tables. The
+internal tables.
+The
.Em response
packet generated contains a list of known routes, each marked
-with a ``hop count'' metric (a count of 16, or greater, is
-considered ``infinite''). The metric associated with each
-route returned provides a metric
-.Em relative to the sender .
+with a "hop count" metric (a count of 16 or greater is
+considered "infinite").
+Advertised metrics reflect the metric associated with interface
+(see
+.Xr ifconfig 8 ),
+so setting the metric on an interface
+is an effective way to steer traffic.
.Pp
-.Em Response
-packets received by
-.Nm routed
-are used to update the routing tables if one of the following
-conditions is satisfied:
-.Bl -enum
-.It
-No routing table entry exists for the destination network
-or host, and the metric indicates the destination is ``reachable''
-(i.e. the hop count is not infinite).
-.It
-The source host of the packet is the same as the router in the
-existing routing table entry. That is, updated information is
-being received from the very internetwork router through which
-packets for the destination are being routed.
-.It
-The existing entry in the routing table has not been updated for
-some time (defined to be 90 seconds) and the route is at least
-as cost effective as the current route.
-.It
-The new route describes a shorter route to the destination than
-the one currently stored in the routing tables; the metric of
-the new route is compared against the one stored in the table
-to decide this.
-.El
+Responses do not contain routes with a first hop on the requesting
+network to implement in part
+.Em split-horizon .
+Requests from query programs
+such as
+.Xr rtquery 8
+are answered with the complete table.
+.Pp
+The routing table maintained by the daemon
+includes space for several gateways for each destination
+to speed recovery from a failing router.
+RIP
+.Em response
+packets received are used to update the routing tables provided they are
+from one of the several currently recognized gateways or
+advertise a better metric than at least one of the existing
+gateways.
.Pp
When an update is applied,
-.Nm routed
-records the change in its internal tables and updates the kernel
-routing table.
-The change is reflected in the next
+.Nm
+records the change in its own tables and updates the kernel routing table
+if the best route to the destination changes.
+The change in the kernel routing tableis reflected in the next batch of
.Em response
-packet sent.
+packets sent.
+If the next response is not scheduled for a while, a
+.Em flash update
+response containing only recently changed routes is sent.
.Pp
In addition to processing incoming packets,
-.Nm routed
+.Nm
also periodically checks the routing table entries.
If an entry has not been updated for 3 minutes, the entry's metric
-is set to infinity and marked for deletion. Deletions are delayed
-an additional 60 seconds to insure the invalidation is propagated
-throughout the local internet.
+is set to infinity and marked for deletion.
+Deletions are delayed until the route has been advertised with
+an infinite metric to insure the invalidation
+is propagated throughout the local internet.
+This is a form of
+.Em poison reverse .
+.Pp
+Routes in the kernel table that are added or changed as a result
+of ICMP Redirect messages are deleted after a while to minimize
+.Em black-holes .
+When a TCP connection suffers a timeout,
+the kernel tells
+.Nm routed ,
+which deletes all redirected routes
+through the gateway involved, advances the age of all RIP routes through
+the gateway to allow an alternate to be chosen, and advances of the
+age of any relevant Router Discovery Protocol default routes.
.Pp
Hosts acting as internetwork routers gratuitously supply their
routing tables every 30 seconds to all directly connected hosts
and networks.
-The response is sent to the broadcast address on nets capable of that function,
+These RIP responses are sent to the broadcast address on nets that support
+broadcasting,
to the destination address on point-to-point links, and to the router's
own address on other networks.
-The normal routing tables are bypassed when sending gratuitous responses.
-The reception of responses on each network is used to determine that the
-network and interface are functioning correctly.
-If no response is received on an interface, another route may be chosen
-to route around the interface, or the route may be dropped if no alternative
-is available.
+If RIPv2 is enabled, multicast packets are sent on interfaces that
+support multicasting.
+.Pp
+If no response is received on a remote interface, if there are errors
+while sending responses,
+or if there are more errors than input or output (see
+.Xr netstat 8 ),
+then the cable or some other part of the interface is assumed to be
+disconnected or broken, and routes are adjusted appropriately.
+.Pp
+The
+.Em Internet Router Discovery Protocol
+is handled similarly.
+When the daemon is supplying RIP routes, it also listens for
+Router Discovery Solicitations and sends Advertisements.
+When it is quiet and only listening to other RIP routers, it
+sends Solicitations and listens for Advertisements.
+If it receives
+a good Advertisement, it stops listening for broadcast or multicast
+RIP responses.
+It tracks several advertising routers to speed recovery when the
+currently chosen router dies.
+If all discovered routers disappear,
+the daemon resumes listening to RIP responses.
+.Pp
+While using Router Discovery (which happens by default when
+the system has a single network interface and a Router Discover Advertisement
+is received), there is a single default route and a variable number of
+redirected host routes in the kernel table.
+.Pp
+The Router Discover standard requires that advertisements
+have a default "lifetime" of 30 minutes. That means should
+something happen, a client can be without a good route for
+30 minutes. It is a good idea to reduce the default to 45
+seconds using
+.Fl P Cm rdisc_interval=45
+on the command line or
+.Cm rdisc_interval=45
+in the
+.Pa /etc/gateways
+file.
+.Pp
+While using Router Discovery (which happens by default when
+the system has a single network interface and a Router Discover Advertisement
+is received), there is a single default route and a variable number of
+redirected host routes in the kernel table.
+.Pp
+See the
+.Cm pm_rdisc
+facility described below to support "legacy" systems
+that can handle neither RIPv2 nor Router Discovery.
+.Pp
+By default, neither Router Discovery advertisements nor solicications
+are sent over point to point links (e.g. PPP).
+
.Pp
Options supported by
.Nm routed :
.Bl -tag -width Ds
+.It Fl s
+this option forces
+.Nm
+to supply routing information.
+This is the default if multiple network interfaces are present on which
+RIP or Router Discovery have not been disabled, and if the kernel switch
+ipforwarding=1.
+.It Fl q
+is the opposite of the
+.Fl s
+option.
.It Fl d
-Enable additional debugging information to be logged,
-such as bad packets received.
+Do not run in the background.
+This option is meant for interactive use.
.It Fl g
This flag is used on internetwork routers to offer a route
-to the ``default'' destination.
+to the "default" destination.
+It is equivalent to
+.Fl F
+.Cm 0/0,1
+and is present mostly for historical reasons.
+A better choice is
+.Fl P Cm pm_rdisc
+on the command line or
+.CM pm_rdisc in the
+.Pa /etc/gateways
+file.
+since a larger metric
+will be used, reducing the spread of the potentially dangerous
+default route.
This is typically used on a gateway to the Internet,
or on a gateway that uses another routing protocol whose routes
are not reported to other local routers.
-.It Fl s
-Supplying this
-option forces
-.Nm routed
-to supply routing information whether it is acting as an internetwork
-router or not.
-This is the default if multiple network interfaces are present,
-or if a point-to-point link is in use.
-.It Fl q
-This
-is the opposite of the
-.Fl s
-option.
+Notice that because a metric of 1 is used, this feature is
+dangerous. It is more commonly accidently used to create chaos with routing
+loop than to solve problems.
+.It Fl h
+This causes host or point-to-point routes to not be advertised,
+provided there is a network route going the same direction.
+That is a limited kind of aggregation.
+This option is useful on gateways to ethernets that have other gateway
+machines connected with point-to-point links such as SLIP.
+.It Fl m
+This causes the machine to advertise a host or point-to-point route to
+its primary interface.
+It is useful on multi-homed machines such as NFS servers.
+This option should not be used except when the cost of
+the host routes it generates is justified by the popularity of
+the server.
+It is effective only when the machine is supplying
+routing information, because there is more than one interface.
+The
+.Fl m
+option overrides the
+.Fl q
+option to the limited extent of advertising the host route.
+.It Fl A
+do not ignore RIPv2 authentication if we do not care about RIPv2
+authentication.
+This option is required for conformance with RFC 1723.
+However, it makes no sense and breaks using RIP as a discovery protocol
+to ignore all RIPv2 packets that carry authentication when this machine
+does not care about authentication.
+.It Fl T Ar tracefile
+increases the debugging level to at least 1 and
+causes debugging information to be appended to the trace file.
.It Fl t
-If the
-.Fl t
-option is specified, all packets sent or received are
-printed on the standard output. In addition,
-.Nm routed
-will not divorce itself from the controlling terminal
-so that interrupts from the keyboard will kill the process.
+increases the debugging level, which causes more information to be logged
+on the tracefile specified with
+.Fl T
+or standard out.
+The debugging level can be increased or decreased
+with the
+.Em SIGUSR1
+or
+.Em SIGUSR2
+signals or with the
+.Cm rtquery
+command.
+.It Fl F Ar net[/mask][,metric]
+minimize routes in transmissions via interfaces with addresses that match
+.Em net/mask ,
+and synthesizes a default route to this machine with the
+.Em metric .
+The intent is to reduce RIP traffic on slow, point-to-point links
+such as PPP links by replacing many large UDP packets of RIP information
+with a single, small packet containing a "fake" default route.
+If
+.Em metric
+is absent, a value of 14 is assumed to limit
+the spread of the "fake" default route.
+
+This is a dangerous feature that when used carelessly can cause routing
+loops.
+Notice also that more than one interface can match the specified network
+number and mask.
+See also
+.Fl g .
+.It Fl P Ar parms
+is equivalent to adding the parameter
+line
+.Em parms
+to the
+.Pa /etc/gateways
+file.
.El
.Pp
Any other argument supplied is interpreted as the name
-of file in which
-.Nm routed Ns \'s
-actions should be logged. This log contains information
-about any changes to the routing tables and, if not tracing all packets,
-a history of recent messages sent and received which are related to
-the changed route.
-.Pp
-In addition to the facilities described above,
-.Nm routed
-supports the notion of ``distant''
+of a file in which the actions of
+.Nm
+should be logged.
+It is better to use
+.Fl T
+instead of
+appending the name of the trace file to the command.
+.Pp
+.Nm
+also supports the notion of
+"distant"
.Em passive
-and
+or
.Em active
-gateways. When
-.Nm routed
-is started up, it reads the file
+gateways.
+When
+.Nm
+is started, it reads the file
.Pa /etc/gateways
-to find gateways which may not be located using
-only information from the
-.Dv SIOGIFCONF
-.Xr ioctl 2 .
+to find such distant gateways which may not be located using
+only information from a routing socket, to discover if some
+of the local gateways are
+.Em passive ,
+and to obtain other parameters.
Gateways specified in this manner should be marked passive
if they are not expected to exchange routing information,
while gateways marked active
-should be willing to exchange routing information (i.e.
-they should have a
-.Nm routed
-process running on the machine).
-Routes through passive gateways are installed in the
-kernel's routing tables once upon startup.
-Such routes are not included in
-any routing information transmitted.
-Active gateways are treated equally to network
-interfaces. Routing information is distributed
-to the gateway and if no routing information is
-received for a period of time, the associated
-route is deleted.
+should be willing to exchange RIP packets.
+Routes through
+.Em passive
+gateways are installed in the
+kernel's routing tables once upon startup and are not included in
+transmitted RIP responses.
+.Pp
+Distant active gateways are treated like network interfaces.
+RIP responses are sent
+to the distant
+.Em active
+gateway.
+If no responses are received, the associated route is deleted from
+the kernel table and RIP responses advertised via other interfaces.
+If the distant gateway resumes sending RIP responses, the associated
+route is restored.
+.Pp
+Such gateways can be useful on media that do not support broadcasts
+or multicasts but otherwise act like classic shared media like
+Ethernets such as some ATM networks.
+One can list all RIP routers reachable on the ATM network in
+.Pa /etc/gateways
+with a series of
+"host" lines.
+.Pp
Gateways marked
.Em external
are also passive, but are not placed in the kernel
routing table nor are they included in routing updates.
-The function of external entries is to inform
-.Nm routed
+The function of external entries is to indicate
that another routing process
-will install such a route, and that alternate routes to that destination
-should not be installed.
+will install such a route if ncessary,
+and that alternate routes to that destination should not be installed
+by
+.Nm routed .
Such entries are only required when both routers may learn of routes
to the same destination.
.Pp
-The
-.Pa /etc/gateways
-file is composed of a series of lines, each in
-the following format:
+The
+.Em /etc/gateways
+file is comprised of a series of lines, each in
+one of the following formats or consist of parameters described below:
+.Pp
.Bd -ragged
-.Pf < Cm net No \&|
-.Cm host Ns >
-.Ar name1
+.Cm net
+.Ar Nname[/mask]
.Cm gateway
-.Ar name2
+.Ar Gname
.Cm metric
.Ar value
.Pf < Cm passive No \&|
.Cm active No \&|
-.Cm external Ns >
+.Cm extern Ns >
.Ed
-.Pp
-The
-.Cm net
-or
+.Bd -ragged
.Cm host
-keyword indicates if the route is to a network or specific host.
+.Ar Hname
+.Cm gateway
+.Ar Gname
+.Cm metric
+.Ar value
+.Pf < Cm passive No \&|
+.Cm active No \&|
+.Cm extern Ns >
+.Ed
.Pp
-.Ar Name1
-is the name of the destination network or host. This may be a
-symbolic name located in
+.Ar Nname
+or
+.Ar Hname
+is the name of the destination network or host.
+It may be a symbolic network name or an Internet address
+specified in "dot" notation (see
+.Xr inet 3 ).
+(If it is a name, then it must either be defined in
.Pa /etc/networks
or
-.Pa /etc/hosts
-(or, if started after
+.Pa /etc/hosts ,
+or
.Xr named 8 ,
-known to the name server),
-or an Internet address specified in ``dot'' notation; see
-.Xr inet 3 .
+must have been started before
+.Xr routed Ns .)
+.Pp
+.Ar mask
+is an optional number between 1 and 32 indicating the netmask associated
+with
+.Ar Nname .
.Pp
-.Ar Name2
-is the name or address of the gateway to which messages should
+.Ar Gname
+is the name or address of the gateway to which RIP responses should
be forwarded.
.Pp
.Ar Value
-is a metric indicating the hop count to the destination host
-or network.
+is the hop count to the destination host or network.
+.Ar " host hname "
+is equivalent to
+.Ar " net nname/32 ".
.Pp
One of the keywords
.Cm passive ,
.Cm active
or
.Cm external
-indicates if the gateway should be treated as
-.Em passive
+must be present to indicate whether the gateway should be treated as
+.Cm passive
or
-.Em active
+.Cm active
(as described above),
or whether the gateway is
-.Em external
-to the scope of the
+.Cm external
+to the scope of the RIP protocol.
+.Pp
+Lines that start with neither "net" nor "host" must consist of one
+or more of the following parameter settings, separated by commas or
+blanks:
+.Bl -tag -width Ds
+.It Cm if Ns \&= Ns Ar ifname
+indicates that the other parameters on the line apply to the interface
+name
+.Ar ifname .
+.It Cm subnet Ns \&= Ns Ar nname[/mask][,metric]
+advertises a route to network
+.AR nname
+with mask
+.AR mask
+and the supplied metric (default 1).
+This is useful for filling "holes" in CIDR allocations.
+This parameter must appear by itself on a line.
+.Pp
+Do not use this feature unless necessary. It is dangerous.
+.It Cm passwd Ns \&= Ns Ar XXX
+specifies a RIPv2 password that will be included on all RIPv2
+responses sent and checked on all RIPv2 responses received.
+The password must not contain any blanks, tab characters, commas
+or '#' characters.
+.It Cm no_ag
+turns off aggregation of subnets in RIPv1 and RIPv2 responses.
+.It Cm no_super_ag
+turns off aggregation of networks into supernets in RIPv2 responses.
+.It Cm passive
+is equivalent
+.Cm no_rip Cm no_rdisc .
+.It Cm no_rip
+disables all RIP processing on the specified interface.
+If no interfaces are allowed to process RIP packets,
+.Nm
+acts purely as a router discovery daemon.
+.Cm No_rip
+is equivalent to
+.Cm no_ripv1_in no_ripv2_in no_ripv1_out no_ripv2_out .
+
+Note that turning off RIP without explicitly turning on router
+discovery advertisements with
+.Cm rdisc_adv
+or
+.Fl s
+causes
.Nm routed
-protocol.
-.Pp
-Internetwork routers that are directly attached to the Arpanet or Milnet
-should use the Exterior Gateway Protocol
-.Pq Tn EGP
-to gather routing information
-rather then using a static routing table of passive gateways.
-.Tn EGP
-is required in order to provide routes for local networks to the rest
-of the Internet system.
+to act as a client router discovery daemon, not adveritising.
+.It Cm no_ripv1_in
+causes RIPv1 received responses to be ignored.
+.It Cm no_ripv2_in
+causes RIPv2 received responses to be ignored.
+.It Cm ripv2_out
+turns off RIPv1 output and causes RIPv2 advertisements to be
+multicast when possible.
+.It Cm no_rdisc
+disables the Internet Router Discovery Protocol.
+.It Cm no_solicit
+disables the tranmission of Router Discovery Solicitations.
+.It Cm send_solicit
+specifies that Router Discovery solicitations should be sent,
+even on point-to-point links,
+which by default only listen to Router Discovery messages.
+.It Cm no_rdisc_adv
+disables the transmission of Router Discovery Advertisements
+.It Cm rdisc_adv
+specifies that Router Discovery advertisements should be sent,
+even on point-to-point links,
+which by default only listen to Router Discovery messages
+.It Cm bcast_rdisc
+specifies that Router Discovery packets should be broadcast instead of
+multicast.
+.It Cm rdisc_pref Ns \&= Ns Ar N
+sets the preference in Router Discovery Advertisements to the integer
+.Ar N .
+.It Cm rdisc_interval Ns \&= Ns Ar N
+sets the nominal interval with which Router Discovery Advertisements
+are transmitted to N seconds and their lifetime to 3*N.
+.It Cm fake_default Ns \&= Ns Ar metric
+has an identical effect to
+.Fl F Ar net[/mask][,metric]
+with the network and mask coming from the sepcified interface.
+.It Cm pm_rdisc
+is similar to
+.Cm fake_default .
+When RIPv2 routes are multicast, so that RIPv1 listeners cannot
+receive them, this feature causes a RIPv1 default route to be
+broadcast to RIPv1 listeners.
+Unless modified with
+.Cm fake_default ,
+the default route is broadcast with a metric of 14.
+That serves as a "poor man's router discovery" protocol.
+.El
+.Pp
+Note that the netmask associated with point-to-point links (such as SLIP
+or PPP, with the IFF_POINTOPOINT flag) is used by
+.Nm routed
+to infer the netmask used by the remote system when RIPv1 is used.
+.Pp
.Sh FILES
.Bl -tag -width /etc/gateways -compact
.It Pa /etc/gateways
for distant gateways
.El
.Sh SEE ALSO
+.Xr gated 8 ,
.Xr udp 4 ,
.Xr icmp 4 ,
-.Xr XNSrouted 8 ,
-.Xr htable 8
+.Xr htable 8 ,
+.Xr rtquery 8 .
.Rs
.%T Internet Transport Protocols
.%R XSIS 028112
.%Q Xerox System Integration Standard
.Re
.Sh BUGS
-The kernel's routing tables may not correspond to those of
-.Nm routed
-when redirects change or add routes.
-.Nm Routed
-should note any redirects received by reading
-the
-.Tn ICMP
-packets received via a raw socket.
-.Pp
-.Nm Routed
-should incorporate other routing protocols,
-such as Xerox
-.Tn \&NS
-.Pq Xr XNSrouted 8
-and
-.Tn EGP .
-Using separate processes for each requires configuration options
-to avoid redundant or competing routes.
-.Pp
-.Nm Routed
-should listen to intelligent interfaces, such as an
-.Tn IMP ,
-to gather more information.
It does not always detect unidirectional failures in network interfaces
(e.g., when the output side fails).
.Sh HISTORY
diff --git a/sbin/routed/startup.c b/sbin/routed/startup.c
deleted file mode 100644
index 4129ec4355c..00000000000
--- a/sbin/routed/startup.c
+++ /dev/null
@@ -1,531 +0,0 @@
-/* $OpenBSD: startup.c,v 1.2 1996/06/23 14:32:31 deraadt Exp $ */
-/* $NetBSD: startup.c,v 1.14 1995/06/20 22:27:56 christos Exp $ */
-
-/*
- * Copyright (c) 1983, 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)startup.c 8.1 (Berkeley) 6/5/93";
-#else
-/*###40 [cc] warning: `rcsid' defined but not used%%%*/
-static char rcsid[] = "$OpenBSD: startup.c,v 1.2 1996/06/23 14:32:31 deraadt Exp $";
-#endif
-#endif /* not lint */
-
-/*
- * Routing Table Management Daemon
- */
-#include "defs.h"
-#include <sys/ioctl.h>
-#include <sys/sysctl.h>
-#include <net/if.h>
-#include <net/if_dl.h>
-#include <syslog.h>
-#include "pathnames.h"
-
-struct interface *ifnet;
-struct interface **ifnext = &ifnet;
-int lookforinterfaces = 1;
-int externalinterfaces = 0; /* # of remote and local interfaces */
-int foundloopback; /* valid flag for loopaddr */
-struct sockaddr loopaddr; /* our address on loopback */
-
-void add_ptopt_localrt __P((struct interface *));
-int getnetorhostname __P((char *, char *, struct sockaddr_in *));
-int gethostnameornumber __P((char *, struct sockaddr_in *));
-
-void
-quit(s)
- char *s;
-{
- extern int errno;
- int sverrno = errno;
-
- (void) fprintf(stderr, "route: ");
- if (s)
- (void) fprintf(stderr, "%s: ", s);
- (void) fprintf(stderr, "%s\n", strerror(sverrno));
- exit(1);
- /* NOTREACHED */
-}
-
-struct rt_addrinfo info;
-/* Sleazy use of local variables throughout file, warning!!!! */
-#define netmask info.rti_info[RTAX_NETMASK]
-#define ifaaddr info.rti_info[RTAX_IFA]
-#define brdaddr info.rti_info[RTAX_BRD]
-
-#define ROUNDUP(a) \
- ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
-
-void
-rt_xaddrs(cp, cplim, rtinfo)
- register caddr_t cp, cplim;
- register struct rt_addrinfo *rtinfo;
-{
- register struct sockaddr *sa;
- register int i;
-
- memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
- for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
- if ((rtinfo->rti_addrs & (1 << i)) == 0)
- continue;
- rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
- ADVANCE(cp, sa);
- }
-}
-
-/*
- * Find the network interfaces which have configured themselves.
- * If the interface is present but not yet up (for example an
- * ARPANET IMP), set the lookforinterfaces flag so we'll
- * come back later and look again.
- */
-void
-ifinit()
-{
- struct interface ifs, *ifp;
- size_t needed;
- int mib[6], no_ipaddr = 0, flags = 0;
- char *buf, *cplim, *cp;
- register struct if_msghdr *ifm;
- register struct ifa_msghdr *ifam;
- struct sockaddr_dl *sdl = NULL;
- struct sockaddr_in *sin;
- u_long i;
-
- mib[0] = CTL_NET;
- mib[1] = PF_ROUTE;
- mib[2] = 0;
- mib[3] = AF_INET;
- mib[4] = NET_RT_IFLIST;
- mib[5] = 0;
- if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
- quit("route-sysctl-estimate");
- if ((buf = malloc(needed)) == NULL)
- quit("malloc");
- if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
- quit("actual retrieval of interface table");
- lookforinterfaces = 0;
- cplim = buf + needed;
- for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) {
- ifm = (struct if_msghdr *)cp;
- if (ifm->ifm_type == RTM_IFINFO) {
- memset(&ifs, 0, sizeof(ifs));
- ifs.int_flags = flags = (0xffff & ifm->ifm_flags) | IFF_INTERFACE;
- if ((flags & IFF_UP) == 0 || no_ipaddr)
- lookforinterfaces = 1;
- sdl = (struct sockaddr_dl *) (ifm + 1);
- sdl->sdl_data[sdl->sdl_nlen] = 0;
- no_ipaddr = 1;
- continue;
- }
- if (ifm->ifm_type != RTM_NEWADDR)
- quit("ifinit: out of sync");
- if ((flags & IFF_UP) == 0) {
- lookforinterfaces = 1;
- continue;
- }
- ifam = (struct ifa_msghdr *)ifm;
- info.rti_addrs = ifam->ifam_addrs;
- rt_xaddrs((char *)(ifam + 1), cp + ifam->ifam_msglen, &info);
- if (ifaaddr == 0) {
- syslog(LOG_ERR, "%s: (get addr)", sdl->sdl_data);
- continue;
- }
- ifs.int_addr = *ifaaddr;
- if (ifs.int_addr.sa_family != AF_INET)
- continue;
- no_ipaddr = 0;
- if (ifs.int_flags & IFF_POINTOPOINT) {
- if (brdaddr == 0) {
- syslog(LOG_ERR, "%s: (get dstaddr)",
- sdl->sdl_data);
- continue;
- }
- if (brdaddr->sa_family == AF_UNSPEC) {
- lookforinterfaces = 1;
- continue;
- }
- ifs.int_dstaddr = *brdaddr;
- }
- /*
- * already known to us?
- * This allows multiple point-to-point links
- * to share a source address (possibly with one
- * other link), but assumes that there will not be
- * multiple links with the same destination address.
- */
- if (ifs.int_flags & IFF_POINTOPOINT) {
- if (if_ifwithdstaddr(&ifs.int_dstaddr))
- continue;
- } else if (if_ifwithaddr(&ifs.int_addr))
- continue;
- if (ifs.int_flags & IFF_LOOPBACK) {
- ifs.int_flags |= IFF_PASSIVE;
- foundloopback = 1;
- loopaddr = ifs.int_addr;
- for (ifp = ifnet; ifp; ifp = ifp->int_next)
- if (ifp->int_flags & IFF_POINTOPOINT)
- add_ptopt_localrt(ifp);
- }
- if (ifs.int_flags & IFF_BROADCAST) {
- if (brdaddr == 0) {
- syslog(LOG_ERR, "%s: (get broadaddr)",
- sdl->sdl_data);
- continue;
- }
- ifs.int_dstaddr = *brdaddr;
- }
- /*
- * Use a minimum metric of one;
- * treat the interface metric (default 0)
- * as an increment to the hop count of one.
- */
- ifs.int_metric = ifam->ifam_metric + 1;
- if (netmask == 0) {
- syslog(LOG_ERR, "%s: (get netmask)",
- sdl->sdl_data);
- continue;
- }
- sin = (struct sockaddr_in *)netmask;
- ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr);
- sin = (struct sockaddr_in *)&ifs.int_addr;
- i = ntohl(sin->sin_addr.s_addr);
- if (IN_CLASSA(i))
- ifs.int_netmask = IN_CLASSA_NET;
- else if (IN_CLASSB(i))
- ifs.int_netmask = IN_CLASSB_NET;
- else
- ifs.int_netmask = IN_CLASSC_NET;
- ifs.int_net = i & ifs.int_netmask;
- ifs.int_subnet = i & ifs.int_subnetmask;
- if (ifs.int_subnetmask != ifs.int_netmask)
- ifs.int_flags |= IFF_SUBNET;
- ifp = (struct interface *)
- malloc(sdl->sdl_nlen + 1 + sizeof(ifs));
- if (ifp == 0) {
- printf("routed: out of memory\n");
- lookforinterfaces = 1;
- break;
- }
- *ifp = ifs;
- /*
- * Count the # of directly connected networks
- * and point to point links which aren't looped
- * back to ourself. This is used below to
- * decide if we should be a routing ``supplier''.
- */
- if ((ifs.int_flags & IFF_LOOPBACK) == 0 &&
- ((ifs.int_flags & IFF_POINTOPOINT) == 0 ||
- if_ifwithaddr(&ifs.int_dstaddr) == 0))
- externalinterfaces++;
- /*
- * If we have a point-to-point link, we want to act
- * as a supplier even if it's our only interface,
- * as that's the only way our peer on the other end
- * can tell that the link is up.
- */
- if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0)
- supplier = 1;
- ifp->int_name = (char *)(ifp + 1);
- strcpy(ifp->int_name, sdl->sdl_data);
- *ifnext = ifp;
- ifnext = &ifp->int_next;
- traceinit(ifp);
- addrouteforif(ifp);
- }
- if (externalinterfaces > 1 && supplier < 0)
- supplier = 1;
- free(buf);
-}
-
-/*
- * Add route for interface if not currently installed.
- * Create route to other end if a point-to-point link,
- * otherwise a route to this (sub)network.
- * INTERNET SPECIFIC.
- */
-void
-addrouteforif(ifp)
- register struct interface *ifp;
-{
- struct sockaddr_in net;
- struct sockaddr *dst;
- int state;
- register struct rt_entry *rt;
- struct sockaddr mask;
-
- memset(&mask, 0, sizeof(mask));
- if (ifp->int_flags & IFF_POINTOPOINT)
- dst = &ifp->int_dstaddr;
- else {
- memset(&net, 0, sizeof (net));
- net.sin_family = AF_INET;
- net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY);
- dst = (struct sockaddr *)&net;
- }
- rt = rtfind(dst);
- if (rt &&
- (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE)
- return;
- if (rt)
- rtdelete(rt);
- /*
- * If interface on subnetted network,
- * install route to network as well.
- * This is meant for external viewers.
- */
- if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) {
- struct in_addr subnet;
-
- subnet = net.sin_addr;
- net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
- rt = rtfind(dst);
- if (rt == 0)
- rtadd(dst, &ifp->int_addr, &mask, ifp->int_metric,
- ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) |
- RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET));
- else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) ==
- (RTS_INTERNAL|RTS_SUBNET) &&
- ifp->int_metric < rt->rt_metric)
- rtchange(rt, &rt->rt_router, &mask, ifp->int_metric);
- net.sin_addr = subnet;
- }
- if (ifp->int_transitions++ > 0)
- syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
- state = ifp->int_flags &
- (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET);
- if (ifp->int_flags & IFF_POINTOPOINT &&
- (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) &
- ifp->int_netmask) != ifp->int_net)
- state &= ~RTS_SUBNET;
- if (ifp->int_flags & IFF_LOOPBACK)
- state |= RTS_EXTERNAL;
- rtadd(dst, &ifp->int_addr, &mask, ifp->int_metric, state);
- if (ifp->int_flags & IFF_POINTOPOINT && foundloopback)
- add_ptopt_localrt(ifp);
-}
-
-/*
- * Add route to local end of point-to-point using loopback.
- * If a route to this network is being sent to neighbors on other nets,
- * mark this route as subnet so we don't have to propagate it too.
- */
-void
-add_ptopt_localrt(ifp)
- register struct interface *ifp;
-{
- struct rt_entry *rt;
- struct sockaddr *dst;
- struct sockaddr_in net;
- int state;
- struct sockaddr mask;
-
- memset(&mask, 0, sizeof(mask));
- state = RTS_INTERFACE | RTS_PASSIVE;
-
- /* look for route to logical network */
- memset(&net, 0, sizeof (net));
- net.sin_family = AF_INET;
- net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
- dst = (struct sockaddr *)&net;
- rt = rtfind(dst);
- if (rt && rt->rt_state & RTS_INTERNAL)
- state |= RTS_SUBNET;
-
- dst = &ifp->int_addr;
- if ((rt = rtfind(dst)) != NULL) {
- if (rt && rt->rt_state & RTS_INTERFACE)
- return;
- rtdelete(rt);
- }
- rtadd(dst, &loopaddr, &mask, 1, state);
-}
-
-/*
- * As a concession to the ARPANET we read a list of gateways
- * from /etc/gateways and add them to our tables. This file
- * exists at each ARPANET gateway and indicates a set of ``remote''
- * gateways (i.e. a gateway which we can't immediately determine
- * if it's present or not as we can do for those directly connected
- * at the hardware level). If a gateway is marked ``passive''
- * in the file, then we assume it doesn't have a routing process
- * of our design and simply assume it's always present. Those
- * not marked passive are treated as if they were directly
- * connected -- they're added into the interface list so we'll
- * send them routing updates.
- *
- * PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP.
- */
-void
-gwkludge()
-{
- struct sockaddr_in dst, gate;
- FILE *fp;
- char *type, *dname, *gname, *qual, buf[BUFSIZ];
- struct interface *ifp;
- int metric, n;
- struct rt_entry route;
- struct sockaddr mask;
- memset(&mask, 0, sizeof(mask));
-
-
- fp = fopen(_PATH_GATEWAYS, "r");
- if (fp == NULL)
- return;
- qual = buf;
- dname = buf + 64;
- gname = buf + ((BUFSIZ - 64) / 3);
- type = buf + (((BUFSIZ - 64) * 2) / 3);
- memset(&dst, 0, sizeof (dst));
- memset(&gate, 0, sizeof (gate));
- memset(&route, 0, sizeof(route));
-/* format: {net | host} XX gateway XX metric DD [passive | external]\n */
-#define readentry(fp) \
- fscanf((fp), "%s %s gateway %s metric %d %s\n", \
- type, dname, gname, &metric, qual)
- for (;;) {
- if ((n = readentry(fp)) == EOF)
- break;
- if (!getnetorhostname(type, dname, &dst))
- continue;
- if (!gethostnameornumber(gname, &gate))
- continue;
- if (metric == 0) /* XXX */
- metric = 1;
- if (strcmp(qual, "passive") == 0) {
- /*
- * Passive entries aren't placed in our tables,
- * only the kernel's, so we don't copy all of the
- * external routing information within a net.
- * Internal machines should use the default
- * route to a suitable gateway (like us).
- */
- route.rt_dst = *(struct sockaddr *) &dst;
- route.rt_router = *(struct sockaddr *) &gate;
- route.rt_flags = RTF_UP;
- if (strcmp(type, "host") == 0)
- route.rt_flags |= RTF_HOST;
- if (metric)
- route.rt_flags |= RTF_GATEWAY;
- (void) rtioctl(ADD, &route.rt_rt);
- continue;
- }
- if (strcmp(qual, "external") == 0) {
- /*
- * Entries marked external are handled
- * by other means, e.g. EGP,
- * and are placed in our tables only
- * to prevent overriding them
- * with something else.
- */
- rtadd((struct sockaddr *)&dst,
- (struct sockaddr *)&gate, &mask, metric,
- RTS_EXTERNAL|RTS_PASSIVE);
- continue;
- }
- /* assume no duplicate entries */
- externalinterfaces++;
- ifp = (struct interface *)malloc(sizeof (*ifp));
- memset(ifp, 0, sizeof (*ifp));
- ifp->int_flags = IFF_REMOTE;
- /* can't identify broadcast capability */
- ifp->int_net = inet_netof_subnet(dst.sin_addr);
- if (strcmp(type, "host") == 0) {
- ifp->int_flags |= IFF_POINTOPOINT;
- ifp->int_dstaddr = *((struct sockaddr *)&dst);
- }
- ifp->int_addr = *((struct sockaddr *)&gate);
- ifp->int_metric = metric;
- ifp->int_next = ifnet;
- ifnet = ifp;
- addrouteforif(ifp);
- }
- fclose(fp);
-}
-
-int
-getnetorhostname(type, name, sin)
- char *type, *name;
- struct sockaddr_in *sin;
-{
-
- if (strcmp(type, "net") == 0) {
- struct netent *np = getnetbyname(name);
- int n;
-
- if (np == 0)
- n = inet_network(name);
- else {
- if (np->n_addrtype != AF_INET)
- return (0);
- n = np->n_net;
- /*
- * getnetbyname returns right-adjusted value.
- */
- if (n < 128)
- n <<= IN_CLASSA_NSHIFT;
- else if (n < 65536)
- n <<= IN_CLASSB_NSHIFT;
- else
- n <<= IN_CLASSC_NSHIFT;
- }
- sin->sin_family = AF_INET;
- sin->sin_addr = inet_makeaddr(n, INADDR_ANY);
- return (1);
- }
- if (strcmp(type, "host") == 0)
- return (gethostnameornumber(name, sin));
- return (0);
-}
-
-int
-gethostnameornumber(name, sin)
- char *name;
- struct sockaddr_in *sin;
-{
- struct hostent *hp;
-
- if (inet_aton(name, &sin->sin_addr) == 0) {
- hp = gethostbyname(name);
- if (hp == 0)
- return (0);
- memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
- sin->sin_family = hp->h_addrtype;
- } else
- sin->sin_family = AF_INET;
- return (1);
-}
diff --git a/sbin/routed/table.h b/sbin/routed/table.h
deleted file mode 100644
index 6b64b8ac7b9..00000000000
--- a/sbin/routed/table.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* $OpenBSD: table.h,v 1.2 1996/06/23 14:32:32 deraadt Exp $ */
-/* $NetBSD: table.h,v 1.7 1995/06/20 22:27:58 christos Exp $ */
-
-/*
- * Copyright (c) 1983, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)table.h 8.1 (Berkeley) 6/5/93
- */
-
-/*
- * Routing table management daemon.
- */
-#include <sys/queue.h>
-/*
- * Routing table structure; differs a bit from kernel tables.
- *
- * Note: the union below must agree in the first 4 members
- * so the ioctl's will work.
- */
-#ifdef RTM_ADD
-#define rtentry ortentry
-#endif
-
-struct rt_entry {
- CIRCLEQ_ENTRY(rt_entry) rt_entry;
- union {
- struct rtentry rtu_rt;
- struct rtuentry {
- u_long rtu_hash;
- struct sockaddr rtu_dst;
- struct sockaddr rtu_router;
- struct sockaddr rtu_netmask;
- short rtu_rtflags; /* used by rtioctl */
- short rtu_wasted[5];
- int rtu_flags;
- int rtu_state;
- int rtu_timer;
- int rtu_metric;
- int rtu_ifmetric;
- struct interface *rtu_ifp;
- } rtu_entry;
- } rt_rtu;
-};
-
-#define rt_rt rt_rtu.rtu_entry /* pass to ioctl */
-#define rt_hash rt_rtu.rtu_entry.rtu_hash /* for net or host */
-#define rt_dst rt_rtu.rtu_entry.rtu_dst /* match value */
-#define rt_router rt_rtu.rtu_entry.rtu_router /* who to forward to */
-#define rt_netmask rt_rtu.rtu_entry.rtu_netmask /* mask for the route */
-#define rt_flags rt_rtu.rtu_entry.rtu_flags /* kernel flags */
-#define rt_timer rt_rtu.rtu_entry.rtu_timer /* for invalidation */
-#define rt_state rt_rtu.rtu_entry.rtu_state /* see below */
-#define rt_metric rt_rtu.rtu_entry.rtu_metric /* cost of route */
-#define rt_ifmetric rt_rtu.rtu_entry.rtu_ifmetric /* cost of route if */
-#define rt_ifp rt_rtu.rtu_entry.rtu_ifp /* interface to take */
-
-#define ROUTEHASHSIZ 32 /* must be a power of 2 */
-#define ROUTEHASHMASK (ROUTEHASHSIZ - 1)
-
-/*
- * "State" of routing table entry.
- */
-#define RTS_CHANGED 0x1 /* route has been altered recently */
-#define RTS_EXTERNAL 0x2 /* extern info, not installed or sent */
-#define RTS_INTERNAL 0x4 /* internal route, not installed */
-#define RTS_PASSIVE IFF_PASSIVE /* don't time out route */
-#define RTS_INTERFACE IFF_INTERFACE /* route is for network interface */
-#define RTS_REMOTE IFF_REMOTE /* route is for ``remote'' entity */
-#define RTS_SUBNET IFF_SUBNET /* route is for network subnet */
-
-/*
- * Flags are same as kernel, with this addition for af_rtflags:
- */
-#define RTF_SUBNET 0x80000 /* pseudo: route to subnet */
-
-CIRCLEQ_HEAD(rthash, rt_entry);
-
-struct rthash nethash[ROUTEHASHSIZ];
-struct rthash hosthash[ROUTEHASHSIZ];
-
-struct rt_entry *rtlookup __P((struct sockaddr *));
-struct rt_entry *rtfind __P((struct sockaddr *));
-struct rthash *rthead __P((struct sockaddr *, u_int *, int *));
-void rtadd __P((struct sockaddr *, struct sockaddr *, struct sockaddr *,
- int, int ));
-void rtchange __P((struct rt_entry *, struct sockaddr *, struct sockaddr *,
- int));
-void rtdelete __P((struct rt_entry *));
-void rtdeleteall __P((int));
-void rtdefault __P((void));
-void rtinit __P((void));
-int rtioctl __P((int, struct rtuentry *));
diff --git a/sbin/routed/tables.c b/sbin/routed/tables.c
deleted file mode 100644
index aae9e180b6a..00000000000
--- a/sbin/routed/tables.c
+++ /dev/null
@@ -1,496 +0,0 @@
-/* $OpenBSD: tables.c,v 1.2 1996/06/23 14:32:33 deraadt Exp $ */
-/* $NetBSD: tables.c,v 1.15 1995/06/20 22:27:59 christos Exp $ */
-
-/*
- * Copyright (c) 1983, 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93";
-#else
-static char rcsid[] = "$OpenBSD: tables.c,v 1.2 1996/06/23 14:32:33 deraadt Exp $";
-#endif
-#endif /* not lint */
-
-/*
- * Routing Table Management Daemon
- */
-#include "defs.h"
-#include <sys/ioctl.h>
-#include <syslog.h>
-#include <errno.h>
-#include <search.h>
-
-#ifndef DEBUG
-#define DEBUG 0
-#endif
-
-#ifdef RTM_ADD
-#define FIXLEN(s) {if ((s)->sa_len == 0) (s)->sa_len = sizeof *(s);}
-#else
-#define FIXLEN(s) { }
-#endif
-
-int install = !DEBUG; /* if 1 call kernel */
-
-/*
- * Lookup dst in the tables for an exact match.
- */
-struct rt_entry *
-rtlookup(dst)
- struct sockaddr *dst;
-{
- register struct rt_entry *rt;
- register struct rthash *rh;
- register u_int hash;
- struct afhash h;
- int doinghost = 1;
-
- if (dst->sa_family >= af_max)
- return (0);
- (*afswitch[dst->sa_family].af_hash)(dst, &h);
- hash = h.afh_hosthash;
- rh = &hosthash[hash & ROUTEHASHMASK];
-again:
- for (rt = rh->cqh_first; rt != (void *)rh; rt = rt->rt_entry.cqe_next) {
- if (rt->rt_hash != hash)
- continue;
- if (equal(&rt->rt_dst, dst))
- return (rt);
- }
- if (doinghost) {
- doinghost = 0;
- hash = h.afh_nethash;
- rh = &nethash[hash & ROUTEHASHMASK];
- goto again;
- }
- return (0);
-}
-
-struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
-
-/*
- * Find a route to dst as the kernel would.
- */
-struct rt_entry *
-rtfind(dst)
- struct sockaddr *dst;
-{
- register struct rt_entry *rt;
- register struct rthash *rh;
- register u_int hash;
- struct afhash h;
- int af = dst->sa_family;
- int doinghost = 1,
- (*match) __P((struct sockaddr *, struct sockaddr *)) = NULL;
-
- if (af >= af_max)
- return (0);
- (*afswitch[af].af_hash)(dst, &h);
- hash = h.afh_hosthash;
- rh = &hosthash[hash & ROUTEHASHMASK];
-
-again:
- for (rt = rh->cqh_first; rt != (void *)rh; rt = rt->rt_entry.cqe_next) {
- if (rt->rt_hash != hash)
- continue;
- if (doinghost) {
- if (equal(&rt->rt_dst, dst))
- return (rt);
- } else {
- if (rt->rt_dst.sa_family == af && match &&
- (*match)(&rt->rt_dst, dst))
- return (rt);
- }
- }
- if (doinghost) {
- doinghost = 0;
- hash = h.afh_nethash;
- rh = &nethash[hash & ROUTEHASHMASK];
- match = afswitch[af].af_netmatch;
- goto again;
- }
-#ifdef notyet
- /*
- * Check for wildcard gateway, by convention network 0.
- */
- if (dst != &wildcard) {
- dst = &wildcard, hash = 0;
- goto again;
- }
-#endif
- return (0);
-}
-
-struct rthash *
-rthead(dst, hashp, flagsp)
- struct sockaddr *dst;
- u_int *hashp;
- int *flagsp;
-{
- struct afhash h;
- int af = dst->sa_family;
-
- if (af >= af_max)
- return NULL;
-
- (*afswitch[af].af_hash)(dst, &h);
-
- *flagsp = (*afswitch[af].af_rtflags)(dst);
-
- if (*flagsp & RTF_HOST) {
- *hashp = h.afh_hosthash;
- return &hosthash[*hashp & ROUTEHASHMASK];
- } else {
- *hashp = h.afh_nethash;
- return &nethash[*hashp & ROUTEHASHMASK];
- }
-}
-
-void
-rtadd(dst, gate, netmask, metric, state)
- struct sockaddr *dst, *gate, *netmask;
- int metric, state;
-{
- register struct rt_entry *rt;
- struct rthash *rh;
- int flags;
- u_int hash;
- char buf1[256], buf2[256];
-
- /*
- * Subnet flag isn't visible to kernel, move to state. XXX
- */
- FIXLEN(dst);
- FIXLEN(gate);
-
- rh = rthead(dst, &hash, &flags);
-
- if (rh == NULL) {
- syslog(LOG_ERR, "rtadd: Internal error finding route\n");
- return;
- }
-
- if (flags & RTF_SUBNET) {
- state |= RTS_SUBNET;
- flags &= ~RTF_SUBNET;
- }
-
- rt = (struct rt_entry *)malloc(sizeof (*rt));
- if (rt == 0)
- return;
- rt->rt_hash = hash;
- rt->rt_dst = *dst;
- rt->rt_router = *gate;
- rt->rt_netmask = *netmask;
- rt->rt_timer = 0;
- rt->rt_flags = RTF_UP | flags;
- rt->rt_state = state | RTS_CHANGED;
- rt->rt_ifp = if_ifwithdstaddr(&rt->rt_dst);
- if (rt->rt_ifp == 0)
- rt->rt_ifp = if_ifwithnet(&rt->rt_router);
- if ((state & RTS_INTERFACE) == 0)
- rt->rt_flags |= RTF_GATEWAY;
- rt->rt_metric = metric;
- CIRCLEQ_INSERT_HEAD(rh, rt, rt_entry);
- TRACE_ACTION("ADD", rt);
- /*
- * If the ioctl fails because the gateway is unreachable
- * from this host, discard the entry. This should only
- * occur because of an incorrect entry in /etc/gateways.
- */
- if ((rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
- rtioctl(ADD, &rt->rt_rt) < 0) {
- if (errno != EEXIST && gate->sa_family < af_max)
- syslog(LOG_ERR,
- "adding route to net/host %s through gateway %s: %m\n",
- (*afswitch[dst->sa_family].af_format)(dst, buf1,
- sizeof(buf1)),
- (*afswitch[gate->sa_family].af_format)(gate, buf2,
- sizeof(buf2)));
- perror("ADD ROUTE");
- if (errno == ENETUNREACH) {
- TRACE_ACTION("DELETE", rt);
- CIRCLEQ_REMOVE(rh, rt, rt_entry);
- free((char *)rt);
- }
- }
-}
-
-void
-rtchange(rt, gate, netmask, metric)
- struct rt_entry *rt;
- struct sockaddr *gate;
- struct sockaddr *netmask;
- short metric;
-{
- int add = 0, delete = 0, newgateway = 0;
- struct rtuentry oldroute;
-
- FIXLEN(gate);
- FIXLEN(netmask);
- FIXLEN(&(rt->rt_router));
- FIXLEN(&(rt->rt_dst));
- if (!equal(&rt->rt_router, gate)) {
- newgateway++;
- TRACE_ACTION("CHANGE FROM ", rt);
- } else if (metric != rt->rt_metric)
- TRACE_NEWMETRIC(rt, metric);
- if ((rt->rt_state & RTS_INTERNAL) == 0) {
- /*
- * If changing to different router, we need to add
- * new route and delete old one if in the kernel.
- * If the router is the same, we need to delete
- * the route if has become unreachable, or re-add
- * it if it had been unreachable.
- */
- if (newgateway) {
- add++;
- if (rt->rt_metric != HOPCNT_INFINITY)
- delete++;
- } else if (metric == HOPCNT_INFINITY)
- delete++;
- else if (rt->rt_metric == HOPCNT_INFINITY)
- add++;
- }
- if (delete)
- oldroute = rt->rt_rt;
- if ((rt->rt_state & RTS_INTERFACE) && delete) {
- rt->rt_state &= ~RTS_INTERFACE;
- rt->rt_flags |= RTF_GATEWAY;
- if (metric > rt->rt_metric && delete)
- syslog(LOG_ERR, "%s route to interface %s (timed out)",
- add? "changing" : "deleting",
- rt->rt_ifp ? rt->rt_ifp->int_name : "?");
- }
- if (add) {
- rt->rt_router = *gate;
- rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
- if (rt->rt_ifp == 0)
- rt->rt_ifp = if_ifwithnet(&rt->rt_router);
- }
- rt->rt_netmask = *netmask;
- rt->rt_metric = metric;
- rt->rt_state |= RTS_CHANGED;
- if (newgateway)
- TRACE_ACTION("CHANGE TO ", rt);
-#ifndef RTM_ADD
- if (add && rtioctl(ADD, &rt->rt_rt) < 0)
- perror("ADD ROUTE");
- if (delete && rtioctl(DELETE, &oldroute) < 0)
- perror("DELETE ROUTE");
-#else
- if (delete && !add) {
- if (rtioctl(DELETE, &oldroute) < 0)
- perror("DELETE ROUTE");
- } else if (!delete && add) {
- if (rtioctl(ADD, &rt->rt_rt) < 0)
- perror("ADD ROUTE");
- } else if (delete && add) {
- if (rtioctl(CHANGE, &rt->rt_rt) < 0)
- perror("CHANGE ROUTE");
- }
-#endif
-}
-
-void
-rtdelete(rt)
- struct rt_entry *rt;
-{
- u_int hash;
- int flags;
- struct rthash *rh = rthead(&rt->rt_dst, &hash, &flags);
-
- if (rh == NULL) {
- syslog(LOG_ERR, "rtdelete: Internal error finding route\n");
- return;
- }
-
- TRACE_ACTION("DELETE", rt);
- FIXLEN(&(rt->rt_router));
- FIXLEN(&(rt->rt_dst));
- if (rt->rt_metric < HOPCNT_INFINITY) {
- if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE)
- syslog(LOG_ERR,
- "deleting route to interface %s? (timed out?)",
- rt->rt_ifp->int_name);
- if ((rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
- rtioctl(DELETE, &rt->rt_rt) < 0)
- perror("rtdelete");
- }
- CIRCLEQ_REMOVE(rh, rt, rt_entry);
- free((char *)rt);
-}
-
-void
-rtdeleteall(sig)
- int sig;
-{
- register struct rthash *rh;
- register struct rt_entry *rt;
- struct rthash *base = hosthash;
- int doinghost = 1;
-
-again:
- for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
- rt = rh->cqh_first;
- for (; rt != (void *)rh; rt = rt->rt_entry.cqe_next) {
- if (rt->rt_state & RTS_INTERFACE ||
- rt->rt_metric >= HOPCNT_INFINITY)
- continue;
- TRACE_ACTION("DELETE", rt);
- if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 &&
- rtioctl(DELETE, &rt->rt_rt) < 0)
- perror("rtdeleteall");
- }
- }
- if (doinghost) {
- doinghost = 0;
- base = nethash;
- goto again;
- }
- exit(sig);
-}
-
-/*
- * If we have an interface to the wide, wide world,
- * add an entry for an Internet default route (wildcard) to the internal
- * tables and advertise it. This route is not added to the kernel routes,
- * but this entry prevents us from listening to other people's defaults
- * and installing them in the kernel here.
- */
-void
-rtdefault()
-{
- extern struct sockaddr inet_default;
-
- rtadd(&inet_default, &inet_default, &inet_default, 1,
- RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
-}
-
-void
-rtinit()
-{
- register struct rthash *rh;
-
- for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
- CIRCLEQ_INIT(rh);
- for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
- CIRCLEQ_INIT(rh);
-}
-
-int
-rtioctl(action, ort)
- int action;
- struct rtuentry *ort;
-{
-#ifndef RTM_ADD
- if (install == 0)
- return (errno = 0);
- ort->rtu_rtflags = ort->rtu_flags;
- switch (action) {
-
- case ADD:
- return (ioctl(s, SIOCADDRT, (char *)ort));
-
- case DELETE:
- return (ioctl(s, SIOCDELRT, (char *)ort));
-
- default:
- return (-1);
- }
-#else /* RTM_ADD */
- struct {
- struct rt_msghdr w_rtm;
- struct sockaddr_in w_dst;
- struct sockaddr w_gate;
- struct sockaddr_in w_netmask;
- } w;
-#define rtm w.w_rtm
-
- memset(&w, 0, sizeof(w));
- rtm.rtm_msglen = sizeof(w);
- rtm.rtm_version = RTM_VERSION;
- rtm.rtm_type = (action == ADD ? RTM_ADD :
- (action == DELETE ? RTM_DELETE : RTM_CHANGE));
-#undef rt_dst
- rtm.rtm_flags = ort->rtu_flags;
- rtm.rtm_seq = ++seqno;
- rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
- memcpy(&w.w_dst, &ort->rtu_dst, sizeof(w.w_dst));
- memcpy(&w.w_gate, &ort->rtu_router, sizeof(w.w_gate));
- memcpy(&w.w_netmask, &ort->rtu_netmask, sizeof(w.w_netmask));
- w.w_dst.sin_family = AF_INET;
- w.w_dst.sin_len = sizeof(w.w_dst);
- w.w_gate.sa_family = AF_INET;
- w.w_gate.sa_len = sizeof(w.w_gate);
- if (rtm.rtm_flags & RTF_HOST) {
- rtm.rtm_msglen -= sizeof(w.w_netmask);
- } else {
- register char *cp;
- int len;
-
- rtm.rtm_addrs |= RTA_NETMASK;
- /*
- * Check if we had a version 2 rip packet that sets the
- * netmask, and otherwise set it to the default for
- * the destination of the interface.
- */
- if (w.w_netmask.sin_family == AF_UNSPEC) {
- w.w_netmask.sin_addr.s_addr =
- inet_maskof(w.w_dst.sin_addr.s_addr);
- }
-
- for (cp = (char *)(1 + &w.w_netmask.sin_addr);
- --cp > (char *) &w.w_netmask; )
- if (*cp)
- break;
- len = cp - (char *)&w.w_netmask;
- if (len) {
- len++;
- w.w_netmask.sin_len = len;
- len = 1 + ((len - 1) | (sizeof(long) - 1));
- } else
- len = sizeof(long);
- rtm.rtm_msglen -= (sizeof(w.w_netmask) - len);
- }
-#if 0
- fprintf(stderr, "%s ", action == ADD ? "add" : (action == DELETE ? "delete" : "change"));
- fprintf(stderr, "dst = %s, ", inet_ntoa(w.w_dst.sin_addr));
- fprintf(stderr, "gate = %s, ", inet_ntoa(((struct sockaddr_in *) &w.w_gate)->sin_addr));
- fprintf(stderr, "mask = %s\n", inet_ntoa(w.w_netmask.sin_addr));
-#endif
- errno = 0;
- return (install ? write(r, (char *)&w, rtm.rtm_msglen) : (errno = 0));
-#endif /* RTM_ADD */
-}
diff --git a/sbin/routed/timer.c b/sbin/routed/timer.c
deleted file mode 100644
index 2430836cdf1..00000000000
--- a/sbin/routed/timer.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/* $OpenBSD: timer.c,v 1.2 1996/06/23 14:32:33 deraadt Exp $ */
-/* $NetBSD: timer.c,v 1.8 1995/06/20 22:28:02 christos Exp $ */
-
-/*
- * Copyright (c) 1983, 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)timer.c 8.1 (Berkeley) 6/5/93";
-#else
-static char rcsid[] = "$OpenBSD: timer.c,v 1.2 1996/06/23 14:32:33 deraadt Exp $";
-#endif
-#endif /* not lint */
-
-/*
- * Routing Table Management Daemon
- */
-#include "defs.h"
-
-int faketime;
-
-/*
- * Timer routine. Performs routing information supply
- * duties and manages timers on routing table entries.
- * Management of the RTS_CHANGED bit assumes that we broadcast
- * each time called.
- */
-void
-timer(sig)
- int sig;
-{
- register struct rthash *rh;
- register struct rt_entry *rt;
- struct rthash *base = hosthash;
- int doinghost = 1, timetobroadcast;
-
- (void) gettimeofday(&now, NULL);
- faketime += TIMER_RATE;
- if (lookforinterfaces && (faketime % CHECK_INTERVAL) == 0)
- ifinit();
- timetobroadcast = supplier && (faketime % SUPPLY_INTERVAL) == 0;
-again:
- for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
- rt = rh->cqh_first;
- for (; rt != (void *)rh; rt = rt->rt_entry.cqe_next) {
- /*
- * We don't advance time on a routing entry for
- * a passive gateway, or any interface if we're
- * not acting as supplier.
- */
- if (!(rt->rt_state & RTS_PASSIVE) &&
- (supplier || !(rt->rt_state & RTS_INTERFACE)))
- rt->rt_timer += TIMER_RATE;
- if (rt->rt_timer >= GARBAGE_TIME) {
- rt = rt->rt_entry.cqe_prev;
- rtdelete(rt->rt_entry.cqe_next);
- continue;
- }
- if (rt->rt_timer >= EXPIRE_TIME &&
- rt->rt_metric < HOPCNT_INFINITY)
- rtchange(rt, &rt->rt_router,
- &rt->rt_netmask, HOPCNT_INFINITY);
- rt->rt_state &= ~RTS_CHANGED;
- }
- }
- if (doinghost) {
- doinghost = 0;
- base = nethash;
- goto again;
- }
- if (timetobroadcast) {
- toall(supply, 0, NULL);
- lastbcast = now;
- lastfullupdate = now;
- needupdate = 0; /* cancel any pending dynamic update */
- nextbcast.tv_sec = 0;
- }
-}
-
-/*
- * On hangup, let everyone know we're going away.
- */
-void
-hup(sig)
- int sig;
-{
- register struct rthash *rh;
- register struct rt_entry *rt;
- struct rthash *base = hosthash;
- int doinghost = 1;
-
- if (supplier) {
-again:
- for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
- rt = rh->cqh_first;
- for (; rt != (void *)rh; rt = rt->rt_entry.cqe_next)
- rt->rt_metric = HOPCNT_INFINITY;
- }
- if (doinghost) {
- doinghost = 0;
- base = nethash;
- goto again;
- }
- toall(supply, 0, NULL);
- }
- exit(1);
-}
diff --git a/sbin/routed/trace.c b/sbin/routed/trace.c
index c419182c0c0..3d592643644 100644
--- a/sbin/routed/trace.c
+++ b/sbin/routed/trace.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trace.c,v 1.2 1996/06/23 14:32:34 deraadt Exp $ */
+/* $OpenBSD: trace.c,v 1.3 1996/09/05 14:31:52 mickey Exp $ */
/* $NetBSD: trace.c,v 1.13 1995/06/20 22:28:03 christos Exp $ */
/*
@@ -34,419 +34,787 @@
* SUCH DAMAGE.
*/
-#ifndef lint
-#if 0
+#if !defined(lint)
static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93";
#else
-static char rcsid[] = "$OpenBSD: trace.c,v 1.2 1996/06/23 14:32:34 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: trace.c,v 1.3 1996/09/05 14:31:52 mickey Exp $";
#endif
-#endif /* not lint */
-/*
- * Routing Table Management Daemon
- */
#define RIPCMDS
#include "defs.h"
+#include "pathnames.h"
#include <sys/stat.h>
-#include <signal.h>
+#include <sys/signal.h>
#include <fcntl.h>
-#include "pathnames.h"
-#define NRECORDS 50 /* size of circular trace buffer */
-#ifdef DEBUG
-FILE *ftrace = stdout;
-int traceactions = 0;
+
+#ifdef sgi
+/* use *stat64 for files on large filesystems */
+#define stat stat64
#endif
-static struct timeval lastlog;
-static char *savetracename;
-static int iftraceinit __P((struct interface *, struct ifdebug *));
-void dumpif __P((FILE *, struct interface *));
-void dumptrace __P((FILE *, char *, struct ifdebug *));
+#define NRECORDS 50 /* size of circular trace buffer */
-void
-traceinit(ifp)
- register struct interface *ifp;
+u_int tracelevel, new_tracelevel;
+FILE *ftrace = stdout; /* output trace file */
+static char *tracelevel_pat = "%s\n";
+
+char savetracename[MAXPATHLEN+1];
+
+
+/* convert IP address to a string, but not into a single buffer
+ */
+char *
+naddr_ntoa(naddr a)
{
- if (iftraceinit(ifp, &ifp->int_input) &&
- iftraceinit(ifp, &ifp->int_output))
- return;
- tracehistory = 0;
- fprintf(stderr, "traceinit: can't init %s\n", ifp->int_name);
+#define NUM_BUFS 4
+ static int bufno;
+ static struct {
+ char str[16]; /* xxx.xxx.xxx.xxx\0 */
+ } bufs[NUM_BUFS];
+ char *s;
+ struct in_addr addr;
+
+ addr.s_addr = a;
+ s = strcpy(bufs[bufno].str, inet_ntoa(addr));
+ bufno = (bufno+1) % NUM_BUFS;
+ return s;
+#undef NUM_BUFS
}
-static int
-iftraceinit(ifp, ifd)
- struct interface *ifp;
- register struct ifdebug *ifd;
+
+char *
+saddr_ntoa(struct sockaddr *sa)
{
- register struct iftrace *t;
-
- ifd->ifd_records =
- (struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace));
- if (ifd->ifd_records == 0)
- return (0);
- ifd->ifd_front = ifd->ifd_records;
- ifd->ifd_count = 0;
- for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
- t->ift_size = 0;
- t->ift_packet = 0;
- }
- ifd->ifd_if = ifp;
- return (1);
+ return (sa == 0) ? "?" : naddr_ntoa(S_ADDR(sa));
+}
+
+
+static char *
+ts(time_t secs) {
+ static char s[20];
+
+ secs += epoch.tv_sec;
+#ifdef sgi
+ (void)cftime(s, "%T", &secs);
+#else
+ bcopy(ctime(&secs)+11, s, 8);
+ s[8] = '\0';
+#endif
+ return s;
}
+
+/* On each event, display a time stamp.
+ * This assumes that 'now' is update once for each event, and
+ * that at least now.tv_usec changes.
+ */
void
-traceon(file)
- char *file;
+lastlog(void)
{
- struct stat stbuf;
+ static struct timeval last;
- if (ftrace != NULL)
- return;
- if (stat(file, &stbuf) >= 0 && !S_ISREG(stbuf.st_mode))
- return;
- savetracename = file;
- (void) gettimeofday(&now, NULL);
- ftrace = fopen(file, "a");
- if (ftrace == NULL)
- return;
- dup2(fileno(ftrace), 1);
- dup2(fileno(ftrace), 2);
- traceactions = 1;
- fprintf(ftrace, "Tracing enabled %s\n", ctime((time_t *)&now.tv_sec));
+ if (last.tv_sec != now.tv_sec
+ || last.tv_usec != now.tv_usec) {
+ (void)fprintf(ftrace, "-- %s --\n", ts(now.tv_sec));
+ last = now;
+ }
}
-void
-traceoff()
+
+static void
+tmsg(char *p, ...)
{
- if (!traceactions)
- return;
- if (ftrace != NULL) {
- int fd = open(_PATH_DEVNULL, O_RDWR);
+ va_list args;
- fprintf(ftrace, "Tracing disabled %s\n",
- ctime((time_t *)&now.tv_sec));
+ if (ftrace != 0) {
+ lastlog();
+ va_start(args, p);
+ vfprintf(ftrace, p, args);
fflush(ftrace);
- (void) dup2(fd, 1);
- (void) dup2(fd, 2);
- (void) close(fd);
+ }
+}
+
+
+static void
+trace_close(void)
+{
+ int fd;
+
+
+ fflush(stdout);
+ fflush(stderr);
+
+ if (ftrace != 0
+ && savetracename[0] != '\0') {
+ fd = open(_PATH_DEVNULL, O_RDWR);
+ (void)dup2(fd, STDOUT_FILENO);
+ (void)dup2(fd, STDERR_FILENO);
+ (void)close(fd);
fclose(ftrace);
- ftrace = NULL;
+ ftrace = 0;
}
- traceactions = 0;
- tracehistory = 0;
- tracepackets = 0;
- tracecontents = 0;
}
+
void
-sigtrace(s)
- int s;
+trace_flush(void)
{
-
- if (s == SIGUSR2)
- traceoff();
- else if (ftrace == NULL && savetracename)
- traceon(savetracename);
- else
- bumploglevel();
+ if (ftrace != 0) {
+ fflush(ftrace);
+ if (ferror(ftrace))
+ trace_off("tracing off: ", strerror(ferror(ftrace)));
+ }
}
-/*
- * Move to next higher level of tracing when -t option processed or
- * SIGUSR1 is received. Successive levels are:
- * traceactions
- * traceactions + tracepackets
- * traceactions + tracehistory (packets and contents after change)
- * traceactions + tracepackets + tracecontents
- */
+
void
-bumploglevel()
+trace_off(char *p, ...)
{
+ va_list args;
- (void) gettimeofday(&now, NULL);
- if (traceactions == 0) {
- traceactions++;
- if (ftrace)
- fprintf(ftrace, "Tracing actions started %s\n",
- ctime((time_t *)&now.tv_sec));
- } else if (tracepackets == 0) {
- tracepackets++;
- tracehistory = 0;
- tracecontents = 0;
- if (ftrace)
- fprintf(ftrace, "Tracing packets started %s\n",
- ctime((time_t *)&now.tv_sec));
- } else if (tracehistory == 0) {
- tracehistory++;
- if (ftrace)
- fprintf(ftrace, "Tracing history started %s\n",
- ctime((time_t *)&now.tv_sec));
- } else {
- tracepackets++;
- tracecontents++;
- tracehistory = 0;
- if (ftrace)
- fprintf(ftrace, "Tracing packet contents started %s\n",
- ctime((time_t *)&now.tv_sec));
- }
- if (ftrace)
+
+ if (ftrace != 0) {
+ lastlog();
+ va_start(args, p);
+ vfprintf(ftrace, p, args);
fflush(ftrace);
+ }
+ trace_close();
+
+ new_tracelevel = tracelevel = 0;
}
+
void
-trace(ifd, who, p, len, m)
- register struct ifdebug *ifd;
- struct sockaddr *who;
- char *p;
- int len, m;
+trace_on(char *filename,
+ int trusted)
{
- register struct iftrace *t;
+ struct stat stbuf;
+ FILE *n_ftrace;
+
+
+ /* Given a null filename when tracing is already on, increase the
+ * debugging level and re-open the file in case it has been unlinked.
+ */
+ if (filename[0] == '\0') {
+ if (tracelevel != 0) {
+ new_tracelevel++;
+ tracelevel_pat = "trace command: %s\n";
+ } else if (savetracename[0] == '\0') {
+ msglog("missing trace file name");
+ return;
+ }
+ filename = savetracename;
- if (ifd->ifd_records == 0)
- return;
- t = ifd->ifd_front++;
- if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
- ifd->ifd_front = ifd->ifd_records;
- if (ifd->ifd_count < NRECORDS)
- ifd->ifd_count++;
- if (t->ift_size > 0 && t->ift_size < len && t->ift_packet) {
- free(t->ift_packet);
- t->ift_packet = 0;
+ } else if (stat(filename, &stbuf) >= 0) {
+ if (!trusted) {
+ msglog("trace file \"%s\" already exists");
+ return;
+ }
+ if ((stbuf.st_mode & S_IFMT) != S_IFREG) {
+ msglog("wrong type (%#x) of trace file \"%s\"",
+ stbuf.st_mode, filename);
+ return;
+ }
+
+ if (!trusted
+ && strcmp(filename, savetracename)
+ && strncmp(filename, _PATH_TRACE, sizeof(_PATH_TRACE)-1)) {
+ msglog("wrong directory for trace file: \"%s\"",
+ filename);
+ return;
+ }
}
- t->ift_stamp = now;
- t->ift_who = *who;
- if (len > 0 && t->ift_packet == 0) {
- t->ift_packet = malloc(len);
- if (t->ift_packet == 0)
- len = 0;
+
+ n_ftrace = fopen(filename, "a");
+ if (n_ftrace == 0) {
+ msglog("failed to open trace file \"%s\" %s",
+ filename, strerror(errno));
+ return;
}
- if (len > 0)
- memcpy(t->ift_packet, p, len);
- t->ift_size = len;
- t->ift_metric = m;
+
+ tmsg("switch to trace file %s\n", filename);
+ trace_close();
+ if (filename != savetracename)
+ strncpy(savetracename, filename, sizeof(savetracename)-1);
+ ftrace = n_ftrace;
+
+ fflush(stdout);
+ fflush(stderr);
+ dup2(fileno(ftrace), STDOUT_FILENO);
+ dup2(fileno(ftrace), STDERR_FILENO);
+
+ if (new_tracelevel == 0)
+ new_tracelevel = 1;
+ set_tracelevel();
}
+
+/* ARGSUSED */
void
-traceaction(fd, action, rt)
- FILE *fd;
- char *action;
- struct rt_entry *rt;
+sigtrace_on(int s)
{
- struct sockaddr_in *dst, *gate, *netmask;
- static struct bits {
- int t_bits;
- char *t_name;
- } flagbits[] = {
- { RTF_UP, "UP" },
- { RTF_GATEWAY, "GATEWAY" },
- { RTF_HOST, "HOST" },
- { 0 }
- }, statebits[] = {
- { RTS_PASSIVE, "PASSIVE" },
- { RTS_REMOTE, "REMOTE" },
- { RTS_INTERFACE,"INTERFACE" },
- { RTS_CHANGED, "CHANGED" },
- { RTS_INTERNAL, "INTERNAL" },
- { RTS_EXTERNAL, "EXTERNAL" },
- { RTS_SUBNET, "SUBNET" },
- { 0 }
+ new_tracelevel++;
+ tracelevel_pat = "SIGUSR1: %s\n";
+}
+
+
+/* ARGSUSED */
+void
+sigtrace_off(int s)
+{
+ new_tracelevel--;
+ tracelevel_pat = "SIGUSR2: %s\n";
+}
+
+
+/* Move to next higher level of tracing when -t option processed or
+ * SIGUSR1 is received. Successive levels are:
+ * actions
+ * actions + packets
+ * actions + packets + contents
+ */
+void
+set_tracelevel(void)
+{
+ static char *off_msgs[MAX_TRACELEVEL] = {
+ "Tracing actions stopped",
+ "Tracing packets stopped",
+ "Tracing packet contents stopped",
+ "Tracing kernel changes stopped",
+ };
+ static char *on_msgs[MAX_TRACELEVEL] = {
+ "Tracing actions started",
+ "Tracing packets started",
+ "Tracing packet contents started",
+ "Tracing kernel changes started",
};
- register struct bits *p;
- register int first;
- char *cp;
- if (fd == NULL)
- return;
- if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
- fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
- lastlog = now;
+
+ if (new_tracelevel > MAX_TRACELEVEL) {
+ new_tracelevel = MAX_TRACELEVEL;
+ if (new_tracelevel == tracelevel) {
+ tmsg(tracelevel_pat, on_msgs[tracelevel-1]);
+ return;
+ }
+ }
+ while (new_tracelevel != tracelevel) {
+ if (new_tracelevel < tracelevel) {
+ if (--tracelevel == 0)
+ trace_off(tracelevel_pat, off_msgs[0]);
+ else
+ tmsg(tracelevel_pat, off_msgs[tracelevel]);
+ } else {
+ if (ftrace == 0) {
+ if (savetracename[0] != '\0')
+ trace_on(savetracename, 1);
+ else
+ ftrace = stdout;
+ }
+ tmsg(tracelevel_pat, on_msgs[tracelevel++]);
+ }
}
- fprintf(fd, "%s ", action);
- dst = (struct sockaddr_in *)&rt->rt_dst;
- gate = (struct sockaddr_in *)&rt->rt_router;
- netmask = (struct sockaddr_in *)&rt->rt_netmask;
- fprintf(fd, "dst %s, ", inet_ntoa(dst->sin_addr));
- fprintf(fd, "router %s, ", inet_ntoa(gate->sin_addr));
- fprintf(fd, " netmask %s, metric %d, flags",
- inet_ntoa(netmask->sin_addr), rt->rt_metric);
- cp = " %s";
- for (first = 1, p = flagbits; p->t_bits > 0; p++) {
- if ((rt->rt_flags & p->t_bits) == 0)
- continue;
- fprintf(fd, cp, p->t_name);
- if (first) {
- cp = "|%s";
- first = 0;
+ tracelevel_pat = "%s\n";
+}
+
+
+/* display an address
+ */
+char *
+addrname(naddr addr, /* in network byte order */
+ naddr mask,
+ int force) /* 0=show mask if nonstandard, */
+{ /* 1=always show mask, 2=never */
+#define NUM_BUFS 4
+ static int bufno;
+ static struct {
+ char str[15+20];
+ } bufs[NUM_BUFS];
+ char *s, *sp;
+ naddr dmask;
+ int i;
+
+ s = strcpy(bufs[bufno].str, naddr_ntoa(addr));
+ bufno = (bufno+1) % NUM_BUFS;
+
+ if (force == 1 || (force == 0 && mask != std_mask(addr))) {
+ sp = &s[strlen(s)];
+
+ dmask = mask & -mask;
+ if (mask + dmask == 0) {
+ for (i = 0; i != 32 && ((1<<i) & mask) == 0; i++)
+ continue;
+ (void)sprintf(sp, "/%d", 32-i);
+
+ } else {
+ (void)sprintf(sp, " (mask %#x)", (u_int)mask);
}
}
- fprintf(fd, " state");
- cp = " %s";
- for (first = 1, p = statebits; p->t_bits > 0; p++) {
- if ((rt->rt_state & p->t_bits) == 0)
- continue;
- fprintf(fd, cp, p->t_name);
- if (first) {
- cp = "|%s";
- first = 0;
+
+ return s;
+#undef NUM_BUFS
+}
+
+
+/* display a bit-field
+ */
+struct bits {
+ int bits_mask;
+ int bits_clear;
+ char *bits_name;
+};
+
+static struct bits if_bits[] = {
+ { IFF_LOOPBACK, 0, "LOOPBACK" },
+ { IFF_POINTOPOINT, 0, "PT-TO-PT" },
+ { 0, 0, 0}
+};
+
+static struct bits is_bits[] = {
+ { IS_SUBNET, 0, "" },
+ { IS_REMOTE, 0, "REMOTE" },
+ { IS_PASSIVE, (IS_NO_RDISC
+ | IS_BCAST_RDISC
+ | IS_NO_RIP
+ | IS_NO_SUPER_AG
+ | IS_PM_RDISC
+ | IS_NO_AG), "PASSIVE" },
+ { IS_EXTERNAL, 0, "EXTERNAL" },
+ { IS_CHECKED, 0, "" },
+ { IS_ALL_HOSTS, 0, "" },
+ { IS_ALL_ROUTERS, 0, "" },
+ { IS_RIP_QUERIED, 0, "" },
+ { IS_BROKE, IS_SICK, "BROKEN" },
+ { IS_SICK, 0, "SICK" },
+ { IS_ACTIVE, 0, "ACTIVE" },
+ { IS_NEED_NET_SYN, 0, "" },
+ { IS_NO_AG, IS_NO_SUPER_AG, "NO_AG" },
+ { IS_NO_SUPER_AG, 0, "NO_SUPER_AG" },
+ { (IS_NO_RIPV1_IN
+ | IS_NO_RIPV2_IN
+ | IS_NO_RIPV1_OUT
+ | IS_NO_RIPV2_OUT), 0, "NO_RIP" },
+ { (IS_NO_RIPV1_IN
+ | IS_NO_RIPV1_OUT), 0, "RIPV2" },
+ { IS_NO_RIPV1_IN, 0, "NO_RIPV1_IN" },
+ { IS_NO_RIPV2_IN, 0, "NO_RIPV2_IN" },
+ { IS_NO_RIPV1_OUT, 0, "NO_RIPV1_OUT" },
+ { IS_NO_RIPV2_OUT, 0, "NO_RIPV2_OUT" },
+ { (IS_NO_ADV_IN
+ | IS_NO_SOL_OUT
+ | IS_NO_ADV_OUT), IS_BCAST_RDISC, "NO_RDISC" },
+ { IS_NO_SOL_OUT, 0, "NO_SOLICIT" },
+ { IS_SOL_OUT, 0, "SEND_SOLICIT" },
+ { IS_NO_ADV_OUT, IS_BCAST_RDISC, "NO_RDISC_ADV" },
+ { IS_ADV_OUT, 0, "RDISC_ADV" },
+ { IS_BCAST_RDISC, 0, "BCAST_RDISC" },
+ { IS_PM_RDISC, 0, "PM_RDISC" },
+ { 0, 0, "%#x"}
+};
+
+static struct bits rs_bits[] = {
+ { RS_IF, 0, "IF" },
+ { RS_NET_INT, RS_NET_SYN, "NET_INT" },
+ { RS_NET_SYN, 0, "NET_SYN" },
+ { RS_SUBNET, 0, "" },
+ { RS_LOCAL, 0, "LOCAL" },
+ { RS_MHOME, 0, "MHOME" },
+ { RS_STATIC, 0, "STATIC" },
+ { RS_RDISC, 0, "RDISC" },
+ { 0, 0, "%#x"}
+};
+
+
+static void
+trace_bits(struct bits *tbl,
+ u_int field,
+ int force)
+{
+ int b;
+ char c;
+
+ if (force) {
+ (void)putc('<', ftrace);
+ c = 0;
+ } else {
+ c = '<';
+ }
+
+ while (field != 0
+ && (b = tbl->bits_mask) != 0) {
+ if ((b & field) == b) {
+ if (tbl->bits_name[0] != '\0') {
+ if (c)
+ (void)putc(c, ftrace);
+ (void)fprintf(ftrace, "%s", tbl->bits_name);
+ c = '|';
+ }
+ if (0 == (field &= ~(b | tbl->bits_clear)))
+ break;
}
+ tbl++;
+ }
+ if (field != 0 && tbl->bits_name != 0) {
+ if (c)
+ (void)putc(c, ftrace);
+ (void)fprintf(ftrace, tbl->bits_name, field);
+ c = '|';
}
- fprintf(fd, " timer %d\n", rt->rt_timer);
- if (tracehistory && !tracepackets &&
- (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
- dumpif(fd, rt->rt_ifp);
- fflush(fd);
- if (ferror(fd))
- traceoff();
+
+ if (c != '<' || force)
+ (void)fputs("> ", ftrace);
+}
+
+
+static char *
+trace_pair(naddr dst,
+ naddr mask,
+ char *gate)
+{
+ static char buf[3*4+3+1+2+3 /* "xxx.xxx.xxx.xxx/xx-->" */
+ +3*4+3+1]; /* "xxx.xxx.xxx.xxx" */
+ int i;
+
+ i = sprintf(buf, "%-16s-->", addrname(dst, mask, 0));
+ (void)sprintf(&buf[i], "%-*s", 15+20-MAX(20,i), gate);
+ return buf;
}
+
void
-tracenewmetric(fd, rt, newmetric)
- FILE *fd;
- struct rt_entry *rt;
- int newmetric;
+trace_if(char *act,
+ struct interface *ifp)
{
- struct sockaddr_in *dst, *gate;
+ if (!TRACEACTIONS || ftrace == 0)
+ return;
- if (fd == NULL)
+ lastlog();
+ (void)fprintf(ftrace, "%s interface %-4s ", act, ifp->int_name);
+ (void)fprintf(ftrace, "%-15s-->%-15s ",
+ naddr_ntoa(ifp->int_addr),
+ addrname(htonl((ifp->int_if_flags & IFF_POINTOPOINT)
+ ? ifp->int_dstaddr
+ : ifp->int_net),
+ ifp->int_mask, 1));
+ if (ifp->int_metric != 0)
+ (void)fprintf(ftrace, "metric=%d ", ifp->int_metric);
+ trace_bits(if_bits, ifp->int_if_flags, 0);
+ trace_bits(is_bits, ifp->int_state, 0);
+ (void)fputc('\n',ftrace);
+}
+
+
+void
+trace_upslot(struct rt_entry *rt,
+ struct rt_spare *rts,
+ naddr gate,
+ naddr router,
+ struct interface *ifp,
+ int metric,
+ u_short tag,
+ time_t new_time)
+{
+ if (!TRACEACTIONS || ftrace == 0)
+ return;
+ if (rts->rts_gate == gate
+ && rts->rts_router == router
+ && rts->rts_metric == metric
+ && rts->rts_tag == tag)
return;
- if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
- fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
- lastlog = now;
+
+ lastlog();
+ if (rts->rts_gate != RIP_DEFAULT) {
+ (void)fprintf(ftrace, "Chg #%d %-35s ",
+ rts - rt->rt_spares,
+ trace_pair(rt->rt_dst, rt->rt_mask,
+ naddr_ntoa(rts->rts_gate)));
+ if (rts->rts_gate != rts->rts_gate)
+ (void)fprintf(ftrace, "router=%s ",
+ naddr_ntoa(rts->rts_gate));
+ if (rts->rts_tag != 0)
+ (void)fprintf(ftrace, "tag=%#x ", ntohs(rts->rts_tag));
+ (void)fprintf(ftrace, "metric=%-2d ", rts->rts_metric);
+ if (rts->rts_ifp != 0)
+ (void)fprintf(ftrace, "%s ",
+ rts->rts_ifp->int_name);
+ (void)fprintf(ftrace, "%s\n", ts(rts->rts_time));
+
+ (void)fprintf(ftrace, " %19s%-16s ",
+ "",
+ gate != rts->rts_gate ? naddr_ntoa(gate) : "");
+ if (gate != router)
+ (void)fprintf(ftrace,"router=%s ",naddr_ntoa(router));
+ if (tag != rts->rts_tag)
+ (void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
+ if (metric != rts->rts_metric)
+ (void)fprintf(ftrace, "metric=%-2d ", metric);
+ if (ifp != rts->rts_ifp && ifp != 0 )
+ (void)fprintf(ftrace, "%s ", ifp->int_name);
+ (void)fprintf(ftrace, "%s\n",
+ new_time != rts->rts_time ? ts(new_time) : "");
+
+ } else {
+ (void)fprintf(ftrace, "Add #%d %-35s ",
+ rts - rt->rt_spares,
+ trace_pair(rt->rt_dst, rt->rt_mask,
+ naddr_ntoa(gate)));
+ if (gate != router)
+ (void)fprintf(ftrace, "router=%s ", naddr_ntoa(gate));
+ if (tag != 0)
+ (void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
+ (void)fprintf(ftrace, "metric=%-2d ", metric);
+ if (ifp != 0)
+ (void)fprintf(ftrace, "%s ", ifp->int_name);
+ (void)fprintf(ftrace, "%s\n", ts(new_time));
}
- dst = (struct sockaddr_in *)&rt->rt_dst;
- gate = (struct sockaddr_in *)&rt->rt_router;
- fprintf(fd, "CHANGE metric dst %s, ", inet_ntoa(dst->sin_addr));
- fprintf(fd, "router %s, from %d to %d\n",
- inet_ntoa(gate->sin_addr), rt->rt_metric, newmetric);
- fflush(fd);
- if (ferror(fd))
- traceoff();
}
+
+/* talk about a change made to the kernel table
+ */
void
-dumpif(fd, ifp)
- FILE *fd;
- register struct interface *ifp;
+trace_kernel(char *p, ...)
{
- if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
- fprintf(fd, "*** Packet history for interface %s ***\n",
- ifp->int_name);
-#ifdef notneeded
- dumptrace(fd, "to", &ifp->int_output);
-#endif
- dumptrace(fd, "from", &ifp->int_input);
- fprintf(fd, "*** end packet history ***\n");
- }
+ va_list args;
+
+ if (!TRACEKERNEL || ftrace == 0)
+ return;
+
+ lastlog();
+ va_start(args, p);
+ vfprintf(ftrace, p, args);
}
+
+/* display a message if tracing actions
+ */
void
-dumptrace(fd, dir, ifd)
- FILE *fd;
- char *dir;
- register struct ifdebug *ifd;
+trace_act(char *p, ...)
{
- register struct iftrace *t;
- char *cp = !strcmp(dir, "to") ? "Output" : "Input";
+ va_list args;
- if (ifd->ifd_front == ifd->ifd_records &&
- ifd->ifd_front->ift_size == 0) {
- fprintf(fd, "%s: no packets.\n", cp);
- fflush(fd);
+ if (!TRACEACTIONS || ftrace == 0)
return;
- }
- fprintf(fd, "%s trace:\n", cp);
- t = ifd->ifd_front - ifd->ifd_count;
- if (t < ifd->ifd_records)
- t += NRECORDS;
- for ( ; ifd->ifd_count; ifd->ifd_count--, t++) {
- if (t >= ifd->ifd_records + NRECORDS)
- t = ifd->ifd_records;
- if (t->ift_size == 0)
- continue;
- dumppacket(fd, dir, (struct sockaddr_in *)&t->ift_who,
- t->ift_packet, t->ift_size, &t->ift_stamp);
- }
+
+ lastlog();
+ va_start(args, p);
+ vfprintf(ftrace, p, args);
}
+
+/* display a message if tracing packets
+ */
void
-dumppacket(fd, dir, who, cp, size, stamp)
- FILE *fd;
- struct sockaddr_in *who; /* should be sockaddr */
- char *dir, *cp;
- register int size;
- struct timeval *stamp;
+trace_pkt(char *p, ...)
{
- register struct rip *msg = (struct rip *)cp;
- register struct netinfo *n;
+ va_list args;
- if (fd == NULL)
+ if (!TRACEPACKETS || ftrace == 0)
return;
- if (msg->rip_cmd && msg->rip_cmd < RIPCMD_MAX)
- fprintf(fd, "%s %s %s.%d %.19s:\n", ripcmds[msg->rip_cmd],
- dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port),
- ctime((time_t *)&stamp->tv_sec));
- else {
- fprintf(fd, "Bad cmd 0x%x %s %s.%d %.19s\n", msg->rip_cmd,
- dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port),
- ctime((time_t *)&stamp->tv_sec));
- fprintf(fd, "size=%d cp=%lx packet=%lx\n", size,
- (u_long) cp, (u_long) packet);
- fflush(fd);
+
+ lastlog();
+ va_start(args, p);
+ vfprintf(ftrace, p, args);
+}
+
+
+void
+trace_change(struct rt_entry *rt,
+ u_int state,
+ naddr gate, /* forward packets here */
+ naddr router, /* on the authority of this router */
+ int metric,
+ u_short tag,
+ struct interface *ifp,
+ time_t new_time,
+ char *label)
+{
+ if (ftrace == 0)
return;
- }
- if (tracepackets && tracecontents == 0) {
- fflush(fd);
+
+ if (rt->rt_metric == metric
+ && rt->rt_gate == gate
+ && rt->rt_router == router
+ && rt->rt_state == state
+ && rt->rt_tag == tag)
+ return;
+
+ lastlog();
+ (void)fprintf(ftrace, "%s %-35s metric=%-2d ",
+ label,
+ trace_pair(rt->rt_dst, rt->rt_mask,
+ naddr_ntoa(rt->rt_gate)),
+ rt->rt_metric);
+ if (rt->rt_router != rt->rt_gate)
+ (void)fprintf(ftrace, "router=%s ",
+ naddr_ntoa(rt->rt_router));
+ if (rt->rt_tag != 0)
+ (void)fprintf(ftrace, "tag=%#x ", ntohs(rt->rt_tag));
+ trace_bits(rs_bits, rt->rt_state, rt->rt_state != state);
+ (void)fprintf(ftrace, "%s ",
+ rt->rt_ifp == 0 ? "?" : rt->rt_ifp->int_name);
+ (void)fprintf(ftrace, "%s\n",
+ AGE_RT(rt->rt_state, rt->rt_ifp) ? ts(rt->rt_time) : "");
+
+ (void)fprintf(ftrace, "%*s %19s%-16s ",
+ strlen(label), "", "",
+ rt->rt_gate != gate ? naddr_ntoa(gate) : "");
+ if (rt->rt_metric != metric)
+ (void)fprintf(ftrace, "metric=%-2d ", metric);
+ if (router != gate)
+ (void)fprintf(ftrace, "router=%s ", naddr_ntoa(router));
+ if (rt->rt_tag != tag)
+ (void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
+ if (rt->rt_state != state)
+ trace_bits(rs_bits, state, 1);
+ if (rt->rt_ifp != ifp)
+ (void)fprintf(ftrace, "%s ",
+ ifp != 0 ? ifp->int_name : "?");
+ (void)fprintf(ftrace, "%s\n",
+ ((rt->rt_time == new_time || !AGE_RT(rt->rt_state, ifp))
+ ? "" : ts(new_time)));
+}
+
+
+void
+trace_add_del(char * action, struct rt_entry *rt)
+{
+ u_int state = rt->rt_state;
+
+ if (ftrace == 0)
+ return;
+
+ lastlog();
+ (void)fprintf(ftrace, "%s %-35s metric=%-2d ",
+ action,
+ trace_pair(rt->rt_dst, rt->rt_mask,
+ naddr_ntoa(rt->rt_gate)),
+ rt->rt_metric);
+ if (rt->rt_router != rt->rt_gate)
+ (void)fprintf(ftrace, "router=%s ",
+ naddr_ntoa(rt->rt_router));
+ if (rt->rt_tag != 0)
+ (void)fprintf(ftrace, "tag=%#x ", ntohs(rt->rt_tag));
+ trace_bits(rs_bits, state, 0);
+ (void)fprintf(ftrace, "%s ",
+ rt->rt_ifp != 0 ? rt->rt_ifp->int_name : "?");
+ (void)fprintf(ftrace, "%s\n", ts(rt->rt_time));
+}
+
+
+void
+trace_rip(char *dir1, char *dir2,
+ struct sockaddr_in *who,
+ struct interface *ifp,
+ struct rip *msg,
+ int size) /* total size of message */
+{
+ struct netinfo *n, *lim;
+ struct netauth *a;
+ int i;
+
+ if (!TRACEPACKETS || ftrace == 0)
+ return;
+
+ lastlog();
+ if (msg->rip_cmd >= RIPCMD_MAX
+ || msg->rip_vers == 0) {
+ (void)fprintf(ftrace, "%s bad RIPv%d cmd=%d %s"
+ " %s.%d size=%d\n",
+ dir1, msg->rip_vers, msg->rip_cmd, dir2,
+ naddr_ntoa(who->sin_addr.s_addr),
+ ntohs(who->sin_port),
+ size);
return;
}
- switch (msg->rip_cmd) {
+ (void)fprintf(ftrace, "%s RIPv%d %s %s %s.%d%s%s\n",
+ dir1, msg->rip_vers, ripcmds[msg->rip_cmd], dir2,
+ naddr_ntoa(who->sin_addr.s_addr), ntohs(who->sin_port),
+ ifp ? " via " : "", ifp ? ifp->int_name : "");
+ if (!TRACECONTENTS)
+ return;
+
+ switch (msg->rip_cmd) {
case RIPCMD_REQUEST:
case RIPCMD_RESPONSE:
- size -= 4 * sizeof (char);
n = msg->rip_nets;
- for (; size > 0; n++, size -= sizeof (struct netinfo)) {
- if (size < sizeof (struct netinfo)) {
- fprintf(fd, "(truncated record, len %d)\n",
- size);
- break;
+ lim = (struct netinfo *)((char*)msg + size);
+ for (; n < lim; n++) {
+ if (n->n_family == RIP_AF_UNSPEC
+ && ntohl(n->n_metric) == HOPCNT_INFINITY
+ && n+1 == lim
+ && n == msg->rip_nets
+ && msg->rip_cmd == RIPCMD_REQUEST) {
+ (void)fputs("\tQUERY ", ftrace);
+ if (n->n_dst != 0)
+ (void)fprintf(ftrace, "%s ",
+ naddr_ntoa(n->n_dst));
+ if (n->n_mask != 0)
+ (void)fprintf(ftrace, "mask=%#x ",
+ (u_int)ntohl(n->n_mask));
+ if (n->n_nhop != 0)
+ (void)fprintf(ftrace, " nhop=%s ",
+ naddr_ntoa(n->n_nhop));
+ if (n->n_tag != 0)
+ (void)fprintf(ftrace, "tag=%#x",
+ ntohs(n->n_tag));
+ (void)fputc('\n',ftrace);
+ continue;
}
- switch (n->rip_family) {
-
- case AF_INET:
- {
- struct sockaddr_in sa;
- sa.sin_addr.s_addr = n->rip_dst;
- fprintf(fd, "\tdst %s",
- inet_ntoa(sa.sin_addr));
- if (msg->rip_vers > RIP_VERSION_1) {
- fprintf(fd, ", mask 0x%.8x",
- n->rip_netmask);
- sa.sin_addr.s_addr =
- n->rip_router;
- fprintf(fd, ", router %s",
- inet_ntoa(sa.sin_addr));
- }
- }
- break;
- default:
- fprintf(fd, "\taf %d?", n->rip_family);
- break;
+ if (n->n_family == RIP_AF_AUTH) {
+ a = (struct netauth*)n;
+ (void)fprintf(ftrace,
+ "\tAuthentication type %d: ",
+ ntohs(a->a_type));
+ for (i = 0;
+ i < sizeof(a->au.au_pw);
+ i++)
+ (void)fprintf(ftrace, "%02x ",
+ a->au.au_pw[i]);
+ (void)fputc('\n',ftrace);
+ continue;
+ }
+
+ if (n->n_family != RIP_AF_INET) {
+ (void)fprintf(ftrace,
+ "\t(af %d) %-18s mask=%#x",
+ ntohs(n->n_family),
+ naddr_ntoa(n->n_dst),
+ (u_int)ntohl(n->n_mask));
+ } else if (msg->rip_vers == RIPv1) {
+ (void)fprintf(ftrace, "\t%-18s ",
+ addrname(n->n_dst,
+ ntohl(n->n_mask),
+ n->n_mask==0 ? 2 : 1));
+ } else {
+ (void)fprintf(ftrace, "\t%-18s ",
+ addrname(n->n_dst,
+ ntohl(n->n_mask),
+ n->n_mask==0 ? 2 : 0));
}
- fprintf(fd, ", metric %d\n", ntohl(n->rip_metric));
+ (void)fprintf(ftrace, "metric=%-2d ",
+ (u_int)ntohl(n->n_metric));
+ if (n->n_nhop != 0)
+ (void)fprintf(ftrace, " nhop=%s ",
+ naddr_ntoa(n->n_nhop));
+ if (n->n_tag != 0)
+ (void)fprintf(ftrace, "tag=%#x",
+ ntohs(n->n_tag));
+ (void)fputc('\n',ftrace);
}
+ if (size != (char *)n - (char *)msg)
+ (void)fprintf(ftrace, "truncated record, len %d\n",
+ size);
break;
case RIPCMD_TRACEON:
- fprintf(fd, "\tfile=%*s\n", size, msg->rip_tracefile);
+ fprintf(ftrace, "\tfile=%*s\n", size-4, msg->rip_tracefile);
break;
case RIPCMD_TRACEOFF:
break;
}
- fflush(fd);
- if (ferror(fd))
- traceoff();
}
diff --git a/sbin/routed/trace.h b/sbin/routed/trace.h
deleted file mode 100644
index c8c4beb7c16..00000000000
--- a/sbin/routed/trace.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/* $OpenBSD: trace.h,v 1.2 1996/06/23 14:32:35 deraadt Exp $ */
-/* $NetBSD: trace.h,v 1.8 1995/06/20 22:28:04 christos Exp $ */
-
-/*
- * Copyright (c) 1983, 1988, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)trace.h 8.1 (Berkeley) 6/5/93
- */
-
-/*
- * Routing table management daemon.
- */
-
-/*
- * Trace record format.
- */
-struct iftrace {
- struct timeval ift_stamp; /* time stamp */
- struct sockaddr ift_who; /* from/to */
- char *ift_packet; /* pointer to packet */
- short ift_size; /* size of packet */
- short ift_metric; /* metric on associated metric */
-};
-
-/*
- * Per interface packet tracing buffers. An incoming and
- * outgoing circular buffer of packets is maintained, per
- * interface, for debugging. Buffers are dumped whenever
- * an interface is marked down.
- */
-struct ifdebug {
- struct iftrace *ifd_records; /* array of trace records */
- struct iftrace *ifd_front; /* next empty trace record */
- int ifd_count; /* number of unprinted records */
- struct interface *ifd_if; /* for locating stuff */
-};
-
-/*
- * Packet tracing stuff.
- */
-int tracepackets; /* watch packets as they go by */
-int tracecontents; /* watch packet contents as they go by */
-int traceactions; /* on/off */
-int tracehistory; /* on/off */
-FILE *ftrace; /* output trace file */
-
-#define TRACE_ACTION(action, route) { \
- if (traceactions) \
- traceaction(ftrace, action, route); \
- }
-#define TRACE_NEWMETRIC(route, newmetric) { \
- if (traceactions) \
- tracenewmetric(ftrace, route, newmetric); \
- }
-#define TRACE_INPUT(ifp, src, pack, size) { \
- if (tracehistory) { \
- ifp = if_iflookup(src); \
- if (ifp) \
- trace(&ifp->int_input, src, pack, size, \
- ntohl(ifp->int_metric)); \
- } \
- if (tracepackets) \
- dumppacket(ftrace, "from", (struct sockaddr_in *)src, pack, \
- size, &now); \
- }
-#define TRACE_OUTPUT(ifp, dst, size) { \
- if (tracehistory && ifp) \
- trace(&ifp->int_output, dst, packet, size, ifp->int_metric); \
- if (tracepackets) \
- dumppacket(ftrace, "to", (struct sockaddr_in *)dst, packet, \
- size, &now); \
- }
-
-/* trace.c */
-void traceinit __P((struct interface *));
-void traceon __P((char *));
-void traceoff __P((void));
-void sigtrace __P((int));
-void bumploglevel __P((void));
-void trace __P((struct ifdebug *, struct sockaddr *, char *, int, int ));
-void traceaction __P((FILE *, char *, struct rt_entry *));
-void tracenewmetric __P((FILE *, struct rt_entry *, int));
-void dumpif __P((FILE *, struct interface *));
-void dumptrace __P((FILE *, char *, struct ifdebug *));
-void dumppacket __P((FILE *, char *, struct sockaddr_in *, char *, int, struct timeval *));
-