X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/8870953172b9e7f400d17deec06dbbc8c28e8c53..787d3210186ed1c1d0479fd7c0cc0ca6256380ff:/usr/src/sbin/routed/input.c diff --git a/usr/src/sbin/routed/input.c b/usr/src/sbin/routed/input.c index b9ac834b61..fb34398c7f 100644 --- a/usr/src/sbin/routed/input.c +++ b/usr/src/sbin/routed/input.c @@ -1,12 +1,23 @@ /* - * Copyright (c) 1983 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. + * Copyright (c) 1983, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef lint -static char sccsid[] = "@(#)input.c 5.10 (Berkeley) %G%"; -#endif not lint +static char sccsid[] = "@(#)input.c 5.20 (Berkeley) %G%"; +#endif /* not lint */ /* * Routing Table Management Daemon @@ -17,43 +28,52 @@ static char sccsid[] = "@(#)input.c 5.10 (Berkeley) %G%"; /* * Process a newly received packet. */ -rip_input(from, size) +rip_input(from, rip, size) struct sockaddr *from; + register struct rip *rip; int size; { register struct rt_entry *rt; register struct netinfo *n; register struct interface *ifp; struct interface *if_ifwithdstaddr(); - int newsize; + int count, changes = 0; register struct afswitch *afp; - static struct sockaddr badfrom; + static struct sockaddr badfrom, badfrom2; ifp = 0; - TRACE_INPUT(ifp, from, size); + TRACE_INPUT(ifp, from, (char *)rip, size); if (from->sa_family >= af_max || (afp = &afswitch[from->sa_family])->af_hash == (int (*)())0) { syslog(LOG_INFO, "\"from\" address in unsupported address family (%d), cmd %d\n", - from->sa_family, msg->rip_cmd); + from->sa_family, rip->rip_cmd); return; } - switch (msg->rip_cmd) { + if (rip->rip_vers == 0) { + syslog(LOG_ERR, + "RIP version 0 packet received from %s! (cmd %d)", + (*afswitch[from->sa_family].af_format)(from), rip->rip_cmd); + return; + } + switch (rip->rip_cmd) { case RIPCMD_REQUEST: - newsize = 0; - size -= 4 * sizeof (char); - n = msg->rip_nets; - while (size > 0) { - if (size < sizeof (struct netinfo)) + n = rip->rip_nets; + count = size - ((char *)n - (char *)rip); + if (count < sizeof (struct netinfo)) + return; + for (; count > 0; n++) { + if (count < sizeof (struct netinfo)) break; - size -= sizeof (struct netinfo); + count -= sizeof (struct netinfo); - if (msg->rip_vers > 0) { +#if BSD < 198810 + if (sizeof(n->rip_dst.sa_family) > 1)/* XXX */ n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family); - n->rip_metric = ntohl(n->rip_metric); - } +#endif + n->rip_metric = ntohl(n->rip_metric); /* * A single entry with sa_family == AF_UNSPEC and * metric ``infinity'' means ``all routes''. @@ -62,9 +82,9 @@ rip_input(from, size) * (eg, query). */ if (n->rip_dst.sa_family == AF_UNSPEC && - n->rip_metric == HOPCNT_INFINITY && size == 0) { + n->rip_metric == HOPCNT_INFINITY && count == 0) { if (supplier || (*afp->af_portmatch)(from) == 0) - supply(from, 0, 0); + supply(from, 0, 0, 0); return; } if (n->rip_dst.sa_family < af_max && @@ -73,19 +93,16 @@ rip_input(from, size) else rt = 0; n->rip_metric = rt == 0 ? HOPCNT_INFINITY : - min(rt->rt_metric+1, HOPCNT_INFINITY); - if (msg->rip_vers > 0) { - n->rip_dst.sa_family = - htons(n->rip_dst.sa_family); - n->rip_metric = htonl(n->rip_metric); - } - n++, newsize += sizeof (struct netinfo); - } - if (newsize > 0) { - msg->rip_cmd = RIPCMD_RESPONSE; - newsize += sizeof (int); - (*afp->af_output)(s, 0, from, newsize); + min(rt->rt_metric + 1, HOPCNT_INFINITY); +#if BSD < 198810 + if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */ + n->rip_dst.sa_family = htons(n->rip_dst.sa_family); +#endif + n->rip_metric = htonl(n->rip_metric); } + rip->rip_cmd = RIPCMD_RESPONSE; + bcopy((char *)rip, packet, size); + (*afp->af_output)(s, 0, from, size); return; case RIPCMD_TRACEON: @@ -94,14 +111,15 @@ rip_input(from, size) if ((*afp->af_portcheck)(from) == 0) return; if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags & - (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0) { + (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 || + ifp->int_flags & IFF_PASSIVE) { syslog(LOG_ERR, "trace command from unknown router, %s", (*afswitch[from->sa_family].af_format)(from)); return; } - packet[size] = '\0'; - if (msg->rip_cmd == RIPCMD_TRACEON) - traceon(msg->rip_tracefile); + ((char *)rip)[size] = '\0'; + if (rip->rip_cmd == RIPCMD_TRACEON) + traceon(rip->rip_tracefile); else traceoff(); return; @@ -114,8 +132,15 @@ rip_input(from, size) /* are we talking to ourselves? */ ifp = if_ifwithaddr(from); if (ifp) { + if (ifp->int_flags & IFF_PASSIVE) { + syslog(LOG_ERR, + "bogus input (from passive interface, %s)", + (*afswitch[from->sa_family].af_format)(from)); + return; + } rt = rtfind(from); - if (rt == 0 || (rt->rt_state & RTS_INTERFACE) == 0) + if (rt == 0 || ((rt->rt_state & RTS_INTERFACE) == 0) && + rt->rt_metric >= ifp->int_metric) addrouteforif(ifp); else rt->rt_timer = 0; @@ -129,7 +154,8 @@ rip_input(from, size) if ((rt = rtfind(from)) && (rt->rt_state & (RTS_INTERFACE | RTS_REMOTE))) rt->rt_timer = 0; - else if (ifp = if_ifwithdstaddr(from)) + else if ((ifp = if_ifwithdstaddr(from)) && + (rt == 0 || rt->rt_metric >= ifp->int_metric)) addrouteforif(ifp); /* * "Authenticate" router from which message originated. @@ -138,7 +164,8 @@ rip_input(from, size) * and from those listed in /etc/gateways. */ if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags & - (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0) { + (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 || + ifp->int_flags & IFF_PASSIVE) { if (bcmp((char *)from, (char *)&badfrom, sizeof(badfrom)) != 0) { syslog(LOG_ERR, @@ -149,17 +176,16 @@ rip_input(from, size) return; } size -= 4 * sizeof (char); - n = msg->rip_nets; + n = rip->rip_nets; for (; size > 0; size -= sizeof (struct netinfo), n++) { if (size < sizeof (struct netinfo)) break; - if (msg->rip_vers > 0) { +#if BSD < 198810 + if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */ n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family); - n->rip_metric = ntohl(n->rip_metric); - } - if ((unsigned) n->rip_metric > HOPCNT_INFINITY) - continue; +#endif + n->rip_metric = ntohl(n->rip_metric); if (n->rip_dst.sa_family >= af_max || (afp = &afswitch[n->rip_dst.sa_family])->af_hash == (int (*)())0) { @@ -177,38 +203,132 @@ rip_input(from, size) from->sa_family); continue; } + if (n->rip_metric == 0 || + (unsigned) n->rip_metric > HOPCNT_INFINITY) { + if (bcmp((char *)from, (char *)&badfrom2, + sizeof(badfrom2)) != 0) { + syslog(LOG_ERR, + "bad metric (%d) from %s\n", + n->rip_metric, + (*afswitch[from->sa_family].af_format)(from)); + badfrom2 = *from; + } + continue; + } + /* + * Adjust metric according to incoming interface. + */ + if ((unsigned) n->rip_metric < HOPCNT_INFINITY) + n->rip_metric += ifp->int_metric; + if ((unsigned) n->rip_metric > HOPCNT_INFINITY) + n->rip_metric = HOPCNT_INFINITY; rt = rtlookup(&n->rip_dst); if (rt == 0 || (rt->rt_state & (RTS_INTERNAL|RTS_INTERFACE)) == (RTS_INTERNAL|RTS_INTERFACE)) { - rt = rtfind(&n->rip_dst); - if (rt && equal(from, &rt->rt_router) && - rt->rt_metric == n->rip_metric) + /* + * If we're hearing a logical network route + * back from a peer to which we sent it, + * ignore it. + */ + if (rt && rt->rt_state & RTS_SUBNET && + (*afp->af_sendroute)(rt, from)) continue; - if (n->rip_metric < HOPCNT_INFINITY) + if ((unsigned)n->rip_metric < HOPCNT_INFINITY) { + /* + * Look for an equivalent route that + * includes this one before adding + * this route. + */ + rt = rtfind(&n->rip_dst); + if (rt && equal(from, &rt->rt_router)) + continue; rtadd(&n->rip_dst, from, n->rip_metric, 0); + changes++; + } continue; } /* * Update if from gateway and different, - * shorter, or getting stale and equivalent. + * shorter, or equivalent but old route + * is getting stale. */ if (equal(from, &rt->rt_router)) { if (n->rip_metric != rt->rt_metric) { rtchange(rt, from, n->rip_metric); - if (rt->rt_metric == HOPCNT_INFINITY) + changes++; + rt->rt_timer = 0; + if (rt->rt_metric >= HOPCNT_INFINITY) rt->rt_timer = GARBAGE_TIME - EXPIRE_TIME; } else if (rt->rt_metric < HOPCNT_INFINITY) rt->rt_timer = 0; - } else if ((unsigned) (n->rip_metric) < rt->rt_metric || - (rt->rt_timer > (EXPIRE_TIME/2) && - rt->rt_metric == n->rip_metric)) { + } else if ((unsigned) n->rip_metric < rt->rt_metric || + (rt->rt_metric == n->rip_metric && + rt->rt_timer > (EXPIRE_TIME/2) && + (unsigned) n->rip_metric < HOPCNT_INFINITY)) { rtchange(rt, from, n->rip_metric); + changes++; rt->rt_timer = 0; } } - return; + break; + } + + /* + * If changes have occurred, and if we have not sent a broadcast + * recently, send a dynamic update. This update is sent only + * on interfaces other than the one on which we received notice + * of the change. If we are within MIN_WAITTIME of a full update, + * don't bother sending; if we just sent a dynamic update + * and set a timer (nextbcast), delay until that time. + * If we just sent a full update, delay the dynamic update. + * Set a timer for a randomized value to suppress additional + * dynamic updates until it expires; if we delayed sending + * the current changes, set needupdate. + */ + if (changes && supplier && + now.tv_sec - lastfullupdate.tv_sec < SUPPLY_INTERVAL-MAX_WAITTIME) { + u_long delay; + extern long random(); + + if (now.tv_sec - lastbcast.tv_sec >= MIN_WAITTIME && + timercmp(&nextbcast, &now, <)) { + if (traceactions) + fprintf(ftrace, "send dynamic update\n"); + toall(supply, RTS_CHANGED, ifp); + lastbcast = now; + needupdate = 0; + nextbcast.tv_sec = 0; + } else { + needupdate++; + if (traceactions) + fprintf(ftrace, "delay dynamic update\n"); + } +#define RANDOMDELAY() (MIN_WAITTIME * 1000000 + \ + (u_long)random() % ((MAX_WAITTIME - MIN_WAITTIME) * 1000000)) + + if (nextbcast.tv_sec == 0) { + delay = RANDOMDELAY(); + if (traceactions) + fprintf(ftrace, + "inhibit dynamic update for %d usec\n", + delay); + nextbcast.tv_sec = delay / 1000000; + nextbcast.tv_usec = delay % 1000000; + timevaladd(&nextbcast, &now); + /* + * If the next possibly dynamic update + * is within MIN_WAITTIME of the next full update, + * force the delay past the full update, + * or we might send a dynamic update just before + * the full update. + */ + if (nextbcast.tv_sec > lastfullupdate.tv_sec + + SUPPLY_INTERVAL - MIN_WAITTIME) + nextbcast.tv_sec = lastfullupdate.tv_sec + + SUPPLY_INTERVAL + 1; + } } }