From 36f5656cf14d7d1c420853b4997c6e640aaba3c7 Mon Sep 17 00:00:00 2001 From: mickey Date: Thu, 5 Sep 1996 14:31:10 +0000 Subject: [PATCH] fix import. mention that routed is from vjs@sgi.com --- sbin/routed/Makefile | 18 +- sbin/routed/af.c | 254 --------- sbin/routed/af.h | 85 --- sbin/routed/defs.h | 593 ++++++++++++++++---- sbin/routed/if.c | 1140 ++++++++++++++++++++++++++++++++++++--- sbin/routed/inet.c | 260 --------- sbin/routed/input.c | 918 +++++++++++++++++++++---------- sbin/routed/interface.h | 93 ---- sbin/routed/main.c | 988 ++++++++++++++++++++++++--------- sbin/routed/output.c | 920 +++++++++++++++++++++++++++---- sbin/routed/pathnames.h | 11 +- sbin/routed/routed.8 | 679 +++++++++++++++-------- sbin/routed/startup.c | 531 ------------------ sbin/routed/table.h | 121 ----- sbin/routed/tables.c | 496 ----------------- sbin/routed/timer.c | 137 ----- sbin/routed/trace.c | 1004 +++++++++++++++++++++++----------- sbin/routed/trace.h | 115 ---- 18 files changed, 4897 insertions(+), 3466 deletions(-) delete mode 100644 sbin/routed/af.c delete mode 100644 sbin/routed/af.h delete mode 100644 sbin/routed/inet.c delete mode 100644 sbin/routed/interface.h delete mode 100644 sbin/routed/startup.c delete mode 100644 sbin/routed/table.h delete mode 100644 sbin/routed/tables.c delete mode 100644 sbin/routed/timer.c delete mode 100644 sbin/routed/trace.h 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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include #include -#include - +#include +#include #include +#include #include -#include #include +#define RIPVERSION RIPv2 +#include -#include -#include -#include -#include -#include -#include -#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 +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 +#include "pathnames.h" +#ifdef sgi +#include "math.h" +#endif +#include +#include #include -#include +pid_t mypid; -#include -#include -#include -#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 #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 -#include -#include -#include -#include -#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 -/* - * 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 -#include -#include -#include - -#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 -#include +#include #include -#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<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 *)); - -- 2.20.1