118316Swollman/*
218316Swollman * Copyright (c) 1983, 1988, 1993
318316Swollman *	The Regents of the University of California.  All rights reserved.
418316Swollman *
518316Swollman * Redistribution and use in source and binary forms, with or without
618316Swollman * modification, are permitted provided that the following conditions
718316Swollman * are met:
818316Swollman * 1. Redistributions of source code must retain the above copyright
918316Swollman *    notice, this list of conditions and the following disclaimer.
1018316Swollman * 2. Redistributions in binary form must reproduce the above copyright
1118316Swollman *    notice, this list of conditions and the following disclaimer in the
1218316Swollman *    documentation and/or other materials provided with the distribution.
1318316Swollman * 4. Neither the name of the University nor the names of its contributors
1418316Swollman *    may be used to endorse or promote products derived from this software
1518316Swollman *    without specific prior written permission.
1618316Swollman *
1718316Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1818316Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1918316Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2018316Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2118316Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2218316Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2318316Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2418316Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2518316Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2618316Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2718316Swollman * SUCH DAMAGE.
2846303Smarkm *
2950476Speter * $FreeBSD$
3018316Swollman */
3118316Swollman
3246303Smarkm#include "defs.h"
3346303Smarkm
34126250Sbms#ifdef __NetBSD__
3546303Smarkm__RCSID("$NetBSD$");
36126250Sbms#elif defined(__FreeBSD__)
37126250Sbms__RCSID("$FreeBSD$");
38126250Sbms#else
39126250Sbms__RCSID("$Revision: 2.26 $");
40126250Sbms#ident "$Revision: 2.26 $"
4118316Swollman#endif
4218316Swollman
4319880Swollmanstatic void input(struct sockaddr_in *, struct interface *, struct interface *,
4419880Swollman		  struct rip *, int);
4546303Smarkmstatic void input_route(naddr, naddr, struct rt_spare *, struct netinfo *);
4619880Swollmanstatic int ck_passwd(struct interface *, struct rip *, void *,
4719880Swollman		     naddr, struct msg_limit *);
4818316Swollman
4918316Swollman
5018316Swollman/* process RIP input
5118316Swollman */
5218316Swollmanvoid
5318316Swollmanread_rip(int sock,
5419880Swollman	 struct interface *sifp)
5518316Swollman{
5618316Swollman	struct sockaddr_in from;
5719880Swollman	struct interface *aifp;
58148726Sstefanf	socklen_t fromlen;
59148726Sstefanf	int cc;
6020339Swollman#ifdef USE_PASSIFNAME
6120339Swollman	static struct msg_limit  bad_name;
6219880Swollman	struct {
6319880Swollman		char	ifname[IFNAMSIZ];
6419880Swollman		union pkt_buf pbuf;
6519880Swollman	} inbuf;
6620339Swollman#else
6720339Swollman	struct {
6820339Swollman		union pkt_buf pbuf;
6920339Swollman	} inbuf;
7020339Swollman#endif
7118316Swollman
7218316Swollman
7318316Swollman	for (;;) {
7418316Swollman		fromlen = sizeof(from);
7518316Swollman		cc = recvfrom(sock, &inbuf, sizeof(inbuf), 0,
7618316Swollman			      (struct sockaddr*)&from, &fromlen);
7718316Swollman		if (cc <= 0) {
7818316Swollman			if (cc < 0 && errno != EWOULDBLOCK)
7918316Swollman				LOGERR("recvfrom(rip)");
8018316Swollman			break;
8118316Swollman		}
8218316Swollman		if (fromlen != sizeof(struct sockaddr_in))
8318316Swollman			logbad(1,"impossible recvfrom(rip) fromlen=%d",
84148726Sstefanf			       (int)fromlen);
8518316Swollman
8619880Swollman		/* aifp is the "authenticated" interface via which the packet
8719880Swollman		 *	arrived.  In fact, it is only the interface on which
8819880Swollman		 *	the packet should have arrived based on is source
8919880Swollman		 *	address.
9019880Swollman		 * sifp is interface associated with the socket through which
9119880Swollman		 *	the packet was received.
9219880Swollman		 */
9319880Swollman#ifdef USE_PASSIFNAME
9419880Swollman		if ((cc -= sizeof(inbuf.ifname)) < 0)
9519880Swollman			logbad(0,"missing USE_PASSIFNAME; only %d bytes",
9619880Swollman			       cc+sizeof(inbuf.ifname));
9719880Swollman
9819880Swollman		/* check the remote interfaces first */
99190713Sphk		LIST_FOREACH(aifp, &remote_if, remote_list) {
10019880Swollman			if (aifp->int_addr == from.sin_addr.s_addr)
10119880Swollman				break;
10219880Swollman		}
10319880Swollman		if (aifp == 0) {
10419880Swollman			aifp = ifwithname(inbuf.ifname, 0);
10519880Swollman			if (aifp == 0) {
10620606Swollman				msglim(&bad_name, from.sin_addr.s_addr,
10720606Swollman				       "impossible interface name %.*s",
10820606Swollman				       IFNAMSIZ, inbuf.ifname);
10920606Swollman			} else if (((aifp->int_if_flags & IFF_POINTOPOINT)
11020606Swollman				    && aifp->int_dstaddr!=from.sin_addr.s_addr)
11120606Swollman				   || (!(aifp->int_if_flags & IFF_POINTOPOINT)
11220606Swollman				       && !on_net(from.sin_addr.s_addr,
11320606Swollman						  aifp->int_net,
11420606Swollman						  aifp->int_mask))) {
11520606Swollman				/* If it came via the wrong interface, do not
11620606Swollman				 * trust it.
11720606Swollman				 */
11820606Swollman				aifp = 0;
11919880Swollman			}
12019880Swollman		}
12119880Swollman#else
12219880Swollman		aifp = iflookup(from.sin_addr.s_addr);
12319880Swollman#endif
12419880Swollman		if (sifp == 0)
12519880Swollman			sifp = aifp;
12619880Swollman
12719880Swollman		input(&from, sifp, aifp, &inbuf.pbuf.rip, cc);
12818316Swollman	}
12918316Swollman}
13018316Swollman
13118316Swollman
13218316Swollman/* Process a RIP packet
13318316Swollman */
13418316Swollmanstatic void
13518316Swollmaninput(struct sockaddr_in *from,		/* received from this IP address */
13619880Swollman      struct interface *sifp,		/* interface of incoming socket */
13719880Swollman      struct interface *aifp,		/* "authenticated" interface */
13818316Swollman      struct rip *rip,
13919880Swollman      int cc)
14018316Swollman{
14118316Swollman#	define FROM_NADDR from->sin_addr.s_addr
14219880Swollman	static struct msg_limit use_auth, bad_len, bad_mask;
14346303Smarkm	static struct msg_limit unk_router, bad_router, bad_nhop;
14418316Swollman
14518316Swollman	struct rt_entry *rt;
14646303Smarkm	struct rt_spare new;
14718316Swollman	struct netinfo *n, *lim;
14818316Swollman	struct interface *ifp1;
14946303Smarkm	naddr gate, mask, v1_mask, dst, ddst_h = 0;
15020339Swollman	struct auth *ap;
15146303Smarkm	struct tgate *tg = 0;
15246303Smarkm	struct tgate_net *tn;
15346303Smarkm	int i, j;
15418316Swollman
15519880Swollman	/* Notice when we hear from a remote gateway
15619880Swollman	 */
15719880Swollman	if (aifp != 0
15819880Swollman	    && (aifp->int_state & IS_REMOTE))
15919880Swollman		aifp->int_act_time = now.tv_sec;
16018316Swollman
16119880Swollman	trace_rip("Recv", "from", from, sifp, rip, cc);
16218316Swollman
163286348Sdelphij	if (sifp == 0) {
164286348Sdelphij		trace_pkt("    discard a request from an indirect router"
165286348Sdelphij		    " (possibly an attack)");
166286348Sdelphij		return;
167286348Sdelphij	}
168286348Sdelphij
16918316Swollman	if (rip->rip_vers == 0) {
17019880Swollman		msglim(&bad_router, FROM_NADDR,
17119880Swollman		       "RIP version 0, cmd %d, packet received from %s",
17219880Swollman		       rip->rip_cmd, naddr_ntoa(FROM_NADDR));
17318316Swollman		return;
17418316Swollman	} else if (rip->rip_vers > RIPv2) {
17518316Swollman		rip->rip_vers = RIPv2;
17618316Swollman	}
17746303Smarkm	if (cc > (int)OVER_MAXPACKETSIZE) {
17819880Swollman		msglim(&bad_router, FROM_NADDR,
17919880Swollman		       "packet at least %d bytes too long received from %s",
18019880Swollman		       cc-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR));
18118316Swollman		return;
18218316Swollman	}
18318316Swollman
18418316Swollman	n = rip->rip_nets;
18519880Swollman	lim = (struct netinfo *)((char*)rip + cc);
18618316Swollman
18718316Swollman	/* Notice authentication.
18818316Swollman	 * As required by section 4.2 in RFC 1723, discard authenticated
18918316Swollman	 * RIPv2 messages, but only if configured for that silliness.
19018316Swollman	 *
19119880Swollman	 * RIPv2 authentication is lame.  Why authenticate queries?
19218316Swollman	 * Why should a RIPv2 implementation with authentication disabled
19337908Scharnier	 * not be able to listen to RIPv2 packets with authentication, while
19418316Swollman	 * RIPv1 systems will listen?  Crazy!
19518316Swollman	 */
19618316Swollman	if (!auth_ok
19718316Swollman	    && rip->rip_vers == RIPv2
19818316Swollman	    && n < lim && n->n_family == RIP_AF_AUTH) {
19919880Swollman		msglim(&use_auth, FROM_NADDR,
20019880Swollman		       "RIPv2 message with authentication from %s discarded",
20119880Swollman		       naddr_ntoa(FROM_NADDR));
20218316Swollman		return;
20318316Swollman	}
20418316Swollman
20518316Swollman	switch (rip->rip_cmd) {
20618316Swollman	case RIPCMD_REQUEST:
20719880Swollman		/* For mere requests, be a little sloppy about the source
20818316Swollman		 */
20919880Swollman		if (aifp == 0)
21019880Swollman			aifp = sifp;
21119880Swollman
21219880Swollman		/* Are we talking to ourself or a remote gateway?
21319880Swollman		 */
21419880Swollman		ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
21519880Swollman		if (ifp1) {
21619880Swollman			if (ifp1->int_state & IS_REMOTE) {
21719880Swollman				/* remote gateway */
21819880Swollman				aifp = ifp1;
21919880Swollman				if (check_remote(aifp)) {
22019880Swollman					aifp->int_act_time = now.tv_sec;
22119880Swollman					(void)if_ok(aifp, "remote ");
22219880Swollman				}
22319880Swollman			} else if (from->sin_port == htons(RIP_PORT)) {
22419880Swollman				trace_pkt("    discard our own RIP request");
22518316Swollman				return;
22618316Swollman			}
22719880Swollman		}
22818316Swollman
22919880Swollman		/* did the request come from a router?
23019880Swollman		 */
23119880Swollman		if (from->sin_port == htons(RIP_PORT)) {
23219880Swollman			/* yes, ignore the request if RIP is off so that
23319880Swollman			 * the router does not depend on us.
23418316Swollman			 */
23519880Swollman			if (rip_sock < 0
23619880Swollman			    || (aifp != 0
23719880Swollman				&& IS_RIP_OUT_OFF(aifp->int_state))) {
23819880Swollman				trace_pkt("    discard request while RIP off");
23918316Swollman				return;
24018316Swollman			}
24118316Swollman		}
24218316Swollman
24337908Scharnier		/* According to RFC 1723, we should ignore unauthenticated
24418316Swollman		 * queries.  That is too silly to bother with.  Sheesh!
24519880Swollman		 * Are forwarding tables supposed to be secret, when
24619880Swollman		 * a bad guy can infer them with test traffic?  When RIP
24719880Swollman		 * is still the most common router-discovery protocol
24819880Swollman		 * and so hosts need to send queries that will be answered?
24919880Swollman		 * What about `rtquery`?
25018316Swollman		 * Maybe on firewalls you'd care, but not enough to
25118316Swollman		 * give up the diagnostic facilities of remote probing.
25218316Swollman		 */
25318316Swollman
25419880Swollman		if (n >= lim) {
25519880Swollman			msglim(&bad_len, FROM_NADDR, "empty request from %s",
25619880Swollman			       naddr_ntoa(FROM_NADDR));
25719880Swollman			return;
25818316Swollman		}
25919880Swollman		if (cc%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
26019880Swollman			msglim(&bad_len, FROM_NADDR,
26119880Swollman			       "request of bad length (%d) from %s",
26219880Swollman			       cc, naddr_ntoa(FROM_NADDR));
26319880Swollman		}
26418316Swollman
26519880Swollman		if (rip->rip_vers == RIPv2
26619880Swollman		    && (aifp == 0 || (aifp->int_state & IS_NO_RIPV1_OUT))) {
26719880Swollman			v12buf.buf->rip_vers = RIPv2;
26819880Swollman			/* If we have a secret but it is a cleartext secret,
26919880Swollman			 * do not disclose our secret unless the other guy
27019880Swollman			 * already knows it.
27119880Swollman			 */
27220339Swollman			ap = find_auth(aifp);
27320735Sache			if (ap != 0 && ap->type == RIP_AUTH_PW
27420339Swollman			    && n->n_family == RIP_AF_AUTH
27519880Swollman			    && !ck_passwd(aifp,rip,lim,FROM_NADDR,&use_auth))
27619880Swollman				ap = 0;
27719880Swollman		} else {
27819880Swollman			v12buf.buf->rip_vers = RIPv1;
27919880Swollman			ap = 0;
28019880Swollman		}
28120339Swollman		clr_ws_buf(&v12buf, ap);
28219880Swollman
28319880Swollman		do {
28490868Smike			n->n_metric = ntohl(n->n_metric);
28519880Swollman
28618316Swollman			/* A single entry with family RIP_AF_UNSPEC and
28718316Swollman			 * metric HOPCNT_INFINITY means "all routes".
28818316Swollman			 * We respond to routers only if we are acting
28918316Swollman			 * as a supplier, or to anyone other than a router
29018316Swollman			 * (i.e. a query).
29118316Swollman			 */
29218316Swollman			if (n->n_family == RIP_AF_UNSPEC
29319880Swollman			    && n->n_metric == HOPCNT_INFINITY) {
29446303Smarkm				/* Answer a query from a utility program
29546303Smarkm				 * with all we know.
29646303Smarkm				 */
29718316Swollman				if (from->sin_port != htons(RIP_PORT)) {
298272872Shrs					/*
299272872Shrs					 * insecure: query from non-router node
300272872Shrs					 *   > 1: allow from distant node
301272872Shrs					 *   > 0: allow from neighbor node
302272872Shrs					 *  == 0: deny
303272872Shrs					 */
304272872Shrs					if ((aifp != NULL && insecure > 0) ||
305272872Shrs					    (aifp == NULL && insecure > 1))
306272872Shrs						supply(from, aifp, OUT_QUERY, 0,
307272872Shrs						       rip->rip_vers, ap != 0);
308272872Shrs					else
309272872Shrs						trace_pkt("Warning: "
310272872Shrs						    "possible attack detected");
31118316Swollman					return;
31218316Swollman				}
31319880Swollman
31418316Swollman				/* A router trying to prime its tables.
31518316Swollman				 * Filter the answer in the about same way
31618316Swollman				 * broadcasts are filtered.
31718316Swollman				 *
31818316Swollman				 * Only answer a router if we are a supplier
31918316Swollman				 * to keep an unwary host that is just starting
32046303Smarkm				 * from picking us as a router.
32118316Swollman				 */
32219880Swollman				if (aifp == 0) {
32319880Swollman					trace_pkt("ignore distant router");
32419880Swollman					return;
32519880Swollman				}
32618316Swollman				if (!supplier
32719880Swollman				    || IS_RIP_OFF(aifp->int_state)) {
32819880Swollman					trace_pkt("ignore; not supplying");
32918316Swollman					return;
33019880Swollman				}
33118316Swollman
33246303Smarkm				/* Do not answer a RIPv1 router if
33346303Smarkm				 * we are sending RIPv2.  But do offer
33446303Smarkm				 * poor man's router discovery.
33546303Smarkm				 */
33646303Smarkm				if ((aifp->int_state & IS_NO_RIPV1_OUT)
33746303Smarkm				    && rip->rip_vers == RIPv1) {
33846303Smarkm					if (!(aifp->int_state & IS_PM_RDISC)) {
33946303Smarkm					    trace_pkt("ignore; sending RIPv2");
34046303Smarkm					    return;
34146303Smarkm					}
34246303Smarkm
34346303Smarkm					v12buf.n->n_family = RIP_AF_INET;
34446303Smarkm					v12buf.n->n_dst = RIP_DEFAULT;
34546303Smarkm					i = aifp->int_d_metric;
346126250Sbms					if (0 != (rt = rtget(RIP_DEFAULT, 0))) {
347126250Sbms					    j = (rt->rt_metric
348126250Sbms						 +aifp->int_metric
349126250Sbms						 +aifp->int_adj_outmetric
350126250Sbms						 +1);
351126250Sbms					    if (i > j)
352126250Sbms						i = j;
353126250Sbms					}
35446303Smarkm					v12buf.n->n_metric = htonl(i);
35546303Smarkm					v12buf.n++;
35646303Smarkm					break;
35746303Smarkm				}
35846303Smarkm
35946303Smarkm				/* Respond with RIPv1 instead of RIPv2 if
36046303Smarkm				 * that is what we are broadcasting on the
36146303Smarkm				 * interface to keep the remote router from
36246303Smarkm				 * getting the wrong initial idea of the
36346303Smarkm				 * routes we send.
36446303Smarkm				 */
36518316Swollman				supply(from, aifp, OUT_UNICAST, 0,
36646303Smarkm				       (aifp->int_state & IS_NO_RIPV1_OUT)
36719880Swollman				       ? RIPv2 : RIPv1,
36819880Swollman				       ap != 0);
36918316Swollman				return;
37018316Swollman			}
37118316Swollman
37219880Swollman			/* Ignore authentication */
37319880Swollman			if (n->n_family == RIP_AF_AUTH)
37419880Swollman				continue;
37519880Swollman
37618316Swollman			if (n->n_family != RIP_AF_INET) {
37719880Swollman				msglim(&bad_router, FROM_NADDR,
37846303Smarkm				       "request from %s for unsupported"
37946303Smarkm				       " (af %d) %s",
38019880Swollman				       naddr_ntoa(FROM_NADDR),
38119880Swollman				       ntohs(n->n_family),
38219880Swollman				       naddr_ntoa(n->n_dst));
38318316Swollman				return;
38418316Swollman			}
38518316Swollman
38619880Swollman			/* We are being asked about a specific destination.
38719880Swollman			 */
38818316Swollman			dst = n->n_dst;
38918316Swollman			if (!check_dst(dst)) {
39019880Swollman				msglim(&bad_router, FROM_NADDR,
39119880Swollman				       "bad queried destination %s from %s",
39219880Swollman				       naddr_ntoa(dst),
39319880Swollman				       naddr_ntoa(FROM_NADDR));
39418316Swollman				return;
39518316Swollman			}
39618316Swollman
39719880Swollman			/* decide what mask was intended */
39818316Swollman			if (rip->rip_vers == RIPv1
39918316Swollman			    || 0 == (mask = ntohl(n->n_mask))
40018316Swollman			    || 0 != (ntohl(dst) & ~mask))
40119880Swollman				mask = ripv1_mask_host(dst, aifp);
40218316Swollman
40319880Swollman			/* try to find the answer */
40418316Swollman			rt = rtget(dst, mask);
40518316Swollman			if (!rt && dst != RIP_DEFAULT)
40618316Swollman				rt = rtfind(n->n_dst);
40718316Swollman
40819880Swollman			if (v12buf.buf->rip_vers != RIPv1)
40919880Swollman				v12buf.n->n_mask = mask;
41018316Swollman			if (rt == 0) {
41119880Swollman				/* we do not have the answer */
41219880Swollman				v12buf.n->n_metric = HOPCNT_INFINITY;
41318316Swollman			} else {
41419880Swollman				/* we have the answer, so compute the
41519880Swollman				 * right metric and next hop.
41619880Swollman				 */
41719880Swollman				v12buf.n->n_family = RIP_AF_INET;
41819880Swollman				v12buf.n->n_dst = dst;
419126250Sbms				j = rt->rt_metric+1;
420126250Sbms				if (!aifp)
421126250Sbms					++j;
422126250Sbms				else
423126250Sbms					j += (aifp->int_metric
424126250Sbms					      + aifp->int_adj_outmetric);
425126250Sbms				if (j < HOPCNT_INFINITY)
426126250Sbms					v12buf.n->n_metric = j;
427126250Sbms				else
42819880Swollman					v12buf.n->n_metric = HOPCNT_INFINITY;
42919880Swollman				if (v12buf.buf->rip_vers != RIPv1) {
43019880Swollman					v12buf.n->n_tag = rt->rt_tag;
43119880Swollman					v12buf.n->n_mask = mask;
43219880Swollman					if (aifp != 0
43318316Swollman					    && on_net(rt->rt_gate,
43419880Swollman						      aifp->int_net,
43519880Swollman						      aifp->int_mask)
43619880Swollman					    && rt->rt_gate != aifp->int_addr)
43719880Swollman					    v12buf.n->n_nhop = rt->rt_gate;
43818316Swollman				}
43918316Swollman			}
44090868Smike			v12buf.n->n_metric = htonl(v12buf.n->n_metric);
44119880Swollman
44219880Swollman			/* Stop paying attention if we fill the output buffer.
44319880Swollman			 */
44419880Swollman			if (++v12buf.n >= v12buf.lim)
44519880Swollman				break;
44619880Swollman		} while (++n < lim);
44719880Swollman
44819880Swollman		/* Send the answer about specific routes.
44918316Swollman		 */
45020339Swollman		if (ap != 0 && ap->type == RIP_AUTH_MD5)
45119880Swollman			end_md5_auth(&v12buf, ap);
45219880Swollman
45318316Swollman		if (from->sin_port != htons(RIP_PORT)) {
45418316Swollman			/* query */
45519880Swollman			(void)output(OUT_QUERY, from, aifp,
45619880Swollman				     v12buf.buf,
45719880Swollman				     ((char *)v12buf.n - (char*)v12buf.buf));
45818316Swollman		} else if (supplier) {
45919880Swollman			(void)output(OUT_UNICAST, from, aifp,
46019880Swollman				     v12buf.buf,
46119880Swollman				     ((char *)v12buf.n - (char*)v12buf.buf));
46219880Swollman		} else {
46319880Swollman			/* Only answer a router if we are a supplier
46419880Swollman			 * to keep an unwary host that is just starting
46519880Swollman			 * from picking us an a router.
46619880Swollman			 */
46719880Swollman			;
46818316Swollman		}
46918316Swollman		return;
47018316Swollman
47118316Swollman	case RIPCMD_TRACEON:
47218316Swollman	case RIPCMD_TRACEOFF:
47346303Smarkm		/* Notice that trace messages are turned off for all possible
47446303Smarkm		 * abuse if _PATH_TRACE is undefined in pathnames.h.
47546303Smarkm		 * Notice also that because of the way the trace file is
47646303Smarkm		 * handled in trace.c, no abuse is plausible even if
47746303Smarkm		 * _PATH_TRACE_ is defined.
47846303Smarkm		 *
47946303Smarkm		 * First verify message came from a privileged port. */
48018316Swollman		if (ntohs(from->sin_port) > IPPORT_RESERVED) {
48118316Swollman			msglog("trace command from untrusted port on %s",
48218316Swollman			       naddr_ntoa(FROM_NADDR));
48318316Swollman			return;
48418316Swollman		}
48518316Swollman		if (aifp == 0) {
48618316Swollman			msglog("trace command from unknown router %s",
48718316Swollman			       naddr_ntoa(FROM_NADDR));
48818316Swollman			return;
48918316Swollman		}
49018316Swollman		if (rip->rip_cmd == RIPCMD_TRACEON) {
49119880Swollman			rip->rip_tracefile[cc-4] = '\0';
49220339Swollman			set_tracefile((char*)rip->rip_tracefile,
49320339Swollman				      "trace command: %s\n", 0);
49418316Swollman		} else {
49546303Smarkm			trace_off("tracing turned off by %s",
49618316Swollman				  naddr_ntoa(FROM_NADDR));
49718316Swollman		}
49818316Swollman		return;
49918316Swollman
50018316Swollman	case RIPCMD_RESPONSE:
50119880Swollman		if (cc%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
50219880Swollman			msglim(&bad_len, FROM_NADDR,
50319880Swollman			       "response of bad length (%d) from %s",
50419880Swollman			       cc, naddr_ntoa(FROM_NADDR));
50518316Swollman		}
50618316Swollman
50718316Swollman		/* verify message came from a router */
50818316Swollman		if (from->sin_port != ntohs(RIP_PORT)) {
50919880Swollman			msglim(&bad_router, FROM_NADDR,
51019880Swollman			       "    discard RIP response from unknown port"
511126250Sbms			       " %d on %s",
512126250Sbms			       ntohs(from->sin_port), naddr_ntoa(FROM_NADDR));
51318316Swollman			return;
51418316Swollman		}
51518316Swollman
51618316Swollman		if (rip_sock < 0) {
51719880Swollman			trace_pkt("    discard response while RIP off");
51818316Swollman			return;
51918316Swollman		}
52018316Swollman
52118316Swollman		/* Are we talking to ourself or a remote gateway?
52218316Swollman		 */
52318316Swollman		ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
52418316Swollman		if (ifp1) {
52518316Swollman			if (ifp1->int_state & IS_REMOTE) {
52619880Swollman				/* remote gateway */
52719880Swollman				aifp = ifp1;
52819880Swollman				if (check_remote(aifp)) {
52919880Swollman					aifp->int_act_time = now.tv_sec;
53019880Swollman					(void)if_ok(aifp, "remote ");
53118316Swollman				}
53218316Swollman			} else {
53319880Swollman				trace_pkt("    discard our own RIP response");
53419880Swollman				return;
53518316Swollman			}
53618316Swollman		}
53718316Swollman
53819880Swollman		/* Accept routing packets from routers directly connected
53919880Swollman		 * via broadcast or point-to-point networks, and from
54018316Swollman		 * those listed in /etc/gateways.
54118316Swollman		 */
54219880Swollman		if (aifp == 0) {
54319880Swollman			msglim(&unk_router, FROM_NADDR,
54419880Swollman			       "   discard response from %s"
54519880Swollman			       " via unexpected interface",
54619880Swollman			       naddr_ntoa(FROM_NADDR));
54718316Swollman			return;
54818316Swollman		}
54919880Swollman		if (IS_RIP_IN_OFF(aifp->int_state)) {
55019880Swollman			trace_pkt("    discard RIPv%d response"
55119880Swollman				  " via disabled interface %s",
55219880Swollman				  rip->rip_vers, aifp->int_name);
55318316Swollman			return;
55418316Swollman		}
55518316Swollman
55619880Swollman		if (n >= lim) {
55719880Swollman			msglim(&bad_len, FROM_NADDR, "empty response from %s",
55819880Swollman			       naddr_ntoa(FROM_NADDR));
55919880Swollman			return;
56019880Swollman		}
56119880Swollman
56218316Swollman		if (((aifp->int_state & IS_NO_RIPV1_IN)
56318316Swollman		     && rip->rip_vers == RIPv1)
56418316Swollman		    || ((aifp->int_state & IS_NO_RIPV2_IN)
56518316Swollman			&& rip->rip_vers != RIPv1)) {
56619880Swollman			trace_pkt("    discard RIPv%d response",
56718316Swollman				  rip->rip_vers);
56818316Swollman			return;
56918316Swollman		}
57018316Swollman
57118316Swollman		/* Ignore routes via dead interface.
57218316Swollman		 */
57318316Swollman		if (aifp->int_state & IS_BROKE) {
57446303Smarkm			trace_pkt("discard response via broken interface %s",
57518316Swollman				  aifp->int_name);
57618316Swollman			return;
57718316Swollman		}
57818316Swollman
57919880Swollman		/* If the interface cares, ignore bad routers.
58020339Swollman		 * Trace but do not log this problem, because where it
58120339Swollman		 * happens, it happens frequently.
58219880Swollman		 */
58319880Swollman		if (aifp->int_state & IS_DISTRUST) {
58446303Smarkm			tg = tgates;
58519880Swollman			while (tg->tgate_addr != FROM_NADDR) {
58619880Swollman				tg = tg->tgate_next;
58719880Swollman				if (tg == 0) {
58819880Swollman					trace_pkt("    discard RIP response"
58919880Swollman						  " from untrusted router %s",
59019880Swollman						  naddr_ntoa(FROM_NADDR));
59119880Swollman					return;
59219880Swollman				}
59319880Swollman			}
59419880Swollman		}
59519880Swollman
59618316Swollman		/* Authenticate the packet if we have a secret.
59720339Swollman		 * If we do not have any secrets, ignore the error in
59820339Swollman		 * RFC 1723 and accept it regardless.
59918316Swollman		 */
60020339Swollman		if (aifp->int_auth[0].type != RIP_AUTH_NONE
60120339Swollman		    && rip->rip_vers != RIPv1
60220339Swollman		    && !ck_passwd(aifp,rip,lim,FROM_NADDR,&use_auth))
60320339Swollman			return;
60418316Swollman
60519880Swollman		do {
60618316Swollman			if (n->n_family == RIP_AF_AUTH)
60718316Swollman				continue;
60818316Swollman
60990868Smike			n->n_metric = ntohl(n->n_metric);
61018316Swollman			dst = n->n_dst;
61118316Swollman			if (n->n_family != RIP_AF_INET
61218316Swollman			    && (n->n_family != RIP_AF_UNSPEC
61318316Swollman				|| dst != RIP_DEFAULT)) {
61419880Swollman				msglim(&bad_router, FROM_NADDR,
61519880Swollman				       "route from %s to unsupported"
61619880Swollman				       " address family=%d destination=%s",
61719880Swollman				       naddr_ntoa(FROM_NADDR),
61819880Swollman				       n->n_family,
61919880Swollman				       naddr_ntoa(dst));
62018316Swollman				continue;
62118316Swollman			}
62218316Swollman			if (!check_dst(dst)) {
62319880Swollman				msglim(&bad_router, FROM_NADDR,
62419880Swollman				       "bad destination %s from %s",
62519880Swollman				       naddr_ntoa(dst),
62619880Swollman				       naddr_ntoa(FROM_NADDR));
62718316Swollman				return;
62818316Swollman			}
62918316Swollman			if (n->n_metric == 0
63018316Swollman			    || n->n_metric > HOPCNT_INFINITY) {
63119880Swollman				msglim(&bad_router, FROM_NADDR,
63219880Swollman				       "bad metric %d from %s"
63319880Swollman				       " for destination %s",
63419880Swollman				       n->n_metric,
63519880Swollman				       naddr_ntoa(FROM_NADDR),
63619880Swollman				       naddr_ntoa(dst));
63718316Swollman				return;
63818316Swollman			}
63918316Swollman
64018316Swollman			/* Notice the next-hop.
64118316Swollman			 */
64219880Swollman			gate = FROM_NADDR;
64318316Swollman			if (n->n_nhop != 0) {
64446303Smarkm				if (rip->rip_vers == RIPv1) {
64518316Swollman					n->n_nhop = 0;
64618316Swollman				} else {
64718316Swollman				    /* Use it only if it is valid. */
64818316Swollman				    if (on_net(n->n_nhop,
64918316Swollman					       aifp->int_net, aifp->int_mask)
65018316Swollman					&& check_dst(n->n_nhop)) {
65118316Swollman					    gate = n->n_nhop;
65218316Swollman				    } else {
65319880Swollman					    msglim(&bad_nhop, FROM_NADDR,
65419880Swollman						   "router %s to %s"
65519880Swollman						   " has bad next hop %s",
65619880Swollman						   naddr_ntoa(FROM_NADDR),
65719880Swollman						   naddr_ntoa(dst),
65819880Swollman						   naddr_ntoa(n->n_nhop));
65919880Swollman					    n->n_nhop = 0;
66018316Swollman				    }
66118316Swollman				}
66218316Swollman			}
66318316Swollman
66418316Swollman			if (rip->rip_vers == RIPv1
66518316Swollman			    || 0 == (mask = ntohl(n->n_mask))) {
66618316Swollman				mask = ripv1_mask_host(dst,aifp);
66718316Swollman			} else if ((ntohl(dst) & ~mask) != 0) {
66819880Swollman				msglim(&bad_mask, FROM_NADDR,
66919880Swollman				       "router %s sent bad netmask"
67046303Smarkm				       " %#lx with %s",
67119880Swollman				       naddr_ntoa(FROM_NADDR),
67246303Smarkm				       (u_long)mask,
67319880Swollman				       naddr_ntoa(dst));
67418316Swollman				continue;
67518316Swollman			}
67618316Swollman			if (rip->rip_vers == RIPv1)
67718316Swollman				n->n_tag = 0;
67818316Swollman
67918316Swollman			/* Adjust metric according to incoming interface..
68018316Swollman			 */
681126250Sbms			n->n_metric += (aifp->int_metric
682126250Sbms					+ aifp->int_adj_inmetric);
68318316Swollman			if (n->n_metric > HOPCNT_INFINITY)
68418316Swollman				n->n_metric = HOPCNT_INFINITY;
68518316Swollman
68646303Smarkm			/* Should we trust this route from this router? */
68746303Smarkm			if (tg && (tn = tg->tgate_nets)->mask != 0) {
68846303Smarkm				for (i = 0; i < MAX_TGATE_NETS; i++, tn++) {
68946303Smarkm					if (on_net(dst, tn->net, tn->mask)
69046303Smarkm					    && tn->mask <= mask)
69146303Smarkm					    break;
69246303Smarkm				}
69346303Smarkm				if (i >= MAX_TGATE_NETS || tn->mask == 0) {
69446303Smarkm					trace_pkt("   ignored unauthorized %s",
69546303Smarkm						  addrname(dst,mask,0));
69646303Smarkm					continue;
69746303Smarkm				}
69846303Smarkm			}
69946303Smarkm
70018316Swollman			/* Recognize and ignore a default route we faked
70118316Swollman			 * which is being sent back to us by a machine with
70218316Swollman			 * broken split-horizon.
70318316Swollman			 * Be a little more paranoid than that, and reject
70418316Swollman			 * default routes with the same metric we advertised.
70518316Swollman			 */
70618316Swollman			if (aifp->int_d_metric != 0
70718316Swollman			    && dst == RIP_DEFAULT
70846303Smarkm			    && (int)n->n_metric >= aifp->int_d_metric)
70918316Swollman				continue;
71018316Swollman
71118316Swollman			/* We can receive aggregated RIPv2 routes that must
71218316Swollman			 * be broken down before they are transmitted by
71318316Swollman			 * RIPv1 via an interface on a subnet.
71418316Swollman			 * We might also receive the same routes aggregated
71518316Swollman			 * via other RIPv2 interfaces.
71618316Swollman			 * This could cause duplicate routes to be sent on
71718316Swollman			 * the RIPv1 interfaces.  "Longest matching variable
71818316Swollman			 * length netmasks" lets RIPv2 listeners understand,
71918316Swollman			 * but breaking down the aggregated routes for RIPv1
72018316Swollman			 * listeners can produce duplicate routes.
72118316Swollman			 *
72218316Swollman			 * Breaking down aggregated routes here bloats
72318316Swollman			 * the daemon table, but does not hurt the kernel
72418316Swollman			 * table, since routes are always aggregated for
72518316Swollman			 * the kernel.
72618316Swollman			 *
72718316Swollman			 * Notice that this does not break down network
72818316Swollman			 * routes corresponding to subnets.  This is part
72918316Swollman			 * of the defense against RS_NET_SYN.
73018316Swollman			 */
73118316Swollman			if (have_ripv1_out
73218316Swollman			    && (((rt = rtget(dst,mask)) == 0
73319880Swollman				 || !(rt->rt_state & RS_NET_SYN)))
73419880Swollman			    && (v1_mask = ripv1_mask_net(dst,0)) > mask) {
73518316Swollman				ddst_h = v1_mask & -v1_mask;
73618316Swollman				i = (v1_mask & ~mask)/ddst_h;
73718316Swollman				if (i >= 511) {
73818316Swollman					/* Punt if we would have to generate
73918316Swollman					 * an unreasonable number of routes.
74018316Swollman					 */
74146303Smarkm					if (TRACECONTENTS)
74246303Smarkm					    trace_misc("accept %s-->%s as 1"
74346303Smarkm						       " instead of %d routes",
74446303Smarkm						       addrname(dst,mask,0),
74546303Smarkm						       naddr_ntoa(FROM_NADDR),
74646303Smarkm						       i+1);
74718316Swollman					i = 0;
74818316Swollman				} else {
74918316Swollman					mask = v1_mask;
75018316Swollman				}
75118316Swollman			} else {
75218316Swollman				i = 0;
75318316Swollman			}
75418316Swollman
75546303Smarkm			new.rts_gate = gate;
75646303Smarkm			new.rts_router = FROM_NADDR;
75746303Smarkm			new.rts_metric = n->n_metric;
75846303Smarkm			new.rts_tag = n->n_tag;
75946303Smarkm			new.rts_time = now.tv_sec;
76046303Smarkm			new.rts_ifp = aifp;
76146303Smarkm			new.rts_de_ag = i;
76246303Smarkm			j = 0;
76318316Swollman			for (;;) {
76446303Smarkm				input_route(dst, mask, &new, n);
76546303Smarkm				if (++j > i)
76618316Swollman					break;
76718316Swollman				dst = htonl(ntohl(dst) + ddst_h);
76818316Swollman			}
76919880Swollman		} while (++n < lim);
77018316Swollman		break;
77118316Swollman	}
77219880Swollman#undef FROM_NADDR
77318316Swollman}
77418316Swollman
77518316Swollman
77618316Swollman/* Process a single input route.
77718316Swollman */
77818316Swollmanstatic void
77946303Smarkminput_route(naddr dst,			/* network order */
78018316Swollman	    naddr mask,
78146303Smarkm	    struct rt_spare *new,
78218316Swollman	    struct netinfo *n)
78318316Swollman{
78418316Swollman	int i;
78518316Swollman	struct rt_entry *rt;
78618316Swollman	struct rt_spare *rts, *rts0;
78718316Swollman	struct interface *ifp1;
78818316Swollman
78918316Swollman
79018316Swollman	/* See if the other guy is telling us to send our packets to him.
79118316Swollman	 * Sometimes network routes arrive over a point-to-point link for
79218316Swollman	 * the network containing the address(es) of the link.
79318316Swollman	 *
79418316Swollman	 * If our interface is broken, switch to using the other guy.
79518316Swollman	 */
79618316Swollman	ifp1 = ifwithaddr(dst, 1, 1);
79718316Swollman	if (ifp1 != 0
79819880Swollman	    && (!(ifp1->int_state & IS_BROKE)
79919880Swollman		|| (ifp1->int_state & IS_PASSIVE)))
80018316Swollman		return;
80118316Swollman
80218316Swollman	/* Look for the route in our table.
80318316Swollman	 */
80418316Swollman	rt = rtget(dst, mask);
80518316Swollman
80618316Swollman	/* Consider adding the route if we do not already have it.
80718316Swollman	 */
80818316Swollman	if (rt == 0) {
80918316Swollman		/* Ignore unknown routes being poisoned.
81018316Swollman		 */
81146303Smarkm		if (new->rts_metric == HOPCNT_INFINITY)
81218316Swollman			return;
81318316Swollman
81418316Swollman		/* Ignore the route if it points to us */
81518316Swollman		if (n->n_nhop != 0
81618316Swollman		    && 0 != ifwithaddr(n->n_nhop, 1, 0))
81718316Swollman			return;
81818316Swollman
81918316Swollman		/* If something has not gone crazy and tried to fill
82018316Swollman		 * our memory, accept the new route.
82118316Swollman		 */
82218316Swollman		if (total_routes < MAX_ROUTES)
82346303Smarkm			rtadd(dst, mask, 0, new);
82418316Swollman		return;
82518316Swollman	}
82618316Swollman
82718316Swollman	/* We already know about the route.  Consider this update.
82818316Swollman	 *
82918316Swollman	 * If (rt->rt_state & RS_NET_SYN), then this route
83018316Swollman	 * is the same as a network route we have inferred
83118316Swollman	 * for subnets we know, in order to tell RIPv1 routers
83218316Swollman	 * about the subnets.
83318316Swollman	 *
83418316Swollman	 * It is impossible to tell if the route is coming
83518316Swollman	 * from a distant RIPv2 router with the standard
83618316Swollman	 * netmask because that router knows about the entire
83718316Swollman	 * network, or if it is a round-about echo of a
83818316Swollman	 * synthetic, RIPv1 network route of our own.
83918316Swollman	 * The worst is that both kinds of routes might be
84018316Swollman	 * received, and the bad one might have the smaller
84118316Swollman	 * metric.  Partly solve this problem by never
84218316Swollman	 * aggregating into such a route.  Also keep it
84318316Swollman	 * around as long as the interface exists.
84418316Swollman	 */
84518316Swollman
84618316Swollman	rts0 = rt->rt_spares;
84718316Swollman	for (rts = rts0, i = NUM_SPARES; i != 0; i--, rts++) {
84846303Smarkm		if (rts->rts_router == new->rts_router)
84918316Swollman			break;
85018316Swollman		/* Note the worst slot to reuse,
85118316Swollman		 * other than the current slot.
85218316Swollman		 */
85318316Swollman		if (rts0 == rt->rt_spares
85418316Swollman		    || BETTER_LINK(rt, rts0, rts))
85518316Swollman			rts0 = rts;
85618316Swollman	}
85718316Swollman	if (i != 0) {
85846303Smarkm		/* Found a route from the router already in the table.
85918316Swollman		 */
86018316Swollman
86146303Smarkm		/* If the new route is a route broken down from an
86246303Smarkm		 * aggregated route, and if the previous route is either
86346303Smarkm		 * not a broken down route or was broken down from a finer
86446303Smarkm		 * netmask, and if the previous route is current,
86546303Smarkm		 * then forget this one.
86646303Smarkm		 */
86746303Smarkm		if (new->rts_de_ag > rts->rts_de_ag
86846303Smarkm		    && now_stale <= rts->rts_time)
86946303Smarkm			return;
87046303Smarkm
87118316Swollman		/* Keep poisoned routes around only long enough to pass
87246303Smarkm		 * the poison on.  Use a new timestamp for good routes.
87318316Swollman		 */
87446303Smarkm		if (rts->rts_metric == HOPCNT_INFINITY
87546303Smarkm		    && new->rts_metric == HOPCNT_INFINITY)
87646303Smarkm			new->rts_time = rts->rts_time;
87718316Swollman
87818316Swollman		/* If this is an update for the router we currently prefer,
87918316Swollman		 * then note it.
88018316Swollman		 */
88118316Swollman		if (i == NUM_SPARES) {
88246303Smarkm			rtchange(rt, rt->rt_state, new, 0);
88318316Swollman			/* If the route got worse, check for something better.
88418316Swollman			 */
88546303Smarkm			if (new->rts_metric > rts->rts_metric)
88618316Swollman				rtswitch(rt, 0);
88718316Swollman			return;
88818316Swollman		}
88918316Swollman
89018316Swollman		/* This is an update for a spare route.
89118316Swollman		 * Finished if the route is unchanged.
89218316Swollman		 */
89346303Smarkm		if (rts->rts_gate == new->rts_gate
89446303Smarkm		    && rts->rts_metric == new->rts_metric
89546303Smarkm		    && rts->rts_tag == new->rts_tag) {
89646303Smarkm			trace_upslot(rt, rts, new);
89746303Smarkm			*rts = *new;
89818316Swollman			return;
89918316Swollman		}
90046303Smarkm		/* Forget it if it has gone bad.
90146303Smarkm		 */
90246303Smarkm		if (new->rts_metric == HOPCNT_INFINITY) {
90346303Smarkm			rts_delete(rt, rts);
90446303Smarkm			return;
90546303Smarkm		}
90618316Swollman
90718316Swollman	} else {
90818316Swollman		/* The update is for a route we know about,
90918316Swollman		 * but not from a familiar router.
91018316Swollman		 *
91118316Swollman		 * Ignore the route if it points to us.
91218316Swollman		 */
91318316Swollman		if (n->n_nhop != 0
91418316Swollman		    && 0 != ifwithaddr(n->n_nhop, 1, 0))
91518316Swollman			return;
91618316Swollman
91746303Smarkm		/* the loop above set rts0=worst spare */
91818316Swollman		rts = rts0;
91918316Swollman
92018316Swollman		/* Save the route as a spare only if it has
92118316Swollman		 * a better metric than our worst spare.
92218316Swollman		 * This also ignores poisoned routes (those
92318316Swollman		 * received with metric HOPCNT_INFINITY).
92418316Swollman		 */
92546303Smarkm		if (new->rts_metric >= rts->rts_metric)
92618316Swollman			return;
92718316Swollman	}
92818316Swollman
92946303Smarkm	trace_upslot(rt, rts, new);
93046303Smarkm	*rts = *new;
93118316Swollman
93218316Swollman	/* try to switch to a better route */
93318316Swollman	rtswitch(rt, rts);
93418316Swollman}
93519880Swollman
93619880Swollman
93719880Swollmanstatic int				/* 0 if bad */
93819880Swollmanck_passwd(struct interface *aifp,
93919880Swollman	  struct rip *rip,
94019880Swollman	  void *lim,
94119880Swollman	  naddr from,
94219880Swollman	  struct msg_limit *use_authp)
94319880Swollman{
94419880Swollman#	define NA (rip->rip_auths)
94519880Swollman	struct netauth *na2;
94620339Swollman	struct auth *ap;
94719880Swollman	MD5_CTX md5_ctx;
94819880Swollman	u_char hash[RIP_AUTH_PW_LEN];
94946303Smarkm	int i, len;
95019880Swollman
951190718Sphk	assert(aifp != NULL);
95219880Swollman	if ((void *)NA >= lim || NA->a_family != RIP_AF_AUTH) {
95319880Swollman		msglim(use_authp, from, "missing password from %s",
95419880Swollman		       naddr_ntoa(from));
95519880Swollman		return 0;
95619880Swollman	}
95719880Swollman
95820339Swollman	/* accept any current (+/- 24 hours) password
95920339Swollman	 */
96020339Swollman	for (ap = aifp->int_auth, i = 0; i < MAX_AUTH_KEYS; i++, ap++) {
96120339Swollman		if (ap->type != NA->a_type
96220339Swollman		    || (u_long)ap->start > (u_long)clk.tv_sec+DAY
96320339Swollman		    || (u_long)ap->end+DAY < (u_long)clk.tv_sec)
96420339Swollman			continue;
96519880Swollman
96620339Swollman		if (NA->a_type == RIP_AUTH_PW) {
96746303Smarkm			if (!memcmp(NA->au.au_pw, ap->key, RIP_AUTH_PW_LEN))
96819880Swollman				return 1;
96919880Swollman
97020339Swollman		} else {
97120339Swollman			/* accept MD5 secret with the right key ID
97220339Swollman			 */
97320339Swollman			if (NA->au.a_md5.md5_keyid != ap->keyid)
97420339Swollman				continue;
97519880Swollman
97646303Smarkm			len = ntohs(NA->au.a_md5.md5_pkt_len);
97746303Smarkm			if ((len-sizeof(*rip)) % sizeof(*NA) != 0
97846303Smarkm			    || len != (char *)lim-(char*)rip-(int)sizeof(*NA)) {
97919880Swollman				msglim(use_authp, from,
98046303Smarkm				       "wrong MD5 RIPv2 packet length of %d"
98146303Smarkm				       " instead of %d from %s",
98246303Smarkm				       len, (int)((char *)lim-(char *)rip
98346303Smarkm						  -sizeof(*NA)),
98419880Swollman				       naddr_ntoa(from));
98519880Swollman				return 0;
98619880Swollman			}
98746303Smarkm			na2 = (struct netauth *)((char *)rip+len);
98846303Smarkm
98946303Smarkm			/* Given a good hash value, these are not security
99046303Smarkm			 * problems so be generous and accept the routes,
99146303Smarkm			 * after complaining.
99246303Smarkm			 */
99346303Smarkm			if (TRACEPACKETS) {
99446303Smarkm				if (NA->au.a_md5.md5_auth_len
995126250Sbms				    != RIP_AUTH_MD5_HASH_LEN)
99646303Smarkm					msglim(use_authp, from,
99746303Smarkm					       "unknown MD5 RIPv2 auth len %#x"
99846303Smarkm					       " instead of %#x from %s",
99946303Smarkm					       NA->au.a_md5.md5_auth_len,
1000190745Sphk					       (unsigned)RIP_AUTH_MD5_HASH_LEN,
100146303Smarkm					       naddr_ntoa(from));
100246303Smarkm				if (na2->a_family != RIP_AF_AUTH)
100346303Smarkm					msglim(use_authp, from,
100446303Smarkm					       "unknown MD5 RIPv2 family %#x"
100546303Smarkm					       " instead of %#x from %s",
100646303Smarkm					       na2->a_family, RIP_AF_AUTH,
100746303Smarkm					       naddr_ntoa(from));
100846303Smarkm				if (na2->a_type != ntohs(1))
100946303Smarkm					msglim(use_authp, from,
101046303Smarkm					       "MD5 RIPv2 hash has %#x"
101146303Smarkm					       " instead of %#x from %s",
101246303Smarkm					       na2->a_type, ntohs(1),
101346303Smarkm					       naddr_ntoa(from));
101446303Smarkm			}
101546303Smarkm
101619880Swollman			MD5Init(&md5_ctx);
1017126250Sbms			MD5Update(&md5_ctx, (u_char *)rip,
1018126250Sbms				  len + RIP_AUTH_MD5_HASH_XTRA);
1019126250Sbms			MD5Update(&md5_ctx, ap->key, RIP_AUTH_MD5_KEY_LEN);
102019880Swollman			MD5Final(hash, &md5_ctx);
102146303Smarkm			if (!memcmp(hash, na2->au.au_pw, sizeof(hash)))
102246303Smarkm				return 1;
102319880Swollman		}
102419880Swollman	}
102519880Swollman
102619880Swollman	msglim(use_authp, from, "bad password from %s",
102719880Swollman	       naddr_ntoa(from));
102819880Swollman	return 0;
102919880Swollman#undef NA
103019880Swollman}
1031