|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983, 1988 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that: (1) source distributions retain this entire copyright ! 7: * notice and comment, and (2) distributions including binaries display ! 8: * the following acknowledgement: ``This product includes software ! 9: * developed by the University of California, Berkeley and its contributors'' ! 10: * in the documentation or other materials provided with the distribution ! 11: * and in all advertising materials mentioning features or use of this ! 12: * software. Neither the name of the University nor the names of its ! 13: * contributors may be used to endorse or promote products derived ! 14: * from this software without specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)input.c 5.22 (Berkeley) 6/1/90"; ! 22: #endif /* not lint */ ! 23: ! 24: /* ! 25: * Routing Table Management Daemon ! 26: */ ! 27: #include "defs.h" ! 28: #include <sys/syslog.h> ! 29: ! 30: /* ! 31: * Process a newly received packet. ! 32: */ ! 33: rip_input(from, rip, size) ! 34: struct sockaddr *from; ! 35: register struct rip *rip; ! 36: int size; ! 37: { ! 38: register struct rt_entry *rt; ! 39: register struct netinfo *n; ! 40: register struct interface *ifp; ! 41: struct interface *if_ifwithdstaddr(); ! 42: int count, changes = 0; ! 43: register struct afswitch *afp; ! 44: static struct sockaddr badfrom, badfrom2; ! 45: ! 46: ifp = 0; ! 47: TRACE_INPUT(ifp, from, (char *)rip, size); ! 48: if (from->sa_family >= af_max || ! 49: (afp = &afswitch[from->sa_family])->af_hash == (int (*)())0) { ! 50: syslog(LOG_INFO, ! 51: "\"from\" address in unsupported address family (%d), cmd %d\n", ! 52: from->sa_family, rip->rip_cmd); ! 53: return; ! 54: } ! 55: if (rip->rip_vers == 0) { ! 56: syslog(LOG_ERR, ! 57: "RIP version 0 packet received from %s! (cmd %d)", ! 58: (*afswitch[from->sa_family].af_format)(from), rip->rip_cmd); ! 59: return; ! 60: } ! 61: switch (rip->rip_cmd) { ! 62: ! 63: case RIPCMD_REQUEST: ! 64: n = rip->rip_nets; ! 65: count = size - ((char *)n - (char *)rip); ! 66: if (count < sizeof (struct netinfo)) ! 67: return; ! 68: for (; count > 0; n++) { ! 69: if (count < sizeof (struct netinfo)) ! 70: break; ! 71: count -= sizeof (struct netinfo); ! 72: ! 73: #if BSD < 198810 ! 74: if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */ ! 75: n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family); ! 76: #else ! 77: #define osa(x) ((struct osockaddr *)(&(x))) ! 78: n->rip_dst.sa_family = ! 79: ntohs(osa(n->rip_dst)->sa_family); ! 80: n->rip_dst.sa_len = sizeof(n->rip_dst); ! 81: #endif ! 82: n->rip_metric = ntohl(n->rip_metric); ! 83: /* ! 84: * A single entry with sa_family == AF_UNSPEC and ! 85: * metric ``infinity'' means ``all routes''. ! 86: * We respond to routers only if we are acting ! 87: * as a supplier, or to anyone other than a router ! 88: * (eg, query). ! 89: */ ! 90: if (n->rip_dst.sa_family == AF_UNSPEC && ! 91: n->rip_metric == HOPCNT_INFINITY && count == 0) { ! 92: if (supplier || (*afp->af_portmatch)(from) == 0) ! 93: supply(from, 0, 0, 0); ! 94: return; ! 95: } ! 96: if (n->rip_dst.sa_family < af_max && ! 97: afswitch[n->rip_dst.sa_family].af_hash) ! 98: rt = rtlookup(&n->rip_dst); ! 99: else ! 100: rt = 0; ! 101: #define min(a, b) (a < b ? a : b) ! 102: n->rip_metric = rt == 0 ? HOPCNT_INFINITY : ! 103: min(rt->rt_metric + 1, HOPCNT_INFINITY); ! 104: #if BSD < 198810 ! 105: if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */ ! 106: n->rip_dst.sa_family = htons(n->rip_dst.sa_family); ! 107: #else ! 108: osa(n->rip_dst)->sa_family = ! 109: htons(n->rip_dst.sa_family); ! 110: #endif ! 111: n->rip_metric = htonl(n->rip_metric); ! 112: } ! 113: rip->rip_cmd = RIPCMD_RESPONSE; ! 114: bcopy((char *)rip, packet, size); ! 115: (*afp->af_output)(s, 0, from, size); ! 116: return; ! 117: ! 118: case RIPCMD_TRACEON: ! 119: case RIPCMD_TRACEOFF: ! 120: /* verify message came from a privileged port */ ! 121: if ((*afp->af_portcheck)(from) == 0) ! 122: return; ! 123: if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags & ! 124: (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 || ! 125: ifp->int_flags & IFF_PASSIVE) { ! 126: syslog(LOG_ERR, "trace command from unknown router, %s", ! 127: (*afswitch[from->sa_family].af_format)(from)); ! 128: return; ! 129: } ! 130: ((char *)rip)[size] = '\0'; ! 131: if (rip->rip_cmd == RIPCMD_TRACEON) ! 132: traceon(rip->rip_tracefile); ! 133: else ! 134: traceoff(); ! 135: return; ! 136: ! 137: case RIPCMD_RESPONSE: ! 138: /* verify message came from a router */ ! 139: if ((*afp->af_portmatch)(from) == 0) ! 140: return; ! 141: (*afp->af_canon)(from); ! 142: /* are we talking to ourselves? */ ! 143: ifp = if_ifwithaddr(from); ! 144: if (ifp) { ! 145: if (ifp->int_flags & IFF_PASSIVE) { ! 146: syslog(LOG_ERR, ! 147: "bogus input (from passive interface, %s)", ! 148: (*afswitch[from->sa_family].af_format)(from)); ! 149: return; ! 150: } ! 151: rt = rtfind(from); ! 152: if (rt == 0 || ((rt->rt_state & RTS_INTERFACE) == 0) && ! 153: rt->rt_metric >= ifp->int_metric) ! 154: addrouteforif(ifp); ! 155: else ! 156: rt->rt_timer = 0; ! 157: return; ! 158: } ! 159: /* ! 160: * Update timer for interface on which the packet arrived. ! 161: * If from other end of a point-to-point link that isn't ! 162: * in the routing tables, (re-)add the route. ! 163: */ ! 164: if ((rt = rtfind(from)) && ! 165: (rt->rt_state & (RTS_INTERFACE | RTS_REMOTE))) ! 166: rt->rt_timer = 0; ! 167: else if ((ifp = if_ifwithdstaddr(from)) && ! 168: (rt == 0 || rt->rt_metric >= ifp->int_metric)) ! 169: addrouteforif(ifp); ! 170: /* ! 171: * "Authenticate" router from which message originated. ! 172: * We accept routing packets from routers directly connected ! 173: * via broadcast or point-to-point networks, ! 174: * and from those listed in /etc/gateways. ! 175: */ ! 176: if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags & ! 177: (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 || ! 178: ifp->int_flags & IFF_PASSIVE) { ! 179: if (bcmp((char *)from, (char *)&badfrom, ! 180: sizeof(badfrom)) != 0) { ! 181: syslog(LOG_ERR, ! 182: "packet from unknown router, %s", ! 183: (*afswitch[from->sa_family].af_format)(from)); ! 184: badfrom = *from; ! 185: } ! 186: return; ! 187: } ! 188: size -= 4 * sizeof (char); ! 189: n = rip->rip_nets; ! 190: for (; size > 0; size -= sizeof (struct netinfo), n++) { ! 191: if (size < sizeof (struct netinfo)) ! 192: break; ! 193: #if BSD < 198810 ! 194: if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */ ! 195: n->rip_dst.sa_family = ! 196: ntohs(n->rip_dst.sa_family); ! 197: #else ! 198: n->rip_dst.sa_family = ! 199: ntohs(osa(n->rip_dst)->sa_family); ! 200: n->rip_dst.sa_len = sizeof(n->rip_dst); ! 201: #endif ! 202: n->rip_metric = ntohl(n->rip_metric); ! 203: if (n->rip_dst.sa_family >= af_max || ! 204: (afp = &afswitch[n->rip_dst.sa_family])->af_hash == ! 205: (int (*)())0) { ! 206: syslog(LOG_INFO, ! 207: "route in unsupported address family (%d), from %s (af %d)\n", ! 208: n->rip_dst.sa_family, ! 209: (*afswitch[from->sa_family].af_format)(from), ! 210: from->sa_family); ! 211: continue; ! 212: } ! 213: if (((*afp->af_checkhost)(&n->rip_dst)) == 0) { ! 214: syslog(LOG_DEBUG, ! 215: "bad host in route from %s (af %d)\n", ! 216: (*afswitch[from->sa_family].af_format)(from), ! 217: from->sa_family); ! 218: continue; ! 219: } ! 220: if (n->rip_metric == 0 || ! 221: (unsigned) n->rip_metric > HOPCNT_INFINITY) { ! 222: if (bcmp((char *)from, (char *)&badfrom2, ! 223: sizeof(badfrom2)) != 0) { ! 224: syslog(LOG_ERR, ! 225: "bad metric (%d) from %s\n", ! 226: n->rip_metric, ! 227: (*afswitch[from->sa_family].af_format)(from)); ! 228: badfrom2 = *from; ! 229: } ! 230: continue; ! 231: } ! 232: /* ! 233: * Adjust metric according to incoming interface. ! 234: */ ! 235: if ((unsigned) n->rip_metric < HOPCNT_INFINITY) ! 236: n->rip_metric += ifp->int_metric; ! 237: if ((unsigned) n->rip_metric > HOPCNT_INFINITY) ! 238: n->rip_metric = HOPCNT_INFINITY; ! 239: rt = rtlookup(&n->rip_dst); ! 240: if (rt == 0 || ! 241: (rt->rt_state & (RTS_INTERNAL|RTS_INTERFACE)) == ! 242: (RTS_INTERNAL|RTS_INTERFACE)) { ! 243: /* ! 244: * If we're hearing a logical network route ! 245: * back from a peer to which we sent it, ! 246: * ignore it. ! 247: */ ! 248: if (rt && rt->rt_state & RTS_SUBNET && ! 249: (*afp->af_sendroute)(rt, from)) ! 250: continue; ! 251: if ((unsigned)n->rip_metric < HOPCNT_INFINITY) { ! 252: /* ! 253: * Look for an equivalent route that ! 254: * includes this one before adding ! 255: * this route. ! 256: */ ! 257: rt = rtfind(&n->rip_dst); ! 258: if (rt && equal(from, &rt->rt_router)) ! 259: continue; ! 260: rtadd(&n->rip_dst, from, n->rip_metric, 0); ! 261: changes++; ! 262: } ! 263: continue; ! 264: } ! 265: ! 266: /* ! 267: * Update if from gateway and different, ! 268: * shorter, or equivalent but old route ! 269: * is getting stale. ! 270: */ ! 271: if (equal(from, &rt->rt_router)) { ! 272: if (n->rip_metric != rt->rt_metric) { ! 273: rtchange(rt, from, n->rip_metric); ! 274: changes++; ! 275: rt->rt_timer = 0; ! 276: if (rt->rt_metric >= HOPCNT_INFINITY) ! 277: rt->rt_timer = ! 278: GARBAGE_TIME - EXPIRE_TIME; ! 279: } else if (rt->rt_metric < HOPCNT_INFINITY) ! 280: rt->rt_timer = 0; ! 281: } else if ((unsigned) n->rip_metric < rt->rt_metric || ! 282: (rt->rt_metric == n->rip_metric && ! 283: rt->rt_timer > (EXPIRE_TIME/2) && ! 284: (unsigned) n->rip_metric < HOPCNT_INFINITY)) { ! 285: rtchange(rt, from, n->rip_metric); ! 286: changes++; ! 287: rt->rt_timer = 0; ! 288: } ! 289: } ! 290: break; ! 291: } ! 292: ! 293: /* ! 294: * If changes have occurred, and if we have not sent a broadcast ! 295: * recently, send a dynamic update. This update is sent only ! 296: * on interfaces other than the one on which we received notice ! 297: * of the change. If we are within MIN_WAITTIME of a full update, ! 298: * don't bother sending; if we just sent a dynamic update ! 299: * and set a timer (nextbcast), delay until that time. ! 300: * If we just sent a full update, delay the dynamic update. ! 301: * Set a timer for a randomized value to suppress additional ! 302: * dynamic updates until it expires; if we delayed sending ! 303: * the current changes, set needupdate. ! 304: */ ! 305: if (changes && supplier && ! 306: now.tv_sec - lastfullupdate.tv_sec < SUPPLY_INTERVAL-MAX_WAITTIME) { ! 307: u_long delay; ! 308: extern long random(); ! 309: ! 310: if (now.tv_sec - lastbcast.tv_sec >= MIN_WAITTIME && ! 311: timercmp(&nextbcast, &now, <)) { ! 312: if (traceactions) ! 313: fprintf(ftrace, "send dynamic update\n"); ! 314: toall(supply, RTS_CHANGED, ifp); ! 315: lastbcast = now; ! 316: needupdate = 0; ! 317: nextbcast.tv_sec = 0; ! 318: } else { ! 319: needupdate++; ! 320: if (traceactions) ! 321: fprintf(ftrace, "delay dynamic update\n"); ! 322: } ! 323: #define RANDOMDELAY() (MIN_WAITTIME * 1000000 + \ ! 324: (u_long)random() % ((MAX_WAITTIME - MIN_WAITTIME) * 1000000)) ! 325: ! 326: if (nextbcast.tv_sec == 0) { ! 327: delay = RANDOMDELAY(); ! 328: if (traceactions) ! 329: fprintf(ftrace, ! 330: "inhibit dynamic update for %d usec\n", ! 331: delay); ! 332: nextbcast.tv_sec = delay / 1000000; ! 333: nextbcast.tv_usec = delay % 1000000; ! 334: timevaladd(&nextbcast, &now); ! 335: /* ! 336: * If the next possibly dynamic update ! 337: * is within MIN_WAITTIME of the next full update, ! 338: * force the delay past the full update, ! 339: * or we might send a dynamic update just before ! 340: * the full update. ! 341: */ ! 342: if (nextbcast.tv_sec > lastfullupdate.tv_sec + ! 343: SUPPLY_INTERVAL - MIN_WAITTIME) ! 344: nextbcast.tv_sec = lastfullupdate.tv_sec + ! 345: SUPPLY_INTERVAL + 1; ! 346: } ! 347: } ! 348: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.