From c84af5f0b62f430b52bbd5f941176991c76f1929 Mon Sep 17 00:00:00 2001 From: markm Date: Sun, 2 May 1999 13:14:16 +0000 Subject: [PATCH] Merge-o-matic and add a bunch of $Id's --- sbin/routed/Makefile | 20 +- sbin/routed/defs.h | 184 ++++++---- sbin/routed/if.c | 264 ++++++++------ sbin/routed/input.c | 272 ++++++++++----- sbin/routed/main.c | 184 ++++++---- sbin/routed/output.c | 274 ++++++++------- sbin/routed/parms.c | 350 ++++++++++++------- sbin/routed/pathnames.h | 10 +- sbin/routed/radix.c | 124 ++++--- sbin/routed/radix.h | 20 +- sbin/routed/rdisc.c | 166 +++++---- sbin/routed/routed.8 | 146 +++++--- sbin/routed/rtquery/Makefile | 5 +- sbin/routed/rtquery/rtquery.8 | 85 ++--- sbin/routed/rtquery/rtquery.c | 262 +++++++++----- sbin/routed/table.c | 639 +++++++++++++++++++++------------- sbin/routed/trace.c | 288 +++++++-------- 17 files changed, 1943 insertions(+), 1350 deletions(-) diff --git a/sbin/routed/Makefile b/sbin/routed/Makefile index c2187c6a986a..fb8c3de6b475 100644 --- a/sbin/routed/Makefile +++ b/sbin/routed/Makefile @@ -1,13 +1,13 @@ -# From: @(#)Makefile 8.1 (Berkeley) 6/19/93 -# $Id$ +# Make `routed` for FreeBSD +# $Revision: 2.15 $ +# $Id$ -PROG= routed -SRCS= if.c input.c main.c output.c parms.c radix.c rdisc.c table.c \ - trace.c -MAN8= routed.8 -SUBDIR= rtquery -LDADD+= -lmd -DPADD+= ${LIBMD} -#COPTS= -g -DDEBUG -Wall +PROG= routed +SRCS= if.c input.c main.c output.c parms.c radix.c rdisc.c table.c trace.c +MAN8= routed.8 +SUBDIR= rtquery +LDADD+= -lmd +DPADD+= ${LIBMD} +#COPTS= -g -DDEBUG -W -Wall -Wcast-align -Wcast-qual -Winline -Wpointer-arith -Wnested-externs -Wwrite-strings -Wunused .include diff --git a/sbin/routed/defs.h b/sbin/routed/defs.h index 43bbd444a54b..59a9aff33d95 100644 --- a/sbin/routed/defs.h +++ b/sbin/routed/defs.h @@ -11,7 +11,7 @@ * 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: + * must display the following acknowledgment: * 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 @@ -31,9 +31,14 @@ * SUCH DAMAGE. * * @(#)defs.h 8.1 (Berkeley) 6/5/93 - * $Id: defs.h,v 1.9 1997/02/22 14:33:11 peter Exp $ + * + * $Id$ */ +#ifdef sgi +#ident "$Revision: 2.17 $" +#endif + /* Definitions for RIPv2 routing process. * * This code is based on the 4.4BSD `routed` daemon, with extensions to @@ -72,16 +77,20 @@ #include #include #include +#include +#include #include #include #include #include #include -#include #ifdef sgi +#define _USER_ROUTE_TREE #include #else #include "radix.h" +#define UNUSED __attribute__((unused)) +#define PATTRIB(f,l) __attribute__((format (printf,f,l))) #endif #include #include @@ -99,13 +108,13 @@ * It should be defined somewhere netinet/in.h, but it is not. */ #ifdef sgi -#define naddr __uint32_t -#else -#ifdef __NetBSD__ #define naddr u_int32_t +#elif defined (__NetBSD__) +#define naddr u_int32_t +#define _HAVE_SA_LEN +#define _HAVE_SIN_LEN #else #define naddr u_long -#endif #define _HAVE_SA_LEN #define _HAVE_SIN_LEN #endif @@ -113,7 +122,9 @@ /* 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 */ +#ifdef __NetBSD__ +#define MCAST_PPP_BUG +#endif #define DAY (24*60*60) #define NEVER DAY /* a long time */ @@ -165,6 +176,9 @@ union pkt_buf { struct rip rip; }; +#define GNAME_LEN 64 /* assumed=64 in parms.c */ +/* bigger than IFNAMSIZ, with room for "external()" or "remote()" */ +#define IF_NAME_LEN (GNAME_LEN+15) /* No more routes than this, to protect ourself in case something goes * whacko and starts broadcasting zillions of bogus routes. @@ -195,19 +209,21 @@ struct rt_entry { char rts_metric; u_short rts_tag; time_t rts_time; /* timer to junk stale routes */ + u_int rts_de_ag; /* de-aggregation level */ #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 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 rt_de_ag rt_spares[0].rts_de_ag #define HOST_MASK 0xffffffff #define RT_ISHOST(rt) ((rt)->rt_mask == HOST_MASK) @@ -235,7 +251,7 @@ struct rt_entry { * - or the current route is equal but stale * - or it is a host route advertised by a system for itself */ -#define BETTER_LINK(rt,A,B) ((A)->rts_metric < HOPCNT_INFINITY \ +#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 \ @@ -256,7 +272,7 @@ struct interface { struct interface *int_bhash, **int_bhash_prev; struct interface *int_rlink, **int_rlink_prev; struct interface *int_nhash, **int_nhash_prev; - char int_name[IFNAMSIZ+15+1]; /* big enough for IS_REMOTE */ + char int_name[IF_NAME_LEN+1]; u_short int_index; naddr int_addr; /* address on this host (net order) */ naddr int_brdaddr; /* broadcast address (n) */ @@ -287,12 +303,13 @@ struct interface { } int_data; # define MAX_AUTH_KEYS 5 struct auth { /* authentication info */ - u_char type; - u_char key[RIP_AUTH_PW_LEN]; + u_int16_t type; + u_char key[RIP_AUTH_PW_LEN]; u_char keyid; time_t start, end; } int_auth[MAX_AUTH_KEYS]; - int int_rdisc_pref; /* advertised rdisc preference */ + /* router discovery parameters */ + int int_rdisc_pref; /* signed preference to advertise */ int int_rdisc_int; /* MaxAdvertiseInterval */ int int_rdisc_cnt; struct timeval int_rdisc_timer; @@ -325,23 +342,19 @@ struct interface { #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_RIP_MCAST 0x0100000 /* broadcast RIPv2 */ +#define IS_NO_ADV_IN 0x0200000 /* do not listen to advertisements */ +#define IS_NO_SOL_OUT 0x0400000 /* send no solicitations */ +#define IS_SOL_OUT 0x0800000 /* send solicitations */ +#define GROUP_IS_SOL_OUT (IS_SOL_OUT | IS_NO_SOL_OUT) +#define IS_NO_ADV_OUT 0x1000000 /* do not advertise rdisc */ +#define IS_ADV_OUT 0x2000000 /* advertise rdisc */ +#define GROUP_IS_ADV_OUT (IS_NO_ADV_OUT | IS_ADV_OUT) +#define IS_BCAST_RDISC 0x4000000 /* 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 */ +#define IS_PM_RDISC 0x8000000 /* 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) +#define iff_up(f) ((f) & IFF_UP) /* Information for aggregating routes */ @@ -359,7 +372,7 @@ struct ag_info { u_short ag_tag; u_short ag_state; #define AGS_SUPPRESS 0x001 /* combine with coarser mask */ -#define AGS_PROMOTE 0x002 /* synthesize combined routes */ +#define AGS_AGGREGATE 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)) \ @@ -374,37 +387,50 @@ struct ag_info { #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) +#define AGS_AGGREGATE_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]; + char parm_name[IF_NAME_LEN+1]; naddr parm_net; naddr parm_mask; char parm_d_metric; u_int parm_int_state; - int parm_rdisc_pref; - int parm_rdisc_int; + int parm_rdisc_pref; /* signed IRDP preference */ + int parm_rdisc_int; /* IRDP advertising interval */ struct auth parm_auth[MAX_AUTH_KEYS]; } *parms; /* authority for internal networks */ extern struct intnet { struct intnet *intnet_next; - naddr intnet_addr; + naddr intnet_addr; /* network byte order */ naddr intnet_mask; char intnet_metric; } *intnets; +/* defined RIPv1 netmasks */ +extern struct r1net { + struct r1net *r1net_next; + naddr r1net_net; /* host order */ + naddr r1net_match; + naddr r1net_mask; +} *r1nets; + /* trusted routers */ extern struct tgate { struct tgate *tgate_next; naddr tgate_addr; +#define MAX_TGATE_NETS 32 + struct tgate_net { + naddr net; /* host order */ + naddr mask; + } tgate_nets[MAX_TGATE_NETS]; } *tgates; enum output_type {OUT_QUERY, OUT_UNICAST, OUT_BROADCAST, OUT_MULTICAST, @@ -433,8 +459,8 @@ 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 lookforinterfaces; /* 1=probe for new up interfaces */ extern int ridhosts; /* 1=reduce host routes */ extern int mhome; /* 1=want multi-homed host route */ extern int advertise_mhome; /* 1=must continue advertising it */ @@ -464,7 +490,7 @@ 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 update_seqno; /* a route has changed */ extern int tracelevel, new_tracelevel; #define MAX_TRACELEVEL 4 @@ -483,7 +509,7 @@ extern struct radix_node_head *rhead; #define dup2(x,y) BSDdup2(x,y) #endif /* sgi */ -extern void fix_sock(int, char *); +extern void fix_sock(int, const char *); extern void fix_select(void); extern void rip_off(void); extern void rip_on(struct interface *); @@ -497,7 +523,7 @@ extern void rip_bcast(int); extern void supply(struct sockaddr_in *, struct interface *, enum output_type, int, int, int); -extern void msglog(char *, ...); +extern void msglog(const char *, ...) PATTRIB(1,2); struct msg_limit { time_t reuse; struct msg_sub { @@ -506,9 +532,10 @@ struct msg_limit { # define MSG_SUBJECT_N 8 } subs[MSG_SUBJECT_N]; }; -extern void msglim(struct msg_limit *, naddr, char *, ...); +extern void msglim(struct msg_limit *, naddr, + const char *, ...) PATTRIB(3,4); #define LOGERR(msg) msglog(msg ": %s", strerror(errno)) -extern void logbad(int, char *, ...); +extern void logbad(int, const char *, ...) PATTRIB(2,3); #define BADERR(dump,msg) logbad(dump,msg ": %s", strerror(errno)) #ifdef DEBUG #define DBGERR(dump,msg) BADERR(dump,msg) @@ -516,37 +543,38 @@ extern void logbad(int, char *, ...); #define DBGERR(dump,msg) LOGERR(msg) #endif extern char *naddr_ntoa(naddr); -extern char *saddr_ntoa(struct sockaddr *); +extern const char *saddr_ntoa(struct sockaddr *); -extern void *rtmalloc(size_t, char *); +extern void *rtmalloc(size_t, const 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 *, int); -extern char *check_parms(struct parm *); +extern const char *parse_parms(char *, int); +extern const char *check_parms(struct parm *); extern void get_parms(struct interface *); extern void lastlog(void); -extern void set_tracefile(char *, char *, int); -extern void tracelevel_msg(char *, int); -extern void trace_off(char*, ...); +extern void trace_close(int); +extern void set_tracefile(const char *, const char *, int); +extern void tracelevel_msg(const char *, int); +extern void trace_off(const char*, ...) PATTRIB(1,2); extern void set_tracelevel(void); extern void trace_flush(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_misc(const char *, ...) PATTRIB(1,2); +extern void trace_act(const char *, ...) PATTRIB(1,2); +extern void trace_pkt(const char *, ...) PATTRIB(1,2); +extern void trace_add_del(const char *, struct rt_entry *); +extern void trace_change(struct rt_entry *, u_int, struct rt_spare *, + const char *); +extern void trace_if(const 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 rt_spare *); +extern void trace_rip(const char*, const char*, struct sockaddr_in *, struct interface *, struct rip *, int); extern char *addrname(naddr, naddr, int); +extern char *rtname(naddr, naddr, naddr); extern void rdisc_age(naddr); extern void set_rdisc_mg(struct interface *, int); @@ -571,21 +599,19 @@ 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_static(naddr, 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 rtadd(naddr, naddr, u_int, struct rt_spare *); +extern void rtchange(struct rt_entry *, u_int, struct rt_spare *, char *); extern void rtdelete(struct rt_entry *); +extern void rts_delete(struct rt_entry *, struct rt_spare *); 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]) @@ -604,19 +630,27 @@ extern naddr ripv1_mask_host(naddr,struct interface *); extern int check_dst(naddr); extern struct interface *check_dup(naddr, naddr, naddr, int); extern int check_remote(struct interface *); -extern int addrouteforif(register struct interface *); +extern int addrouteforif(struct interface *); extern void ifinit(void); extern int walk_bad(struct radix_node *, struct walkarg *); -extern int if_ok(struct interface *, char *); +extern int if_ok(struct interface *, const char *); extern void if_sick(struct interface *); extern void if_bad(struct interface *); extern void if_link(struct interface *); extern struct interface *ifwithaddr(naddr, int, int); extern struct interface *ifwithname(char *, naddr); -extern struct interface *ifwithindex(u_short); +extern struct interface *ifwithindex(u_short, int); extern struct interface *iflookup(naddr); extern struct auth *find_auth(struct interface *); extern void end_md5_auth(struct ws_buf *, struct auth *); -#include +#define MD5_DIGEST_LEN 16 +typedef struct { + u_int32_t state[4]; /* state (ABCD) */ + u_int32_t count[2]; /* # of bits, modulo 2^64 (LSB 1st) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; +extern void MD5Init(MD5_CTX*); +extern void MD5Update(MD5_CTX*, u_char*, u_int); +extern void MD5Final(u_char[MD5_DIGEST_LEN], MD5_CTX*); diff --git a/sbin/routed/if.c b/sbin/routed/if.c index 0711ba0c2000..7b40d2a6ff14 100644 --- a/sbin/routed/if.c +++ b/sbin/routed/if.c @@ -11,7 +11,7 @@ * 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: + * must display the following acknowledgment: * 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 @@ -29,19 +29,21 @@ * 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. + * + * $Id$ */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93"; -#endif -static const char rcsid[] = - "$Id$"; -#endif /* not lint */ - #include "defs.h" #include "pathnames.h" +#if !defined(sgi) && !defined(__NetBSD__) +static char sccsid[] __attribute__((unused)) = "@(#)if.c 8.1 (Berkeley) 6/5/93"; +#elif defined(__NetBSD__) +#include +__RCSID("$NetBSD$"); +#endif +#ident "$Revision: 2.17 $" + struct interface *ifnet; /* all interfaces */ /* hash table for all interfaces, big enough to tolerate ridiculous @@ -70,18 +72,22 @@ 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 */ +struct rt_spare loop_rts; struct timeval ifinit_timer; static struct timeval last_ifinit; +#define IF_RESCAN_DELAY() (last_ifinit.tv_sec == now.tv_sec \ + && last_ifinit.tv_usec == now.tv_usec \ + && timercmp(&ifinit_timer, &now, >)) int have_ripv1_out; /* have a RIPv1 interface */ int have_ripv1_in; static struct interface** -nhash(register char *p) +nhash(char *p) { - register u_int i; + u_int i; for (i = 0; *p != '\0'; p++) { i = ((i<<1) & 0x7fffffff) | ((i>>31) & 1); @@ -200,8 +206,7 @@ ifwithname(char *name, /* "ec0" or whatever */ /* If there is no known interface, maybe there is a * new interface. So just once look for new interfaces. */ - if (last_ifinit.tv_sec == now.tv_sec - && last_ifinit.tv_usec == now.tv_usec) + if (IF_RESCAN_DELAY()) return 0; ifinit(); } @@ -209,16 +214,25 @@ ifwithname(char *name, /* "ec0" or whatever */ struct interface * -ifwithindex(u_short index) +ifwithindex(u_short index, + int rescan_ok) { struct interface *ifp; + for (;;) { + for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { + if (ifp->int_index == index) + return ifp; + } - for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { - if (ifp->int_index == index) - return ifp; + /* If there is no known interface, maybe there is a + * new interface. So just once look for new interfaces. + */ + if (!rescan_ok + || IF_RESCAN_DELAY()) + return 0; + ifinit(); } - return 0; } @@ -254,8 +268,7 @@ iflookup(naddr addr) } if (maybe != 0 - || (last_ifinit.tv_sec == now.tv_sec - && last_ifinit.tv_usec == now.tv_usec)) + || IF_RESCAN_DELAY()) return maybe; /* If there is no known interface, maybe there is a @@ -291,12 +304,13 @@ naddr ripv1_mask_net(naddr addr, /* in network byte order */ struct interface *ifp) /* as seen on this interface */ { + struct r1net *r1p; naddr mask = 0; if (addr == 0) /* default always has 0 mask */ return mask; - if (ifp != 0) { + if (ifp != 0 && ifp->int_ripv1_mask != HOST_MASK) { /* If the target network is that of the associated interface * on which it arrived, then use the netmask of the interface. */ @@ -312,15 +326,26 @@ ripv1_mask_net(naddr addr, /* in network byte order */ */ 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) + && ifp->int_ripv1_mask > mask + && ifp->int_ripv1_mask != HOST_MASK) mask = ifp->int_ripv1_mask; } + } - /* Otherwise, make the classic A/B/C guess. - */ - if (mask == 0) - mask = std_mask(addr); + /* check special definitions */ + if (mask == 0) { + for (r1p = r1nets; r1p != 0; r1p = r1p->r1net_next) { + if (on_net(addr, r1p->r1net_net, r1p->r1net_match) + && r1p->r1net_mask > mask) + mask = r1p->r1net_mask; + } + + /* Otherwise, make the classic A/B/C guess. + */ + if (mask == 0) + mask = std_mask(addr); + } return mask; } @@ -375,11 +400,11 @@ check_dup(naddr addr, /* IP address, so network byte order */ if (ifp->int_mask != mask) continue; - if (!iff_alive(ifp->int_if_flags)) + if (!iff_up(ifp->int_if_flags)) continue; - /* The local address can only be shared with a point-to- - * point link. + /* The local address can only be shared with a point-to-point + * link. */ if (ifp->int_addr == addr && (((if_flags|ifp->int_if_flags) & IFF_POINTOPOINT) == 0)) @@ -496,8 +521,8 @@ ifdel(struct interface *ifp) 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. + * Assume routes just using gateways beyond this interface + * will timeout naturally, and have probably already died. */ (void)rn_walktree(rhead, walk_bad, 0); @@ -540,7 +565,7 @@ if_bad(struct interface *ifp) ifp->int_state |= (IS_BROKE | IS_SICK); ifp->int_act_time = NEVER; ifp->int_query_time = NEVER; - ifp->int_data.ts = 0; + ifp->int_data.ts = now.tv_sec; trace_if("Chg", ifp); @@ -560,7 +585,7 @@ if_bad(struct interface *ifp) */ int /* 1=it was dead */ if_ok(struct interface *ifp, - char *type) + const char *type) { struct interface *ifp1; @@ -597,12 +622,7 @@ if_ok(struct interface *ifp, } -#ifdef _HAVE_SA_LEN -static struct sockaddr sa_zero = { sizeof(struct sockaddr), AF_INET }; -#endif -/* - * disassemble routing message - * copied bug for bug from the BSD kernel +/* disassemble routing message */ void rt_xaddrs(struct rt_addrinfo *info, @@ -610,9 +630,10 @@ rt_xaddrs(struct rt_addrinfo *info, struct sockaddr *lim, int addrs) { - char *sa_limit; /* next byte after the sockaddr */ int i; - int len; +#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)) @@ -622,36 +643,20 @@ rt_xaddrs(struct rt_addrinfo *info, #endif - bzero(info, sizeof(*info)); + memset(info, 0, sizeof(*info)); info->rti_addrs = addrs; for (i = 0; i < RTAX_MAX && sa < lim; i++) { if ((addrs & (1 << i)) == 0) continue; #ifdef _HAVE_SA_LEN - len = sa->sa_len; - - /* Check the sockaddr doesn't go past the end of the buffer. */ - /* Cope with buggy (malicious?) sender.*/ - if (len) { - sa_limit = ((char*)sa) + len; - if ( sa_limit > (char *)lim ) /* equal is ok */ - return; - } else { - /* - * We allow the last broken sockaddr - * to be replaced by a good null one - * because some old versions of routing stuff - * would do this (4.4 route(1) for example). - * This should go away eventually. - */ - info->rti_info[i] = &sa_zero; - return; /* this one had unknown length */ - } + info->rti_info[i] = (sa->sa_len != 0) ? sa : &sa_zero; + sa = (struct sockaddr *)((char*)(sa) + + ROUNDUP(sa->sa_len)); #else - len = _FAKE_SA_LEN_DST(sa); -#endif info->rti_info[i] = sa; - sa = (struct sockaddr *)((char*)(sa) + ROUNDUP(len)); + sa = (struct sockaddr *)((char*)(sa) + + ROUNDUP(_FAKE_SA_LEN_DST(sa))); +#endif } } @@ -713,14 +718,16 @@ ifinit(void) if ((needed = sysctl_buf_size) != 0) { if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0) break; + /* retry if the table grew */ if (errno != ENOMEM && errno != EFAULT) - BADERR(1, "ifinit: get interface table"); + BADERR(1, "ifinit: sysctl(RT_IFLIST)"); 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"); + BADERR(1,"ifinit: sysctl(RT_IFLIST) estimate"); + sysctl_buf = rtmalloc(sysctl_buf_size = needed, + "ifinit sysctl"); } ifam_lim = (struct ifa_msghdr *)(sysctl_buf + needed); @@ -736,7 +743,7 @@ ifinit(void) ifm = (struct if_msghdr *)ifam; /* make prototype structure for the IP aliases */ - bzero(&ifs0, sizeof(ifs0)); + memset(&ifs0, 0, sizeof(ifs0)); ifs0.int_rip_sock = -1; ifs0.int_index = ifm->ifm_index; ifs0.int_if_flags = ifm->ifm_flags; @@ -769,11 +776,11 @@ ifinit(void) * will be an alias. * Do not output RIP or Router-Discovery packets via aliases. */ - bcopy(&ifs0, &ifs, sizeof(ifs)); - ifs0.int_state |= (IS_ALIAS | IS_NO_RIP | IS_NO_RDISC); + memcpy(&ifs, &ifs0, sizeof(ifs)); + ifs0.int_state |= (IS_ALIAS | IS_NO_RIP_OUT | IS_NO_RDISC); if (INFO_IFA(&info) == 0) { - if (iff_alive(ifs.int_if_flags)) { + if (iff_up(ifs.int_if_flags)) { if (!(prev_complaints & COMP_NOADDR)) msglog("%s has no address", ifs.int_name); @@ -782,7 +789,7 @@ ifinit(void) continue; } if (INFO_IFA(&info)->sa_family != AF_INET) { - if (iff_alive(ifs.int_if_flags)) { + if (iff_up(ifs.int_if_flags)) { if (!(prev_complaints & COMP_NOT_INET)) trace_act("%s: not AF_INET", ifs.int_name); @@ -795,7 +802,7 @@ ifinit(void) if (ntohl(ifs.int_addr)>>24 == 0 || ntohl(ifs.int_addr)>>24 == 0xff) { - if (iff_alive(ifs.int_if_flags)) { + if (iff_up(ifs.int_if_flags)) { if (!(prev_complaints & COMP_BADADDR)) msglog("%s has a bad address", ifs.int_name); @@ -814,12 +821,14 @@ ifinit(void) if (!foundloopback) { foundloopback = 1; loopaddr = ifs.int_addr; + loop_rts.rts_gate = loopaddr; + loop_rts.rts_router = loopaddr; } } 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 (iff_up(ifs.int_if_flags)) { if (!(prev_complaints & COMP_NODST)) msglog("%s has a bad" " destination address", @@ -831,7 +840,7 @@ ifinit(void) ifs.int_dstaddr = S_ADDR(INFO_BRD(&info)); if (ntohl(ifs.int_dstaddr)>>24 == 0 || ntohl(ifs.int_dstaddr)>>24 == 0xff) { - if (iff_alive(ifs.int_if_flags)) { + if (iff_up(ifs.int_if_flags)) { if (!(prev_complaints & COMP_NODST)) msglog("%s has a bad" " destination address", @@ -847,7 +856,7 @@ ifinit(void) } else { if (INFO_MASK(&info) == 0) { - if (iff_alive(ifs.int_if_flags)) { + if (iff_up(ifs.int_if_flags)) { if (!(prev_complaints & COMP_NOMASK)) msglog("%s has no netmask", ifs.int_name); @@ -865,7 +874,7 @@ ifinit(void) if (ifs.int_if_flags & IFF_BROADCAST) { if (INFO_BRD(&info) == 0) { - if (iff_alive(ifs.int_if_flags)) { + if (iff_up(ifs.int_if_flags)) { if (!(prev_complaints & COMP_NOBADR)) msglog("%s has" @@ -902,7 +911,7 @@ ifinit(void) if (ifs.int_metric > HOPCNT_INFINITY) { ifs.int_metric = 0; if (!(prev_complaints & COMP_BAD_METRIC) - && iff_alive(ifs.int_if_flags)) { + && iff_up(ifs.int_if_flags)) { complaints |= COMP_BAD_METRIC; msglog("%s has a metric of %d", ifs.int_name, ifs.int_metric); @@ -951,19 +960,26 @@ ifinit(void) /* note interfaces that have been turned off */ - if (!iff_alive(ifs.int_if_flags)) { - if (iff_alive(ifp->int_if_flags)) { + if (!iff_up(ifs.int_if_flags)) { + if (iff_up(ifp->int_if_flags)) { msglog("interface %s to %s turned off", ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); if_bad(ifp); - ifp->int_if_flags &= ~IFF_UP_RUNNING; + ifp->int_if_flags &= ~IFF_UP; + } else if (now.tv_sec>(ifp->int_data.ts + + CHECK_BAD_INTERVAL)) { + trace_act("interface %s has been off" + " %ld seconds; forget it", + ifp->int_name, + now.tv_sec-ifp->int_data.ts); + ifdel(ifp); } continue; } /* or that were off and are now ok */ - if (!iff_alive(ifp->int_if_flags)) { - ifp->int_if_flags |= IFF_UP_RUNNING; + if (!iff_up(ifp->int_if_flags)) { + ifp->int_if_flags |= IFF_UP; (void)if_ok(ifp, ""); } @@ -979,7 +995,7 @@ ifinit(void) 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. + * count packets dropped by the filters. * But FDDI rings stuck non-operational count * dropped packets as they wait for improvement. */ @@ -1045,7 +1061,7 @@ ifinit(void) /* This is a new interface. * If it is dead, forget it. */ - if (!iff_alive(ifs.int_if_flags)) + if (!iff_up(ifs.int_if_flags)) continue; /* If it duplicates an existing interface, @@ -1055,6 +1071,12 @@ ifinit(void) ifp = check_dup(ifs.int_addr,ifs.int_dstaddr,ifs.int_mask, ifs.int_if_flags); if (ifp != 0) { + /* Ignore duplicates of itself, caused by having + * IP aliases on the same network. + */ + if (!strcmp(ifp->int_name, ifs.int_name)) + continue; + if (!(prev_complaints & COMP_DUP)) { complaints |= COMP_DUP; msglog("%s (%s%s%s) is duplicated by" @@ -1088,8 +1110,8 @@ ifinit(void) /* It is new and ok. Add it to the list of interfaces */ - ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit"); - bcopy(&ifs, ifp, sizeof(*ifp)); + ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit ifp"); + memcpy(ifp, &ifs, sizeof(*ifp)); get_parms(ifp); if_link(ifp); trace_if("Add", ifp); @@ -1159,14 +1181,18 @@ ifinit(void) rtdelete(rt); rt = 0; } else { + loop_rts.rts_ifp = ifp; + loop_rts.rts_metric = 0; + loop_rts.rts_time = rt->rt_time; rtchange(rt, rt->rt_state | RS_MHOME, - loopaddr, loopaddr, - 0, 0, ifp, rt->rt_time, 0); + &loop_rts, 0); } } - if (rt == 0) - rtadd(myaddr, HOST_MASK, loopaddr, loopaddr, - 0, 0, RS_MHOME, ifp); + if (rt == 0) { + loop_rts.rts_ifp = ifp; + loop_rts.rts_metric = 0; + rtadd(myaddr, HOST_MASK, RS_MHOME, &loop_rts); + } } for (ifp = ifnet; ifp != 0; ifp = ifp1) { @@ -1211,7 +1237,7 @@ ifinit(void) /* Delete any routes to the network address through * foreign routers. Remove even static routes. */ - del_static(ifp->int_addr, HOST_MASK, 0); + del_static(ifp->int_addr, HOST_MASK, 0, 0); rt = rtget(ifp->int_addr, HOST_MASK); if (rt != 0 && rt->rt_router != loopaddr) { rtdelete(rt); @@ -1224,14 +1250,17 @@ ifinit(void) } 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); + loop_rts.rts_ifp = ifp1; + loop_rts.rts_metric = 0; + loop_rts.rts_time = rt->rt_time; + rtchange(rt, ((rt->rt_state & ~RS_NET_SYN) + | (RS_IF|RS_LOCAL)), + &loop_rts, 0); } else { + loop_rts.rts_ifp = ifp; + loop_rts.rts_metric = 0; rtadd(ifp->int_addr, HOST_MASK, - loopaddr, loopaddr, - 0, 0, (RS_IF | RS_LOCAL), ifp); + (RS_IF | RS_LOCAL), &loop_rts); } } } @@ -1245,10 +1274,12 @@ ifinit(void) rtdelete(rt); rt = 0; } - if (rt == 0) + if (rt == 0) { + loop_rts.rts_ifp = 0; + loop_rts.rts_metric = intnetp->intnet_metric-1; rtadd(intnetp->intnet_addr, intnetp->intnet_mask, - loopaddr, loopaddr, intnetp->intnet_metric-1, - 0, RS_NET_SYN | RS_NET_INT, 0); + RS_NET_SYN | RS_NET_INT, &loop_rts); + } } prev_complaints = complaints; @@ -1259,6 +1290,7 @@ static void check_net_syn(struct interface *ifp) { struct rt_entry *rt; + static struct rt_spare new; /* Turn on the need to automatically synthesize a network route @@ -1275,10 +1307,14 @@ check_net_syn(struct interface *ifp) rtdelete(rt); rt = 0; } - if (rt == 0) + if (rt == 0) { + new.rts_ifp = ifp; + new.rts_gate = ifp->int_addr; + new.rts_router = ifp->int_addr; + new.rts_metric = ifp->int_metric; rtadd(ifp->int_std_addr, ifp->int_std_mask, - ifp->int_addr, ifp->int_addr, - ifp->int_metric, 0, RS_NET_SYN, ifp); + RS_NET_SYN, &new); + } } else { ifp->int_state &= ~IS_NEED_NET_SYN; @@ -1301,7 +1337,8 @@ int /* 0=bad interface */ addrouteforif(struct interface *ifp) { struct rt_entry *rt; - naddr dst, gate; + static struct rt_spare new; + naddr dst; /* skip sick interfaces @@ -1315,11 +1352,16 @@ addrouteforif(struct interface *ifp) if (ifp->int_state & IS_SUBNET) check_net_syn(ifp); - gate = ifp->int_addr; dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) ? ifp->int_dstaddr : htonl(ifp->int_net)); + new.rts_ifp = ifp; + new.rts_router = ifp->int_addr; + new.rts_gate = ifp->int_addr; + new.rts_metric = ifp->int_metric; + new.rts_time = now.tv_sec; + /* If we are going to send packets to the gateway, * it must be reachable using our physical interfaces */ @@ -1332,7 +1374,7 @@ addrouteforif(struct interface *ifp) * 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); + del_static(dst, ifp->int_mask, 0, 0); rt = rtget(dst, ifp->int_mask); if (rt != 0) { if ((rt->rt_ifp != ifp @@ -1345,8 +1387,7 @@ addrouteforif(struct interface *ifp) } 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); + &new, 0); } } if (rt == 0) { @@ -1354,8 +1395,7 @@ addrouteforif(struct interface *ifp) trace_act("re-install interface %s", ifp->int_name); - rtadd(dst, ifp->int_mask, gate, gate, - ifp->int_metric, 0, RS_IF, ifp); + rtadd(dst, ifp->int_mask, RS_IF, &new); } return 1; diff --git a/sbin/routed/input.c b/sbin/routed/input.c index 4f5c947b3c14..cf5171d3863c 100644 --- a/sbin/routed/input.c +++ b/sbin/routed/input.c @@ -11,7 +11,7 @@ * 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: + * must display the following acknowledgment: * 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 @@ -29,22 +29,23 @@ * 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. + * + * $Id$ */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93"; -#endif -static const char rcsid[] = - "$Id$"; -#endif /* not lint */ - #include "defs.h" +#if !defined(sgi) && !defined(__NetBSD__) +static char sccsid[] __attribute__((unused)) = "@(#)input.c 8.1 (Berkeley) 6/5/93"; +#elif defined(__NetBSD__) +#include +__RCSID("$NetBSD$"); +#endif +#ident "$Revision: 2.17 $" + static void input(struct sockaddr_in *, struct interface *, struct interface *, struct rip *, int); -static void input_route(struct interface *, naddr, - naddr, naddr, naddr, struct netinfo *); +static void input_route(naddr, naddr, struct rt_spare *, struct netinfo *); static int ck_passwd(struct interface *, struct rip *, void *, naddr, struct msg_limit *); @@ -141,14 +142,17 @@ input(struct sockaddr_in *from, /* received from this IP address */ { # define FROM_NADDR from->sin_addr.s_addr static struct msg_limit use_auth, bad_len, bad_mask; - static struct msg_limit unk_router, bad_router, bad_nhop; + static struct msg_limit unk_router, bad_router, bad_nhop; struct rt_entry *rt; + struct rt_spare new; struct netinfo *n, *lim; struct interface *ifp1; - naddr gate, mask, v1_mask, dst, ddst_h; + naddr gate, mask, v1_mask, dst, ddst_h = 0; struct auth *ap; - int i; + struct tgate *tg = 0; + struct tgate_net *tn; + int i, j; /* Notice when we hear from a remote gateway */ @@ -166,7 +170,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ } else if (rip->rip_vers > RIPv2) { rip->rip_vers = RIPv2; } - if (cc > OVER_MAXPACKETSIZE) { + if (cc > (int)OVER_MAXPACKETSIZE) { msglim(&bad_router, FROM_NADDR, "packet at least %d bytes too long received from %s", cc-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR)); @@ -283,10 +287,10 @@ input(struct sockaddr_in *from, /* received from this IP address */ */ if (n->n_family == RIP_AF_UNSPEC && n->n_metric == HOPCNT_INFINITY) { + /* Answer a query from a utility program + * with all we know. + */ if (from->sin_port != htons(RIP_PORT)) { - /* Answer a query from a utility - * program with all we know. - */ supply(from, aifp, OUT_QUERY, 0, rip->rip_vers, ap != 0); return; @@ -298,11 +302,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ * * Only answer a router if we are a supplier * to keep an unwary host that is just starting - * from picking us as a router. Respond with - * RIPv1 instead of RIPv2 if that is what we - * are broadcasting on the interface to keep - * the remote router from getting the wrong - * initial idea of the routes we send. + * from picking us as a router. */ if (aifp == 0) { trace_pkt("ignore distant router"); @@ -314,8 +314,36 @@ input(struct sockaddr_in *from, /* received from this IP address */ return; } + /* Do not answer a RIPv1 router if + * we are sending RIPv2. But do offer + * poor man's router discovery. + */ + if ((aifp->int_state & IS_NO_RIPV1_OUT) + && rip->rip_vers == RIPv1) { + if (!(aifp->int_state & IS_PM_RDISC)) { + trace_pkt("ignore; sending RIPv2"); + return; + } + + v12buf.n->n_family = RIP_AF_INET; + v12buf.n->n_dst = RIP_DEFAULT; + i = aifp->int_d_metric; + if (0 != (rt = rtget(RIP_DEFAULT, 0))) + i = MIN(i, (rt->rt_metric + +aifp->int_metric+1)); + v12buf.n->n_metric = htonl(i); + v12buf.n++; + break; + } + + /* Respond with RIPv1 instead of RIPv2 if + * that is what we are broadcasting on the + * interface to keep the remote router from + * getting the wrong initial idea of the + * routes we send. + */ supply(from, aifp, OUT_UNICAST, 0, - (aifp->int_state&IS_NO_RIPV1_OUT) + (aifp->int_state & IS_NO_RIPV1_OUT) ? RIPv2 : RIPv1, ap != 0); return; @@ -327,8 +355,8 @@ input(struct sockaddr_in *from, /* received from this IP address */ if (n->n_family != RIP_AF_INET) { msglim(&bad_router, FROM_NADDR, - "request from %s for unsupported (af" - " %d) %s", + "request from %s for unsupported" + " (af %d) %s", naddr_ntoa(FROM_NADDR), ntohs(n->n_family), naddr_ntoa(n->n_dst)); @@ -418,7 +446,13 @@ input(struct sockaddr_in *from, /* received from this IP address */ case RIPCMD_TRACEON: case RIPCMD_TRACEOFF: - /* verify message came from a privileged port */ + /* Notice that trace messages are turned off for all possible + * abuse if _PATH_TRACE is undefined in pathnames.h. + * Notice also that because of the way the trace file is + * handled in trace.c, no abuse is plausible even if + * _PATH_TRACE_ is defined. + * + * First verify message came from a privileged port. */ if (ntohs(from->sin_port) > IPPORT_RESERVED) { msglog("trace command from untrusted port on %s", naddr_ntoa(FROM_NADDR)); @@ -434,7 +468,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ set_tracefile((char*)rip->rip_tracefile, "trace command: %s\n", 0); } else { - trace_off("tracing turned off by %s\n", + trace_off("tracing turned off by %s", naddr_ntoa(FROM_NADDR)); } return; @@ -512,7 +546,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ /* Ignore routes via dead interface. */ if (aifp->int_state & IS_BROKE) { - trace_pkt("%sdiscard response via broken interface %s", + trace_pkt("discard response via broken interface %s", aifp->int_name); return; } @@ -522,7 +556,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ * happens, it happens frequently. */ if (aifp->int_state & IS_DISTRUST) { - struct tgate *tg = tgates; + tg = tgates; while (tg->tgate_addr != FROM_NADDR) { tg = tg->tgate_next; if (tg == 0) { @@ -582,7 +616,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ */ gate = FROM_NADDR; if (n->n_nhop != 0) { - if (rip->rip_vers == RIPv2) { + if (rip->rip_vers == RIPv1) { n->n_nhop = 0; } else { /* Use it only if it is valid. */ @@ -608,9 +642,9 @@ input(struct sockaddr_in *from, /* received from this IP address */ } else if ((ntohl(dst) & ~mask) != 0) { msglim(&bad_mask, FROM_NADDR, "router %s sent bad netmask" - " %#x with %s", + " %#lx with %s", naddr_ntoa(FROM_NADDR), - mask, + (u_long)mask, naddr_ntoa(dst)); continue; } @@ -623,6 +657,20 @@ input(struct sockaddr_in *from, /* received from this IP address */ if (n->n_metric > HOPCNT_INFINITY) n->n_metric = HOPCNT_INFINITY; + /* Should we trust this route from this router? */ + if (tg && (tn = tg->tgate_nets)->mask != 0) { + for (i = 0; i < MAX_TGATE_NETS; i++, tn++) { + if (on_net(dst, tn->net, tn->mask) + && tn->mask <= mask) + break; + } + if (i >= MAX_TGATE_NETS || tn->mask == 0) { + trace_pkt(" ignored unauthorized %s", + addrname(dst,mask,0)); + continue; + } + } + /* Recognize and ignore a default route we faked * which is being sent back to us by a machine with * broken split-horizon. @@ -631,7 +679,7 @@ input(struct sockaddr_in *from, /* received from this IP address */ */ if (aifp->int_d_metric != 0 && dst == RIP_DEFAULT - && n->n_metric >= aifp->int_d_metric) + && (int)n->n_metric >= aifp->int_d_metric) continue; /* We can receive aggregated RIPv2 routes that must @@ -664,13 +712,12 @@ input(struct sockaddr_in *from, /* received from this IP address */ /* 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 + if (TRACECONTENTS) + trace_misc("accept %s-->%s as 1" + " instead of %d routes", + addrname(dst,mask,0), + naddr_ntoa(FROM_NADDR), + i+1); i = 0; } else { mask = v1_mask; @@ -679,10 +726,17 @@ input(struct sockaddr_in *from, /* received from this IP address */ i = 0; } + new.rts_gate = gate; + new.rts_router = FROM_NADDR; + new.rts_metric = n->n_metric; + new.rts_tag = n->n_tag; + new.rts_time = now.tv_sec; + new.rts_ifp = aifp; + new.rts_de_ag = i; + j = 0; for (;;) { - input_route(aifp, FROM_NADDR, - dst, mask, gate, n); - if (i-- == 0) + input_route(dst, mask, &new, n); + if (++j > i) break; dst = htonl(ntohl(dst) + ddst_h); } @@ -696,18 +750,15 @@ input(struct sockaddr_in *from, /* received from this IP address */ /* Process a single input route. */ static void -input_route(struct interface *ifp, - naddr from, - naddr dst, +input_route(naddr dst, /* network order */ naddr mask, - naddr gate, + struct rt_spare *new, 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. @@ -731,7 +782,7 @@ input_route(struct interface *ifp, if (rt == 0) { /* Ignore unknown routes being poisoned. */ - if (n->n_metric == HOPCNT_INFINITY) + if (new->rts_metric == HOPCNT_INFINITY) return; /* Ignore the route if it points to us */ @@ -743,8 +794,7 @@ input_route(struct interface *ifp, * our memory, accept the new route. */ if (total_routes < MAX_ROUTES) - rtadd(dst, mask, gate, from, n->n_metric, - n->n_tag, 0, ifp); + rtadd(dst, mask, 0, new); return; } @@ -769,7 +819,7 @@ input_route(struct interface *ifp, rts0 = rt->rt_spares; for (rts = rts0, i = NUM_SPARES; i != 0; i--, rts++) { - if (rts->rts_router == from) + if (rts->rts_router == new->rts_router) break; /* Note the worst slot to reuse, * other than the current slot. @@ -779,26 +829,34 @@ input_route(struct interface *ifp, rts0 = rts; } if (i != 0) { - /* Found the router + /* Found a route from the router already in the table. */ - int old_metric = rts->rts_metric; + + /* If the new route is a route broken down from an + * aggregated route, and if the previous route is either + * not a broken down route or was broken down from a finer + * netmask, and if the previous route is current, + * then forget this one. + */ + if (new->rts_de_ag > rts->rts_de_ag + && now_stale <= rts->rts_time) + return; /* Keep poisoned routes around only long enough to pass - * the poison on. Get a new timestamp for good routes. + * the poison on. Use a new timestamp for good routes. */ - new_time =((old_metric == HOPCNT_INFINITY) - ? rts->rts_time - : now.tv_sec); + if (rts->rts_metric == HOPCNT_INFINITY + && new->rts_metric == HOPCNT_INFINITY) + new->rts_time = rts->rts_time; /* 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); + rtchange(rt, rt->rt_state, new, 0); /* If the route got worse, check for something better. */ - if (n->n_metric > old_metric) + if (new->rts_metric > rts->rts_metric) rtswitch(rt, 0); return; } @@ -806,10 +864,17 @@ input_route(struct interface *ifp, /* 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; + if (rts->rts_gate == new->rts_gate + && rts->rts_metric == new->rts_metric + && rts->rts_tag == new->rts_tag) { + trace_upslot(rt, rts, new); + *rts = *new; + return; + } + /* Forget it if it has gone bad. + */ + if (new->rts_metric == HOPCNT_INFINITY) { + rts_delete(rt, rts); return; } @@ -823,6 +888,7 @@ input_route(struct interface *ifp, && 0 != ifwithaddr(n->n_nhop, 1, 0)) return; + /* the loop above set rts0=worst spare */ rts = rts0; /* Save the route as a spare only if it has @@ -830,20 +896,12 @@ input_route(struct interface *ifp, * This also ignores poisoned routes (those * received with metric HOPCNT_INFINITY). */ - if (n->n_metric >= rts->rts_metric) + if (new->rts_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; + trace_upslot(rt, rts, new); + *rts = *new; /* try to switch to a better route */ rtswitch(rt, rts); @@ -862,7 +920,7 @@ ck_passwd(struct interface *aifp, struct auth *ap; MD5_CTX md5_ctx; u_char hash[RIP_AUTH_PW_LEN]; - int i; + int i, len; if ((void *)NA >= lim || NA->a_family != RIP_AF_AUTH) { @@ -880,7 +938,7 @@ ck_passwd(struct interface *aifp, continue; if (NA->a_type == RIP_AUTH_PW) { - if (!bcmp(NA->au.au_pw, ap->key, RIP_AUTH_PW_LEN)) + if (!memcmp(NA->au.au_pw, ap->key, RIP_AUTH_PW_LEN)) return 1; } else { @@ -889,28 +947,52 @@ ck_passwd(struct interface *aifp, if (NA->au.a_md5.md5_keyid != ap->keyid) continue; - na2 = (struct netauth *)((char *)(NA+1) - + NA->au.a_md5.md5_pkt_len); - if (NA->au.a_md5.md5_pkt_len % sizeof(*NA) != 0 - || lim < (void *)(na2+1)) { + len = ntohs(NA->au.a_md5.md5_pkt_len); + if ((len-sizeof(*rip)) % sizeof(*NA) != 0 + || len != (char *)lim-(char*)rip-(int)sizeof(*NA)) { msglim(use_authp, from, - "bad MD5 RIP-II pkt length %d from %s", - NA->au.a_md5.md5_pkt_len, + "wrong MD5 RIPv2 packet length of %d" + " instead of %d from %s", + len, (int)((char *)lim-(char *)rip + -sizeof(*NA)), naddr_ntoa(from)); return 0; } + na2 = (struct netauth *)((char *)rip+len); + + /* Given a good hash value, these are not security + * problems so be generous and accept the routes, + * after complaining. + */ + if (TRACEPACKETS) { + if (NA->au.a_md5.md5_auth_len + != RIP_AUTH_MD5_LEN) + msglim(use_authp, from, + "unknown MD5 RIPv2 auth len %#x" + " instead of %#x from %s", + NA->au.a_md5.md5_auth_len, + RIP_AUTH_MD5_LEN, + naddr_ntoa(from)); + if (na2->a_family != RIP_AF_AUTH) + msglim(use_authp, from, + "unknown MD5 RIPv2 family %#x" + " instead of %#x from %s", + na2->a_family, RIP_AF_AUTH, + naddr_ntoa(from)); + if (na2->a_type != ntohs(1)) + msglim(use_authp, from, + "MD5 RIPv2 hash has %#x" + " instead of %#x from %s", + na2->a_type, ntohs(1), + naddr_ntoa(from)); + } + MD5Init(&md5_ctx); - MD5Update(&md5_ctx, (u_char *)NA, - (char *)na2->au.au_pw - (char *)NA); - MD5Update(&md5_ctx, - (u_char *)ap->key, sizeof(ap->key)); + MD5Update(&md5_ctx, (u_char *)rip, len); + MD5Update(&md5_ctx, ap->key, RIP_AUTH_MD5_LEN); MD5Final(hash, &md5_ctx); - if (na2->a_family != RIP_AF_AUTH - || na2->a_type != 1 - || NA->au.a_md5.md5_auth_len != RIP_AUTH_PW_LEN - || bcmp(hash, na2->au.au_pw, sizeof(hash))) - return 0; - return 1; + if (!memcmp(hash, na2->au.au_pw, sizeof(hash))) + return 1; } } diff --git a/sbin/routed/main.c b/sbin/routed/main.c index 06f91cd9a6d6..dfd436e5de53 100644 --- a/sbin/routed/main.c +++ b/sbin/routed/main.c @@ -11,7 +11,7 @@ * 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: + * must display the following acknowledgment: * 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 @@ -29,33 +29,39 @@ * 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. + * + * $Id$ */ -#ifndef lint -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 -static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/5/93"; -#endif -static const char rcsid[] = - "$Id$"; -#endif /* not lint */ - #include "defs.h" +#include "pathnames.h" #ifdef sgi #include "math.h" #endif +#include #include +#include + +#if !defined(sgi) && !defined(__NetBSD__) +char copyright[] = +"@(#) Copyright (c) 1983, 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +static char sccsid[] __attribute__((unused)) = "@(#)main.c 8.1 (Berkeley) 6/5/93"; +#elif defined(__NetBSD__) +__RCSID("$NetBSD$"); +__COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"); +#endif +#ident "$Revision: 2.17 $" + pid_t mypid; naddr myaddr; /* system address */ char myname[MAXHOSTNAMELEN+1]; +int verbose; + int supplier; /* supply or broadcast updates */ int supplier_set; int ipforwarding = 1; /* kernel forwarding on */ @@ -69,6 +75,7 @@ int auth_ok = 1; /* 1=ignore auth if we do not care */ struct timeval epoch; /* when started */ struct timeval clk, prev_clk; +static int usec_fudge; struct timeval now; /* current idea of time */ time_t now_stale; time_t now_expire; @@ -77,6 +84,8 @@ time_t now_garbage; struct timeval next_bcast; /* next general broadcast */ struct timeval no_flash = {EPOCH+SUPPLY_INTERVAL}; /* inhibit flash update */ +struct timeval flush_kern_timer; + fd_set fdbits; int sock_max; int rip_sock = -1; /* RIP socket */ @@ -95,6 +104,7 @@ main(int argc, int n, mib[4], off; size_t len; char *p, *q; + const char *cp; struct timeval wtime, t2; time_t dt; fd_set ibits; @@ -125,7 +135,7 @@ main(int argc, (void)gethostname(myname, sizeof(myname)-1); (void)gethost(myname, &myaddr); - while ((n = getopt(argc, argv, "sqdghmAtT:F:P:")) != -1) { + while ((n = getopt(argc, argv, "sqdghmpAtvT:F:P:")) != -1) { switch (n) { case 's': supplier = 1; @@ -142,11 +152,11 @@ main(int argc, break; case 'g': - bzero(&parm, sizeof(parm)); + memset(&parm, 0, sizeof(parm)); parm.parm_d_metric = 1; - p = check_parms(&parm); - if (p != 0) - msglog("bad -g: %s", p); + cp = check_parms(&parm); + if (cp != 0) + msglog("bad -g: %s", cp); else default_gateway = 1; break; @@ -189,26 +199,29 @@ main(int argc, optarg); break; } - bzero(&parm, sizeof(parm)); + memset(&parm, 0, sizeof(parm)); parm.parm_net = p_net; parm.parm_mask = p_mask; parm.parm_d_metric = n; - p = check_parms(&parm); - if (p != 0) - msglog("bad -F: %s", p); + cp = check_parms(&parm); + if (cp != 0) + msglog("bad -F: %s", cp); break; case 'P': - /* handle arbitrary, (usually) per-interface - * parameters. + /* handle arbitrary parameters. */ - p = parse_parms(optarg, 0); - if (p != 0) { - if (strcasecmp(p,optarg)) - msglog("%s in \"%s\"", p, optarg); - else - msglog("bad \"-P %s\"", optarg); - } + q = strdup(optarg); + cp = parse_parms(q, 0); + if (cp != 0) + msglog("%s in \"-P %s\"", cp, optarg); + free(q); + break; + + case 'v': + /* display version */ + verbose++; + msglog("version 2.17"); break; default: @@ -226,11 +239,14 @@ main(int argc, goto usage; if (argc != 0) { usage: - logbad(0, "usage: routed [-sqdghmpAt] [-T tracefile]" - " [-F net[/mask[,metric]]] [-P parms]"); + logbad(0, "usage: routed [-sqdghmpAtv] [-T tracefile]" + " [-F net[,metric]] [-P parms]"); } - if (geteuid() != 0) + if (geteuid() != 0) { + if (verbose) + exit(0); logbad(0, "requires UID 0"); + } mib[0] = CTL_NET; mib[1] = PF_INET; @@ -271,12 +287,10 @@ main(int argc, /* get into the background */ #ifdef sgi if (0 > _daemonize(background ? 0 : (_DF_NOCHDIR|_DF_NOFORK), - new_tracelevel == 0 ? -1 : STDOUT_FILENO, - new_tracelevel == 0 ? -1 : STDERR_FILENO, - -1)) + STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)) BADERR(0, "_daemonize()"); #else - if (background && daemon(0, new_tracelevel) < 0) + if (background && daemon(0, 1) < 0) BADERR(0,"daemon()"); #endif @@ -298,13 +312,11 @@ main(int argc, fix_select(); - if (background && new_tracelevel == 0) - ftrace = 0; if (tracename != 0) { strncpy(inittracename, tracename, sizeof(inittracename)-1); - set_tracefile(inittracename, "%s\n", -1); + set_tracefile(inittracename, "%s", -1); } else { - tracelevel_msg("%s\n", -1); /* turn on tracing to stdio */ + tracelevel_msg("%s", -1); /* turn on tracing to stdio */ } bufinit(); @@ -330,28 +342,45 @@ main(int argc, */ gwkludge(); ifinit(); - flush_kern(); /* Ask for routes */ rip_query(); rdisc_sol(); + /* Now turn off stdio if not tracing */ + if (new_tracelevel == 0) + trace_close(background); + /* 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. + if (prev_clk.tv_sec == clk.tv_sec + && prev_clk.tv_usec == clk.tv_usec+usec_fudge) { + /* Much of `routed` depends on time always advancing. + * On systems that do not guarantee that gettimeofday() + * produces unique timestamps even if called within + * a single tick, use trickery like that in classic + * BSD kernels. */ - dt = t2.tv_sec; - if (dt > 0) - dt -= wtime.tv_sec; - trace_act("time changed by %d sec", dt); - epoch.tv_sec += dt; + clk.tv_usec += ++usec_fudge; + + } else { + usec_fudge = 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", (int)dt); + epoch.tv_sec += dt; + } } timevalsub(&now, &clk, &epoch); now_stale = now.tv_sec - STALE_TIME; @@ -364,7 +393,7 @@ main(int argc, if (stopint != 0) { rip_bcast(0); rdisc_adv(); - trace_off("exiting with signal %d\n", stopint); + trace_off("exiting with signal %d", stopint); exit(stopint | 128); } @@ -377,6 +406,19 @@ main(int argc, continue; } + /* Check the kernel table occassionally for mysteriously + * evaporated routes + */ + timevalsub(&t2, &flush_kern_timer, &now); + if (t2.tv_sec <= 0) { + flush_kern(); + flush_kern_timer.tv_sec = (now.tv_sec + + CHECK_QUIET_INTERVAL); + continue; + } + if (timercmp(&t2, &wtime, <)) + wtime = t2; + /* If it is time, then broadcast our routes. */ if (supplier || advertise_mhome) { @@ -447,7 +489,7 @@ main(int argc, wtime = t2; /* take care of router discovery, - * but do it to the millisecond + * but do it in the correct the millisecond */ if (!timercmp(&rdisc_timer, &now, >)) { rdisc_age(0); @@ -495,7 +537,7 @@ main(int argc, /* ARGSUSED */ void -sigalrm(int s) +sigalrm(int s UNUSED) { /* Historically, SIGALRM would cause the daemon to check for * new and broken interfaces. @@ -548,7 +590,7 @@ fix_select(void) void fix_sock(int sock, - char *name) + const char *name) { int on; #define MIN_SOCKBUF (4*1024) @@ -604,14 +646,14 @@ get_rip_sock(naddr addr, if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) BADERR(1,"rip_sock = socket()"); - bzero(&sin,sizeof(sin)); + memset(&sin, 0, sizeof(sin)); #ifdef _HAVE_SIN_LEN sin.sin_len = sizeof(sin); #endif 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 (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { if (serious) BADERR(errno != EADDRINUSE, "bind(rip_sock)"); return -1; @@ -632,7 +674,7 @@ void rip_off(void) { struct interface *ifp; - register naddr addr; + naddr addr; if (rip_sock >= 0 && !mhome) { @@ -701,8 +743,10 @@ rip_on(struct interface *ifp) /* If the main RIP socket is off and it makes sense to turn it on, * then turn it on for all of the interfaces. + * It makes sense if either router discovery is off, or if + * router discover is on and at most one interface is doing RIP. */ - if (rip_interfaces > 0 && !rdisc_ok) { + if (rip_interfaces > 0 && (!rdisc_ok || rip_interfaces > 1)) { trace_act("turn on RIP"); /* Close all of the query sockets so that we can open @@ -748,11 +792,11 @@ rip_on(struct interface *ifp) */ void * rtmalloc(size_t size, - char *msg) + const char *msg) { void *p = malloc(size); - if (p == NULL) - logbad(1,"malloc() failed in %s", msg); + if (p == 0) + logbad(1,"malloc(%lu) failed in %s", (u_long)size, msg); return p; } @@ -802,7 +846,7 @@ timevalsub(struct timeval *t1, /* put a message into the system log */ void -msglog(char *p, ...) +msglog(const char *p, ...) { va_list args; @@ -828,12 +872,12 @@ msglog(char *p, ...) * For example, there can be many systems with the wrong password. */ void -msglim(struct msg_limit *lim, naddr addr, char *p, ...) +msglim(struct msg_limit *lim, naddr addr, const char *p, ...) { va_list args; int i; struct msg_sub *ms1, *ms; - char *p1; + const char *p1; va_start(args, p); @@ -883,7 +927,7 @@ msglim(struct msg_limit *lim, naddr addr, char *p, ...) void -logbad(int dump, char *p, ...) +logbad(int dump, const char *p, ...) { va_list args; diff --git a/sbin/routed/output.c b/sbin/routed/output.c index 546a350ca937..b1593b86f7e7 100644 --- a/sbin/routed/output.c +++ b/sbin/routed/output.c @@ -11,7 +11,7 @@ * 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: + * must display the following acknowledgment: * 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 @@ -29,20 +29,21 @@ * 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. + * + * $Id$ */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 6/5/93"; -#endif -static const char rcsid[] = - "$Id$"; -#endif /* not lint */ - #include "defs.h" +#if !defined(sgi) && !defined(__NetBSD__) +static char sccsid[] __attribute__((unused)) = "@(#)output.c 8.1 (Berkeley) 6/5/93"; +#elif defined(__NetBSD__) +__RCSID("$NetBSD$"); +#endif +#ident "$Revision: 2.17 $" -int update_seqno; + +u_int update_seqno; /* walk the tree of routes with this for output @@ -63,10 +64,9 @@ struct { #define WS_ST_RIP2_ALL 0x002 /* send full featured RIPv2 */ #define WS_ST_AG 0x004 /* ok to aggregate subnets */ #define WS_ST_SUPER_AG 0x008 /* ok to aggregate networks */ -#define WS_ST_SUB_AG 0x010 /* aggregate subnets in odd case */ -#define WS_ST_QUERY 0x020 /* responding to a query */ -#define WS_ST_TO_ON_NET 0x040 /* sending onto one of our nets */ -#define WS_ST_DEFAULT 0x080 /* faking a default */ +#define WS_ST_QUERY 0x010 /* responding to a query */ +#define WS_ST_TO_ON_NET 0x020 /* sending onto one of our nets */ +#define WS_ST_DEFAULT 0x040 /* faking a default */ } ws; /* A buffer for what can be heard by both RIPv1 and RIPv2 listeners */ @@ -104,7 +104,7 @@ output(enum output_type type, { struct sockaddr_in sin; int flags; - char *msg; + const char *msg; int res; naddr tgt_mcast; int soc; @@ -233,7 +233,7 @@ find_auth(struct interface *ifp) /* stop looking after the last key */ if (ap->type == RIP_AUTH_NONE) break; - + /* ignore keys that are not ready yet */ if ((u_long)ap->start > (u_long)clk.tv_sec) continue; @@ -261,25 +261,26 @@ clr_ws_buf(struct ws_buf *wb, wb->lim = wb->base + NETS_LEN; wb->n = wb->base; - bzero(wb->n, NETS_LEN*sizeof(*wb->n)); + memset(wb->n, 0, NETS_LEN*sizeof(*wb->n)); - /* install authentication if appropriate + /* (start to) install authentication if appropriate */ if (ap == 0) return; + na = (struct netauth*)wb->n; if (ap->type == RIP_AUTH_PW) { na->a_family = RIP_AF_AUTH; na->a_type = RIP_AUTH_PW; - bcopy(ap->key, na->au.au_pw, sizeof(na->au.au_pw)); + memcpy(na->au.au_pw, ap->key, sizeof(na->au.au_pw)); wb->n++; } else if (ap->type == RIP_AUTH_MD5) { na->a_family = RIP_AF_AUTH; na->a_type = RIP_AUTH_MD5; na->au.a_md5.md5_keyid = ap->keyid; - na->au.a_md5.md5_auth_len = RIP_AUTH_PW_LEN; - na->au.a_md5.md5_seqno = clk.tv_sec; + na->au.a_md5.md5_auth_len = RIP_AUTH_MD5_LEN; + na->au.a_md5.md5_seqno = htonl(clk.tv_sec); wb->n++; wb->lim--; /* make room for trailer */ } @@ -292,17 +293,18 @@ end_md5_auth(struct ws_buf *wb, { struct netauth *na, *na2; MD5_CTX md5_ctx; + int len; na = (struct netauth*)wb->base; na2 = (struct netauth*)wb->n; + len = (char *)na2-(char *)wb->buf; na2->a_family = RIP_AF_AUTH; - na2->a_type = 1; - bcopy(ap->key, na2->au.au_pw, sizeof(na2->au.au_pw)); - na->au.a_md5.md5_pkt_len = (char *)na2-(char *)(na+1); + na2->a_type = htons(1); + na->au.a_md5.md5_pkt_len = htons(len); MD5Init(&md5_ctx); - MD5Update(&md5_ctx, (u_char *)na, - (char *)(na2+1) - (char *)na); + MD5Update(&md5_ctx, (u_char *)wb->buf, len); + MD5Update(&md5_ctx, ap->key, RIP_AUTH_MD5_LEN); MD5Final(na2->au.au_pw, &md5_ctx); wb->n++; } @@ -356,11 +358,6 @@ supply_out(struct ag_info *ag) && (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), @@ -396,13 +393,14 @@ supply_out(struct ag_info *ag) /* 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 + if (TRACECONTENTS) + trace_misc("sending %s-->%s as 1" + " instead of %d routes", + addrname(htonl(dst_h), mask, + 1), + naddr_ntoa(ws.to.sin_addr + .s_addr), + i+1); i = 0; } else { @@ -451,12 +449,14 @@ supply_out(struct ag_info *ag) /* ARGSUSED */ static int walk_supply(struct radix_node *rn, - struct walkarg *w) + struct walkarg *argp UNUSED) { #define RT ((struct rt_entry *)rn) u_short ags; char metric, pref; naddr dst, nhop; + struct rt_spare *rts; + int i; /* Do not advertise external remote interfaces or passive interfaces. @@ -512,6 +512,7 @@ walk_supply(struct radix_node *rn, /* 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. + * The final determination is made by supply_out(). */ if (!(RT->rt_state & RS_IF) && RT->rt_gate != myaddr @@ -529,23 +530,30 @@ walk_supply(struct radix_node *rn, ; } else if (RT_ISHOST(RT)) { - /* We should always aggregate the host routes - * for the local end of our point-to-point links. + /* We should always suppress (into existing network routes) + * 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; + /* Aggregate stray host routes into network routes if allowed. + * We cannot aggregate host routes into small network routes + * without confusing RIPv1 listeners into thinking the + * network routes are host routes. + */ + if ((ws.state & WS_ST_AG) + && !(ws.state & WS_ST_RIP2_ALL)) + ags |= AGS_AGGREGATE; - } else if (ws.state & WS_ST_AG) { - /* Aggregate network routes, if we are allowed. + } else { + /* Always suppress network routes into other, existing + * network routes */ ags |= AGS_SUPPRESS; @@ -554,10 +562,10 @@ walk_supply(struct radix_node *rn, * 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; - + if ((ws.state & WS_ST_AG) + && ((RT->rt_state & RS_SUBNET) + || (ws.state & WS_ST_SUPER_AG))) + ags |= AGS_AGGREGATE; } /* Do not send RIPv1 advertisements of subnets to other @@ -565,11 +573,9 @@ walk_supply(struct radix_node *rn, */ 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; - } + && !on_net(dst, ws.to_std_net, ws.to_std_mask)) + ags |= AGS_RIPV2 | AGS_AGGREGATE; + /* Do not send a route back to where it came from, except in * response to a query. This is "split-horizon". That means not @@ -578,61 +584,72 @@ walk_supply(struct radix_node *rn, * 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. + * suppress the fragmented routes and then itself be forgotten. * * Include the routes for both ends of point-to-point interfaces * among those suppressed by split-horizon, since the other side * should knows them as well as we do. + * + * Notice spare routes with the same metric that we are about to + * advertise, to split the horizon on redundant, inactive paths. */ - if (RT->rt_ifp == ws.ifp && ws.ifp != 0 + if (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)) { - /* If we do not mark the route with AGS_SPLIT_HZ here, - * it will be poisoned-reverse, or advertised back toward - * its source with an infinite metric. If we have recently - * advertised the route with a better metric than we now - * have, then we should poison-reverse the route before - * suppressing it for split-horizon. - * - * In almost all cases, if there is no spare for the route - * then it is either old and dead or a brand new route. - * If it is brand new, there is no need for poison-reverse. - * If it is old and dead, it is already poisoned. - */ - if (RT->rt_poison_time < now_expire - || RT->rt_poison_metric >= metric - || RT->rt_spares[1].rts_gate == 0) { - ags |= AGS_SPLIT_HZ; - ags &= ~(AGS_PROMOTE | AGS_SUPPRESS); + for (rts = RT->rt_spares, i = NUM_SPARES; i != 0; i--, rts++) { + if (rts->rts_metric > metric + || rts->rts_ifp != ws.ifp) + continue; + + /* If we do not mark the route with AGS_SPLIT_HZ here, + * it will be poisoned-reverse, or advertised back + * toward its source with an infinite metric. + * If we have recently advertised the route with a + * better metric than we now have, then we should + * poison-reverse the route before suppressing it for + * split-horizon. + * + * In almost all cases, if there is no spare for the + * route then it is either old and dead or a brand + * new route. If it is brand new, there is no need + * for poison-reverse. If it is old and dead, it + * is already poisoned. + */ + if (RT->rt_poison_time < now_expire + || RT->rt_poison_metric >= metric + || RT->rt_spares[1].rts_gate == 0) { + ags |= AGS_SPLIT_HZ; + ags &= ~AGS_SUPPRESS; + } + metric = HOPCNT_INFINITY; + break; } - metric = 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; } /* Adjust the outgoing metric by the cost of the link. + * Avoid aggregation when a route is counting to infinity. */ - 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; + pref = RT->rt_poison_metric + ws.metric; + metric += ws.metric; - } else { - /* Do not advertise stable routes that will be ignored, - * unless we are answering a query. - * 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; + /* Do not advertise stable routes that will be ignored, + * unless we are answering a query. + * 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. + */ + if (metric >= HOPCNT_INFINITY) { if (!(ws.state & WS_ST_QUERY) && (pref >= HOPCNT_INFINITY || RT->rt_poison_time < now_garbage)) @@ -687,8 +704,6 @@ supply(struct sockaddr_in *dst, 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; @@ -702,44 +717,42 @@ supply(struct sockaddr_in *dst, ripv12_buf.rip.rip_vers = vers; switch (type) { - case OUT_BROADCAST: - v2buf.type = ((ifp != 0 && (ifp->int_if_flags & IFF_MULTICAST)) - ? OUT_MULTICAST - : NO_OUT_MULTICAST); - v12buf.type = OUT_BROADCAST; - break; case OUT_MULTICAST: - v2buf.type = ((ifp != 0 && (ifp->int_if_flags & IFF_MULTICAST)) - ? OUT_MULTICAST - : NO_OUT_MULTICAST); + if (ifp->int_if_flags & IFF_MULTICAST) + v2buf.type = OUT_MULTICAST; + else + v2buf.type = NO_OUT_MULTICAST; v12buf.type = OUT_BROADCAST; break; - case OUT_UNICAST: + case OUT_QUERY: + ws.state |= WS_ST_QUERY; + /* fall through */ + case OUT_BROADCAST: + case OUT_UNICAST: v2buf.type = (vers == RIPv2) ? type : NO_OUT_RIPV2; v12buf.type = type; break; - default: - v2buf.type = type; - v12buf.type = type; - break; + + case NO_OUT_MULTICAST: + case NO_OUT_RIPV2: + break; /* no output */ } if (vers == RIPv2) { /* 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)) { + if ((ws.state & WS_ST_QUERY) + || !(ws.state & WS_ST_TO_ON_NET)) { ws.state |= (WS_ST_AG | WS_ST_SUPER_AG); } else if (ifp == 0 || !(ifp->int_state & IS_NO_AG)) { ws.state |= WS_ST_AG; if (type != OUT_BROADCAST - && (ifp == 0 || !(ifp->int_state&IS_NO_SUPER_AG))) + && (ifp == 0 + || !(ifp->int_state & IS_NO_SUPER_AG))) ws.state |= WS_ST_SUPER_AG; } - - } else if (ifp == 0 || !(ifp->int_state & IS_NO_AG)) { - ws.state |= WS_ST_SUB_AG; } ws.a = (vers == RIPv2) ? find_auth(ifp) : 0; @@ -835,7 +848,7 @@ rip_bcast(int flash) continue; /* skip turned off interfaces */ - if (!iff_alive(ifp->int_if_flags)) + if (!iff_up(ifp->int_if_flags)) continue; vers = (ifp->int_state & IS_NO_RIPV1_OUT) ? RIPv2 : RIPv1; @@ -844,11 +857,8 @@ rip_bcast(int flash) /* 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)) { + && !(ifp->int_state & IS_NO_RIP_MCAST)) { type = OUT_MULTICAST; } else { type = OUT_BROADCAST; @@ -896,7 +906,7 @@ rip_query(void) if (rip_sock < 0) return; - bzero(&buf, sizeof(buf)); + memset(&buf, 0, sizeof(buf)); for (ifp = ifnet; ifp; ifp = ifp->int_next) { /* Skip interfaces those already queried. @@ -910,7 +920,7 @@ rip_query(void) continue; /* skip turned off interfaces */ - if (!iff_alive(ifp->int_if_flags)) + if (!iff_up(ifp->int_if_flags)) continue; buf.rip_vers = (ifp->int_state&IS_NO_RIPV1_OUT) ? RIPv2:RIPv1; @@ -918,14 +928,26 @@ rip_query(void) buf.rip_nets[0].n_family = RIP_AF_UNSPEC; buf.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); + /* Send a RIPv1 query only if allowed and if we will + * listen to RIPv1 routers. + */ + if ((ifp->int_state & IS_NO_RIPV1_OUT) + || (ifp->int_state & IS_NO_RIPV1_IN)) { + buf.rip_vers = RIPv2; + } else { + buf.rip_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. + + /* Broadcast RIPv1 queries and RIPv2 queries + * when the hardware cannot multicast. */ if (buf.rip_vers == RIPv2 - && (ifp->int_state & IS_NO_RIPV1_OUT)) { + && (ifp->int_if_flags & IFF_MULTICAST) + && !(ifp->int_state & IS_NO_RIP_MCAST)) { type = OUT_MULTICAST; } else { type = OUT_BROADCAST; diff --git a/sbin/routed/parms.c b/sbin/routed/parms.c index 9e1cbce72e0a..7e6a2a4beb69 100644 --- a/sbin/routed/parms.c +++ b/sbin/routed/parms.c @@ -11,7 +11,7 @@ * 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: + * must display the following acknowledgment: * 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 @@ -29,22 +29,25 @@ * 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. + * + * $Id$ */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93"; -#endif -static const char rcsid[] = - "$Id$"; -#endif /* not lint */ - #include "defs.h" #include "pathnames.h" #include +#if !defined(sgi) && !defined(__NetBSD__) +static char sccsid[] __attribute__((unused)) = "@(#)if.c 8.1 (Berkeley) 6/5/93"; +#elif defined(__NetBSD__) +__RCSID("$NetBSD$"); +#endif +#ident "$Revision: 2.17 $" + + struct parm *parms; struct intnet *intnets; +struct r1net *r1nets; struct tgate *tgates; @@ -53,7 +56,7 @@ struct tgate *tgates; void get_parms(struct interface *ifp) { - static warned_auth_in, warned_auth_out; + static int warned_auth_in, warned_auth_out; struct parm *parmp; int i, num_passwds = 0; @@ -74,9 +77,9 @@ get_parms(struct interface *ifp) if (parmp->parm_auth[0].type == RIP_AUTH_NONE || num_passwds >= MAX_AUTH_KEYS) break; - bcopy(&parmp->parm_auth[i], - &ifp->int_auth[num_passwds++], - sizeof(ifp->int_auth[0])); + memcpy(&ifp->int_auth[num_passwds++], + &parmp->parm_auth[i], + sizeof(ifp->int_auth[0])); } if (parmp->parm_rdisc_pref != 0) ifp->int_rdisc_pref = parmp->parm_rdisc_pref; @@ -109,9 +112,9 @@ get_parms(struct interface *ifp) /* By default, point-to-point links should be passive * about router-discovery for the sake of demand-dialing. */ - if (0 == (ifp->int_state & GROUP_IS_SOL)) + if (0 == (ifp->int_state & GROUP_IS_SOL_OUT)) ifp->int_state |= IS_NO_SOL_OUT; - if (0 == (ifp->int_state & GROUP_IS_ADV)) + if (0 == (ifp->int_state & GROUP_IS_ADV_OUT)) ifp->int_state |= IS_NO_ADV_OUT; } @@ -163,13 +166,15 @@ gwkludge(void) { FILE *fp; char *p, *lptr; - char lbuf[200], net_host[5], dname[64+1+64+1], gname[64+1], qual[9]; + const char *cp; + char lbuf[200], net_host[5], dname[64+1+64+1]; + char gname[GNAME_LEN+1], qual[9]; struct interface *ifp; naddr dst, netmask, gate; - int metric, n; + int metric, n, lnum; struct stat sb; u_int state; - char *type; + const char *type; fp = fopen(_PATH_GATEWAYS, "r"); @@ -182,39 +187,36 @@ gwkludge(void) return; } - for (;;) { - if (0 == fgets(lbuf, sizeof(lbuf)-1, fp)) + for (lnum = 1; ; lnum++) { + if (0 == fgets(lbuf, sizeof(lbuf), fp)) break; lptr = lbuf; while (*lptr == ' ') lptr++; - if (*lptr == '\n' /* ignore null and comment lines */ + p = lptr+strlen(lptr)-1; + while (*p == '\n' + || (*p == ' ' && (p == lptr+1 || *(p-1) != '\\'))) + *p-- = '\0'; + if (*lptr == '\0' /* ignore null and comment lines */ || *lptr == '#') continue; - p = lptr+strlen(lptr)-1; - while (*p == '\n' || *p == ' ') - *p-- = '\0'; /* notice newfangled parameter lines */ if (strncasecmp("net", lptr, 3) && strncasecmp("host", lptr, 4)) { - p = parse_parms(lptr, - (sb.st_uid == 0 - && !(sb.st_mode&(S_IRWXG|S_IRWXO)))); - if (p != 0) { - if (strcasecmp(p,lptr)) - msglog("%s in "_PATH_GATEWAYS - " entry \"%s\"", p, lptr); - else - msglog("bad \"%s\" in "_PATH_GATEWAYS, - lptr); - } + cp = parse_parms(lptr, + (sb.st_uid == 0 + && !(sb.st_mode&(S_IRWXG|S_IRWXO)))); + if (cp != 0) + msglog("%s in line %d of "_PATH_GATEWAYS, + cp, lnum); continue; } /* {net | host} XX[/M] XX gateway XX metric DD [passive | external]\n */ qual[0] = '\0'; + /* the '64' here must be GNAME_LEN */ n = sscanf(lptr, "%4s %129[^ \t] gateway" " %64[^ / \t] metric %u %8s\n", net_host, dname, gname, &metric, qual); @@ -241,10 +243,16 @@ gwkludge(void) " entry \"%s\"", dname, lptr); continue; } + if (dst == RIP_DEFAULT) { + msglog("bad net \"%s\" in "_PATH_GATEWAYS + " entry \"%s\"--cannot be default", + dname, lptr); + continue; + } HTONL(dst); /* make network # into IP address */ } else { msglog("bad \"%s\" in "_PATH_GATEWAYS - " entry \"%s\"", lptr); + " entry \"%s\"", net_host, lptr); continue; } @@ -311,14 +319,14 @@ gwkludge(void) continue; } - ifp = (struct interface *)rtmalloc(sizeof(*ifp), "gwkludge"); - bzero(ifp, sizeof(*ifp)); + ifp = (struct interface *)rtmalloc(sizeof(*ifp), "gwkludge()"); + memset(ifp, 0, sizeof(*ifp)); ifp->int_state = state; if (netmask == HOST_MASK) - ifp->int_if_flags = IFF_POINTOPOINT | IFF_UP_RUNNING; + ifp->int_if_flags = IFF_POINTOPOINT | IFF_UP; else - ifp->int_if_flags = IFF_UP_RUNNING; + ifp->int_if_flags = IFF_UP; ifp->int_act_time = NEVER; ifp->int_addr = gate; ifp->int_dstaddr = dst; @@ -355,16 +363,17 @@ gwkludge(void) } -/* strtok(), but honoring backslash +/* like strtok(), but honoring backslash and not changing the source string */ static int /* 0=ok, -1=bad */ -parse_quote(char **linep, - char *delims, - char *delimp, - char *buf, - int lim) +parse_quote(char **linep, /* look here */ + const char *delims, /* for these delimiters */ + char *delimp, /* 0 or put found delimiter here */ + char *buf, /* copy token to here */ + int lim) /* at most this many bytes */ { - char c, *pc, *p; + char c = '\0', *pc; + const char *p; pc = *linep; @@ -408,10 +417,10 @@ parse_quote(char **linep, if (lim == 0) return -1; - *buf = '\0'; + *buf = '\0'; /* terminate copy of token */ if (delimp != 0) - *delimp = c; - *linep = pc-1; + *delimp = c; /* return delimiter */ + *linep = pc-1; /* say where we ended */ return 0; } @@ -427,6 +436,9 @@ parse_ts(time_t *tp, u_int bufsize) { struct tm tm; +#if defined(sgi) || defined(__NetBSD__) + char *ptr; +#endif if (0 > parse_quote(valp, "| ,\n\r", delimp, buf,bufsize) @@ -436,15 +448,26 @@ parse_ts(time_t *tp, return buf; } strcat(buf,"\n"); - bzero(&tm, sizeof(tm)); - if (5 != sscanf(buf, "%u/%u/%u@%u:%u\n", - &tm.tm_year, &tm.tm_mon, &tm.tm_mday, - &tm.tm_hour, &tm.tm_min)) { + memset(&tm, 0, sizeof(tm)); +#if defined(sgi) || defined(__NetBSD__) + ptr = strptime(buf, "%y/%m/%d@%H:%M\n", &tm); + if (ptr == NULL || *ptr != '\0') { sprintf(buf,"bad timestamp %.25s", val0); return buf; } - if (tm.tm_year <= 37) - tm.tm_year += 100; +#else + if (5 != sscanf(buf, "%u/%u/%u@%u:%u\n", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min) + || tm.tm_mon < 1 || tm.tm_mon > 12 + || tm.tm_mday < 1 || tm.tm_mday > 31) { + sprintf(buf,"bad timestamp %.25s", val0); + return buf; + } + tm.tm_mon--; + if (tm.tm_year <= 37) /* assume small years are in the */ + tm.tm_year += 100; /* 3rd millenium */ +#endif if ((*tp = mktime(&tm)) == -1) { sprintf(buf,"bad timestamp %.25s", val0); @@ -458,11 +481,11 @@ parse_ts(time_t *tp, /* Get a password, key ID, and expiration date in the format * passwd|keyID|year/mon/day@hour:min|year/mon/day@hour:min */ -static char * /* 0 or error message */ +static const char * /* 0 or error message */ get_passwd(char *tgt, char *val, struct parm *parmp, - u_char type, + u_int16_t type, int safe) /* 1=from secure file */ { static char buf[80]; @@ -473,7 +496,7 @@ get_passwd(char *tgt, if (!safe) - return "unsafe password"; + return "ignore unsafe password"; for (ap = parmp->parm_auth, i = 0; ap->type != RIP_AUTH_NONE; i++, ap++) { @@ -481,7 +504,7 @@ get_passwd(char *tgt, return "too many passwords"; } - bzero(&k, sizeof(k)); + memset(&k, 0, sizeof(k)); k.type = type; k.end = -1-DAY; @@ -532,14 +555,24 @@ get_passwd(char *tgt, if (delim != '\0') return tgt; - bcopy(&k, ap, sizeof(*ap)); + memmove(ap, &k, sizeof(*ap)); return 0; } +static const char * +bad_str(const char *estr) +{ + static char buf[100+8]; + + sprintf(buf, "bad \"%.100s\"", estr); + return buf; +} + + /* Parse a set of parameters for an interface. */ -char * /* 0 or error message */ +const char * /* 0 or error message */ parse_parms(char *line, int safe) /* 1=from secure file */ { @@ -549,31 +582,35 @@ parse_parms(char *line, parm.parm_int_state |= (b);} struct parm parm; struct intnet *intnetp; + struct r1net *r1netp; struct tgate *tg; naddr addr, mask; - char delim, *val0, *tgt, *val, *p; - char buf[64]; + char delim, *val0 = 0, *tgt, *val, *p; + const char *msg; + char buf[BUFSIZ], buf2[BUFSIZ]; + int i; - /* "subnet=x.y.z.u/mask,metric" must be alone on the line */ + /* "subnet=x.y.z.u/mask[,metric]" must be alone on the line */ if (!strncasecmp(line, "subnet=", sizeof("subnet=")-1) && *(val = &line[sizeof("subnet=")-1]) != '\0') { - intnetp = (struct intnet*) - rtmalloc(sizeof(*intnetp), "parse_parms"); + if (0 > parse_quote(&val, ",", &delim, buf, sizeof(buf))) + return bad_str(line); + intnetp = (struct intnet*)rtmalloc(sizeof(*intnetp), + "parse_parms subnet"); intnetp->intnet_metric = 1; - if ((p = strrchr(val,','))) { - *p++ = '\0'; - intnetp->intnet_metric = (int)strtol(p,&p,0); + if (delim == ',') { + intnetp->intnet_metric = (int)strtol(val+1,&p,0); if (*p != '\0' || intnetp->intnet_metric <= 0 || intnetp->intnet_metric >= HOPCNT_INFINITY) - return line; + return bad_str(line); } - if (!getnet(val, &intnetp->intnet_addr, &intnetp->intnet_mask) + if (!getnet(buf, &intnetp->intnet_addr, &intnetp->intnet_mask) || intnetp->intnet_mask == HOST_MASK || intnetp->intnet_addr == RIP_DEFAULT) { free(intnetp); - return line; + return bad_str(line); } HTONL(intnetp->intnet_addr); intnetp->intnet_next = intnets; @@ -581,29 +618,62 @@ parse_parms(char *line, return 0; } - bzero(&parm, sizeof(parm)); + /* "ripv1_mask=x.y.z.u/mask1,mask2" must be alone on the line. + * This requires that x.y.z.u/mask1 be considered a subnet of + * x.y.z.u/mask2, as if x.y.z.u/mask2 were a class-full network. + */ + if (!strncasecmp(line, "ripv1_mask=", sizeof("ripv1_mask=")-1) + && *(val = &line[sizeof("ripv1_mask=")-1]) != '\0') { + if (0 > parse_quote(&val, ",", &delim, buf, sizeof(buf)) + || delim == '\0') + return bad_str(line); + if ((i = (int)strtol(val+1, &p, 0)) <= 0 + || i > 32 || *p != '\0') + return bad_str(line); + r1netp = (struct r1net *)rtmalloc(sizeof(*r1netp), + "parse_parms ripv1_mask"); + r1netp->r1net_mask = HOST_MASK << (32-i); + if (!getnet(buf, &r1netp->r1net_net, &r1netp->r1net_match) + || r1netp->r1net_net == RIP_DEFAULT + || r1netp->r1net_mask > r1netp->r1net_match) { + free(r1netp); + return bad_str(line); + } + r1netp->r1net_next = r1nets; + r1nets = r1netp; + return 0; + } + + memset(&parm, 0, sizeof(parm)); - tgt = "null"; for (;;) { tgt = line + strspn(line, " ,\n\r"); - if (*tgt == '\0') + if (*tgt == '\0' || *tgt == '#') break; - - line += strcspn(tgt, "= ,\n\r"); + line = tgt+strcspn(tgt, "= #,\n\r"); delim = *line; if (delim == '=') { val0 = ++line; - if (0 > parse_quote(&line," ,\n\r",&delim, + if (0 > parse_quote(&line, " #,\n\r",&delim, buf,sizeof(buf))) - return tgt; + return bad_str(tgt); + } + if (delim != '\0') { + for (;;) { + *line = '\0'; + if (delim == '#') + break; + ++line; + if (delim != ' ' + || (delim = *line) != ' ') + break; + } } - if (delim != '\0') - *line++ = '\0'; if (PARSEQ("if")) { if (parm.parm_name[0] != '\0' - || strlen(buf) > IFNAMSIZ) - return tgt; + || strlen(buf) > IF_NAME_LEN) + return bad_str(tgt); strcpy(parm.parm_name, buf); } else if (PARSEQ("addr")) { @@ -615,7 +685,7 @@ parse_parms(char *line, */ if (!getnet(val0, &addr, &mask) || parm.parm_name[0] != '\0') - return tgt; + return bad_str(tgt); parm.parm_net = addr; parm.parm_mask = mask; parm.parm_name[0] = '\n'; @@ -624,17 +694,17 @@ parse_parms(char *line, /* since cleartext passwords are so weak allow * them anywhere */ - tgt = get_passwd(tgt,val0,&parm,RIP_AUTH_PW,1); - if (tgt) { + msg = get_passwd(tgt,val0,&parm,RIP_AUTH_PW,1); + if (msg) { *val0 = '\0'; - return tgt; + return bad_str(msg); } } else if (PARSEQ("md5_passwd")) { - tgt = get_passwd(tgt,val0,&parm,RIP_AUTH_MD5,safe); - if (tgt) { + msg = get_passwd(tgt,val0,&parm,RIP_AUTH_MD5,safe); + if (msg) { *val0 = '\0'; - return tgt; + return bad_str(msg); } } else if (PARS("no_ag")) { @@ -651,50 +721,53 @@ parse_parms(char *line, } else if (PARS("ripv2_out")) { if (parm.parm_int_state & IS_NO_RIPV2_OUT) - return tgt; + return bad_str(tgt); parm.parm_int_state |= IS_NO_RIPV1_OUT; } else if (PARS("ripv2")) { if ((parm.parm_int_state & IS_NO_RIPV2_OUT) || (parm.parm_int_state & IS_NO_RIPV2_IN)) - return tgt; + return bad_str(tgt); parm.parm_int_state |= (IS_NO_RIPV1_IN | IS_NO_RIPV1_OUT); } else if (PARS("no_rip")) { CKF(IS_PM_RDISC, IS_NO_RIP); + } else if (PARS("no_rip_mcast")) { + parm.parm_int_state |= IS_NO_RIP_MCAST; + } else if (PARS("no_rdisc")) { - CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC); + CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC); } else if (PARS("no_solicit")) { - CKF(GROUP_IS_SOL, IS_NO_SOL_OUT); + CKF(GROUP_IS_SOL_OUT, IS_NO_SOL_OUT); } else if (PARS("send_solicit")) { - CKF(GROUP_IS_SOL, IS_SOL_OUT); + CKF(GROUP_IS_SOL_OUT, IS_SOL_OUT); } else if (PARS("no_rdisc_adv")) { - CKF(GROUP_IS_ADV, IS_NO_ADV_OUT); + CKF(GROUP_IS_ADV_OUT, IS_NO_ADV_OUT); } else if (PARS("rdisc_adv")) { - CKF(GROUP_IS_ADV, IS_ADV_OUT); + CKF(GROUP_IS_ADV_OUT, IS_ADV_OUT); } else if (PARS("bcast_rdisc")) { parm.parm_int_state |= IS_BCAST_RDISC; } else if (PARS("passive")) { - CKF((GROUP_IS_SOL|GROUP_IS_ADV), IS_NO_RDISC); + CKF((GROUP_IS_SOL_OUT|GROUP_IS_ADV_OUT), IS_NO_RDISC); parm.parm_int_state |= IS_NO_RIP; } else if (PARSEQ("rdisc_pref")) { if (parm.parm_rdisc_pref != 0 - || (parm.parm_rdisc_pref = (int)strtoul(buf, &p,0), + || (parm.parm_rdisc_pref = (int)strtol(buf,&p,0), *p != '\0')) - return tgt; + return bad_str(tgt); } else if (PARS("pm_rdisc")) { if (IS_RIP_OUT_OFF(parm.parm_int_state)) - return tgt; + return bad_str(tgt); parm.parm_int_state |= IS_PM_RDISC; } else if (PARSEQ("rdisc_interval")) { @@ -703,7 +776,7 @@ parse_parms(char *line, *p != '\0') || parm.parm_rdisc_int < MinMaxAdvertiseInterval || parm.parm_rdisc_int > MaxMaxAdvertiseInterval) - return tgt; + return bad_str(tgt); } else if (PARSEQ("fake_default")) { if (parm.parm_d_metric != 0 @@ -711,15 +784,35 @@ parse_parms(char *line, || (parm.parm_d_metric = (int)strtoul(buf,&p,0), *p != '\0') || parm.parm_d_metric > HOPCNT_INFINITY-1) - return tgt; + return bad_str(tgt); } else if (PARSEQ("trust_gateway")) { - if (!gethost(buf,&addr)) - return tgt; - tg = (struct tgate *) - rtmalloc(sizeof(*tg), "parse_parms"); - tg->tgate_next = tgates; + /* look for trust_gateway=x.y.z|net/mask|...) */ + p = buf; + if (0 > parse_quote(&p, "|", &delim, + buf2, sizeof(buf2)) + || !gethost(buf2,&addr)) + return bad_str(tgt); + tg = (struct tgate *)rtmalloc(sizeof(*tg), + "parse_parms" + "trust_gateway"); + memset(tg, 0, sizeof(*tg)); tg->tgate_addr = addr; + i = 0; + /* The default is to trust all routes. */ + while (delim == '|') { + p++; + if (i >= MAX_TGATE_NETS + || 0 > parse_quote(&p, "|", &delim, + buf2, sizeof(buf2)) + || !getnet(buf2, &tg->tgate_nets[i].net, + &tg->tgate_nets[i].mask) + || tg->tgate_nets[i].net == RIP_DEFAULT + || tg->tgate_nets[i].mask == 0) + return bad_str(tgt); + i++; + } + tg->tgate_next = tgates; tgates = tg; parm.parm_int_state |= IS_DISTRUST; @@ -727,7 +820,7 @@ parse_parms(char *line, parm.parm_int_state |= IS_REDIRECT_OK; } else { - return tgt; /* error */ + return bad_str(tgt); /* error */ } } @@ -738,7 +831,7 @@ parse_parms(char *line, /* check for duplicate parameter specifications */ -char * /* 0 or error message */ +const char * /* 0 or error message */ check_parms(struct parm *new) { struct parm *parmp, **parmpp; @@ -748,6 +841,8 @@ check_parms(struct parm *new) */ if (new->parm_int_state & IS_NO_ADV_IN) new->parm_int_state |= IS_NO_SOL_OUT; + if (new->parm_int_state & IS_NO_SOL_OUT) + new->parm_int_state |= IS_NO_ADV_IN; for (i = num_passwds = 0; i < MAX_AUTH_KEYS; i++) { if (new->parm_auth[i].type != RIP_AUTH_NONE) @@ -774,14 +869,14 @@ check_parms(struct parm *new) if (num_passwds > MAX_AUTH_KEYS) return "too many conflicting passwords"; - if ((0 != (new->parm_int_state & GROUP_IS_SOL) - && 0 != (parmp->parm_int_state & GROUP_IS_SOL) + if ((0 != (new->parm_int_state & GROUP_IS_SOL_OUT) + && 0 != (parmp->parm_int_state & GROUP_IS_SOL_OUT) && 0 != ((new->parm_int_state ^ parmp->parm_int_state) - && GROUP_IS_SOL)) - || (0 != (new->parm_int_state & GROUP_IS_ADV) - && 0 != (parmp->parm_int_state & GROUP_IS_ADV) + && GROUP_IS_SOL_OUT)) + || (0 != (new->parm_int_state & GROUP_IS_ADV_OUT) + && 0 != (parmp->parm_int_state & GROUP_IS_ADV_OUT) && 0 != ((new->parm_int_state ^ parmp->parm_int_state) - && GROUP_IS_ADV)) + && GROUP_IS_ADV_OUT)) || (new->parm_rdisc_pref != 0 && parmp->parm_rdisc_pref != 0 && new->parm_rdisc_pref != parmp->parm_rdisc_pref) @@ -805,7 +900,7 @@ check_parms(struct parm *new) * they affect the result in the order the operator specified. */ parmp = (struct parm*)rtmalloc(sizeof(*parmp), "check_parms"); - bcopy(new, parmp, sizeof(*parmp)); + memcpy(parmp, new, sizeof(*parmp)); *parmpp = parmp; return 0; @@ -817,7 +912,7 @@ check_parms(struct parm *new) */ int /* 0=bad */ getnet(char *name, - naddr *netp, /* a network so host byte order */ + naddr *netp, /* network in host byte order */ naddr *maskp) /* masks are always in host order */ { int i; @@ -830,11 +925,11 @@ getnet(char *name, /* Detect and separate "1.2.3.4/24" */ - if (0 != (mname = rindex(name,'/'))) { + if (0 != (mname = strrchr(name,'/'))) { i = (int)(mname - name); - if (i > sizeof(hname)-1) /* name too long */ + if (i > (int)sizeof(hname)-1) /* name too long */ return 0; - bcopy(name, hname, i); + memmove(hname, name, i); hname[i] = '\0'; mname++; name = hname; @@ -843,6 +938,12 @@ getnet(char *name, np = getnetbyname(name); if (np != 0) { in.s_addr = (naddr)np->n_net; + if (0 == (in.s_addr & 0xff000000)) + in.s_addr <<= 8; + if (0 == (in.s_addr & 0xff000000)) + in.s_addr <<= 8; + if (0 == (in.s_addr & 0xff000000)) + in.s_addr <<= 8; } else if (inet_aton(name, &in) == 1) { NTOHL(in.s_addr); } else if (!mname && !strcasecmp(name,"default")) { @@ -862,7 +963,8 @@ getnet(char *name, mask = (naddr)strtoul(mname, &p, 0); if (*p != '\0' || mask > 32) return 0; - mask = HOST_MASK << (32-mask); + if (mask != 0) + mask = HOST_MASK << (32-mask); } /* must have mask of 0 with default */ @@ -910,7 +1012,7 @@ gethost(char *name, hp = gethostbyname(name); if (hp) { - bcopy(hp->h_addr, addrp, sizeof(*addrp)); + memcpy(addrp, hp->h_addr, sizeof(*addrp)); return 1; } diff --git a/sbin/routed/pathnames.h b/sbin/routed/pathnames.h index 441ef59f8f55..9a9466ff9bf7 100644 --- a/sbin/routed/pathnames.h +++ b/sbin/routed/pathnames.h @@ -11,7 +11,7 @@ * 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: + * must display the following acknowledgment: * 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 @@ -31,8 +31,8 @@ * SUCH DAMAGE. * * @(#)pathnames.h 8.1 (Berkeley) 6/5/93 + * * $Id$ - * $NetBSD$ */ #include @@ -47,6 +47,8 @@ * Leave this undefined, and only the trace file originally specified * when routed was started, if any, will be appended to. */ -#if 0 -#define _PATH_TRACE "/var/log/routed.trace" +#ifndef __NetBSD__ +#define _PATH_TRACE "/etc/routed.trace" +#else +#undef _PATH_TRACE #endif diff --git a/sbin/routed/radix.c b/sbin/routed/radix.c index 5feb655aed2d..9d45b5996d32 100644 --- a/sbin/routed/radix.c +++ b/sbin/routed/radix.c @@ -11,7 +11,7 @@ * 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: + * must display the following acknowledgment: * 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 @@ -30,22 +30,24 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * @(#)radix.c 8.4 (Berkeley) 11/2/94 + * + * $Id$ */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)radix.c 8.4 (Berkeley) 11/2/94"; -#endif -static const char rcsid[] = - "$Id$"; -#endif /* not lint */ - /* * Routines to build and maintain radix trees for routing lookups. */ #include "defs.h" +#if !defined(sgi) && !defined(__NetBSD__) +static char sccsid[] __attribute__((unused)) = "@(#)rdisc.c 8.1 (Berkeley) x/y/95"; +#elif defined(__NetBSD__) +__RCSID("$NetBSD$"); +#endif +#ident "$Revision: 2.17 $" + #define log(x, msg) syslog(x, msg) #define panic(s) {log(LOG_ERR,s); exit(1);} #define min(a,b) (((a)<(b))?(a):(b)) @@ -59,9 +61,10 @@ static char *rn_zeros, *rn_ones; #define rn_masktop (mask_rnhead->rnh_treetop) #undef Bcmp -#define Bcmp(a, b, l) (l == 0 ? 0 : bcmp((caddr_t)(a), (caddr_t)(b), (u_long)l)) +#define Bcmp(a, b, l) (l == 0 ? 0 \ + : memcmp((caddr_t)(a), (caddr_t)(b), (size_t)l)) -static int rn_satsifies_leaf(char *, struct radix_node *, int); +static int rn_satisfies_leaf(char *, struct radix_node *, int); /* * The data structure for the keys is a radix tree with one way @@ -101,8 +104,8 @@ struct radix_node * rn_search(void *v_arg, struct radix_node *head) { - register struct radix_node *x; - register caddr_t v; + struct radix_node *x; + caddr_t v; for (x = head, v = v_arg; x->rn_b >= 0;) { if (x->rn_bmask & v[x->rn_off]) @@ -118,8 +121,8 @@ rn_search_m(void *v_arg, struct radix_node *head, void *m_arg) { - register struct radix_node *x; - register caddr_t v = v_arg, m = m_arg; + struct radix_node *x; + caddr_t v = v_arg, m = m_arg; for (x = head; x->rn_b >= 0;) { if ((x->rn_bmask & m[x->rn_off]) && @@ -134,8 +137,8 @@ rn_search_m(void *v_arg, int rn_refines(void* m_arg, void *n_arg) { - register caddr_t m = m_arg, n = n_arg; - register caddr_t lim, lim2 = lim = n + *(u_char *)n; + caddr_t m = m_arg, n = n_arg; + caddr_t lim, lim2 = lim = n + *(u_char *)n; int longer = (*(u_char *)n++) - (int)(*(u_char *)m++); int masks_are_equal = 1; @@ -158,11 +161,9 @@ rn_refines(void* m_arg, void *n_arg) } struct radix_node * -rn_lookup(v_arg, m_arg, head) - void *v_arg, *m_arg; - struct radix_node_head *head; +rn_lookup(void *v_arg, void *m_arg, struct radix_node_head *head) { - register struct radix_node *x; + struct radix_node *x; caddr_t netmask = 0; if (m_arg) { @@ -179,11 +180,11 @@ rn_lookup(v_arg, m_arg, head) } static int -rn_satsifies_leaf(char *trial, - register struct radix_node *leaf, +rn_satisfies_leaf(char *trial, + struct radix_node *leaf, int skip) { - register char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask; + char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask; char *cplim; int length = min(*(u_char *)cp, *(u_char *)cp2); @@ -203,12 +204,12 @@ rn_match(void *v_arg, struct radix_node_head *head) { caddr_t v = v_arg; - register struct radix_node *t = head->rnh_treetop, *x; - register caddr_t cp = v, cp2; + struct radix_node *t = head->rnh_treetop, *x; + caddr_t cp = v, cp2; caddr_t cplim; struct radix_node *saved_t, *top = t; int off = t->rn_off, vlen = *(u_char *)cp, matched_off; - register int test, b, rn_b; + int test, b, rn_b; /* * Open code rn_search(v, top) to avoid overhead of extra @@ -272,7 +273,7 @@ rn_match(void *v_arg, */ if ((saved_t = t)->rn_mask == 0) t = t->rn_dupedkey; - for (; t; t = t->rn_dupedkey) + for (; t; t = t->rn_dupedkey) { /* * Even if we don't match exactly as a host, * we may match if the leaf we wound up at is @@ -281,12 +282,14 @@ rn_match(void *v_arg, if (t->rn_flags & RNF_NORMAL) { if (rn_b <= t->rn_b) return t; - } else if (rn_satsifies_leaf(v, t, matched_off)) - return t; + } else if (rn_satisfies_leaf(v, t, matched_off)) { + return t; + } + } t = saved_t; /* start searching up the tree */ do { - register struct radix_mask *m; + struct radix_mask *m; t = t->rn_p; if ((m = t->rn_mklist)) { /* @@ -304,7 +307,7 @@ rn_match(void *v_arg, x = rn_search_m(v, t, m->rm_mask); while (x && x->rn_mask != m->rm_mask) x = x->rn_dupedkey; - if (x && rn_satsifies_leaf(v, x, off)) + if (x && rn_satisfies_leaf(v, x, off)) return x; } } while ((m = m->rm_mklist)); @@ -323,7 +326,7 @@ int rn_debug = 1; struct radix_node * rn_newpair(void *v, int b, struct radix_node nodes[2]) { - register struct radix_node *tt = nodes, *t = tt + 1; + struct radix_node *tt = nodes, *t = tt + 1; t->rn_b = b; t->rn_bmask = 0x80 >> (b & 7); t->rn_l = tt; t->rn_off = b >> 3; tt->rn_b = -1; tt->rn_key = (caddr_t)v; tt->rn_p = t; @@ -344,17 +347,17 @@ rn_insert(void* v_arg, caddr_t v = v_arg; struct radix_node *top = head->rnh_treetop; int head_off = top->rn_off, vlen = (int)*((u_char *)v); - register struct radix_node *t = rn_search(v_arg, top); - register caddr_t cp = v + head_off; - register int b; + struct radix_node *t = rn_search(v_arg, top); + caddr_t cp = v + head_off; + int b; struct radix_node *tt; /* * Find first bit at which v and t->rn_key differ */ { - register caddr_t cp2 = t->rn_key + head_off; - register int cmp_res; + caddr_t cp2 = t->rn_key + head_off; + int cmp_res; caddr_t cplim = v + vlen; while (cp < cplim) @@ -372,14 +375,14 @@ rn_insert(void* v_arg, cmp_res >>= 1; } { - register struct radix_node *p, *x = top; + struct radix_node *p, *x = top; cp = v; do { p = x; if (cp[x->rn_off] & x->rn_bmask) x = x->rn_r; else x = x->rn_l; - } while (b > (unsigned) x->rn_b); /* x->rn_b < b && x->rn_b >= 0 */ + } while ((unsigned)b > (unsigned)x->rn_b); #ifdef RN_DEBUG if (rn_debug) log(LOG_DEBUG, "rn_insert: Going In:\n"), traverse(p); @@ -407,9 +410,9 @@ struct radix_node * rn_addmask(void *n_arg, int search, int skip) { caddr_t netmask = (caddr_t)n_arg; - register struct radix_node *x; - register caddr_t cp, cplim; - register int b = 0, mlen, j; + struct radix_node *x; + caddr_t cp, cplim; + int b = 0, mlen, j; int maskduplicated, m0, isnormal; struct radix_node *saved_x; static int last_zeroed = 0; @@ -443,10 +446,9 @@ rn_addmask(void *n_arg, int search, int skip) x = 0; if (x || search) return (x); - x = (struct radix_node *) - rtmalloc(max_keylen + 2 * sizeof (*x), "rn_addmask"); - if ((saved_x = x) == 0) - return (0); + x = (struct radix_node *)rtmalloc(max_keylen + 2*sizeof(*x), + "rn_addmask"); + saved_x = x; Bzero(x, max_keylen + 2 * sizeof (*x)); netmask = cp = (caddr_t)(x + 2); Bcopy(addmask_key, cp, mlen); @@ -478,7 +480,7 @@ rn_addmask(void *n_arg, int search, int skip) static int /* XXX: arbitrary ordering for non-contiguous masks */ rn_lexobetter(void *m_arg, void *n_arg) { - register u_char *mp = m_arg, *np = n_arg, *lim; + u_char *mp = m_arg, *np = n_arg, *lim; if (*mp > *np) return 1; /* not really, but need to check longer one first */ @@ -490,10 +492,10 @@ rn_lexobetter(void *m_arg, void *n_arg) } static struct radix_mask * -rn_new_radix_mask(register struct radix_node *tt, - register struct radix_mask *next) +rn_new_radix_mask(struct radix_node *tt, + struct radix_mask *next) { - register struct radix_mask *m; + struct radix_mask *m; MKGet(m); if (m == 0) { @@ -519,7 +521,7 @@ rn_addroute(void *v_arg, struct radix_node treenodes[2]) { caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg; - register struct radix_node *t, *x = 0, *tt; + struct radix_node *t, *x = 0, *tt; struct radix_node *saved_tt, *top = head->rnh_treetop; short b = 0, b_leaf = 0; int keyduplicated; @@ -660,7 +662,7 @@ rn_delete(void *v_arg, void *netmask_arg, struct radix_node_head *head) { - register struct radix_node *t, *p, *x, *tt; + struct radix_node *t, *p, *x, *tt; struct radix_mask *m, *saved_m, **mp; struct radix_node *dupedkey, *saved_tt, *top; caddr_t v, netmask; @@ -781,7 +783,7 @@ rn_delete(void *v_arg, m = mm; } if (m) - syslog(LOG_ERR, "%s %lx at %lx\n", + syslog(LOG_ERR, "%s 0x%lx at 0x%lx\n", "rn_delete: Orphaned Mask", (unsigned long)m, (unsigned long)x); @@ -809,12 +811,12 @@ rn_delete(void *v_arg, int rn_walktree(struct radix_node_head *h, - register int (*f)(struct radix_node *, struct walkarg*), + int (*f)(struct radix_node *, struct walkarg *), struct walkarg *w) { int error; struct radix_node *base, *next; - register struct radix_node *rn = h->rnh_treetop; + struct radix_node *rn = h->rnh_treetop; /* * This gets complicated because we may delete the node * while applying the function f to it, so we need to calculate @@ -848,13 +850,11 @@ rn_walktree(struct radix_node_head *h, int rn_inithead(void **head, int off) { - register struct radix_node_head *rnh; - register struct radix_node *t, *tt, *ttt; + struct radix_node_head *rnh; + struct radix_node *t, *tt, *ttt; if (*head) return (1); - rnh = (struct radix_node_head *)rtmalloc(sizeof (*rnh), "rn_inithead"); - if (rnh == 0) - return (0); + rnh = (struct radix_node_head *)rtmalloc(sizeof(*rnh), "rn_inithead"); Bzero(rnh, sizeof (*rnh)); *head = rnh; t = rn_newpair(rn_zeros, off, rnh->rnh_nodes); @@ -884,8 +884,6 @@ rn_init(void) return; } rn_zeros = (char *)rtmalloc(3 * max_keylen, "rn_init"); - if (rn_zeros == NULL) - panic("rn_init"); Bzero(rn_zeros, 3 * max_keylen); rn_ones = cp = rn_zeros + max_keylen; addmask_key = cplim = rn_ones + max_keylen; diff --git a/sbin/routed/radix.h b/sbin/routed/radix.h index 033f31c31ebc..44fb0621290b 100644 --- a/sbin/routed/radix.h +++ b/sbin/routed/radix.h @@ -11,7 +11,7 @@ * 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: + * must display the following acknowledgment: * 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 @@ -31,6 +31,7 @@ * SUCH DAMAGE. * * @(#)radix.h 8.2 (Berkeley) 10/31/94 + * * $Id$ */ @@ -103,7 +104,7 @@ extern struct radix_mask { m = rn_mkfreelist; \ rn_mkfreelist = (m)->rm_mklist; \ } else \ - m = (struct radix_mask *)rtmalloc(sizeof (*(m)), "MKGet"); }\ + m = (struct radix_mask *)rtmalloc(sizeof(*(m)), "MKGet"); }\ #define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);} @@ -135,17 +136,18 @@ struct radix_node_head { }; -#define Bcmp(a, b, n) bcmp(((char *)(a)), ((char *)(b)), (n)) -#define Bcopy(a, b, n) bcopy(((char *)(a)), ((char *)(b)), (unsigned)(n)) -#define Bzero(p, n) bzero((char *)(p), (int)(n)); -#define Free(p) free((char *)p); +#define Bcmp(a, b, n) memcmp(((void *)(a)), ((void *)(b)), (n)) +#define Bcopy(a, b, n) memmove(((void *)(b)), ((void *)(a)), (size_t)(n)) +#define Bzero(p, n) memset((void *)(p), 0, (size_t)(n)); +#define Free(p) free((void *)p); void rn_init __P((void)); int rn_inithead __P((void **, int)); int rn_refines __P((void *, void *)); int rn_walktree __P((struct radix_node_head *, - int (*)__P((struct radix_node *, struct walkarg*)), - struct walkarg*)); + int (*)__P((struct radix_node *, struct walkarg *)), + struct walkarg *)); + struct radix_node *rn_addmask __P((void *, int, int)), *rn_addroute __P((void *, void *, struct radix_node_head *, @@ -158,4 +160,6 @@ struct radix_node *rn_search __P((void *, struct radix_node *)), *rn_search_m __P((void *, struct radix_node *, void *)); +struct radix_node *rn_lookup __P((void *, void *, struct radix_node_head *)); + #endif /* __RADIX_H_ */ diff --git a/sbin/routed/rdisc.c b/sbin/routed/rdisc.c index 89efd2ce6ee9..4d54b33be342 100644 --- a/sbin/routed/rdisc.c +++ b/sbin/routed/rdisc.c @@ -11,7 +11,7 @@ * 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: + * must display the following acknowledgment: * 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 @@ -29,21 +29,22 @@ * 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. + * + * $Id$ */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)rdisc.c 8.1 (Berkeley) x/y/95"; -#endif -static const char rcsid[] = - "$Id$"; -#endif /* not lint */ - #include "defs.h" #include #include #include +#if !defined(sgi) && !defined(__NetBSD__) +static char sccsid[] __attribute__((unused)) = "@(#)rdisc.c 8.1 (Berkeley) x/y/95"; +#elif defined(__NetBSD__) +__RCSID"$NetBSD$"); +#endif +#ident "$Revision: 2.17 $" + /* router advertisement ICMP packet */ struct icmp_ad { u_int8_t icmp_type; /* type of message */ @@ -80,7 +81,7 @@ struct timeval rdisc_timer; int rdisc_ok; /* using solicited route */ -#define MAX_ADS 5 +#define MAX_ADS 16 /* at least one per interface */ struct dr { /* accumulated advertisements */ struct interface *dr_ifp; naddr dr_gate; /* gateway */ @@ -90,8 +91,13 @@ struct dr { /* accumulated advertisements */ n_long dr_pref; /* preference adjusted by metric */ } *cur_drp, drs[MAX_ADS]; -/* adjust preference by interface metric without driving it to infinity */ -#define PREF(p, ifp) ((p) <= (ifp)->int_metric ? ((p) != 0 ? 1 : 0) \ +/* convert between signed, balanced around zero, + * and unsigned zero-based preferences */ +#define SIGN_PREF(p) ((p) ^ MIN_PreferenceLevel) +#define UNSIGN_PREF(p) SIGN_PREF(p) +/* adjust unsigned preference by interface metric, + * without driving it to infinity */ +#define PREF(p, ifp) ((int)(p) <= (ifp)->int_metric ? ((p) != 0 ? 1 : 0) \ : (p) - ((ifp)->int_metric)) static void rdisc_sort(void); @@ -100,7 +106,7 @@ static void rdisc_sort(void); /* dump an ICMP Router Discovery Advertisement Message */ static void -trace_rdisc(char *act, +trace_rdisc(const char *act, naddr from, naddr to, struct interface *ifp, @@ -138,7 +144,7 @@ trace_rdisc(char *act, trace_act("%s Router Solic. from %s to %s via %s value=%#x", act, naddr_ntoa(from), naddr_ntoa(to), ifp ? ifp->int_name : "?", - ntohl(p->so.icmp_so_rsvd)); + (int)ntohl(p->so.icmp_so_rsvd)); } } @@ -184,7 +190,7 @@ set_rdisc_mg(struct interface *ifp, if (ifp->int_if_flags & IFF_POINTOPOINT) return; #endif - bzero(&m, sizeof(m)); + memset(&m, 0, sizeof(m)); m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) ? ifp->int_dstaddr : ifp->int_addr); @@ -297,7 +303,7 @@ rdisc_age(naddr bad_gate) /* If only advertising, then do only that. */ if (supplier) { - /* if switching from client to server, get rid of old + /* If switching from client to server, get rid of old * default routes. */ if (cur_drp != 0) @@ -337,14 +343,17 @@ rdisc_age(naddr bad_gate) } } - /* delete old redirected routes to keep the kernel table small - */ - sec = (cur_drp == 0) ? MaxMaxAdvertiseInterval : cur_drp->dr_life; - del_redirects(bad_gate, now.tv_sec-sec); - rdisc_sol(); - rdisc_sort(); + + /* Delete old redirected routes to keep the kernel table small, + * and to prevent black holes. Check that the kernel table + * matches the daemon table (i.e. has the default route). + * But only if RIP is not running and we are not dealing with + * a bad gateway, since otherwise age() will be called. + */ + if (rip_sock < 0 && bad_gate == 0) + age(0); } @@ -360,10 +369,12 @@ if_bad_rdisc(struct interface *ifp) if (drp->dr_ifp != ifp) continue; drp->dr_recv_pref = 0; + drp->dr_ts = 0; drp->dr_life = 0; } - rdisc_sort(); + /* make a note to re-solicit, turn RIP on or off, etc. */ + rdisc_timer.tv_sec = 0; } @@ -389,10 +400,11 @@ static void del_rdisc(struct dr *drp) { struct interface *ifp; + naddr gate; int i; - del_redirects(drp->dr_gate, 0); + del_redirects(gate = drp->dr_gate, 0); drp->dr_ts = 0; drp->dr_life = 0; @@ -411,13 +423,21 @@ del_rdisc(struct dr *drp) * then solicit a new one. * This is contrary to RFC 1256, but defends against black holes. */ - if (i == 0 - && ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) { - trace_act("discovered route is bad--re-solicit routers via %s", - ifp->int_name); + if (i != 0) { + trace_act("discovered router %s via %s" + " is bad--have %d remaining", + naddr_ntoa(gate), ifp->int_name, i); + } else if (ifp->int_rdisc_cnt >= MAX_SOLICITATIONS) { + trace_act("last discovered router %s via %s" + " is bad--re-solicit", + naddr_ntoa(gate), ifp->int_name); ifp->int_rdisc_cnt = 0; ifp->int_rdisc_timer.tv_sec = 0; rdisc_sol(); + } else { + trace_act("last discovered router %s via %s" + " is bad--wait to solicit", + naddr_ntoa(gate), ifp->int_name); } } @@ -430,9 +450,10 @@ rdisc_sort(void) { struct dr *drp, *new_drp; struct rt_entry *rt; + struct rt_spare new; struct interface *ifp; - u_int new_st; - n_long new_pref; + u_int new_st = 0; + n_long new_pref = 0; /* Find the best discovered route. @@ -490,23 +511,20 @@ rdisc_sort(void) if (rt != 0 && (rt->rt_state & RS_RDISC)) { + new = rt->rt_spares[0]; + new.rts_metric = HOPCNT_INFINITY; + new.rts_time = now.tv_sec - GARBAGE_TIME; rtchange(rt, rt->rt_state & ~RS_RDISC, - rt->rt_gate, rt->rt_router, - HOPCNT_INFINITY, 0, rt->rt_ifp, - now.tv_sec - GARBAGE_TIME, 0); + &new, 0); rtswitch(rt, 0); } - /* turn on RIP if permitted */ - rip_on(0); - } else { if (cur_drp == 0) { trace_act("turn on Router Discovery client" " using %s via %s", naddr_ntoa(new_drp->dr_gate), new_drp->dr_ifp->int_name); - rdisc_ok = 1; } else { @@ -518,27 +536,28 @@ rdisc_sort(void) new_drp->dr_ifp->int_name); } + memset(&new, 0, sizeof(new)); + new.rts_ifp = new_drp->dr_ifp; + new.rts_gate = new_drp->dr_gate; + new.rts_router = new_drp->dr_gate; + new.rts_metric = HOPCNT_INFINITY-1; + new.rts_time = now.tv_sec; if (rt != 0) { - rtchange(rt, rt->rt_state | RS_RDISC, - new_drp->dr_gate, new_drp->dr_gate, - 0,0, new_drp->dr_ifp, - now.tv_sec, 0); + rtchange(rt, rt->rt_state | RS_RDISC, &new, 0); } else { - rtadd(RIP_DEFAULT, 0, - new_drp->dr_gate, new_drp->dr_gate, - HOPCNT_INFINITY-1, 0, - RS_RDISC, new_drp->dr_ifp); + rtadd(RIP_DEFAULT, 0, RS_RDISC, &new); } - - /* Now turn off RIP and delete RIP routes, - * which might otherwise include the default - * we just modified. - */ - rip_off(); } cur_drp = new_drp; } + + /* turn RIP on or off */ + if (!rdisc_ok || rip_interfaces > 1) { + rip_on(0); + } else { + rip_off(); + } } @@ -547,7 +566,7 @@ rdisc_sort(void) static void parse_ad(naddr from, naddr gate, - n_long pref, + n_long pref, /* signed and in network order */ u_short life, struct interface *ifp) { @@ -578,9 +597,9 @@ parse_ad(naddr from, /* Convert preference to an unsigned value * and later bias it by the metric of the interface. */ - pref = ntohl(pref) ^ MIN_PreferenceLevel; + pref = UNSIGN_PREF(ntohl(pref)); - if (pref == 0 || life == 0) { + if (pref == 0 || life < MinMaxAdvertiseInterval) { pref = 0; life = 0; } @@ -671,16 +690,16 @@ static void send_rdisc(union ad_u *p, int p_size, struct interface *ifp, - naddr dst, /* 0 or UNICAST destination */ + naddr dst, /* 0 or unicast destination */ int type) /* 0=unicast, 1=bcast, 2=mcast */ { struct sockaddr_in sin; int flags; - char *msg; + const char *msg; naddr tgt_mcast; - bzero(&sin, sizeof(sin)); + memset(&sin, 0, sizeof(sin)); sin.sin_addr.s_addr = dst; sin.sin_family = AF_INET; #ifdef _HAVE_SIN_LEN @@ -689,7 +708,7 @@ send_rdisc(union ad_u *p, flags = MSG_DONTROUTE; switch (type) { - case 0: /* UNICAST */ + case 0: /* unicast */ default: msg = "Send"; break; @@ -765,23 +784,27 @@ send_rdisc(union ad_u *p, */ static void send_adv(struct interface *ifp, - naddr dst, /* 0 or UNICAST destination */ + naddr dst, /* 0 or unicast destination */ int type) /* 0=unicast, 1=bcast, 2=mcast */ { union ad_u u; n_long pref; - bzero(&u,sizeof(u.ad)); + memset(&u, 0, sizeof(u.ad)); u.ad.icmp_type = ICMP_ROUTERADVERT; u.ad.icmp_ad_num = 1; u.ad.icmp_ad_asize = sizeof(u.ad.icmp_ad_info[0])/4; u.ad.icmp_ad_life = stopint ? 0 : htons(ifp->int_rdisc_int*3); - pref = ifp->int_rdisc_pref ^ MIN_PreferenceLevel; - pref = PREF(pref, ifp) ^ MIN_PreferenceLevel; - u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(pref); + + /* Convert the configured preference to an unsigned value, + * bias it by the interface metric, and then send it as a + * signed, network byte order value. + */ + pref = UNSIGN_PREF(ifp->int_rdisc_pref); + u.ad.icmp_ad_info[0].icmp_ad_pref = htonl(SIGN_PREF(PREF(pref, ifp))); u.ad.icmp_ad_info[0].icmp_ad_addr = ifp->int_addr; @@ -851,7 +874,7 @@ rdisc_sol(void) continue; if (!timercmp(&ifp->int_rdisc_timer, &now, >)) { - bzero(&u,sizeof(u.so)); + memset(&u, 0, sizeof(u.so)); u.so.icmp_type = ICMP_ROUTERSOLICIT; u.so.icmp_cksum = in_cksum((u_short*)&u.so, sizeof(u.so)); @@ -875,14 +898,14 @@ rdisc_sol(void) /* check the IP header of a possible Router Discovery ICMP packet */ static struct interface * /* 0 if bad */ -ck_icmp(char *act, +ck_icmp(const char *act, naddr from, struct interface *ifp, naddr to, union ad_u *p, u_int len) { - char *type; + const char *type; if (p->icmp.icmp_type == ICMP_ROUTERADVERT) { @@ -988,7 +1011,7 @@ read_d(void) switch (p->icmp.icmp_type) { case ICMP_ROUTERADVERT: if (p->ad.icmp_ad_asize*4 - < sizeof(p->ad.icmp_ad_info[0])) { + < (int)sizeof(p->ad.icmp_ad_info[0])) { msglim(&bad_asize, from.sin_addr.s_addr, "intolerable rdisc address size=%d", p->ad.icmp_ad_asize); @@ -998,9 +1021,10 @@ read_d(void) trace_pkt(" empty?"); continue; } - if (cc != (sizeof(p->ad) - sizeof(p->ad.icmp_ad_info) - + (p->ad.icmp_ad_num - * sizeof(p->ad.icmp_ad_info[0])))) { + if (cc != (int)(sizeof(p->ad) + - sizeof(p->ad.icmp_ad_info) + + (p->ad.icmp_ad_num + * sizeof(p->ad.icmp_ad_info[0])))) { msglim(&bad_len, from.sin_addr.s_addr, "rdisc length %d does not match ad_num" " %d", cc, p->ad.icmp_ad_num); @@ -1027,6 +1051,8 @@ read_d(void) continue; if (ifp->int_state & IS_NO_ADV_OUT) continue; + if (stopint) + continue; /* XXX * We should handle messages from address 0. diff --git a/sbin/routed/routed.8 b/sbin/routed/routed.8 index 36a1705b30c8..d357ba57e760 100644 --- a/sbin/routed/routed.8 +++ b/sbin/routed/routed.8 @@ -1,3 +1,5 @@ +.\" $Revision: 2.17 $ +.\" .\" Copyright (c) 1983, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" @@ -30,17 +32,19 @@ .\" SUCH DAMAGE. .\" .\" @(#)routed.8 8.2 (Berkeley) 12/11/93 -.\" $Id: routed.8,v 1.10 1998/06/17 13:13:41 jkoshy Exp $ +.\" +.\" $Id$ .\" .Dd June 1, 1996 .Dt ROUTED 8 .Os BSD 4.4 .Sh NAME -.Nm routed +.Nm routed , +.Nm rdisc .Nd network RIP and router discovery routing daemon .Sh SYNOPSIS .Nm routed -.Op Fl sqdghmAt +.Op Fl sqdghmpAtv .Op Fl T Ar tracefile .Oo .Fl F @@ -55,7 +59,9 @@ 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. +The RIPv1 protocol is based on the reference +.Bx 4.3 +daemon. .Pp It listens on the .Xr udp 4 @@ -116,7 +122,7 @@ Advertised metrics reflect the metric associated with interface so setting the metric on an interface is an effective way to steer traffic. .Pp -Responses do not contain routes with a first hop on the requesting +Responses do not include routes with a first hop on the requesting network to implement in part .Em split-horizon . Requests from query programs @@ -152,7 +158,7 @@ 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 until the route has been advertised with an infinite metric to insure the invalidation -is propagated throughout the local Internet. +is propagated throughout the local internet. This is a form of .Em poison reverse . .Pp @@ -180,7 +186,7 @@ support multicasting. 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 ), +.Xr netstat 1 ), then the cable or some other part of the interface is assumed to be disconnected or broken, and routes are adjusted appropriately. .Pp @@ -189,15 +195,17 @@ The 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 +When it is quiet and 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. +a good Advertisement and it is not multi-homed, +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. +It continues listening to RIP while using Router Discovery +if multi-homed to ensure all interfaces are used. .Pp The Router Discovery standard requires that advertisements have a default "lifetime" of 30 minutes. That means should @@ -217,9 +225,7 @@ is received), there is a single default route and a variable number of redirected host routes in the kernel table. On a host with more than one network interface, this default route will be via only one of the interfaces. -Thus, multi-homed hosts running with -.Fl q -might need +Thus, multi-homed hosts running with \f3\-q\f1 might need .Cm no_rdisc described below. .Pp @@ -238,22 +244,24 @@ to infer the netmask used by the remote system when RIPv1 is used. The following options are available: .Bl -tag -width indent .It Fl s -Force +force .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 +is the opposite of the .Fl s option. This is the default when only one interface is present. +With this explicit option, the daemon is always in "quite-mode" for RIP +and does not supply routing information to other computers. .It Fl d -Do not run in the background. +do not run in the background. This option is meant for interactive use. .It Fl g -Used on internetwork routers to offer a route +used on internetwork routers to offer a route to the "default" destination. It is equivalent to .Fl F @@ -266,23 +274,23 @@ on the command line or in the .Pa /etc/gateways file. -Since a larger metric +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. Notice that because a metric of 1 is used, this feature is -dangerous. It is more commonly accidentally used to create chaos with routing -loop than to solve problems. +dangerous. It is more commonly accidentally used to create chaos with a +routing loop than to solve problems. .It Fl h -Cause host or point-to-point routes to not be advertised, +cause 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 -Cause the machine to advertise a host or point-to-point route to +cause 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 @@ -296,20 +304,14 @@ 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 +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 -Increase the debugging level to at least 1 and -causes debugging information to be appended to the trace file. -Note that because of security concerns, it is wisest to not run -.Nm -routinely with tracing directed to a file. .It Fl t -Increase the debugging level, which causes more information to be logged +increase the debugging level, which causes more information to be logged on the tracefile specified with .Fl T or standard out. @@ -321,8 +323,16 @@ or signals or with the .Xr rtquery 8 command. +.It Fl T Ar tracefile +increases the debugging level to at least 1 and +causes debugging information to be appended to the trace file. +Note that because of security concerns, it is wisest to not run +.Nm +routinely with tracing directed to a file. +.It Fl v +display and logs the version of daemon. .It Fl F Ar net[/mask][,metric] -Minimize routes in transmissions via interfaces with addresses that match +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 . @@ -333,7 +343,6 @@ 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 @@ -341,7 +350,7 @@ number and mask. See also .Fl g . .It Fl P Ar parms -Is equivalent to adding the parameter +is equivalent to adding the parameter line .Em parms to the @@ -397,10 +406,12 @@ route is restored. 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 +One can list all RIP routers reachable on the HIPPI or ATM network in .Pa /etc/gateways with a series of "host" lines. +Note that it is usually desirable to use RIPv2 in such situations +to avoid generating lists of inferred host routes. .Pp Gateways marked .Em external @@ -409,7 +420,7 @@ routing table nor are they included in routing updates. The function of external entries is to indicate that another routing process will install such a route if necessary, -and that alternate routes to that destination should not be installed +and that other routes to that destination should not be installed by .Nm Ns . Such entries are only required when both routers may learn of routes @@ -418,7 +429,8 @@ to the same destination. The .Pa /etc/gateways file is comprised of a series of lines, each in -one of the following formats or consist of parameters described below: +one of the following two formats or consist of parameters described later. +Blank lines and lines starting with '#' are comments. .Pp .Bd -ragged .Cm net @@ -488,6 +500,15 @@ or whether the gateway is .Cm external to the scope of the RIP protocol. .Pp +As can be seen when debugging is turned on with +.Fl t , +such lines create pseudo-interfaces. +To set parameters for remote or external interfaces, +a line starting with +.Cm if=alias(Hname) , +.Cm if=remote(Hname) , +etc. should be used. +.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: @@ -504,14 +525,21 @@ with 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. +The network number must specify a full, 32-bit value, as in 192.0.2.0 +instead of 192.0.2. .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 passwd Ns \&= Ns Ar XXX1[|KeyID[start|stop]] +.It Cm ripv1_mask Ns \&= Ns Ar nname/mask1,mask2 +specifies that netmask of the network of which +.Cm nname/mask1\f1 +is +a subnet should be +.Cm mask2 . +For example \f2ripv1_mask=192.0.2.16/28,27\f1 marks 192.0.2.16/28 +as a subnet of 192.0.2.0/27 instead of 192.0.2.0/24. +It is better to turn on RIPv2 instead of using this facility, for example +with \f2ripv2_out\f1. +.It Cm passwd Ns \&= Ns Ar XXX[|KeyID[start|stop]] specifies a RIPv2 cleartext password that will be included on all RIPv2 responses sent, and checked on all RIPv2 responses received. Any blanks, tab characters, commas, or '#', '|', or NULL characters in the @@ -533,15 +561,15 @@ recently is used, or unless no passwords are valid yet, in which case no password is output. Incoming packets can carry any password that is valid, will be valid within 24 hours, or that was valid within 24 hours. -.It Cm md5_passwd Ns \&= Ns Ar XXX1|KeyID[start|stop] +To protect the secrets, the passwd settings are valid only in the +.Em /etc/gateways +file and only when that file is readable only by UID 0. +.It Cm md5_passwd Ns \&= Ns Ar XXX|KeyID[start|stop] specifies a RIPv2 MD5 password. Except that a .Cm KeyID is required, this keyword is similar to .Cm passwd . -To protect the secrets, this parameter setting is valid only in the -.Pa /etc/gateways -file and only when that file is readable only by UID 0. .It Cm no_ag turns off aggregation of subnets in RIPv1 and RIPv2 responses. .It Cm no_super_ag @@ -563,18 +591,21 @@ or causes .Nm to act as a client router discovery daemon, not advertising. +.It Cm no_rip_mcast +causes RIPv2 packets to be broadcast instead of multicast. .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 +turns on RIPv2 output and causes RIPv2 advertisements to be multicast when possible. .It Cm ripv2 is equivalent to .Cm no_ripv1_in and .Cm no_ripv1_out . +This enables RIPv2. .It Cm no_rdisc disables the Internet Router Discovery Protocol. .It Cm no_solicit @@ -593,8 +624,12 @@ which by default only listen to Router Discovery messages. 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 +sets the preference in Router Discovery Advertisements to the optionally +signed integer .Ar N . +The default preference is 0. +Default routes with smaller or more negative preferences are preferred by +clients. .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. @@ -612,15 +647,17 @@ 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. -.It Cm trust_gateway Ns \&= Ns Ar rname +.It Cm trust_gateway Ns \&= Ns Ar rname[|net1/mask1|net2/mask2|...] causes RIP packets from that router and other routers named in other .Cm trust_gateway -keywords to be accept, and packets from other routers to be ignored. +keywords to be accepted, and packets from other routers to be ignored. +If networks are specified, then routes to other networks will be ignored +from that router. .It Cm redirect_ok causes RIP to allow ICMP Redirect messages when the system is acting as a router and forwarding packets. -Otherwise, ICMP Redirect messages are are overridden. +Otherwise, ICMP Redirect messages are overridden. .El .Pp .Sh FILES @@ -632,15 +669,16 @@ for distant gateways .Xr icmp 4 , .Xr udp 4 , .Xr gated 8 , -.Xr rtquery 8 +.Xr htable 8 , +.Xr rtquery 8 . .Rs .%T Internet Transport Protocols .%R XSIS 028112 .%Q Xerox System Integration Standard .Re .Sh BUGS -It does not always detect unidirectional failures in network interfaces -(e.g., when the output side fails). +It does not always detect unidirectional failures in network interfaces, +for example, when the output side fails. .Sh HISTORY The .Nm diff --git a/sbin/routed/rtquery/Makefile b/sbin/routed/rtquery/Makefile index adc9d15eb70b..d371d5d6651d 100644 --- a/sbin/routed/rtquery/Makefile +++ b/sbin/routed/rtquery/Makefile @@ -1,10 +1,11 @@ -# From: @(#)Makefile 8.1 (Berkeley) 6/5/93 +# Make `routed` tools for BSD/OS +# $Revision: 2.15 $ # $Id$ PROG= rtquery MAN8= rtquery.8 LDADD+= -lmd DPADD+= ${LIBMD} -#COPTS= -g -DDEBUG -Wall +#COPTS= -g -DDEBUG -W -Wall -Wcast-align -Wcast-qual -Winline -Wpointer-arith -Wnested-externs -Wwrite-strings -Wunused .include diff --git a/sbin/routed/rtquery/rtquery.8 b/sbin/routed/rtquery/rtquery.8 index 4c51c8feb6d0..1f16d59dab88 100644 --- a/sbin/routed/rtquery/rtquery.8 +++ b/sbin/routed/rtquery/rtquery.8 @@ -1,4 +1,6 @@ -.\" $Id: rtquery.8,v 1.7 1997/06/13 20:58:09 max Exp $ +.\" $Revision: 2.17 $ +.\" $Id$ +.\" .Dd June 1, 1996 .Dt RTQUERY 8 .Os BSD 4.4 @@ -6,17 +8,16 @@ .Nm rtquery .Nd query routing daemons for their routing tables .Sh SYNOPSIS -.Nm rtquery +.Nm .Op Fl np1 .Op Fl w Ar timeout .Op Fl r Ar addr .Op Fl a Ar secret -.Ar host -.Ar -.Nm rtquery +.Ar host ... +.br +.Nm .Op Fl t Ar op -.Ar host -.Ar +.Ar host ... .Sh DESCRIPTION .Nm Rtquery is used to query a RIP network routing daemon, @@ -27,7 +28,8 @@ for its routing table by sending a .Em request or .Em poll -command. The routing information in any routing +command. +The routing information in any routing .Em response packets returned is displayed numerically and symbolically. .Pp @@ -51,82 +53,71 @@ the command is preferred over the .Em request command because the response is not subject to Split Horizon and/or -Poisoned Reverse, and because some versions of -.Xr gated 8 -do not answer -the +Poisoned Reverse, and because some versions of gated do not answer the .Em request command. -.Nm Routed +.Xr Routed 8 does not answer the .Em poll -command, but -recognizes -.Em request -commands coming from +command, but recognizes +.Em requests +coming from .Nm and so answers completely. .Pp .Nm Rtquery is also used to turn tracing on or off in -.Nm routed . +.Xr routed 8 . .Pp The following options are available: .Bl -tag -width indent .It Fl n -Normally network and host numbers are displayed both symbolically -and numerically. -The -.Fl n -option displays only the numeric network and host numbers. +displays only the numeric network and host numbers instead of both +numeric and symbolic. .It Fl p -Use the -.Em Poll +uses the +.Em poll command to request full routing information from .Xr gated 8 . This is an undocumented extension RIP protocol supported only by .Xr gated 8 . .It Fl 1 -Query using RIP version 1 instead of RIP version 2. +queries using RIP version 1 instead of RIP version 2. .It Fl w Ar timeout -Change the delay for an answer from each host. +changes the delay for an answer from each host. By default, each host is given 15 seconds to respond. .It Fl r Ar addr -Ask about the route to destination +asks about the route to destination .Em addr . .It Fl a Ar passwd=XXX .It Fl a Ar md5_passwd=XXX|KeyID -Cause the query to be sent with the indicated cleartext or MD5 password. +causes the query to be sent with the indicated cleartext or MD5 password. .It Fl t Ar op -Change tracing, where +changes tracing, where .Em op is one of the following. Requests from processes not running with UID 0 or on distant networks are generally ignored by the daemon except for a message in the system log. -.Xr Gated 8 +.Xr Gated 8 is likely to ignore these debugging requests. .El .Bl -tag -width Ds -offset indent-two .It Em on=tracefile -Turn tracing on into the specified file. That file must usually -have been specified when the daemon was started or be the same -as a fixed name, often +turns tracing on into the specified file. +That file must usually have been specified when the daemon was +started or be the same as a fixed name, often .Pa /etc/routed.trace . .It Em more -Increase the debugging level. +increases the debugging level. .It Em off -Turn off tracing. +turns off tracing. .It Em dump -Dump the daemon's routing table to the current tracefile. +dumps the daemon's routing table to the current tracefile. .El .Sh SEE ALSO -.Xr gated 8 , -.Xr routed 8 -.Rs -.%T Routing Information Protocol, RIPV1 -.%O RFC1058 -.Re -.Rs -.%T Routing Information Protocol, RIPv2 -.%O RFC1723 -.Re +.Xr routed 8 , +.Xr gated 8 +.br +RFC\ 1058 - Routing Information Protocol, RIPv1 +.br +RFC\ 1723 - Routing Information Protocol, RIPv2 diff --git a/sbin/routed/rtquery/rtquery.c b/sbin/routed/rtquery/rtquery.c index 071b8e985267..25d9e8231469 100644 --- a/sbin/routed/rtquery/rtquery.c +++ b/sbin/routed/rtquery/rtquery.c @@ -11,7 +11,7 @@ * 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: + * must display the following acknowledgment: * 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 @@ -29,50 +29,62 @@ * 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. + * + * $Id$ */ -#ifndef lint -static const char copyright[] = +char copyright[] = "@(#) Copyright (c) 1982, 1986, 1993\n\ The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)query.c 8.1 (Berkeley) 6/5/93"; -#endif -static const char rcsid[] = - "$Id: rtquery.c,v 1.8 1998/07/22 05:49:36 phk Exp $"; -#endif /* not lint */ +#include #include +#include #include #include #include #define RIPVERSION RIPv2 #include #include -#include -#include #include +#include +#include #include #include #include -#include #ifdef sgi #include #include #endif +#if !defined(sgi) && !defined(__NetBSD__) +static char sccsid[] __attribute__((unused))= "@(#)query.c 8.1 (Berkeley) 6/5/93"; +#elif defined(__NetBSD__) +__RCSID("$NetBSD: rtquery.c,v 1.10 1999/02/23 10:47:41 christos Exp $"); +#endif +#ident "$Revision: 2.17 $" + #ifndef sgi #define _HAVE_SIN_LEN #endif -#include +#define MD5_DIGEST_LEN 16 +typedef struct { + u_int32_t state[4]; /* state (ABCD) */ + u_int32_t count[2]; /* # of bits, modulo 2^64 (LSB 1st) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; +extern void MD5Init(MD5_CTX*); +extern void MD5Update(MD5_CTX*, u_char*, u_int); +extern void MD5Final(u_char[MD5_DIGEST_LEN], MD5_CTX*); + + #define WTIME 15 /* Time to wait for all responses */ #define STIME (250*1000) /* usec to wait for another response */ -int s; +int soc; + +const char *pgmname; union { struct rip rip; @@ -99,26 +111,32 @@ u_long keyid; struct timeval sent; /* when query sent */ +static char localhost_str[] = "localhost"; +static char *default_argv[] = {localhost_str, 0}; + static void rip_input(struct sockaddr_in*, int); -static int out(char *); -static void trace_loop(char *argv[]); -static void query_loop(char *argv[], int); +static int out(const char *); +static void trace_loop(char *argv[]) __attribute((__noreturn__)); +static void query_loop(char *argv[], int) __attribute((__noreturn__)); static int getnet(char *, struct netinfo *); static u_int std_mask(u_int); -static int parse_quote(char **, char *, char *, char *, int); +static int parse_quote(char **, const char *, char *, char *, int); static void usage(void); + int main(int argc, char *argv[]) { int ch, bsize; char *p, *options, *value, delim; + const char *result; OMSG.rip_nets[0].n_dst = RIP_DEFAULT; OMSG.rip_nets[0].n_family = RIP_AF_UNSPEC; OMSG.rip_nets[0].n_metric = htonl(HOPCNT_INFINITY); + pgmname = argv[0]; while ((ch = getopt(argc, argv, "np1w:r:t:a:")) != -1) switch (ch) { case 'n': @@ -150,11 +168,14 @@ main(int argc, rflag = getnet(optarg, &OMSG.rip_nets[0]); if (!rflag) { struct hostent *hp = gethostbyname(optarg); - if (hp == 0) - errx(1, "%s: %s", - optarg, hstrerror(h_errno)); - bcopy(hp->h_addr, &OMSG.rip_nets[0].n_dst, - sizeof(OMSG.rip_nets[0].n_dst)); + if (hp == 0) { + fprintf(stderr, "%s: %s:", + pgmname, optarg); + herror(0); + exit(1); + } + memcpy(&OMSG.rip_nets[0].n_dst, hp->h_addr, + sizeof(OMSG.rip_nets[0].n_dst)); OMSG.rip_nets[0].n_family = RIP_AF_INET; OMSG.rip_nets[0].n_mask = -1; rflag = 1; @@ -165,47 +186,52 @@ main(int argc, trace = 1; options = optarg; while (*options != '\0') { - char *traceopts[] = { + /* messy complications to make -W -Wall happy */ + static char on_str[] = "on"; + static char more_str[] = "more"; + static char off_str[] = "off"; + static char dump_str[] = "dump"; + static char *traceopts[] = { # define TRACE_ON 0 - "on", + on_str, # define TRACE_MORE 1 - "more", + more_str, # define TRACE_OFF 2 - "off", + off_str, # define TRACE_DUMP 3 - "dump", + dump_str, 0 }; + result = ""; switch (getsubopt(&options,traceopts,&value)) { case TRACE_ON: OMSG.rip_cmd = RIPCMD_TRACEON; if (!value || strlen(value) > MAXPATHLEN) - usage(); + usage(); + result = value; break; case TRACE_MORE: if (value) - usage(); + usage(); OMSG.rip_cmd = RIPCMD_TRACEON; - value = ""; break; case TRACE_OFF: if (value) - usage(); + usage(); OMSG.rip_cmd = RIPCMD_TRACEOFF; - value = ""; break; case TRACE_DUMP: if (value) - usage(); + usage(); OMSG.rip_cmd = RIPCMD_TRACEON; - value = "dump/../table"; + result = "dump/../table"; break; default: usage(); } - strcpy((char*)OMSG.rip_tracefile, value); - omsg_len += strlen(value) - sizeof(OMSG.ripun); + strcpy((char*)OMSG.rip_tracefile, result); + omsg_len += strlen(result) - sizeof(OMSG.ripun); } break; @@ -222,7 +248,7 @@ main(int argc, else usage(); if (0 > parse_quote(&p,"|",&delim, - passwd,sizeof(passwd))) + passwd, sizeof(passwd))) usage(); if (auth_type == RIP_AUTH_MD5 && delim == '|') { @@ -239,20 +265,26 @@ main(int argc, } argv += optind; argc -= optind; - if ((not_trace && trace) || argc == 0) + if (not_trace && trace) usage(); + if (argc == 0) { + argc = 1; + argv = default_argv; + } - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) - err(2, "socket"); + soc = socket(AF_INET, SOCK_DGRAM, 0); + if (soc < 0) { + perror("socket"); + exit(2); + } /* be prepared to receive a lot of routes */ for (bsize = 127*1024; ; bsize -= 1024) { - if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, + if (setsockopt(soc, SOL_SOCKET, SO_RCVBUF, &bsize, sizeof(bsize)) == 0) break; if (bsize <= 4*1024) { - warn("setsockopt SO_RCVBUF"); + perror("setsockopt SO_RCVBUF"); break; } } @@ -261,19 +293,23 @@ main(int argc, trace_loop(argv); else query_loop(argv, argc); - return(0); /* NOTREACHED */ + return 0; } + static void -usage() +usage(void) { - fprintf(stderr, "%s\n%s\n", - "usage: rtquery [-np1v] [-r addr] [-w timeout] [-a secret] host ...", - " rtquery [-t op] host ..."); + fprintf(stderr, + "usage: rtquery [-np1] [-r tgt_rt] [-w wtime]" + " [-a type=passwd] host1 [host2 ...]\n" + "\trtquery -t {on=filename|more|off|dump}" + " host1 [host2 ...]\n"); exit(1); } + /* tell the target hosts about tracing */ static void @@ -282,8 +318,10 @@ trace_loop(char *argv[]) struct sockaddr_in myaddr; int res; - if (geteuid() != 0) - errx(1, "-t requires UID 0"); + if (geteuid() != 0) { + (void)fprintf(stderr, "-t requires UID 0\n"); + exit(1); + } if (ripv2) { OMSG.rip_vers = RIPv2; @@ -291,15 +329,18 @@ trace_loop(char *argv[]) OMSG.rip_vers = RIPv1; } - bzero(&myaddr, sizeof(myaddr)); + memset(&myaddr, 0, sizeof(myaddr)); myaddr.sin_family = AF_INET; #ifdef _HAVE_SIN_LEN myaddr.sin_len = sizeof(myaddr); #endif myaddr.sin_port = htons(IPPORT_RESERVED-1); - while (bind(s, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { - if (errno != EADDRINUSE || myaddr.sin_port == 0) - err(2, "bind"); + while (bind(soc, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { + if (errno != EADDRINUSE + || myaddr.sin_port == 0) { + perror("bind"); + exit(2); + } myaddr.sin_port = htons(ntohs(myaddr.sin_port)-1); } @@ -339,8 +380,7 @@ query_loop(char *argv[], int argc) OMSG.rip_nets[1] = OMSG.rip_nets[0]; NA0.a_family = RIP_AF_AUTH; NA0.a_type = RIP_AUTH_PW; - bcopy(passwd, NA0.au.au_pw, - RIP_AUTH_PW_LEN); + memcpy(NA0.au.au_pw, passwd, RIP_AUTH_PW_LEN); omsg_len += sizeof(OMSG.rip_nets[0]); } else if (auth_type == RIP_AUTH_MD5) { @@ -348,15 +388,17 @@ query_loop(char *argv[], int argc) NA0.a_family = RIP_AF_AUTH; NA0.a_type = RIP_AUTH_MD5; NA0.au.a_md5.md5_keyid = (int8_t)keyid; - NA0.au.a_md5.md5_auth_len = RIP_AUTH_PW_LEN; + NA0.au.a_md5.md5_auth_len = RIP_AUTH_MD5_LEN; NA0.au.a_md5.md5_seqno = 0; - NA0.au.a_md5.md5_pkt_len = sizeof(OMSG.rip_nets[1]); + cc = (char *)&NA2-(char *)&OMSG; + NA0.au.a_md5.md5_pkt_len = htons(cc); NA2.a_family = RIP_AF_AUTH; - NA2.a_type = 1; - bcopy(passwd, NA2.au.au_pw, sizeof(NA2.au.au_pw)); + NA2.a_type = htons(1); MD5Init(&md5_ctx); - MD5Update(&md5_ctx, (u_char *)&NA0, - (char *)(&NA2+1) - (char *)&NA0); + MD5Update(&md5_ctx, + (u_char *)&OMSG, cc); + MD5Update(&md5_ctx, + (u_char *)passwd, RIP_AUTH_MD5_LEN); MD5Final(NA2.au.au_pw, &md5_ctx); omsg_len += 2*sizeof(OMSG.rip_nets[0]); } @@ -370,23 +412,25 @@ query_loop(char *argv[], int argc) seen = 0; while (0 > out(*argv++)) { if (*argv == 0) - exit(1); + exit(-1); answered++; } FD_ZERO(&bits); for (;;) { - FD_SET(s, &bits); + FD_SET(soc, &bits); delay.tv_sec = 0; delay.tv_usec = STIME; - cc = select(s+1, &bits, 0,0, &delay); + cc = select(soc+1, &bits, 0,0, &delay); if (cc > 0) { fromlen = sizeof(from); - cc = recvfrom(s, imsg_buf.packet, + cc = recvfrom(soc, imsg_buf.packet, sizeof(imsg_buf.packet), 0, (struct sockaddr *)&from, &fromlen); - if (cc < 0) - err(1, "recvfrom"); + if (cc < 0) { + perror("recvfrom"); + exit(1); + } /* count the distinct responding hosts. * You cannot match responding hosts with * addresses to which queries were transmitted, @@ -399,6 +443,11 @@ query_loop(char *argv[], int argc) } if (sp == 0) { sp = malloc(sizeof(*sp)); + if (sp == 0) { + fprintf(stderr, + "rtquery: malloc failed\n"); + exit(1); + } sp->addr = from.sin_addr; sp->next = seen; seen = sp; @@ -412,7 +461,8 @@ query_loop(char *argv[], int argc) if (cc < 0) { if (errno == EINTR) continue; - err(1, "select"); + perror("select"); + exit(1); } /* After a pause in responses, probe another host. @@ -429,8 +479,10 @@ query_loop(char *argv[], int argc) /* or until we have waited a long time */ - if (gettimeofday(&now, 0) < 0) - err(1, "gettimeofday(now)"); + if (gettimeofday(&now, 0) < 0) { + perror("gettimeofday(now)"); + exit(1); + } if (sent.tv_sec + wtime <= now.tv_sec) break; } @@ -443,17 +495,17 @@ query_loop(char *argv[], int argc) /* send to one host */ static int -out(char *host) +out(const char *host) { struct sockaddr_in router; struct hostent *hp; if (gettimeofday(&sent, 0) < 0) { - warn("gettimeofday(sent)"); + perror("gettimeofday(sent)"); return -1; } - bzero(&router, sizeof(router)); + memset(&router, 0, sizeof(router)); router.sin_family = AF_INET; #ifdef _HAVE_SIN_LEN router.sin_len = sizeof(router); @@ -464,13 +516,13 @@ out(char *host) herror(host); return -1; } - bcopy(hp->h_addr, &router.sin_addr, sizeof(router.sin_addr)); + memcpy(&router.sin_addr, hp->h_addr, sizeof(router.sin_addr)); } router.sin_port = htons(RIP_PORT); - if (sendto(s, &omsg_buf, omsg_len, 0, + if (sendto(soc, &omsg_buf, omsg_len, 0, (struct sockaddr *)&router, sizeof(router)) < 0) { - warn("%s", host); + perror(host); return -1; } @@ -541,8 +593,11 @@ rip_input(struct sockaddr_in *from, { struct netinfo *n, *lim; struct in_addr in; - char *name; + const char *name; char net_buf[80]; + u_char hash[RIP_AUTH_MD5_LEN]; + MD5_CTX md5_ctx; + u_char md5_authed = 0; u_int mask, dmask; char *sp; int i; @@ -572,10 +627,10 @@ rip_input(struct sockaddr_in *from, (IMSG.rip_vers != RIPv1 && IMSG.rip_vers != RIPv2) ? " ?" : "", size); if (size > MAXPACKETSIZE) { - if (size > sizeof(imsg_buf) - sizeof(*n)) { + if (size > (int)sizeof(imsg_buf) - (int)sizeof(*n)) { printf(" at least %d bytes too long\n", size-MAXPACKETSIZE); - size = sizeof(imsg_buf) - sizeof(*n); + size = (int)sizeof(imsg_buf) - (int)sizeof(*n); } else { printf(" %d bytes too long\n", size-MAXPACKETSIZE); @@ -657,22 +712,38 @@ rip_input(struct sockaddr_in *from, if (na->a_type == RIP_AUTH_MD5 && n == IMSG.rip_nets) { - (void)printf(" MD5 Authentication" + (void)printf(" MD5 Auth" " len=%d KeyID=%d" - " seqno=%d" + " auth_len=%d" + " seqno=%#x" " rsvd=%#x,%#x\n", - na->au.a_md5.md5_pkt_len, + ntohs(na->au.a_md5.md5_pkt_len), na->au.a_md5.md5_keyid, - na->au.a_md5.md5_seqno, + na->au.a_md5.md5_auth_len, + (int)ntohl(na->au.a_md5.md5_seqno), na->au.a_md5.rsvd[0], na->au.a_md5.rsvd[1]); + md5_authed = 1; continue; } (void)printf(" Authentication type %d: ", ntohs(na->a_type)); - for (i = 0; i < sizeof(na->au.au_pw); i++) + for (i = 0; i < (int)sizeof(na->au.au_pw); i++) (void)printf("%02x ", na->au.au_pw[i]); putc('\n', stdout); + if (md5_authed && n+1 > lim + && na->a_type == ntohs(1)) { + MD5Init(&md5_ctx); + MD5Update(&md5_ctx, (u_char *)&IMSG, + (char *)na-(char *)&IMSG); + MD5Update(&md5_ctx, (u_char *)passwd, + RIP_AUTH_MD5_LEN); + MD5Final(hash, &md5_ctx); + (void)printf(" %s hash\n", + memcmp(hash, na->au.au_pw, + sizeof(hash)) + ? "WRONG" : "correct"); + } continue; } else { @@ -685,7 +756,7 @@ rip_input(struct sockaddr_in *from, } (void)printf(" %-18s metric %2d %-10s", - net_buf, ntohl(n->n_metric), name); + net_buf, (int)ntohl(n->n_metric), name); if (n->n_nhop != 0) { in.s_addr = n->n_nhop; @@ -740,11 +811,11 @@ getnet(char *name, /* Detect and separate "1.2.3.4/24" */ - if (0 != (mname = rindex(name,'/'))) { + if (0 != (mname = strrchr(name,'/'))) { i = (int)(mname - name); - if (i > sizeof(hname)-1) /* name too long */ + if (i > (int)sizeof(hname)-1) /* name too long */ return 0; - bcopy(name, hname, i); + memmove(hname, name, i); hname[i] = '\0'; mname++; name = hname; @@ -781,12 +852,13 @@ getnet(char *name, */ static int /* -1=bad */ parse_quote(char **linep, - char *delims, + const char *delims, char *delimp, char *buf, int lim) { - char c, *pc, *p; + char c, *pc; + const char *p; pc = *linep; diff --git a/sbin/routed/table.c b/sbin/routed/table.c index 1d95b12d171a..fa01db3a8e20 100644 --- a/sbin/routed/table.c +++ b/sbin/routed/table.c @@ -11,7 +11,7 @@ * 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: + * must display the following acknowledgment: * 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 @@ -29,19 +29,28 @@ * 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. + * + * $Id$ */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93"; -#endif -static const char rcsid[] = - "$Id$"; -#endif /* not lint */ - #include "defs.h" +#if !defined(sgi) && !defined(__NetBSD__) +static char sccsid[] __attribute__((unused)) = "@(#)tables.c 8.1 (Berkeley) 6/5/93"; +#elif defined(__NetBSD__) +__RCSID("$NetBSD$"); +#endif +#ident "$Revision: 2.17 $" + static struct rt_spare *rts_better(struct rt_entry *); +static struct rt_spare rts_empty = {0,0,0,HOPCNT_INFINITY,0,0,0}; +static void set_need_flash(void); +#ifdef _HAVE_SIN_LEN +static void masktrim(struct sockaddr_in *ap); +#else +static void masktrim(struct sockaddr_in_new *ap); +#endif + struct radix_node_head *rhead; /* root of the radix tree */ @@ -117,6 +126,10 @@ ag_out(struct ag_info *ag, naddr bit; + /* Forget it if this route should not be output for split-horizon. */ + if (ag->ag_state & AGS_SPLIT_HZ) + return; + /* If we output both the even and odd twins, then the immediate parent, * if it is present, is redundant, unless the parent manages to * aggregate into something coarser. @@ -142,12 +155,14 @@ ag_out(struct ag_info *ag, */ if (ag->ag_state & AGS_REDUN0) { if (ag->ag_state & AGS_REDUN1) - return; + return; /* quit if fully redundant */ + /* make it finer if it is half-redundant */ bit = (-ag->ag_mask) >> 1; ag->ag_dst_h |= bit; ag->ag_mask |= bit; } else if (ag->ag_state & AGS_REDUN1) { + /* make it finer if it is half-redundant */ bit = (-ag->ag_mask) >> 1; ag->ag_mask |= bit; } @@ -234,6 +249,8 @@ ag_flush(naddr lim_dst_h, /* flush routes to here */ /* If the coarse route has a good enough * metric, it suppresses the target. + * If the suppressed target was redundant, + * then mark the suppressor redundant. */ if (ag_cors->ag_pref <= ag->ag_pref) { if (ag_cors->ag_seqno > ag->ag_seqno) @@ -331,6 +348,9 @@ ag_check(naddr dst, || (ag_cors->ag_state & AGS_CORS_GATE))) { if (ag_cors->ag_seqno > ag->ag_seqno) ag_cors->ag_seqno = ag->ag_seqno; + /* If the suppressed target was redundant, + * then mark the suppressor redundant. + */ if (AG_IS_REDUN(ag->ag_state) && ag_cors->ag_mask==ag->ag_mask<<1) { if (ag_cors->ag_dst_h == dst) @@ -373,11 +393,11 @@ ag_check(naddr dst, * Routes are encountered in lexical order, so a * route is never promoted until the parent route is * already present. So we know that the new route is - * a promoted pair and the route already in the slot - * is the explicit route. + * a promoted (or aggregated) pair and the route + * already in the slot is the explicit route. * * Prefer the best route if their metrics differ, - * or the promoted one if not, following a sort + * or the aggregated one if not, following a sort * of longest-match rule. */ if (pref <= ag->ag_pref) { @@ -397,9 +417,13 @@ ag_check(naddr dst, if (ag->ag_seqno > seqno) ag->ag_seqno = seqno; - /* some bits are set if they are set on either route */ - ag->ag_state |= (state & (AGS_PROMOTE_EITHER - | AGS_REDUN0 | AGS_REDUN1)); + /* Some bits are set if they are set on either route, + * except when the route is for an interface. + */ + if (!(ag->ag_state & AGS_IF)) + ag->ag_state |= (state & (AGS_AGGREGATE_EITHER + | AGS_REDUN0 + | AGS_REDUN1)); return; } @@ -407,12 +431,12 @@ ag_check(naddr dst, * be suppressed, it may be possible to combine them or * worthwhile to promote one. * - * Note that any route that can be promoted is always + * Any route that can be promoted is always * marked to be eligible to be suppressed. */ - if (!((state & AGS_PROMOTE) + if (!((state & AGS_AGGREGATE) && (ag->ag_state & AGS_SUPPRESS)) - && !((ag->ag_state & AGS_PROMOTE) + && !((ag->ag_state & AGS_AGGREGATE) && (state & AGS_SUPPRESS))) break; @@ -424,13 +448,13 @@ ag_check(naddr dst, || AG_IS_REDUN(state) || (ag->ag_gate == gate && ag->ag_pref == pref - && (state & ag->ag_state & AGS_PROMOTE) != 0)) { + && (state & ag->ag_state & AGS_AGGREGATE) != 0)) { /* We have both the even and odd pairs. * Since the routes are encountered in order, * the route in the slot must be the even twin. * - * Combine and promote the pair of routes. + * Combine and promote (aggregate) the pair of routes. */ if (seqno > ag->ag_seqno) seqno = ag->ag_seqno; @@ -440,7 +464,7 @@ ag_check(naddr dst, state |= AGS_REDUN0; else state &= ~AGS_REDUN0; - state |= (ag->ag_state & AGS_PROMOTE_EITHER); + state |= (ag->ag_state & AGS_AGGREGATE_EITHER); if (ag->ag_tag != tag) tag = 0; if (ag->ag_nhop != nhop) @@ -452,7 +476,7 @@ ag_check(naddr dst, ag_del(ag); } else if (ag->ag_pref >= pref - && (ag->ag_state & AGS_PROMOTE)) { + && (ag->ag_state & AGS_AGGREGATE)) { /* If we cannot combine the pair, maybe the route * with the worse metric can be promoted. * @@ -473,11 +497,17 @@ ag_check(naddr dst, ag->ag_tag = tag; tag = x; + /* The promoted route is even-redundant only if the + * even twin was fully redundant. It is not + * odd-redundant because the odd-twin will still be + * in the table. + */ x = ag->ag_state; + if (!AG_IS_REDUN(x)) + x &= ~AGS_REDUN0; + x &= ~AGS_REDUN1; ag->ag_state = state; state = x; - if (!AG_IS_REDUN(state)) - state &= ~AGS_REDUN0; x = ag->ag_metric; ag->ag_metric = metric; @@ -487,24 +517,30 @@ ag_check(naddr dst, ag->ag_pref = pref; pref = x; + /* take the newest sequence number */ if (seqno >= ag->ag_seqno) seqno = ag->ag_seqno; else ag->ag_seqno = seqno; } else { - if (!(state & AGS_PROMOTE)) + if (!(state & AGS_AGGREGATE)) break; /* cannot promote either twin */ - /* promote the new, odd twin by shaving its + /* Promote the new, odd twin by shaving its * mask and address. + * The promoted route is odd-redundant only if the + * odd twin was fully redundant. It is not + * even-redundant because the even twin is still in + * the table. */ + if (!AG_IS_REDUN(state)) + state &= ~AGS_REDUN1; + state &= ~AGS_REDUN0; if (seqno > ag->ag_seqno) seqno = ag->ag_seqno; else ag->ag_seqno = seqno; - if (!AG_IS_REDUN(state)) - state &= ~AGS_REDUN1; } mask <<= 1; @@ -581,10 +617,10 @@ ag_check(naddr dst, } -static char * +static const char * rtm_type_name(u_char type) { - static char *rtm_types[] = { + static const char *rtm_types[] = { "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", @@ -614,8 +650,8 @@ rtm_type_name(u_char type) /* Trim a mask in a sockaddr - * Produce the index of the first zero byte. - * i.e. Produce a index of 4 for an mask of 0. (default route) + * Produce a length of 0 for an address of 0. + * Otherwise produce the index of the first zero byte. */ void #ifdef _HAVE_SIN_LEN @@ -624,13 +660,15 @@ masktrim(struct sockaddr_in *ap) masktrim(struct sockaddr_in_new *ap) #endif { - register char *cp; + char *cp; - ap->sin_port = 0xffff; /* buffer zone for default route */ + if (ap->sin_addr.s_addr == 0) { + ap->sin_len = 0; + return; + } cp = (char *)(&ap->sin_addr.s_addr+1); while (*--cp == 0) continue; - /*ap->sin_port = 0x0;*/ /* may not be needed (who cares?)*/ ap->sin_len = cp - (char*)ap + 1; } @@ -656,16 +694,18 @@ rtioctl(int action, /* RTM_DELETE, etc */ #endif } w; long cc; +# define PAT " %-10s %s metric=%d flags=%#x" +# define ARGS rtm_type_name(action), rtname(dst,mask,gate), metric, flags again: - bzero(&w, sizeof(w)); + memset(&w, 0, sizeof(w)); w.w_rtm.rtm_msglen = sizeof(w); w.w_rtm.rtm_version = RTM_VERSION; w.w_rtm.rtm_type = action; w.w_rtm.rtm_flags = flags; w.w_rtm.rtm_seq = ++rt_sock_seqno; w.w_rtm.rtm_addrs = RTA_DST|RTA_GATEWAY; - if (metric != 0) { + if (metric != 0 || action == RTM_CHANGE) { w.w_rtm.rtm_rmx.rmx_hopcount = metric; w.w_rtm.rtm_inits |= RTV_HOPCOUNT; } @@ -685,41 +725,36 @@ rtioctl(int action, /* RTM_DELETE, etc */ w.w_mask.sin_addr.s_addr = htonl(mask); #ifdef _HAVE_SA_LEN masktrim(&w.w_mask); + if (w.w_mask.sin_len == 0) + w.w_mask.sin_len = sizeof(long); w.w_rtm.rtm_msglen -= (sizeof(w.w_mask) - w.w_mask.sin_len); #endif } - if (TRACEKERNEL) - trace_kernel("write kernel %s %s->%s metric=%d flags=%#x\n", - rtm_type_name(action), - addrname(dst, mask, 0), naddr_ntoa(gate), - metric, flags); - #ifndef NO_INSTALL cc = write(rt_sock, &w, w.w_rtm.rtm_msglen); - if (cc == w.w_rtm.rtm_msglen) - return; if (cc < 0) { if (errno == ESRCH && (action == RTM_CHANGE || action == RTM_DELETE)) { - trace_act("route to %s disappeared before %s", - addrname(dst, mask, 0), - rtm_type_name(action)); + trace_act("route disappeared before" PAT, ARGS); if (action == RTM_CHANGE) { action = RTM_ADD; goto again; } return; } - msglog("write(rt_sock) %s %s --> %s: %s", - rtm_type_name(action), - addrname(dst, mask, 0), naddr_ntoa(gate), - strerror(errno)); - } else { - msglog("write(rt_sock) wrote %d instead of %d", - cc, w.w_rtm.rtm_msglen); + msglog("write(rt_sock)" PAT ": %s", ARGS, strerror(errno)); + return; + } else if (cc != w.w_rtm.rtm_msglen) { + msglog("write(rt_sock) wrote %ld instead of %d for" PAT, + cc, w.w_rtm.rtm_msglen, ARGS); + return; } #endif + if (TRACEKERNEL) + trace_misc("write kernel" PAT, ARGS); +#undef PAT +#undef ARGS } @@ -733,14 +768,15 @@ static struct khash { short k_metric; u_short k_state; #define KS_NEW 0x001 -#define KS_DELETE 0x002 +#define KS_DELETE 0x002 /* need to delete the route */ #define KS_ADD 0x004 /* add to the kernel */ #define KS_CHANGE 0x008 /* tell kernel to change the route */ #define KS_DEL_ADD 0x010 /* delete & add to change the kernel */ #define KS_STATIC 0x020 /* Static flag in kernel */ #define KS_GATEWAY 0x040 /* G flag in kernel */ #define KS_DYNAMIC 0x080 /* result of redirect */ -#define KS_DELETED 0x100 /* already deleted */ +#define KS_DELETED 0x100 /* already deleted from kernel */ +#define KS_CHECK 0x200 time_t k_keep; #define K_KEEP_LIM 30 time_t k_redirect_time; /* when redirected route 1st seen */ @@ -773,7 +809,7 @@ kern_add(naddr dst, naddr mask) k = (struct khash *)rtmalloc(sizeof(*k), "kern_add"); - bzero(k, sizeof(*k)); + memset(k, 0, sizeof(*k)); k->k_dst = dst; k->k_mask = mask; k->k_state = KS_NEW; @@ -792,26 +828,58 @@ kern_check_static(struct khash *k, struct interface *ifp) { struct rt_entry *rt; - naddr int_addr; + struct rt_spare new; if (k->k_metric == 0) return; - int_addr = (ifp != 0) ? ifp->int_addr : loopaddr; + memset(&new, 0, sizeof(new)); + new.rts_ifp = ifp; + new.rts_gate = k->k_gate; + new.rts_router = (ifp != 0) ? ifp->int_addr : loopaddr; + new.rts_metric = k->k_metric; + new.rts_time = now.tv_sec; rt = rtget(k->k_dst, k->k_mask); if (rt != 0) { if (!(rt->rt_state & RS_STATIC)) - rtchange(rt, rt->rt_state | RS_STATIC, - k->k_gate, int_addr, - k->k_metric, 0, ifp, now.tv_sec, 0); + rtchange(rt, rt->rt_state | RS_STATIC, &new, 0); } else { - rtadd(k->k_dst, k->k_mask, k->k_gate, int_addr, - k->k_metric, 0, RS_STATIC, ifp); + rtadd(k->k_dst, k->k_mask, RS_STATIC, &new); } } +/* operate on a kernel entry + */ +static void +kern_ioctl(struct khash *k, + int action, /* RTM_DELETE, etc */ + int flags) + +{ + switch (action) { + case RTM_DELETE: + k->k_state &= ~KS_DYNAMIC; + if (k->k_state & KS_DELETED) + return; + k->k_state |= KS_DELETED; + break; + case RTM_ADD: + k->k_state &= ~KS_DELETED; + break; + case RTM_CHANGE: + if (k->k_state & KS_DELETED) { + action = RTM_ADD; + k->k_state &= ~KS_DELETED; + } + break; + } + + rtioctl(action, k->k_dst, k->k_gate, k->k_mask, k->k_metric, flags); +} + + /* add a route the kernel told us */ static void @@ -833,23 +901,29 @@ rtm_add(struct rt_msghdr *rtm, return; } - if (INFO_GATE(info) == 0 - || INFO_GATE(info)->sa_family != AF_INET) { - msglog("ignore %s without gateway", - rtm_type_name(rtm->rtm_type)); - return; - } - k = kern_add(S_ADDR(INFO_DST(info)), mask); if (k->k_state & KS_NEW) k->k_keep = now.tv_sec+keep; - k->k_gate = S_ADDR(INFO_GATE(info)); - k->k_metric = rtm->rtm_rmx.rmx_hopcount; - if (k->k_metric < 0) - k->k_metric = 0; - else if (k->k_metric > HOPCNT_INFINITY) - k->k_metric = HOPCNT_INFINITY; - k->k_state &= ~(KS_DELETED | KS_GATEWAY | KS_STATIC | KS_NEW); + if (INFO_GATE(info) == 0) { + trace_act("note %s without gateway", + rtm_type_name(rtm->rtm_type)); + k->k_metric = HOPCNT_INFINITY; + } else if (INFO_GATE(info)->sa_family != AF_INET) { + trace_act("note %s with gateway AF=%d", + rtm_type_name(rtm->rtm_type), + INFO_GATE(info)->sa_family); + k->k_metric = HOPCNT_INFINITY; + } else { + k->k_gate = S_ADDR(INFO_GATE(info)); + k->k_metric = rtm->rtm_rmx.rmx_hopcount; + if (k->k_metric < 0) + k->k_metric = 0; + else if (k->k_metric > HOPCNT_INFINITY-1) + k->k_metric = HOPCNT_INFINITY-1; + } + k->k_state &= ~(KS_DELETE | KS_ADD | KS_CHANGE | KS_DEL_ADD + | KS_DELETED | KS_GATEWAY | KS_STATIC + | KS_NEW | KS_CHECK); if (rtm->rtm_flags & RTF_GATEWAY) k->k_state |= KS_GATEWAY; if (rtm->rtm_flags & RTF_STATIC) @@ -923,44 +997,104 @@ rtm_lose(struct rt_msghdr *rtm, return; } - if (!supplier) + if (rdisc_ok) rdisc_age(S_ADDR(INFO_GATE(info))); - age(S_ADDR(INFO_GATE(info))); } +/* Make the gateway slot of an info structure point to something + * useful. If it is not already useful, but it specifies an interface, + * then fill in the sockaddr_in provided and point it there. + */ +static int +get_info_gate(struct sockaddr **sap, + struct sockaddr_in *sin) +{ + struct sockaddr_dl *sdl = (struct sockaddr_dl *)*sap; + struct interface *ifp; + + if (sdl == 0) + return 0; + if ((sdl)->sdl_family == AF_INET) + return 1; + if ((sdl)->sdl_family != AF_LINK) + return 0; + + ifp = ifwithindex(sdl->sdl_index, 1); + if (ifp == 0) + return 0; + + sin->sin_addr.s_addr = ifp->int_addr; +#ifdef _HAVE_SA_LEN + sin->sin_len = sizeof(*sin); +#endif + sin->sin_family = AF_INET; + *sap = (struct sockaddr*)sin; + + return 1; +} + + /* Clean the kernel table by copying it to the daemon image. * Eventually the daemon will delete any extra routes. */ void flush_kern(void) { + static char *sysctl_buf; + static size_t sysctl_buf_size = 0; size_t needed; int mib[6]; - char *buf, *next, *lim; + char *next, *lim; struct rt_msghdr *rtm; - struct interface *ifp; - static struct sockaddr_in gate_sa; + struct sockaddr_in gate_sin; struct rt_addrinfo info; + int i; + struct khash *k; + for (i = 0; i < KHASH_SIZE; i++) { + for (k = khash_bins[i]; k != 0; k = k->k_next) { + k->k_state |= KS_CHECK; + } + } + mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; /* protocol */ mib[3] = 0; /* wildcard address family */ mib[4] = NET_RT_DUMP; mib[5] = 0; /* no flags */ - if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) { - DBGERR(1,"RT_DUMP-sysctl-estimate"); - return; + 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,"flush_kern: sysctl(RT_DUMP)"); + free(sysctl_buf); + needed = 0; + } + if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) + BADERR(1,"flush_kern: sysctl(RT_DUMP) estimate"); + /* Kludge around the habit of some systems, such as + * BSD/OS 3.1, to not admit how many routes are in the + * kernel, or at least to be quite wrong. + */ + needed += 50*(sizeof(*rtm)+5*sizeof(struct sockaddr)); + sysctl_buf = rtmalloc(sysctl_buf_size = needed, + "flush_kern sysctl(RT_DUMP)"); } - buf = (char *)rtmalloc(needed, "flush_kern"); - if (sysctl(mib, 6, buf, &needed, 0, 0) < 0) - BADERR(1,"RT_DUMP"); - lim = buf + needed; - for (next = buf; next < lim; next += rtm->rtm_msglen) { + + lim = sysctl_buf + needed; + for (next = sysctl_buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; + if (rtm->rtm_msglen == 0) { + msglog("zero length kernel route at " + " %#lx in buffer %#lx before %#lx", + (u_long)rtm, (u_long)sysctl_buf, (u_long)lim); + break; + } rt_xaddrs(&info, (struct sockaddr *)(rtm+1), @@ -977,32 +1111,14 @@ flush_kern(void) if (rtm->rtm_flags & RTF_LLINFO) continue; - if (INFO_GATE(&info) == 0) - continue; - if (INFO_GATE(&info)->sa_family != AF_INET) { - if (INFO_GATE(&info)->sa_family != AF_LINK) - continue; - ifp = ifwithindex(((struct sockaddr_dl *) - INFO_GATE(&info))->sdl_index); - if (ifp == 0) - continue; - if ((ifp->int_if_flags & IFF_POINTOPOINT) - || S_ADDR(INFO_DST(&info)) == ifp->int_addr) - gate_sa.sin_addr.s_addr = ifp->int_addr; - else - gate_sa.sin_addr.s_addr = htonl(ifp->int_net); -#ifdef _HAVE_SA_LEN - gate_sa.sin_len = sizeof(gate_sa); -#endif - gate_sa.sin_family = AF_INET; - INFO_GATE(&info) = (struct sockaddr *)&gate_sa; - } - /* ignore multicast addresses */ if (IN_MULTICAST(ntohl(S_ADDR(INFO_DST(&info))))) continue; + if (!get_info_gate(&INFO_GATE(&info), &gate_sin)) + continue; + /* Note static routes and interface routes, and also * preload the image of the kernel table so that * we can later clean it, as well as avoid making @@ -1012,7 +1128,17 @@ flush_kern(void) */ rtm_add(rtm,&info,MIN_WAITTIME); } - free(buf); + + for (i = 0; i < KHASH_SIZE; i++) { + for (k = khash_bins[i]; k != 0; k = k->k_next) { + if (k->k_state & KS_CHECK) { + msglog("%s --> %s disappeared from kernel", + addrname(k->k_dst, k->k_mask, 0), + naddr_ntoa(k->k_gate)); + del_static(k->k_dst, k->k_mask, k->k_gate, 1); + } + } + } } @@ -1023,7 +1149,8 @@ read_rt(void) { long cc; struct interface *ifp; - naddr mask; + struct sockaddr_in gate_sin; + naddr mask, gate; union { struct { struct rt_msghdr rtm; @@ -1064,10 +1191,11 @@ read_rt(void) if (m.r.rtm.rtm_type == RTM_IFINFO || m.r.rtm.rtm_type == RTM_NEWADDR || m.r.rtm.rtm_type == RTM_DELADDR) { - ifp = ifwithindex(m.ifm.ifm_index); + ifp = ifwithindex(m.ifm.ifm_index, + m.r.rtm.rtm_type != RTM_DELADDR); if (ifp == 0) trace_act("note %s with flags %#x" - " for index #%d", + " for unknown interface index #%d", rtm_type_name(m.r.rtm.rtm_type), m.ifm.ifm_flags, m.ifm.ifm_index); @@ -1086,7 +1214,7 @@ read_rt(void) if (ifinit_timer.tv_sec-now.tv_sec>=CHECK_BAD_INTERVAL || ifp == 0 || ((ifp->int_if_flags ^ m.ifm.ifm_flags) - & IFF_UP_RUNNING) != 0) + & IFF_UP) != 0) ifinit_timer.tv_sec = now.tv_sec; continue; } @@ -1124,10 +1252,17 @@ read_rt(void) continue; } - if (INFO_GATE(&info) != 0 - && INFO_GATE(&info)->sa_family == AF_INET) - strp += sprintf(strp, " --> %s", - saddr_ntoa(INFO_GATE(&info))); + if (m.r.rtm.rtm_flags & RTF_LLINFO) { + trace_act("ignore ARP %s", str); + continue; + } + + if (get_info_gate(&INFO_GATE(&info), &gate_sin)) { + gate = S_ADDR(INFO_GATE(&info)); + strp += sprintf(strp, " --> %s", naddr_ntoa(gate)); + } else { + gate = 0; + } if (INFO_AUTHOR(&info) != 0) strp += sprintf(strp, " by authority of %s", @@ -1147,12 +1282,14 @@ read_rt(void) break; case RTM_DELETE: - if (m.r.rtm.rtm_errno != 0) { + if (m.r.rtm.rtm_errno != 0 + && m.r.rtm.rtm_errno != ESRCH) { trace_act("ignore %s with \"%s\" error", str, strerror(m.r.rtm.rtm_errno)); } else { trace_act("%s", str); - del_static(S_ADDR(INFO_DST(&info)), mask, 1); + del_static(S_ADDR(INFO_DST(&info)), mask, + gate, 1); } break; @@ -1205,12 +1342,20 @@ kern_out(struct ag_info *ag) /* modify existing kernel entry if necessary */ if (k->k_gate != ag->ag_gate || k->k_metric != ag->ag_metric) { + /* Must delete bad interface routes etc. to change them. */ + if (k->k_metric == HOPCNT_INFINITY) + k->k_state |= KS_DEL_ADD; k->k_gate = ag->ag_gate; k->k_metric = ag->ag_metric; k->k_state |= KS_CHANGE; } - if (k->k_state & KS_DYNAMIC) { + /* If the daemon thinks the route should exist, forget + * about any redirections. + * If the daemon thinks the route should exist, eventually + * override manual intervention by the operator. + */ + if ((k->k_state & (KS_DYNAMIC | KS_DELETED)) != 0) { k->k_state &= ~KS_DYNAMIC; k->k_state |= (KS_ADD | KS_DEL_ADD); } @@ -1241,7 +1386,7 @@ kern_out(struct ag_info *ag) /* ARGSUSED */ static int walk_kern(struct radix_node *rn, - struct walkarg *w) + struct walkarg *argp UNUSED) { #define RT ((struct rt_entry *)rn) char metric, pref; @@ -1253,15 +1398,33 @@ walk_kern(struct radix_node *rn, return 0; if (!(RT->rt_state & RS_IF)) { - ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_PROMOTE); + /* This is an ordinary route, not for an interface. + */ + + /* aggregate, ordinary good routes without regard to + * their metric + */ + pref = 1; + ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_AGGREGATE); + + /* Do not install host routes directly to hosts, to avoid + * interfering with ARP entries in the kernel table. + */ + if (RT_ISHOST(RT) + && ntohl(RT->rt_dst) == RT->rt_gate) + return 0; } else { - /* Do not install routes for "external" remote interfaces. + /* This is an interface route. + * Do not install routes for "external" remote interfaces. */ if (RT->rt_ifp != 0 && (RT->rt_ifp->int_state & IS_EXTERNAL)) return 0; - ags |= AGS_IF; + /* Interfaces should override received routes. + */ + pref = 0; + ags |= (AGS_IF | AGS_CORS_GATE); /* If it is not an interface, or an alias for an interface, * it must be a "gateway." @@ -1271,19 +1434,23 @@ walk_kern(struct radix_node *rn, */ if (RT->rt_ifp == 0 || (RT->rt_ifp->int_state & IS_REMOTE)) - ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_PROMOTE); + ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_AGGREGATE); } - if (RT->rt_state & RS_RDISC) + /* If RIP is off and IRDP is on, let the route to the discovered + * route suppress any RIP routes. Eventually the RIP routes + * will time-out and be deleted. This reaches the steady-state + * quicker. + */ + if ((RT->rt_state & RS_RDISC) && rip_sock < 0) ags |= AGS_CORS_GATE; - /* aggregate good routes without regard to their metric */ - pref = 1; metric = RT->rt_metric; if (metric == HOPCNT_INFINITY) { /* if the route is dead, so try hard to aggregate. */ pref = HOPCNT_INFINITY; ags |= (AGS_FINE_GATE | AGS_SUPPRESS); + ags &= ~(AGS_IF | AGS_CORS_GATE); } ag_check(RT->rt_dst, RT->rt_mask, RT->rt_gate, 0, @@ -1298,7 +1465,7 @@ walk_kern(struct radix_node *rn, static void fix_kern(void) { - int i, flags; + int i; struct khash *k, **pk; @@ -1320,46 +1487,37 @@ fix_kern(void) /* check hold on routes deleted by the operator */ if (k->k_keep > now.tv_sec) { + /* ensure we check when the hold is over */ LIM_SEC(need_kern, k->k_keep); + /* mark for the next cycle */ k->k_state |= KS_DELETE; pk = &k->k_next; continue; } - if ((k->k_state & (KS_DELETE | KS_DYNAMIC)) - == KS_DELETE) { - if (!(k->k_state & KS_DELETED)) - rtioctl(RTM_DELETE, - k->k_dst, k->k_gate, k->k_mask, - 0, 0); + if ((k->k_state & KS_DELETE) + && !(k->k_state & KS_DYNAMIC)) { + kern_ioctl(k, RTM_DELETE, 0); *pk = k->k_next; free(k); continue; } - if (0 != (k->k_state&(KS_ADD|KS_CHANGE|KS_DEL_ADD))) { - if (k->k_state & KS_DEL_ADD) { - rtioctl(RTM_DELETE, - k->k_dst,k->k_gate,k->k_mask, - 0, 0); - k->k_state &= ~KS_DYNAMIC; - } + if (k->k_state & KS_DEL_ADD) + kern_ioctl(k, RTM_DELETE, 0); - flags = 0; - if (0 != (k->k_state&(KS_GATEWAY|KS_DYNAMIC))) - flags |= RTF_GATEWAY; - - if (k->k_state & KS_ADD) { - rtioctl(RTM_ADD, - k->k_dst, k->k_gate, k->k_mask, - k->k_metric, flags); - } else if (k->k_state & KS_CHANGE) { - rtioctl(RTM_CHANGE, - k->k_dst,k->k_gate,k->k_mask, - k->k_metric, flags); - } - k->k_state &= ~(KS_ADD|KS_CHANGE|KS_DEL_ADD); + if (k->k_state & KS_ADD) { + kern_ioctl(k, RTM_ADD, + ((0 != (k->k_state & (KS_GATEWAY + | KS_DYNAMIC))) + ? RTF_GATEWAY : 0)); + } else if (k->k_state & KS_CHANGE) { + kern_ioctl(k, RTM_CHANGE, + ((0 != (k->k_state & (KS_GATEWAY + | KS_DYNAMIC))) + ? RTF_GATEWAY : 0)); } + k->k_state &= ~(KS_ADD|KS_CHANGE|KS_DEL_ADD); /* Mark this route to be deleted in the next cycle. * This deletes routes that disappear from the @@ -1379,6 +1537,7 @@ fix_kern(void) void del_static(naddr dst, naddr mask, + naddr gate, int gone) { struct khash *k; @@ -1392,8 +1551,8 @@ del_static(naddr dst, * and add a replacement. */ k = kern_find(dst, mask, 0); - if (k != 0) { - k->k_state &= ~(KS_STATIC | KS_DYNAMIC); + if (k != 0 && (gate == 0 || k->k_gate == gate)) { + k->k_state &= ~(KS_STATIC | KS_DYNAMIC | KS_CHECK); k->k_state |= KS_DELETE; if (gone) { k->k_state |= KS_DELETED; @@ -1442,10 +1601,11 @@ del_redirects(naddr bad_gate, /* Start the daemon tables. */ +extern int max_keylen; + void rtinit(void) { - extern int max_keylen; int i; struct ag_info *ag; @@ -1472,7 +1632,7 @@ static struct sockaddr_in_new mask_sock = {_SIN_ADDR_SIZE, AF_INET}; #endif -void +static void set_need_flash(void) { if (!need_flash) { @@ -1520,12 +1680,8 @@ rtfind(naddr dst) void rtadd(naddr dst, naddr mask, - naddr gate, /* forward packets here */ - naddr router, /* on the authority of this router */ - int metric, - u_short tag, - u_int state, /* rs_state for the entry */ - struct interface *ifp) + u_int state, /* rt_state for the entry */ + struct rt_spare *new) { struct rt_entry *rt; naddr smask; @@ -1533,7 +1689,7 @@ rtadd(naddr dst, struct rt_spare *rts; rt = (struct rt_entry *)rtmalloc(sizeof (*rt), "rtadd"); - bzero(rt, sizeof(*rt)); + memset(rt, 0, sizeof(*rt)); for (rts = rt->rt_spares, i = NUM_SPARES; i != 0; i--, rts++) rts->rts_metric = HOPCNT_INFINITY; @@ -1552,13 +1708,9 @@ rtadd(naddr dst, masktrim(&mask_sock); rt->rt_mask = mask; rt->rt_state = state; - rt->rt_gate = gate; - rt->rt_router = router; + rt->rt_spares[0] = *new; rt->rt_time = now.tv_sec; - rt->rt_metric = metric; rt->rt_poison_metric = HOPCNT_INFINITY; - rt->rt_tag = tag; - rt->rt_ifp = ifp; rt->rt_seqno = update_seqno; if (++total_routes == MAX_ROUTES) @@ -1571,15 +1723,8 @@ rtadd(naddr dst, if (0 == rhead->rnh_addaddr(&rt->rt_dst_sock, &mask_sock, rhead, rt->rt_nodes)) { -/* - * This will happen if RIP1 and RIP2 routeds talk to one another and - * there are variable subnets. This is only good for filling up your - * syslog. -jkh - */ -#if 0 - msglog("rnh_addaddr() failed for %s mask=%#x", - naddr_ntoa(dst), mask); -#endif + msglog("rnh_addaddr() failed for %s mask=%#lx", + naddr_ntoa(dst), (u_long)mask); } } @@ -1589,29 +1734,24 @@ rtadd(naddr dst, void rtchange(struct rt_entry *rt, u_int state, /* new state bits */ - naddr gate, /* now forward packets here */ - naddr router, /* on the authority of this router */ - int metric, /* new metric */ - u_short tag, - struct interface *ifp, - time_t new_time, + struct rt_spare *new, char *label) { - if (rt->rt_metric != metric) { + if (rt->rt_metric != new->rts_metric) { /* Fix the kernel immediately if it seems the route * has gone bad, since there may be a working route that * aggregates this route. */ - if (metric == HOPCNT_INFINITY) { + if (new->rts_metric == HOPCNT_INFINITY) { need_kern.tv_sec = now.tv_sec; - if (new_time >= now.tv_sec - EXPIRE_TIME) - new_time = now.tv_sec - EXPIRE_TIME; + if (new->rts_time >= now.tv_sec - EXPIRE_TIME) + new->rts_time = now.tv_sec - EXPIRE_TIME; } rt->rt_seqno = update_seqno; set_need_flash(); } - if (rt->rt_gate != gate) { + if (rt->rt_gate != new->rts_gate) { need_kern.tv_sec = now.tv_sec; rt->rt_seqno = update_seqno; set_need_flash(); @@ -1621,21 +1761,15 @@ rtchange(struct rt_entry *rt, /* Keep various things from deciding ageless routes are stale. */ - if (!AGE_RT(state, ifp)) - new_time = now.tv_sec; + if (!AGE_RT(state, new->rts_ifp)) + new->rts_time = now.tv_sec; if (TRACEACTIONS) - trace_change(rt, state, gate, router, metric, tag, ifp, - new_time, + trace_change(rt, state, new, label ? label : "Chg "); rt->rt_state = state; - rt->rt_gate = gate; - rt->rt_router = router; - rt->rt_metric = metric; - rt->rt_tag = tag; - rt->rt_ifp = ifp; - rt->rt_time = new_time; + rt->rt_spares[0] = *new; } @@ -1683,11 +1817,13 @@ rtswitch(struct rt_entry *rt, return; swap = rt->rt_spares[0]; - (void)sprintf(label, "Use #%d", rts - rt->rt_spares); - rtchange(rt, rt->rt_state & ~(RS_NET_SYN | RS_RDISC), - rts->rts_gate, rts->rts_router, rts->rts_metric, - rts->rts_tag, rts->rts_ifp, rts->rts_time, label); - *rts = swap; + (void)sprintf(label, "Use #%d", (int)(rts - rt->rt_spares)); + rtchange(rt, rt->rt_state & ~(RS_NET_SYN | RS_RDISC), rts, label); + if (swap.rts_metric == HOPCNT_INFINITY) { + *rts = rts_empty; + } else { + *rts = swap; + } } @@ -1719,16 +1855,26 @@ rtdelete(struct rt_entry *rt) } +void +rts_delete(struct rt_entry *rt, + struct rt_spare *rts) +{ + trace_upslot(rt, rts, &rts_empty); + *rts = rts_empty; +} + + /* Get rid of a bad route, and try to switch to a replacement. */ void rtbad(struct rt_entry *rt) { - /* Poison the route */ - rtchange(rt, rt->rt_state & ~(RS_IF | RS_LOCAL | RS_STATIC), - rt->rt_gate, rt->rt_router, HOPCNT_INFINITY, rt->rt_tag, - 0, rt->rt_time, 0); + struct rt_spare new; + /* Poison the route */ + new = rt->rt_spares[0]; + new.rts_metric = HOPCNT_INFINITY; + rtchange(rt, rt->rt_state & ~(RS_IF | RS_LOCAL | RS_STATIC), &new, 0); rtswitch(rt, 0); } @@ -1793,10 +1939,10 @@ rtbad_sub(struct rt_entry *rt) } if (ifp1 != 0 || (state & RS_NET_SYN)) { - rtchange(rt, ((rt->rt_state & ~(RS_NET_SYN | RS_LOCAL)) - | state), - rt->rt_gate, rt->rt_router, rt->rt_metric, - rt->rt_tag, ifp1, rt->rt_time, 0); + struct rt_spare new = rt->rt_spares[0]; + new.rts_ifp = ifp1; + rtchange(rt, ((rt->rt_state & ~(RS_NET_SYN|RS_LOCAL)) | state), + &new, 0); } else { rtbad(rt); } @@ -1809,12 +1955,11 @@ rtbad_sub(struct rt_entry *rt) /* ARGSUSED */ int walk_bad(struct radix_node *rn, - struct walkarg *w) + struct walkarg *argp UNUSED) { #define RT ((struct rt_entry *)rn) struct rt_spare *rts; int i; - time_t new_time; /* fix any spare routes through the interface @@ -1822,21 +1967,10 @@ walk_bad(struct radix_node *rn, rts = RT->rt_spares; for (i = NUM_SPARES; i != 1; i--) { rts++; - - if (rts->rts_ifp != 0 - && (rts->rts_ifp->int_state & IS_BROKE)) { - /* mark the spare route to be deleted immediately */ - new_time = rts->rts_time; - if (new_time >= now_garbage) - new_time = now_garbage-1; - trace_upslot(RT, rts, rts->rts_gate, - rts->rts_router, 0, - HOPCNT_INFINITY, rts->rts_tag, - new_time); - rts->rts_ifp = 0; - rts->rts_metric = HOPCNT_INFINITY; - rts->rts_time = new_time; - } + if (rts->rts_metric < HOPCNT_INFINITY + && (rts->rts_ifp == 0 + || (rts->rts_ifp->int_state & IS_BROKE))) + rts_delete(RT, rts); } /* Deal with the main route @@ -1864,7 +1998,7 @@ walk_bad(struct radix_node *rn, /* ARGSUSED */ static int walk_age(struct radix_node *rn, - struct walkarg *w) + struct walkarg *argp UNUSED) { #define RT ((struct rt_entry *)rn) struct interface *ifp; @@ -1905,13 +2039,9 @@ walk_age(struct radix_node *rn, /* trash the spare routes when they go bad */ if (rts->rts_metric < HOPCNT_INFINITY - && now_garbage > rts->rts_time) { - trace_upslot(RT, rts, rts->rts_gate, - rts->rts_router, rts->rts_ifp, - HOPCNT_INFINITY, rts->rts_tag, - rts->rts_time); - rts->rts_metric = HOPCNT_INFINITY; - } + && now_garbage > rts->rts_time + && i != NUM_SPARES) + rts_delete(RT, rts); } @@ -1929,10 +2059,11 @@ walk_age(struct radix_node *rn, } /* Start poisoning a bad route before deleting it. */ - if (now.tv_sec - RT->rt_time > EXPIRE_TIME) - rtchange(RT, RT->rt_state, RT->rt_gate, RT->rt_router, - HOPCNT_INFINITY, RT->rt_tag, RT->rt_ifp, - RT->rt_time, 0); + if (now.tv_sec - RT->rt_time > EXPIRE_TIME) { + struct rt_spare new = RT->rt_spares[0]; + new.rts_metric = HOPCNT_INFINITY; + rtchange(RT, RT->rt_state, &new, 0); + } return 0; } @@ -1961,6 +2092,7 @@ age(naddr bad_gate) /* ignore unreachable remote interfaces */ if (!check_remote(ifp)) continue; + /* Restore remote interface that has become reachable */ if (ifp->int_state & IS_BROKE) @@ -1969,7 +2101,7 @@ age(naddr bad_gate) if (ifp->int_act_time != NEVER && now.tv_sec - ifp->int_act_time > EXPIRE_TIME) { msglog("remote interface %s to %s timed out after" - " %d:%d", + " %ld:%ld", ifp->int_name, naddr_ntoa(ifp->int_dstaddr), (now.tv_sec - ifp->int_act_time)/60, @@ -1990,6 +2122,11 @@ age(naddr bad_gate) age_bad_gate = bad_gate; (void)rn_walktree(rhead, walk_age, 0); + /* delete old redirected routes to keep the kernel table small + * and prevent blackholes + */ + del_redirects(bad_gate, now.tv_sec-STALE_TIME); + /* Update the kernel routing table. */ fix_kern(); diff --git a/sbin/routed/trace.c b/sbin/routed/trace.c index e632cc2d80b1..48d383aafbf1 100644 --- a/sbin/routed/trace.c +++ b/sbin/routed/trace.c @@ -11,7 +11,7 @@ * 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: + * must display the following acknowledgment: * 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 @@ -29,22 +29,25 @@ * 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. + * + * $Id$ */ -#ifndef lint -#if 0 -static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93"; -#endif -static const char rcsid[] = - "$Id$"; -#endif /* not lint */ - #define RIPCMDS #include "defs.h" #include "pathnames.h" #include +#include #include +#if !defined(sgi) && !defined(__NetBSD__) +static char sccsid[] __attribute__((unused)) = "@(#)trace.c 8.1 (Berkeley) 6/5/93"; +#elif defined(__NetBSD__) +__RCSID("$NetBSD$"); +#endif +#ident "$Revision: 2.17 $" + + #ifdef sgi /* use *stat64 for files on large filesystems */ #define stat stat64 @@ -54,12 +57,13 @@ static const char rcsid[] = int tracelevel, new_tracelevel; FILE *ftrace = stdout; /* output trace file */ -static char *sigtrace_pat = "%s\n"; +static const char *sigtrace_pat = "%s"; static char savetracename[MAXPATHLEN+1]; char inittracename[MAXPATHLEN+1]; int file_trace; /* 1=tracing to file, not stdout */ static void trace_dump(void); +static void tmsg(const char *, ...) PATTRIB(1,2); /* convert string to printable characters @@ -136,7 +140,7 @@ naddr_ntoa(naddr a) } -char * +const char * saddr_ntoa(struct sockaddr *sa) { return (sa == 0) ? "?" : naddr_ntoa(S_ADDR(sa)); @@ -151,7 +155,7 @@ ts(time_t secs) { #ifdef sgi (void)cftime(s, "%T", &secs); #else - bcopy(ctime(&secs)+11, s, 8); + memcpy(s, ctime(&secs)+11, 8); s[8] = '\0'; #endif return s; @@ -176,7 +180,7 @@ lastlog(void) static void -tmsg(char *p, ...) +tmsg(const char *p, ...) { va_list args; @@ -184,13 +188,14 @@ tmsg(char *p, ...) lastlog(); va_start(args, p); vfprintf(ftrace, p, args); + (void)fputc('\n',ftrace); fflush(ftrace); } } -static void -trace_close(void) +void +trace_close(int zap_stdio) { int fd; @@ -198,14 +203,17 @@ trace_close(void) fflush(stdout); fflush(stderr); - if (ftrace != 0 && file_trace) { + if (ftrace != 0 && zap_stdio) { if (ftrace != stdout) fclose(ftrace); ftrace = 0; fd = open(_PATH_DEVNULL, O_RDWR); - (void)dup2(fd, STDIN_FILENO); - (void)dup2(fd, STDOUT_FILENO); - (void)dup2(fd, STDERR_FILENO); + if (isatty(STDIN_FILENO)) + (void)dup2(fd, STDIN_FILENO); + if (isatty(STDOUT_FILENO)) + (void)dup2(fd, STDOUT_FILENO); + if (isatty(STDERR_FILENO)) + (void)dup2(fd, STDERR_FILENO); (void)close(fd); } lastlog_time.tv_sec = 0; @@ -218,13 +226,13 @@ trace_flush(void) if (ftrace != 0) { fflush(ftrace); if (ferror(ftrace)) - trace_off("tracing off: ", strerror(ferror(ftrace))); + trace_off("tracing off: %s", strerror(ferror(ftrace))); } } void -trace_off(char *p, ...) +trace_off(const char *p, ...) { va_list args; @@ -233,8 +241,9 @@ trace_off(char *p, ...) lastlog(); va_start(args, p); vfprintf(ftrace, p, args); + (void)fputc('\n',ftrace); } - trace_close(); + trace_close(file_trace); new_tracelevel = tracelevel = 0; } @@ -243,16 +252,16 @@ trace_off(char *p, ...) /* log a change in tracing */ void -tracelevel_msg(char *pat, +tracelevel_msg(const char *pat, int dump) /* -1=no dump, 0=default, 1=force */ { - static char *off_msgs[MAX_TRACELEVEL] = { + static const 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] = { + static const char *on_msgs[MAX_TRACELEVEL] = { "Tracing actions started", "Tracing packets started", "Tracing packet contents started", @@ -287,13 +296,13 @@ tracelevel_msg(char *pat, void -set_tracefile(char *filename, - char *pat, +set_tracefile(const char *filename, + const char *pat, int dump) /* -1=no dump, 0=default, 1=force */ { struct stat stbuf; FILE *n_ftrace; - char *fn; + const char *fn; /* Allow a null filename to increase the level if the trace file @@ -335,8 +344,7 @@ set_tracefile(char *filename, /* If the new tracefile exists, it must be a regular file. */ - if (stat(filename, &stbuf) >= 0 - && (stbuf.st_mode & S_IFMT) != S_IFREG) { + if (stat(filename, &stbuf) >= 0 && !S_ISREG(stbuf.st_mode)) { msglog("wrong type (%#x) of trace file \"%s\"", stbuf.st_mode, filename); return; @@ -355,10 +363,9 @@ set_tracefile(char *filename, return; } - tmsg("switch to trace file %s\n", fn); + tmsg("switch to trace file %s", fn); - file_trace = 1; - trace_close(); + trace_close(file_trace = 1); if (fn != savetracename) strncpy(savetracename, fn, sizeof(savetracename)-1); @@ -378,19 +385,19 @@ set_tracefile(char *filename, /* ARGSUSED */ void -sigtrace_on(int s) +sigtrace_on(int s UNUSED) { new_tracelevel++; - sigtrace_pat = "SIGUSR1: %s\n"; + sigtrace_pat = "SIGUSR1: %s"; } /* ARGSUSED */ void -sigtrace_off(int s) +sigtrace_off(int s UNUSED) { new_tracelevel--; - sigtrace_pat = "SIGUSR2: %s\n"; + sigtrace_pat = "SIGUSR2: %s"; } @@ -461,9 +468,9 @@ addrname(naddr addr, /* in network byte order */ /* display a bit-field */ struct bits { - int bits_mask; - int bits_clear; - char *bits_name; + u_int bits_mask; + u_int bits_clear; + const char *bits_name; }; static struct bits if_bits[] = { @@ -530,11 +537,11 @@ static struct bits rs_bits[] = { static void -trace_bits(struct bits *tbl, +trace_bits(const struct bits *tbl, u_int field, int force) { - int b; + u_int b; char c; if (force) { @@ -570,17 +577,17 @@ trace_bits(struct bits *tbl, } -static char * -trace_pair(naddr dst, - naddr mask, - char *gate) +char * +rtname(naddr dst, + naddr mask, + naddr 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); + (void)sprintf(&buf[i], "%-*s", 15+20-MAX(20,i), naddr_ntoa(gate)); return buf; } @@ -593,6 +600,9 @@ print_rts(struct rt_spare *rts, int force_tag, /* -1=suppress, 0=default, 1=display */ int force_time) /* 0=suppress, 1=display */ { + int i; + + if (force_metric >= 0) (void)fprintf(ftrace, "metric=%-2d ", rts->rts_metric); if (force_ifp >= 0) @@ -606,14 +616,19 @@ print_rts(struct rt_spare *rts, (void)fprintf(ftrace, "%s ", ts(rts->rts_time)); if (force_tag > 0 || (force_tag == 0 && rts->rts_tag != 0)) - (void)fprintf(ftrace, "tag=%#x ", - ntohs(rts->rts_tag)); + (void)fprintf(ftrace, "tag=%#x ", ntohs(rts->rts_tag)); + if (rts->rts_de_ag != 0) { + for (i = 1; (u_int)(1 << i) <= rts->rts_de_ag; i++) + continue; + (void)fprintf(ftrace, "de_ag=%d ", i); + } + } void -trace_if(char *act, - struct interface *ifp) +trace_if(const char *act, + struct interface *ifp) { if (!TRACEACTIONS || ftrace == 0) return; @@ -640,85 +655,82 @@ trace_if(char *act, 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) + struct rt_spare *new) { - struct rt_spare new; - if (!TRACEACTIONS || ftrace == 0) return; - if (rts->rts_gate == gate - && rts->rts_router == router - && rts->rts_metric == metric - && rts->rts_tag == tag) + if (rts->rts_gate == new->rts_gate + && rts->rts_router == new->rts_router + && rts->rts_metric == new->rts_metric + && rts->rts_tag == new->rts_tag + && rts->rts_de_ag == new->rts_de_ag) return; - new.rts_ifp = ifp; - new.rts_gate = gate; - new.rts_router = router; - new.rts_metric = metric; - new.rts_time = new_time; - new.rts_tag = tag; lastlog(); - if (rts->rts_gate != RIP_DEFAULT) { + if (new->rts_gate == 0) { + (void)fprintf(ftrace, "Del #%d %-35s ", + (int)(rts - rt->rt_spares), + rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate)); + print_rts(rts, 0,0,0,0, + (rts != rt->rt_spares + || AGE_RT(rt->rt_state,new->rts_ifp))); + + } else 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))); + (int)(rts - rt->rt_spares), + rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate)); print_rts(rts, 0,0, - rts->rts_gate != gate, - rts->rts_tag != tag, + rts->rts_gate != new->rts_gate, + rts->rts_tag != new->rts_tag, rts != rt->rt_spares || AGE_RT(rt->rt_state, rt->rt_ifp)); (void)fprintf(ftrace, "\n %19s%-16s ", "", - gate != rts->rts_gate ? naddr_ntoa(gate) : ""); - print_rts(&new, - -(metric == rts->rts_metric), - -(ifp == rts->rts_ifp), + (new->rts_gate != rts->rts_gate + ? naddr_ntoa(new->rts_gate) : "")); + print_rts(new, + -(new->rts_metric == rts->rts_metric), + -(new->rts_ifp == rts->rts_ifp), 0, - rts->rts_tag != tag, - new_time != rts->rts_time && (rts != rt->rt_spares - || AGE_RT(rt->rt_state, - ifp))); + rts->rts_tag != new->rts_tag, + (new->rts_time != rts->rts_time + && (rts != rt->rt_spares + || AGE_RT(rt->rt_state, new->rts_ifp)))); } else { (void)fprintf(ftrace, "Add #%d %-35s ", - rts - rt->rt_spares, - trace_pair(rt->rt_dst, rt->rt_mask, - naddr_ntoa(gate))); - print_rts(&new, 0,0,0,0, - rts != rt->rt_spares || AGE_RT(rt->rt_state,ifp)); + (int)(rts - rt->rt_spares), + rtname(rt->rt_dst, rt->rt_mask, new->rts_gate)); + print_rts(new, 0,0,0,0, + (rts != rt->rt_spares + || AGE_RT(rt->rt_state,new->rts_ifp))); } (void)fputc('\n',ftrace); } -/* talk about a change made to the kernel table +/* miscellaneous message checked by the caller */ void -trace_kernel(char *p, ...) +trace_misc(const char *p, ...) { va_list args; - if (!TRACEKERNEL || ftrace == 0) + if (ftrace == 0) return; lastlog(); va_start(args, p); vfprintf(ftrace, p, args); + (void)fputc('\n',ftrace); } /* display a message if tracing actions */ void -trace_act(char *p, ...) +trace_act(const char *p, ...) { va_list args; @@ -735,7 +747,7 @@ trace_act(char *p, ...) /* display a message if tracing packets */ void -trace_pkt(char *p, ...) +trace_pkt(const char *p, ...) { va_list args; @@ -752,50 +764,39 @@ trace_pkt(char *p, ...) 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) + struct rt_spare *new, + const char *label) { - struct rt_spare new; - if (ftrace == 0) return; - if (rt->rt_metric == metric - && rt->rt_gate == gate - && rt->rt_router == router + if (rt->rt_metric == new->rts_metric + && rt->rt_gate == new->rts_gate + && rt->rt_router == new->rts_router && rt->rt_state == state - && rt->rt_tag == tag) + && rt->rt_tag == new->rts_tag + && rt->rt_de_ag == new->rts_de_ag) return; - new.rts_ifp = ifp; - new.rts_gate = gate; - new.rts_router = router; - new.rts_metric = metric; - new.rts_time = new_time; - new.rts_tag = tag; lastlog(); (void)fprintf(ftrace, "%s %-35s ", label, - trace_pair(rt->rt_dst, rt->rt_mask, - naddr_ntoa(rt->rt_gate))); + rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate)); print_rts(rt->rt_spares, 0,0,0,0, AGE_RT(rt->rt_state, rt->rt_ifp)); trace_bits(rs_bits, rt->rt_state, rt->rt_state != state); (void)fprintf(ftrace, "\n%*s %19s%-16s ", - strlen(label), "", "", - rt->rt_gate != gate ? naddr_ntoa(gate) : ""); - print_rts(&new, - -(metric == rt->rt_metric), - -(ifp == rt->rt_ifp), + (int)strlen(label), "", "", + (rt->rt_gate != new->rts_gate + ? naddr_ntoa(new->rts_gate) : "")); + print_rts(new, + -(new->rts_metric == rt->rt_metric), + -(new->rts_ifp == rt->rt_ifp), 0, - rt->rt_tag != tag, - rt->rt_time != new_time && AGE_RT(rt->rt_state,ifp)); + rt->rt_tag != new->rts_tag, + (rt->rt_time != new->rts_time + && AGE_RT(rt->rt_state,new->rts_ifp))); if (rt->rt_state != state) trace_bits(rs_bits, state, 1); (void)fputc('\n',ftrace); @@ -803,7 +804,7 @@ trace_change(struct rt_entry *rt, void -trace_add_del(char * action, struct rt_entry *rt) +trace_add_del(const char * action, struct rt_entry *rt) { if (ftrace == 0) return; @@ -811,8 +812,7 @@ trace_add_del(char * action, struct rt_entry *rt) lastlog(); (void)fprintf(ftrace, "%s %-35s ", action, - trace_pair(rt->rt_dst, rt->rt_mask, - naddr_ntoa(rt->rt_gate))); + rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate)); print_rts(rt->rt_spares, 0,0,0,0,AGE_RT(rt->rt_state,rt->rt_ifp)); trace_bits(rs_bits, rt->rt_state, 0); (void)fputc('\n',ftrace); @@ -822,21 +822,20 @@ trace_add_del(char * action, struct rt_entry *rt) /* ARGSUSED */ static int walk_trace(struct radix_node *rn, - struct walkarg *w) + struct walkarg *w UNUSED) { #define RT ((struct rt_entry *)rn) struct rt_spare *rts; - int i, age = AGE_RT(RT->rt_state, RT->rt_ifp); + int i; - (void)fprintf(ftrace, " %-35s ", trace_pair(RT->rt_dst, RT->rt_mask, - naddr_ntoa(RT->rt_gate))); - print_rts(&RT->rt_spares[0], 0,0,0,0,age); + (void)fprintf(ftrace, " %-35s ", + rtname(RT->rt_dst, RT->rt_mask, RT->rt_gate)); + print_rts(&RT->rt_spares[0], 0,0,0,0, AGE_RT(RT->rt_state, RT->rt_ifp)); trace_bits(rs_bits, RT->rt_state, 0); if (RT->rt_poison_time >= now_garbage && RT->rt_poison_metric < RT->rt_metric) (void)fprintf(ftrace, "pm=%d@%s", - RT->rt_poison_metric, - ts(RT->rt_poison_time)); + RT->rt_poison_metric, ts(RT->rt_poison_time)); rts = &RT->rt_spares[1]; for (i = 1; i < NUM_SPARES; i++, rts++) { @@ -869,14 +868,14 @@ trace_dump(void) void -trace_rip(char *dir1, char *dir2, +trace_rip(const char *dir1, const char *dir2, struct sockaddr_in *who, struct interface *ifp, struct rip *msg, int size) /* total size of message */ { struct netinfo *n, *lim; -# define NA (msg->rip_auths) +# define NA ((struct netauth*)n) int i, seen_route; if (!TRACEPACKETS || ftrace == 0) @@ -946,23 +945,24 @@ trace_rip(char *dir1, char *dir2, if (NA->a_type == RIP_AUTH_MD5 && n == msg->rip_nets) { (void)fprintf(ftrace, - "\tMD5 Authentication" - " len=%d KeyID=%u" - " seqno=%u" + "\tMD5 Auth" + " pkt_len=%d KeyID=%u" + " auth_len=%d" + " seqno=%#x" " rsvd=%#x,%#x\n", - NA->au.a_md5.md5_pkt_len, - NA->au.a_md5.md5_keyid, - NA->au.a_md5.md5_seqno, - NA->au.a_md5.rsvd[0], - NA->au.a_md5.rsvd[1]); + ntohs(NA->au.a_md5.md5_pkt_len), + NA->au.a_md5.md5_keyid, + NA->au.a_md5.md5_auth_len, + (int)ntohl(NA->au.a_md5.md5_seqno), + (int)ntohs(NA->au.a_md5.rsvd[0]), + (int)ntohs(NA->au.a_md5.rsvd[1])); continue; } (void)fprintf(ftrace, - "\tAuthentication" - " type %d: ", + "\tAuthentication type %d: ", ntohs(NA->a_type)); for (i = 0; - i < sizeof(NA->au.au_pw); + i < (int)sizeof(NA->au.au_pw); i++) (void)fprintf(ftrace, "%02x ", NA->au.au_pw[i]);