Home | History | Annotate | Line # | Download | only in routed
input.c revision 1.1.1.4
      1 /*
      2  * Copyright (c) 1983, 1988, 1993
      3  *	The Regents of the University of California.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
     35 static char sccsid[] = "@(#)input.c	8.1 (Berkeley) 6/5/93";
     36 #elif defined(__NetBSD__)
     37 static char rcsid[] = "$NetBSD: input.c,v 1.1.1.4 1996/09/24 15:11:36 christos Exp $";
     38 #endif
     39 #ident "$Revision: 1.1.1.4 $"
     40 
     41 #include "defs.h"
     42 
     43 static void input(struct sockaddr_in *, struct interface*, struct rip *, int);
     44 static void input_route(struct interface *, naddr,
     45 			naddr, naddr, naddr, struct netinfo *);
     46 
     47 
     48 /* process RIP input
     49  */
     50 void
     51 read_rip(int sock,
     52 	 struct interface *ifp)
     53 {
     54 	struct sockaddr_in from;
     55 	int fromlen, cc;
     56 	union pkt_buf inbuf;
     57 
     58 
     59 	for (;;) {
     60 		fromlen = sizeof(from);
     61 		cc = recvfrom(sock, &inbuf, sizeof(inbuf), 0,
     62 			      (struct sockaddr*)&from, &fromlen);
     63 		if (cc <= 0) {
     64 			if (cc < 0 && errno != EWOULDBLOCK)
     65 				LOGERR("recvfrom(rip)");
     66 			break;
     67 		}
     68 		if (fromlen != sizeof(struct sockaddr_in))
     69 			logbad(1,"impossible recvfrom(rip) fromlen=%d",
     70 			       fromlen);
     71 
     72 		input(&from, ifp, &inbuf.rip, cc);
     73 	}
     74 }
     75 
     76 
     77 /* Process a RIP packet
     78  */
     79 static void
     80 input(struct sockaddr_in *from,		/* received from this IP address */
     81       struct interface *sifp,		/* interface by which it arrived */
     82       struct rip *rip,
     83       int size)
     84 {
     85 #	define FROM_NADDR from->sin_addr.s_addr
     86 	static naddr use_auth, bad_len, bad_mask;
     87 	static naddr unk_router, bad_router, bad_nhop;
     88 
     89 	struct interface *aifp;		/* interface if via 1 hop */
     90 	struct rt_entry *rt;
     91 	struct netinfo *n, *lim;
     92 	struct interface *ifp1;
     93 	naddr gate, mask, v1_mask, dst, ddst_h;
     94 	int i;
     95 
     96 	aifp = iflookup(from->sin_addr.s_addr);
     97 	if (sifp == 0)
     98 		sifp = aifp;
     99 
    100 	if (sifp != 0)
    101 		sifp->int_state |= IS_ACTIVE;
    102 
    103 	trace_rip("Recv", "from", from, sifp, rip, size);
    104 
    105 	if (rip->rip_vers == 0) {
    106 		if (from->sin_addr.s_addr != bad_router)
    107 			msglog("RIP version 0, cmd %d, packet received"
    108 			       " from %s",
    109 			       rip->rip_cmd, naddr_ntoa(FROM_NADDR));
    110 		bad_router = from->sin_addr.s_addr;
    111 		return;
    112 	} else if (rip->rip_vers > RIPv2) {
    113 		rip->rip_vers = RIPv2;
    114 	}
    115 	if (size > MAXPACKETSIZE) {
    116 		if (from->sin_addr.s_addr != bad_router)
    117 			msglog("packet at least %d bytes too long received"
    118 			       " from %s",
    119 			       size-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR));
    120 		bad_router = from->sin_addr.s_addr;
    121 		return;
    122 	}
    123 
    124 	n = rip->rip_nets;
    125 	lim = (struct netinfo *)((char*)rip + size);
    126 
    127 	/* Notice authentication.
    128 	 * As required by section 4.2 in RFC 1723, discard authenticated
    129 	 * RIPv2 messages, but only if configured for that silliness.
    130 	 *
    131 	 * RIPv2 authentication is lame, since snooping on the wire makes
    132 	 * its simple passwords evident.  Also, why authenticate queries?
    133 	 * Why should a RIPv2 implementation with authentication disabled
    134 	 * not be able to listen to RIPv2 packets with authenication, while
    135 	 * RIPv1 systems will listen?  Crazy!
    136 	 */
    137 	if (!auth_ok
    138 	    && rip->rip_vers == RIPv2
    139 	    && n < lim && n->n_family == RIP_AF_AUTH) {
    140 		if (from->sin_addr.s_addr != use_auth)
    141 			msglog("RIPv2 message with authentication"
    142 			       " from %s discarded",
    143 			       naddr_ntoa(FROM_NADDR));
    144 		use_auth = from->sin_addr.s_addr;
    145 		trace_pkt("discard authenticated RIPv2 message\n");
    146 		return;
    147 	}
    148 
    149 	switch (rip->rip_cmd) {
    150 	case RIPCMD_REQUEST:
    151 		/* did the request come from a router?
    152 		 */
    153 		if (from->sin_port == htons(RIP_PORT)) {
    154 			/* yes, ignore it if RIP is off so that it does not
    155 			 * depend on us.
    156 			 */
    157 			if (rip_sock < 0) {
    158 				trace_pkt("ignore request while RIP off\n");
    159 				return;
    160 			}
    161 
    162 			/* Ignore the request if we talking to ourself
    163 			 * (and not a remote gateway).
    164 			 */
    165 			if (ifwithaddr(FROM_NADDR, 0, 0) != 0) {
    166 				trace_pkt("discard our own RIP request\n");
    167 				return;
    168 			}
    169 		}
    170 
    171 		/* According to RFC 1723, we should ignore unathenticated
    172 		 * queries.  That is too silly to bother with.  Sheesh!
    173 		 * Are forwarding tables supposed to be secret?  When
    174 		 * a bad guy can infer them with test traffic?
    175 		 * Maybe on firewalls you'd care, but not enough to
    176 		 * give up the diagnostic facilities of remote probing.
    177 		 */
    178 
    179 		if (n >= lim
    180 		    || size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
    181 			if (from->sin_addr.s_addr != bad_len)
    182 				msglog("request of bad length (%d) from %s",
    183 				       size, naddr_ntoa(FROM_NADDR));
    184 			bad_len = from->sin_addr.s_addr;
    185 		}
    186 		for (; n < lim; n++) {
    187 			n->n_metric = ntohl(n->n_metric);
    188 
    189 			/* A single entry with family RIP_AF_UNSPEC and
    190 			 * metric HOPCNT_INFINITY means "all routes".
    191 			 * We respond to routers only if we are acting
    192 			 * as a supplier, or to anyone other than a router
    193 			 * (i.e. a query).
    194 			 */
    195 			if (n->n_family == RIP_AF_UNSPEC
    196 			    && n->n_metric == HOPCNT_INFINITY
    197 			    && n == rip->rip_nets
    198 			    && n+1 == lim) {
    199 				if (from->sin_port != htons(RIP_PORT)) {
    200 					/* Answer a query from a utility
    201 					 * program with all we know.
    202 					 */
    203 					supply(from, sifp, OUT_QUERY, 0,
    204 					       rip->rip_vers);
    205 					return;
    206 				}
    207 				/* A router trying to prime its tables.
    208 				 * Filter the answer in the about same way
    209 				 * broadcasts are filtered.
    210 				 *
    211 				 * Only answer a router if we are a supplier
    212 				 * to keep an unwary host that is just starting
    213 				 * from picking us as a router.  Respond with
    214 				 * RIPv1 instead of RIPv2 if that is what we
    215 				 * are broadcasting on the interface to keep
    216 				 * the remote router from getting the wrong
    217 				 * initial idea of the routes we send.
    218 				 */
    219 				if (!supplier
    220 				    || aifp == 0
    221 				    || (aifp->int_state & IS_PASSIVE)
    222 				    || (aifp->int_state & IS_ALIAS)
    223 				    || ((aifp->int_state & IS_NO_RIPV1_OUT)
    224 					&& (aifp->int_state&IS_NO_RIPV2_OUT)))
    225 					return;
    226 
    227 				supply(from, aifp, OUT_UNICAST, 0,
    228 				       (aifp->int_state&IS_NO_RIPV1_OUT)
    229 				       ? RIPv2 : RIPv1);
    230 				return;
    231 			}
    232 
    233 			if (n->n_family != RIP_AF_INET) {
    234 				if (from->sin_addr.s_addr != bad_router)
    235 					msglog("request from %s"
    236 					       " for unsupported (af %d) %s",
    237 					       naddr_ntoa(FROM_NADDR),
    238 					       ntohs(n->n_family),
    239 					       naddr_ntoa(n->n_dst));
    240 				bad_router = from->sin_addr.s_addr;
    241 				return;
    242 			}
    243 
    244 			dst = n->n_dst;
    245 			if (!check_dst(dst)) {
    246 				if (from->sin_addr.s_addr != bad_router)
    247 					msglog("bad queried destination"
    248 					       " %s from %s",
    249 					       naddr_ntoa(dst),
    250 					       naddr_ntoa(FROM_NADDR));
    251 				bad_router = from->sin_addr.s_addr;
    252 				return;
    253 			}
    254 
    255 			if (rip->rip_vers == RIPv1
    256 			    || 0 == (mask = ntohl(n->n_mask))
    257 			    || 0 != (ntohl(dst) & ~mask))
    258 				mask = ripv1_mask_host(dst,sifp);
    259 
    260 			rt = rtget(dst, mask);
    261 			if (!rt && dst != RIP_DEFAULT)
    262 				rt = rtfind(n->n_dst);
    263 
    264 			n->n_tag = 0;
    265 			n->n_nhop = 0;
    266 			if (rip->rip_vers == RIPv1) {
    267 				n->n_mask = 0;
    268 			} else {
    269 				n->n_mask = mask;
    270 			}
    271 			if (rt == 0) {
    272 				n->n_metric = HOPCNT_INFINITY;
    273 			} else {
    274 				n->n_metric = rt->rt_metric+1;
    275 				n->n_metric += (sifp!=0)?sifp->int_metric : 1;
    276 				if (n->n_metric > HOPCNT_INFINITY)
    277 					n->n_metric = HOPCNT_INFINITY;
    278 				if (rip->rip_vers != RIPv1) {
    279 					n->n_tag = rt->rt_tag;
    280 					if (sifp != 0
    281 					    && on_net(rt->rt_gate,
    282 						      sifp->int_net,
    283 						      sifp->int_mask)
    284 					    && rt->rt_gate != sifp->int_addr)
    285 						n->n_nhop = rt->rt_gate;
    286 				}
    287 			}
    288 			HTONL(n->n_metric);
    289 		}
    290 		/* Answer about specific routes.
    291 		 * Only answer a router if we are a supplier
    292 		 * to keep an unwary host that is just starting
    293 		 * from picking us an a router.
    294 		 */
    295 		rip->rip_cmd = RIPCMD_RESPONSE;
    296 		rip->rip_res1 = 0;
    297 		if (rip->rip_vers != RIPv1)
    298 			rip->rip_vers = RIPv2;
    299 		if (from->sin_port != htons(RIP_PORT)) {
    300 			/* query */
    301 			(void)output(OUT_QUERY, from, sifp, rip, size);
    302 		} else if (supplier) {
    303 			(void)output(OUT_UNICAST, from, sifp, rip, size);
    304 		}
    305 		return;
    306 
    307 	case RIPCMD_TRACEON:
    308 	case RIPCMD_TRACEOFF:
    309 		/* verify message came from a privileged port */
    310 		if (ntohs(from->sin_port) > IPPORT_RESERVED) {
    311 			msglog("trace command from untrusted port on %s",
    312 			       naddr_ntoa(FROM_NADDR));
    313 			return;
    314 		}
    315 		if (aifp == 0) {
    316 			msglog("trace command from unknown router %s",
    317 			       naddr_ntoa(FROM_NADDR));
    318 			return;
    319 		}
    320 		if (rip->rip_cmd == RIPCMD_TRACEON) {
    321 			rip->rip_tracefile[size-4] = '\0';
    322 			trace_on((char*)rip->rip_tracefile, 0);
    323 		} else {
    324 			trace_off("tracing turned off by %s\n",
    325 				  naddr_ntoa(FROM_NADDR));
    326 		}
    327 		return;
    328 
    329 	case RIPCMD_RESPONSE:
    330 		if (size%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
    331 			if (from->sin_addr.s_addr != bad_len)
    332 				msglog("response of bad length (%d) from %s",
    333 				       size, naddr_ntoa(FROM_NADDR));
    334 			bad_len = from->sin_addr.s_addr;
    335 		}
    336 
    337 		/* verify message came from a router */
    338 		if (from->sin_port != ntohs(RIP_PORT)) {
    339 			trace_pkt("discard RIP response from unknown port\n");
    340 			return;
    341 		}
    342 
    343 		if (rip_sock < 0) {
    344 			trace_pkt("discard response while RIP off\n");
    345 			return;
    346 		}
    347 
    348 		/* Are we talking to ourself or a remote gateway?
    349 		 */
    350 		ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
    351 		if (ifp1) {
    352 			if (ifp1->int_state & IS_REMOTE) {
    353 				if (ifp1->int_state & IS_PASSIVE) {
    354 					msglog("bogus input from %s on"
    355 					       " supposedly passive %s",
    356 					       naddr_ntoa(FROM_NADDR),
    357 					       ifp1->int_name);
    358 				} else {
    359 					ifp1->int_act_time = now.tv_sec;
    360 					if (if_ok(ifp1, "remote "))
    361 						addrouteforif(ifp1);
    362 				}
    363 			} else {
    364 				trace_pkt("discard our own RIP response\n");
    365 			}
    366 			return;
    367 		}
    368 
    369 		/* Check the router from which message originated. We accept
    370 		 * routing packets from routers directly connected via
    371 		 * broadcast or point-to-point networks, and from
    372 		 * those listed in /etc/gateways.
    373 		 */
    374 		if (!aifp) {
    375 			if (from->sin_addr.s_addr != unk_router)
    376 				msglog("discard packet from unknown router %s"
    377 				       " or via unidentified interface",
    378 				       naddr_ntoa(FROM_NADDR));
    379 			unk_router = from->sin_addr.s_addr;
    380 			return;
    381 		}
    382 		if (aifp->int_state & IS_PASSIVE) {
    383 			trace_act("discard packet from %s"
    384 				  " via passive interface %s\n",
    385 				  naddr_ntoa(FROM_NADDR),
    386 				  aifp->int_name);
    387 			return;
    388 		}
    389 
    390 		/* Check required version
    391 		 */
    392 		if (((aifp->int_state & IS_NO_RIPV1_IN)
    393 		     && rip->rip_vers == RIPv1)
    394 		    || ((aifp->int_state & IS_NO_RIPV2_IN)
    395 			&& rip->rip_vers != RIPv1)) {
    396 			trace_pkt("discard RIPv%d response\n",
    397 				  rip->rip_vers);
    398 			return;
    399 		}
    400 
    401 		/* Ignore routes via dead interface.
    402 		 */
    403 		if (aifp->int_state & IS_BROKE) {
    404 			trace_pkt("discard response via broken interface %s\n",
    405 				  aifp->int_name);
    406 			return;
    407 		}
    408 
    409 		/* Authenticate the packet if we have a secret.
    410 		 */
    411 		if (aifp->int_passwd[0] != '\0') {
    412 			if (n >= lim
    413 			    || n->n_family != RIP_AF_AUTH
    414 			    || ((struct netauth*)n)->a_type != RIP_AUTH_PW) {
    415 				if (from->sin_addr.s_addr != use_auth)
    416 					msglog("missing password from %s",
    417 					       naddr_ntoa(FROM_NADDR));
    418 				use_auth = from->sin_addr.s_addr;
    419 				return;
    420 
    421 			} else if (0 != bcmp(((struct netauth*)n)->au.au_pw,
    422 					     aifp->int_passwd,
    423 					     sizeof(aifp->int_passwd))) {
    424 				if (from->sin_addr.s_addr != use_auth)
    425 					msglog("bad password from %s",
    426 					       naddr_ntoa(FROM_NADDR));
    427 				use_auth = from->sin_addr.s_addr;
    428 				return;
    429 			}
    430 		}
    431 
    432 		for (; n < lim; n++) {
    433 			if (n->n_family == RIP_AF_AUTH)
    434 				continue;
    435 
    436 			NTOHL(n->n_metric);
    437 			dst = n->n_dst;
    438 			if (n->n_family != RIP_AF_INET
    439 			    && (n->n_family != RIP_AF_UNSPEC
    440 				|| dst != RIP_DEFAULT)) {
    441 				if (from->sin_addr.s_addr != bad_router)
    442 					msglog("route from %s to unsupported"
    443 					       " address family %d,"
    444 					       " destination %s",
    445 					       naddr_ntoa(FROM_NADDR),
    446 					       n->n_family,
    447 					       naddr_ntoa(dst));
    448 				bad_router = from->sin_addr.s_addr;
    449 				continue;
    450 			}
    451 			if (!check_dst(dst)) {
    452 				if (from->sin_addr.s_addr != bad_router)
    453 					msglog("bad destination %s from %s",
    454 					       naddr_ntoa(dst),
    455 					       naddr_ntoa(FROM_NADDR));
    456 				bad_router = from->sin_addr.s_addr;
    457 				return;
    458 			}
    459 			if (n->n_metric == 0
    460 			    || n->n_metric > HOPCNT_INFINITY) {
    461 				if (from->sin_addr.s_addr != bad_router)
    462 					msglog("bad metric %d from %s"
    463 					       " for destination %s",
    464 					       n->n_metric,
    465 					       naddr_ntoa(FROM_NADDR),
    466 					       naddr_ntoa(dst));
    467 				bad_router = from->sin_addr.s_addr;
    468 				return;
    469 			}
    470 
    471 			/* Notice the next-hop.
    472 			 */
    473 			gate = from->sin_addr.s_addr;
    474 			if (n->n_nhop != 0) {
    475 				if (rip->rip_vers == RIPv2) {
    476 					n->n_nhop = 0;
    477 				} else {
    478 				    /* Use it only if it is valid. */
    479 				    if (on_net(n->n_nhop,
    480 					       aifp->int_net, aifp->int_mask)
    481 					&& check_dst(n->n_nhop)) {
    482 					    gate = n->n_nhop;
    483 				    } else {
    484 					if (bad_nhop != from->sin_addr.s_addr)
    485 						msglog("router %s to %s has"
    486 						       " bad next hop %s",
    487 						       naddr_ntoa(FROM_NADDR),
    488 						       naddr_ntoa(dst),
    489 						       naddr_ntoa(n->n_nhop));
    490 					bad_nhop = from->sin_addr.s_addr;
    491 					n->n_nhop = 0;
    492 				    }
    493 				}
    494 			}
    495 
    496 			if (rip->rip_vers == RIPv1
    497 			    || 0 == (mask = ntohl(n->n_mask))) {
    498 				mask = ripv1_mask_host(dst,aifp);
    499 			} else if ((ntohl(dst) & ~mask) != 0) {
    500 				if (bad_mask != from->sin_addr.s_addr) {
    501 					msglog("router %s sent bad netmask"
    502 					       " %#x with %s",
    503 					       naddr_ntoa(FROM_NADDR),
    504 					       mask,
    505 					       naddr_ntoa(dst));
    506 					bad_mask = from->sin_addr.s_addr;
    507 				}
    508 				continue;
    509 			}
    510 			if (rip->rip_vers == RIPv1)
    511 				n->n_tag = 0;
    512 
    513 			/* Adjust metric according to incoming interface..
    514 			 */
    515 			n->n_metric += aifp->int_metric;
    516 			if (n->n_metric > HOPCNT_INFINITY)
    517 				n->n_metric = HOPCNT_INFINITY;
    518 
    519 			/* Recognize and ignore a default route we faked
    520 			 * which is being sent back to us by a machine with
    521 			 * broken split-horizon.
    522 			 * Be a little more paranoid than that, and reject
    523 			 * default routes with the same metric we advertised.
    524 			 */
    525 			if (aifp->int_d_metric != 0
    526 			    && dst == RIP_DEFAULT
    527 			    && n->n_metric >= aifp->int_d_metric)
    528 				continue;
    529 
    530 			/* We can receive aggregated RIPv2 routes that must
    531 			 * be broken down before they are transmitted by
    532 			 * RIPv1 via an interface on a subnet.
    533 			 * We might also receive the same routes aggregated
    534 			 * via other RIPv2 interfaces.
    535 			 * This could cause duplicate routes to be sent on
    536 			 * the RIPv1 interfaces.  "Longest matching variable
    537 			 * length netmasks" lets RIPv2 listeners understand,
    538 			 * but breaking down the aggregated routes for RIPv1
    539 			 * listeners can produce duplicate routes.
    540 			 *
    541 			 * Breaking down aggregated routes here bloats
    542 			 * the daemon table, but does not hurt the kernel
    543 			 * table, since routes are always aggregated for
    544 			 * the kernel.
    545 			 *
    546 			 * Notice that this does not break down network
    547 			 * routes corresponding to subnets.  This is part
    548 			 * of the defense against RS_NET_SYN.
    549 			 */
    550 			if (have_ripv1_out
    551 			    && (v1_mask = ripv1_mask_net(dst,0)) > mask
    552 			    && (((rt = rtget(dst,mask)) == 0
    553 				 || !(rt->rt_state & RS_NET_SYN)))) {
    554 				ddst_h = v1_mask & -v1_mask;
    555 				i = (v1_mask & ~mask)/ddst_h;
    556 				if (i >= 511) {
    557 					/* Punt if we would have to generate
    558 					 * an unreasonable number of routes.
    559 					 */
    560 #ifdef DEBUG
    561 					msglog("accept %s from %s as 1"
    562 					       " instead of %d routes",
    563 					       addrname(dst,mask,0),
    564 					       naddr_ntoa(FROM_NADDR),
    565 					       i+1);
    566 #endif
    567 					i = 0;
    568 				} else {
    569 					mask = v1_mask;
    570 				}
    571 			} else {
    572 				i = 0;
    573 			}
    574 
    575 			for (;;) {
    576 				input_route(aifp, FROM_NADDR,
    577 					    dst, mask, gate, n);
    578 				if (i-- == 0)
    579 					break;
    580 				dst = htonl(ntohl(dst) + ddst_h);
    581 			}
    582 		}
    583 		break;
    584 	}
    585 }
    586 
    587 
    588 /* Process a single input route.
    589  */
    590 static void
    591 input_route(struct interface *ifp,
    592 	    naddr from,
    593 	    naddr dst,
    594 	    naddr mask,
    595 	    naddr gate,
    596 	    struct netinfo *n)
    597 {
    598 	int i;
    599 	struct rt_entry *rt;
    600 	struct rt_spare *rts, *rts0;
    601 	struct interface *ifp1;
    602 	time_t new_time;
    603 
    604 
    605 	/* See if the other guy is telling us to send our packets to him.
    606 	 * Sometimes network routes arrive over a point-to-point link for
    607 	 * the network containing the address(es) of the link.
    608 	 *
    609 	 * If our interface is broken, switch to using the other guy.
    610 	 */
    611 	ifp1 = ifwithaddr(dst, 1, 1);
    612 	if (ifp1 != 0
    613 	    && !(ifp1->int_state & IS_BROKE))
    614 		return;
    615 
    616 	/* Look for the route in our table.
    617 	 */
    618 	rt = rtget(dst, mask);
    619 
    620 	/* Consider adding the route if we do not already have it.
    621 	 */
    622 	if (rt == 0) {
    623 		/* Ignore unknown routes being poisoned.
    624 		 */
    625 		if (n->n_metric == HOPCNT_INFINITY)
    626 			return;
    627 
    628 		/* Ignore the route if it points to us */
    629 		if (n->n_nhop != 0
    630 		    && 0 != ifwithaddr(n->n_nhop, 1, 0))
    631 			return;
    632 
    633 		/* If something has not gone crazy and tried to fill
    634 		 * our memory, accept the new route.
    635 		 */
    636 		if (total_routes < MAX_ROUTES)
    637 			rtadd(dst, mask, gate, from, n->n_metric,
    638 			      n->n_tag, 0, ifp);
    639 		return;
    640 	}
    641 
    642 	/* We already know about the route.  Consider this update.
    643 	 *
    644 	 * If (rt->rt_state & RS_NET_SYN), then this route
    645 	 * is the same as a network route we have inferred
    646 	 * for subnets we know, in order to tell RIPv1 routers
    647 	 * about the subnets.
    648 	 *
    649 	 * It is impossible to tell if the route is coming
    650 	 * from a distant RIPv2 router with the standard
    651 	 * netmask because that router knows about the entire
    652 	 * network, or if it is a round-about echo of a
    653 	 * synthetic, RIPv1 network route of our own.
    654 	 * The worst is that both kinds of routes might be
    655 	 * received, and the bad one might have the smaller
    656 	 * metric.  Partly solve this problem by never
    657 	 * aggregating into such a route.  Also keep it
    658 	 * around as long as the interface exists.
    659 	 */
    660 
    661 	rts0 = rt->rt_spares;
    662 	for (rts = rts0, i = NUM_SPARES; i != 0; i--, rts++) {
    663 		if (rts->rts_router == from)
    664 			break;
    665 		/* Note the worst slot to reuse,
    666 		 * other than the current slot.
    667 		 */
    668 		if (rts0 == rt->rt_spares
    669 		    || BETTER_LINK(rt, rts0, rts))
    670 			rts0 = rts;
    671 	}
    672 	if (i != 0) {
    673 		/* Found the router
    674 		 */
    675 		int old_metric = rts->rts_metric;
    676 
    677 		/* Keep poisoned routes around only long enough to pass
    678 		 * the poison on.  Get a new timestamp for good routes.
    679 		 */
    680 		new_time =((old_metric == HOPCNT_INFINITY)
    681 			   ? rts->rts_time
    682 			   : now.tv_sec);
    683 
    684 		/* If this is an update for the router we currently prefer,
    685 		 * then note it.
    686 		 */
    687 		if (i == NUM_SPARES) {
    688 			rtchange(rt,rt->rt_state, gate,rt->rt_router,
    689 				 n->n_metric, n->n_tag, ifp, new_time, 0);
    690 			/* If the route got worse, check for something better.
    691 			 */
    692 			if (n->n_metric > old_metric)
    693 				rtswitch(rt, 0);
    694 			return;
    695 		}
    696 
    697 		/* This is an update for a spare route.
    698 		 * Finished if the route is unchanged.
    699 		 */
    700 		if (rts->rts_gate == gate
    701 		    && old_metric == n->n_metric
    702 		    && rts->rts_tag == n->n_tag) {
    703 			rts->rts_time = new_time;
    704 			return;
    705 		}
    706 
    707 	} else {
    708 		/* The update is for a route we know about,
    709 		 * but not from a familiar router.
    710 		 *
    711 		 * Ignore the route if it points to us.
    712 		 */
    713 		if (n->n_nhop != 0
    714 		    && 0 != ifwithaddr(n->n_nhop, 1, 0))
    715 			return;
    716 
    717 		rts = rts0;
    718 
    719 		/* Save the route as a spare only if it has
    720 		 * a better metric than our worst spare.
    721 		 * This also ignores poisoned routes (those
    722 		 * received with metric HOPCNT_INFINITY).
    723 		 */
    724 		if (n->n_metric >= rts->rts_metric)
    725 			return;
    726 
    727 		new_time = now.tv_sec;
    728 	}
    729 
    730 	trace_upslot(rt, rts, gate, from, ifp, n->n_metric,n->n_tag, new_time);
    731 
    732 	rts->rts_gate = gate;
    733 	rts->rts_router = from;
    734 	rts->rts_metric = n->n_metric;
    735 	rts->rts_tag = n->n_tag;
    736 	rts->rts_time = new_time;
    737 	rts->rts_ifp = ifp;
    738 
    739 	/* try to switch to a better route */
    740 	rtswitch(rt, rts);
    741 }
    742