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