diff options
Diffstat (limited to 'sbin/routed/rdisc.c')
-rw-r--r-- | sbin/routed/rdisc.c | 167 |
1 files changed, 96 insertions, 71 deletions
diff --git a/sbin/routed/rdisc.c b/sbin/routed/rdisc.c index bccb3d9374dd..5123442be844 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 @@ -31,18 +31,18 @@ * SUCH DAMAGE. */ -#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__) -static char sccsid[] = "@(#)rdisc.c 8.1 (Berkeley) x/y/95"; -#elif defined(__NetBSD__) -static char rcsid[] = "$NetBSD$"; -#endif -#ident "$Revision: 1.20 $" - #include "defs.h" #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/ip_icmp.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 $" + /* router advertisement ICMP packet */ struct icmp_ad { u_int8_t icmp_type; /* type of message */ @@ -79,7 +79,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 */ @@ -89,8 +89,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); @@ -99,7 +104,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, @@ -137,7 +142,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)); } } @@ -183,7 +188,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); @@ -252,7 +257,7 @@ set_supplier(void) if (supplier_set) return; - trace_act("start suppying routes"); + trace_act("start supplying routes"); /* Forget discovered routes. */ @@ -294,9 +299,9 @@ rdisc_age(naddr bad_gate) struct dr *drp; - /* If only adverising, then do only that. */ + /* 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) @@ -307,7 +312,7 @@ rdisc_age(naddr bad_gate) /* If we are being told about a bad router, * then age the discovered default route, and if there is - * no alternative, solicite a replacement. + * no alternative, solicit a replacement. */ if (bad_gate != 0) { /* Look for the bad discovered default route. @@ -336,14 +341,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); } @@ -359,10 +367,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; } @@ -388,10 +398,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; @@ -410,13 +421,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); } } @@ -429,9 +448,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. @@ -489,23 +509,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 { @@ -517,27 +534,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(); + } } @@ -546,7 +564,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) { @@ -577,9 +595,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; } @@ -610,7 +628,7 @@ parse_ad(naddr from, new_drp = drp; } else if (new_drp->dr_ts != 0) { - /* look for the least valueable entry to reuse + /* look for the least valuable entry to reuse */ if ((!(new_drp->dr_ifp->int_state & IS_SICK) && (drp->dr_ifp->int_state & IS_SICK)) @@ -675,11 +693,11 @@ send_rdisc(union ad_u *p, { 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 @@ -714,7 +732,7 @@ send_rdisc(union ad_u *p, if (rdisc_sock_mcast != ifp) { /* select the right interface. */ #ifdef MCAST_PPP_BUG - /* Do not specifiy the primary interface explicitly + /* Do not specify the primary interface explicitly * if we have the multicast point-to-point kernel * bug, since the kernel will do the wrong thing * if the local address of a point-to-point link @@ -771,16 +789,20 @@ send_adv(struct interface *ifp, 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; @@ -850,7 +872,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)); @@ -874,14 +896,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) { @@ -987,7 +1009,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); @@ -997,9 +1019,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); @@ -1026,6 +1049,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. |