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