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