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
163286351Sdelphij	if (sifp == 0) {
164286351Sdelphij		trace_pkt("    discard a request from an indirect router"
165286351Sdelphij		    " (possibly an attack)");
166286351Sdelphij		return;
167286351Sdelphij	}
168286351Sdelphij
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				 */
297273414Sdelphij				if (aifp == NULL) {
298273414Sdelphij					trace_pkt("ignore remote query");
299273414Sdelphij					return;
300273414Sdelphij				}
30118316Swollman				if (from->sin_port != htons(RIP_PORT)) {
30219880Swollman					supply(from, aifp, OUT_QUERY, 0,
30319880Swollman					       rip->rip_vers, ap != 0);
30418316Swollman					return;
30518316Swollman				}
30619880Swollman
30718316Swollman				/* A router trying to prime its tables.
30818316Swollman				 * Filter the answer in the about same way
30918316Swollman				 * broadcasts are filtered.
31018316Swollman				 *
31118316Swollman				 * Only answer a router if we are a supplier
31218316Swollman				 * to keep an unwary host that is just starting
31346303Smarkm				 * from picking us as a router.
31418316Swollman				 */
31519880Swollman				if (aifp == 0) {
31619880Swollman					trace_pkt("ignore distant router");
31719880Swollman					return;
31819880Swollman				}
31918316Swollman				if (!supplier
32019880Swollman				    || IS_RIP_OFF(aifp->int_state)) {
32119880Swollman					trace_pkt("ignore; not supplying");
32218316Swollman					return;
32319880Swollman				}
32418316Swollman
32546303Smarkm				/* Do not answer a RIPv1 router if
32646303Smarkm				 * we are sending RIPv2.  But do offer
32746303Smarkm				 * poor man's router discovery.
32846303Smarkm				 */
32946303Smarkm				if ((aifp->int_state & IS_NO_RIPV1_OUT)
33046303Smarkm				    && rip->rip_vers == RIPv1) {
33146303Smarkm					if (!(aifp->int_state & IS_PM_RDISC)) {
33246303Smarkm					    trace_pkt("ignore; sending RIPv2");
33346303Smarkm					    return;
33446303Smarkm					}
33546303Smarkm
33646303Smarkm					v12buf.n->n_family = RIP_AF_INET;
33746303Smarkm					v12buf.n->n_dst = RIP_DEFAULT;
33846303Smarkm					i = aifp->int_d_metric;
339126250Sbms					if (0 != (rt = rtget(RIP_DEFAULT, 0))) {
340126250Sbms					    j = (rt->rt_metric
341126250Sbms						 +aifp->int_metric
342126250Sbms						 +aifp->int_adj_outmetric
343126250Sbms						 +1);
344126250Sbms					    if (i > j)
345126250Sbms						i = j;
346126250Sbms					}
34746303Smarkm					v12buf.n->n_metric = htonl(i);
34846303Smarkm					v12buf.n++;
34946303Smarkm					break;
35046303Smarkm				}
35146303Smarkm
35246303Smarkm				/* Respond with RIPv1 instead of RIPv2 if
35346303Smarkm				 * that is what we are broadcasting on the
35446303Smarkm				 * interface to keep the remote router from
35546303Smarkm				 * getting the wrong initial idea of the
35646303Smarkm				 * routes we send.
35746303Smarkm				 */
35818316Swollman				supply(from, aifp, OUT_UNICAST, 0,
35946303Smarkm				       (aifp->int_state & IS_NO_RIPV1_OUT)
36019880Swollman				       ? RIPv2 : RIPv1,
36119880Swollman				       ap != 0);
36218316Swollman				return;
36318316Swollman			}
36418316Swollman
36519880Swollman			/* Ignore authentication */
36619880Swollman			if (n->n_family == RIP_AF_AUTH)
36719880Swollman				continue;
36819880Swollman
36918316Swollman			if (n->n_family != RIP_AF_INET) {
37019880Swollman				msglim(&bad_router, FROM_NADDR,
37146303Smarkm				       "request from %s for unsupported"
37246303Smarkm				       " (af %d) %s",
37319880Swollman				       naddr_ntoa(FROM_NADDR),
37419880Swollman				       ntohs(n->n_family),
37519880Swollman				       naddr_ntoa(n->n_dst));
37618316Swollman				return;
37718316Swollman			}
37818316Swollman
37919880Swollman			/* We are being asked about a specific destination.
38019880Swollman			 */
38118316Swollman			dst = n->n_dst;
38218316Swollman			if (!check_dst(dst)) {
38319880Swollman				msglim(&bad_router, FROM_NADDR,
38419880Swollman				       "bad queried destination %s from %s",
38519880Swollman				       naddr_ntoa(dst),
38619880Swollman				       naddr_ntoa(FROM_NADDR));
38718316Swollman				return;
38818316Swollman			}
38918316Swollman
39019880Swollman			/* decide what mask was intended */
39118316Swollman			if (rip->rip_vers == RIPv1
39218316Swollman			    || 0 == (mask = ntohl(n->n_mask))
39318316Swollman			    || 0 != (ntohl(dst) & ~mask))
39419880Swollman				mask = ripv1_mask_host(dst, aifp);
39518316Swollman
39619880Swollman			/* try to find the answer */
39718316Swollman			rt = rtget(dst, mask);
39818316Swollman			if (!rt && dst != RIP_DEFAULT)
39918316Swollman				rt = rtfind(n->n_dst);
40018316Swollman
40119880Swollman			if (v12buf.buf->rip_vers != RIPv1)
40219880Swollman				v12buf.n->n_mask = mask;
40318316Swollman			if (rt == 0) {
40419880Swollman				/* we do not have the answer */
40519880Swollman				v12buf.n->n_metric = HOPCNT_INFINITY;
40618316Swollman			} else {
40719880Swollman				/* we have the answer, so compute the
40819880Swollman				 * right metric and next hop.
40919880Swollman				 */
41019880Swollman				v12buf.n->n_family = RIP_AF_INET;
41119880Swollman				v12buf.n->n_dst = dst;
412126250Sbms				j = rt->rt_metric+1;
413126250Sbms				if (!aifp)
414126250Sbms					++j;
415126250Sbms				else
416126250Sbms					j += (aifp->int_metric
417126250Sbms					      + aifp->int_adj_outmetric);
418126250Sbms				if (j < HOPCNT_INFINITY)
419126250Sbms					v12buf.n->n_metric = j;
420126250Sbms				else
42119880Swollman					v12buf.n->n_metric = HOPCNT_INFINITY;
42219880Swollman				if (v12buf.buf->rip_vers != RIPv1) {
42319880Swollman					v12buf.n->n_tag = rt->rt_tag;
42419880Swollman					v12buf.n->n_mask = mask;
42519880Swollman					if (aifp != 0
42618316Swollman					    && on_net(rt->rt_gate,
42719880Swollman						      aifp->int_net,
42819880Swollman						      aifp->int_mask)
42919880Swollman					    && rt->rt_gate != aifp->int_addr)
43019880Swollman					    v12buf.n->n_nhop = rt->rt_gate;
43118316Swollman				}
43218316Swollman			}
43390868Smike			v12buf.n->n_metric = htonl(v12buf.n->n_metric);
43419880Swollman
43519880Swollman			/* Stop paying attention if we fill the output buffer.
43619880Swollman			 */
43719880Swollman			if (++v12buf.n >= v12buf.lim)
43819880Swollman				break;
43919880Swollman		} while (++n < lim);
44019880Swollman
44119880Swollman		/* Send the answer about specific routes.
44218316Swollman		 */
44320339Swollman		if (ap != 0 && ap->type == RIP_AUTH_MD5)
44419880Swollman			end_md5_auth(&v12buf, ap);
44519880Swollman
44618316Swollman		if (from->sin_port != htons(RIP_PORT)) {
44718316Swollman			/* query */
44819880Swollman			(void)output(OUT_QUERY, from, aifp,
44919880Swollman				     v12buf.buf,
45019880Swollman				     ((char *)v12buf.n - (char*)v12buf.buf));
45118316Swollman		} else if (supplier) {
45219880Swollman			(void)output(OUT_UNICAST, from, aifp,
45319880Swollman				     v12buf.buf,
45419880Swollman				     ((char *)v12buf.n - (char*)v12buf.buf));
45519880Swollman		} else {
45619880Swollman			/* Only answer a router if we are a supplier
45719880Swollman			 * to keep an unwary host that is just starting
45819880Swollman			 * from picking us an a router.
45919880Swollman			 */
46019880Swollman			;
46118316Swollman		}
46218316Swollman		return;
46318316Swollman
46418316Swollman	case RIPCMD_TRACEON:
46518316Swollman	case RIPCMD_TRACEOFF:
46646303Smarkm		/* Notice that trace messages are turned off for all possible
46746303Smarkm		 * abuse if _PATH_TRACE is undefined in pathnames.h.
46846303Smarkm		 * Notice also that because of the way the trace file is
46946303Smarkm		 * handled in trace.c, no abuse is plausible even if
47046303Smarkm		 * _PATH_TRACE_ is defined.
47146303Smarkm		 *
47246303Smarkm		 * First verify message came from a privileged port. */
47318316Swollman		if (ntohs(from->sin_port) > IPPORT_RESERVED) {
47418316Swollman			msglog("trace command from untrusted port on %s",
47518316Swollman			       naddr_ntoa(FROM_NADDR));
47618316Swollman			return;
47718316Swollman		}
47818316Swollman		if (aifp == 0) {
47918316Swollman			msglog("trace command from unknown router %s",
48018316Swollman			       naddr_ntoa(FROM_NADDR));
48118316Swollman			return;
48218316Swollman		}
48318316Swollman		if (rip->rip_cmd == RIPCMD_TRACEON) {
48419880Swollman			rip->rip_tracefile[cc-4] = '\0';
48520339Swollman			set_tracefile((char*)rip->rip_tracefile,
48620339Swollman				      "trace command: %s\n", 0);
48718316Swollman		} else {
48846303Smarkm			trace_off("tracing turned off by %s",
48918316Swollman				  naddr_ntoa(FROM_NADDR));
49018316Swollman		}
49118316Swollman		return;
49218316Swollman
49318316Swollman	case RIPCMD_RESPONSE:
49419880Swollman		if (cc%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
49519880Swollman			msglim(&bad_len, FROM_NADDR,
49619880Swollman			       "response of bad length (%d) from %s",
49719880Swollman			       cc, naddr_ntoa(FROM_NADDR));
49818316Swollman		}
49918316Swollman
50018316Swollman		/* verify message came from a router */
50118316Swollman		if (from->sin_port != ntohs(RIP_PORT)) {
50219880Swollman			msglim(&bad_router, FROM_NADDR,
50319880Swollman			       "    discard RIP response from unknown port"
504126250Sbms			       " %d on %s",
505126250Sbms			       ntohs(from->sin_port), naddr_ntoa(FROM_NADDR));
50618316Swollman			return;
50718316Swollman		}
50818316Swollman
50918316Swollman		if (rip_sock < 0) {
51019880Swollman			trace_pkt("    discard response while RIP off");
51118316Swollman			return;
51218316Swollman		}
51318316Swollman
51418316Swollman		/* Are we talking to ourself or a remote gateway?
51518316Swollman		 */
51618316Swollman		ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
51718316Swollman		if (ifp1) {
51818316Swollman			if (ifp1->int_state & IS_REMOTE) {
51919880Swollman				/* remote gateway */
52019880Swollman				aifp = ifp1;
52119880Swollman				if (check_remote(aifp)) {
52219880Swollman					aifp->int_act_time = now.tv_sec;
52319880Swollman					(void)if_ok(aifp, "remote ");
52418316Swollman				}
52518316Swollman			} else {
52619880Swollman				trace_pkt("    discard our own RIP response");
52719880Swollman				return;
52818316Swollman			}
52918316Swollman		}
53018316Swollman
53119880Swollman		/* Accept routing packets from routers directly connected
53219880Swollman		 * via broadcast or point-to-point networks, and from
53318316Swollman		 * those listed in /etc/gateways.
53418316Swollman		 */
53519880Swollman		if (aifp == 0) {
53619880Swollman			msglim(&unk_router, FROM_NADDR,
53719880Swollman			       "   discard response from %s"
53819880Swollman			       " via unexpected interface",
53919880Swollman			       naddr_ntoa(FROM_NADDR));
54018316Swollman			return;
54118316Swollman		}
54219880Swollman		if (IS_RIP_IN_OFF(aifp->int_state)) {
54319880Swollman			trace_pkt("    discard RIPv%d response"
54419880Swollman				  " via disabled interface %s",
54519880Swollman				  rip->rip_vers, aifp->int_name);
54618316Swollman			return;
54718316Swollman		}
54818316Swollman
54919880Swollman		if (n >= lim) {
55019880Swollman			msglim(&bad_len, FROM_NADDR, "empty response from %s",
55119880Swollman			       naddr_ntoa(FROM_NADDR));
55219880Swollman			return;
55319880Swollman		}
55419880Swollman
55518316Swollman		if (((aifp->int_state & IS_NO_RIPV1_IN)
55618316Swollman		     && rip->rip_vers == RIPv1)
55718316Swollman		    || ((aifp->int_state & IS_NO_RIPV2_IN)
55818316Swollman			&& rip->rip_vers != RIPv1)) {
55919880Swollman			trace_pkt("    discard RIPv%d response",
56018316Swollman				  rip->rip_vers);
56118316Swollman			return;
56218316Swollman		}
56318316Swollman
56418316Swollman		/* Ignore routes via dead interface.
56518316Swollman		 */
56618316Swollman		if (aifp->int_state & IS_BROKE) {
56746303Smarkm			trace_pkt("discard response via broken interface %s",
56818316Swollman				  aifp->int_name);
56918316Swollman			return;
57018316Swollman		}
57118316Swollman
57219880Swollman		/* If the interface cares, ignore bad routers.
57320339Swollman		 * Trace but do not log this problem, because where it
57420339Swollman		 * happens, it happens frequently.
57519880Swollman		 */
57619880Swollman		if (aifp->int_state & IS_DISTRUST) {
57746303Smarkm			tg = tgates;
57819880Swollman			while (tg->tgate_addr != FROM_NADDR) {
57919880Swollman				tg = tg->tgate_next;
58019880Swollman				if (tg == 0) {
58119880Swollman					trace_pkt("    discard RIP response"
58219880Swollman						  " from untrusted router %s",
58319880Swollman						  naddr_ntoa(FROM_NADDR));
58419880Swollman					return;
58519880Swollman				}
58619880Swollman			}
58719880Swollman		}
58819880Swollman
58918316Swollman		/* Authenticate the packet if we have a secret.
59020339Swollman		 * If we do not have any secrets, ignore the error in
59120339Swollman		 * RFC 1723 and accept it regardless.
59218316Swollman		 */
59320339Swollman		if (aifp->int_auth[0].type != RIP_AUTH_NONE
59420339Swollman		    && rip->rip_vers != RIPv1
59520339Swollman		    && !ck_passwd(aifp,rip,lim,FROM_NADDR,&use_auth))
59620339Swollman			return;
59718316Swollman
59819880Swollman		do {
59918316Swollman			if (n->n_family == RIP_AF_AUTH)
60018316Swollman				continue;
60118316Swollman
60290868Smike			n->n_metric = ntohl(n->n_metric);
60318316Swollman			dst = n->n_dst;
60418316Swollman			if (n->n_family != RIP_AF_INET
60518316Swollman			    && (n->n_family != RIP_AF_UNSPEC
60618316Swollman				|| dst != RIP_DEFAULT)) {
60719880Swollman				msglim(&bad_router, FROM_NADDR,
60819880Swollman				       "route from %s to unsupported"
60919880Swollman				       " address family=%d destination=%s",
61019880Swollman				       naddr_ntoa(FROM_NADDR),
61119880Swollman				       n->n_family,
61219880Swollman				       naddr_ntoa(dst));
61318316Swollman				continue;
61418316Swollman			}
61518316Swollman			if (!check_dst(dst)) {
61619880Swollman				msglim(&bad_router, FROM_NADDR,
61719880Swollman				       "bad destination %s from %s",
61819880Swollman				       naddr_ntoa(dst),
61919880Swollman				       naddr_ntoa(FROM_NADDR));
62018316Swollman				return;
62118316Swollman			}
62218316Swollman			if (n->n_metric == 0
62318316Swollman			    || n->n_metric > HOPCNT_INFINITY) {
62419880Swollman				msglim(&bad_router, FROM_NADDR,
62519880Swollman				       "bad metric %d from %s"
62619880Swollman				       " for destination %s",
62719880Swollman				       n->n_metric,
62819880Swollman				       naddr_ntoa(FROM_NADDR),
62919880Swollman				       naddr_ntoa(dst));
63018316Swollman				return;
63118316Swollman			}
63218316Swollman
63318316Swollman			/* Notice the next-hop.
63418316Swollman			 */
63519880Swollman			gate = FROM_NADDR;
63618316Swollman			if (n->n_nhop != 0) {
63746303Smarkm				if (rip->rip_vers == RIPv1) {
63818316Swollman					n->n_nhop = 0;
63918316Swollman				} else {
64018316Swollman				    /* Use it only if it is valid. */
64118316Swollman				    if (on_net(n->n_nhop,
64218316Swollman					       aifp->int_net, aifp->int_mask)
64318316Swollman					&& check_dst(n->n_nhop)) {
64418316Swollman					    gate = n->n_nhop;
64518316Swollman				    } else {
64619880Swollman					    msglim(&bad_nhop, FROM_NADDR,
64719880Swollman						   "router %s to %s"
64819880Swollman						   " has bad next hop %s",
64919880Swollman						   naddr_ntoa(FROM_NADDR),
65019880Swollman						   naddr_ntoa(dst),
65119880Swollman						   naddr_ntoa(n->n_nhop));
65219880Swollman					    n->n_nhop = 0;
65318316Swollman				    }
65418316Swollman				}
65518316Swollman			}
65618316Swollman
65718316Swollman			if (rip->rip_vers == RIPv1
65818316Swollman			    || 0 == (mask = ntohl(n->n_mask))) {
65918316Swollman				mask = ripv1_mask_host(dst,aifp);
66018316Swollman			} else if ((ntohl(dst) & ~mask) != 0) {
66119880Swollman				msglim(&bad_mask, FROM_NADDR,
66219880Swollman				       "router %s sent bad netmask"
66346303Smarkm				       " %#lx with %s",
66419880Swollman				       naddr_ntoa(FROM_NADDR),
66546303Smarkm				       (u_long)mask,
66619880Swollman				       naddr_ntoa(dst));
66718316Swollman				continue;
66818316Swollman			}
66918316Swollman			if (rip->rip_vers == RIPv1)
67018316Swollman				n->n_tag = 0;
67118316Swollman
67218316Swollman			/* Adjust metric according to incoming interface..
67318316Swollman			 */
674126250Sbms			n->n_metric += (aifp->int_metric
675126250Sbms					+ aifp->int_adj_inmetric);
67618316Swollman			if (n->n_metric > HOPCNT_INFINITY)
67718316Swollman				n->n_metric = HOPCNT_INFINITY;
67818316Swollman
67946303Smarkm			/* Should we trust this route from this router? */
68046303Smarkm			if (tg && (tn = tg->tgate_nets)->mask != 0) {
68146303Smarkm				for (i = 0; i < MAX_TGATE_NETS; i++, tn++) {
68246303Smarkm					if (on_net(dst, tn->net, tn->mask)
68346303Smarkm					    && tn->mask <= mask)
68446303Smarkm					    break;
68546303Smarkm				}
68646303Smarkm				if (i >= MAX_TGATE_NETS || tn->mask == 0) {
68746303Smarkm					trace_pkt("   ignored unauthorized %s",
68846303Smarkm						  addrname(dst,mask,0));
68946303Smarkm					continue;
69046303Smarkm				}
69146303Smarkm			}
69246303Smarkm
69318316Swollman			/* Recognize and ignore a default route we faked
69418316Swollman			 * which is being sent back to us by a machine with
69518316Swollman			 * broken split-horizon.
69618316Swollman			 * Be a little more paranoid than that, and reject
69718316Swollman			 * default routes with the same metric we advertised.
69818316Swollman			 */
69918316Swollman			if (aifp->int_d_metric != 0
70018316Swollman			    && dst == RIP_DEFAULT
70146303Smarkm			    && (int)n->n_metric >= aifp->int_d_metric)
70218316Swollman				continue;
70318316Swollman
70418316Swollman			/* We can receive aggregated RIPv2 routes that must
70518316Swollman			 * be broken down before they are transmitted by
70618316Swollman			 * RIPv1 via an interface on a subnet.
70718316Swollman			 * We might also receive the same routes aggregated
70818316Swollman			 * via other RIPv2 interfaces.
70918316Swollman			 * This could cause duplicate routes to be sent on
71018316Swollman			 * the RIPv1 interfaces.  "Longest matching variable
71118316Swollman			 * length netmasks" lets RIPv2 listeners understand,
71218316Swollman			 * but breaking down the aggregated routes for RIPv1
71318316Swollman			 * listeners can produce duplicate routes.
71418316Swollman			 *
71518316Swollman			 * Breaking down aggregated routes here bloats
71618316Swollman			 * the daemon table, but does not hurt the kernel
71718316Swollman			 * table, since routes are always aggregated for
71818316Swollman			 * the kernel.
71918316Swollman			 *
72018316Swollman			 * Notice that this does not break down network
72118316Swollman			 * routes corresponding to subnets.  This is part
72218316Swollman			 * of the defense against RS_NET_SYN.
72318316Swollman			 */
72418316Swollman			if (have_ripv1_out
72518316Swollman			    && (((rt = rtget(dst,mask)) == 0
72619880Swollman				 || !(rt->rt_state & RS_NET_SYN)))
72719880Swollman			    && (v1_mask = ripv1_mask_net(dst,0)) > mask) {
72818316Swollman				ddst_h = v1_mask & -v1_mask;
72918316Swollman				i = (v1_mask & ~mask)/ddst_h;
73018316Swollman				if (i >= 511) {
73118316Swollman					/* Punt if we would have to generate
73218316Swollman					 * an unreasonable number of routes.
73318316Swollman					 */
73446303Smarkm					if (TRACECONTENTS)
73546303Smarkm					    trace_misc("accept %s-->%s as 1"
73646303Smarkm						       " instead of %d routes",
73746303Smarkm						       addrname(dst,mask,0),
73846303Smarkm						       naddr_ntoa(FROM_NADDR),
73946303Smarkm						       i+1);
74018316Swollman					i = 0;
74118316Swollman				} else {
74218316Swollman					mask = v1_mask;
74318316Swollman				}
74418316Swollman			} else {
74518316Swollman				i = 0;
74618316Swollman			}
74718316Swollman
74846303Smarkm			new.rts_gate = gate;
74946303Smarkm			new.rts_router = FROM_NADDR;
75046303Smarkm			new.rts_metric = n->n_metric;
75146303Smarkm			new.rts_tag = n->n_tag;
75246303Smarkm			new.rts_time = now.tv_sec;
75346303Smarkm			new.rts_ifp = aifp;
75446303Smarkm			new.rts_de_ag = i;
75546303Smarkm			j = 0;
75618316Swollman			for (;;) {
75746303Smarkm				input_route(dst, mask, &new, n);
75846303Smarkm				if (++j > i)
75918316Swollman					break;
76018316Swollman				dst = htonl(ntohl(dst) + ddst_h);
76118316Swollman			}
76219880Swollman		} while (++n < lim);
76318316Swollman		break;
76418316Swollman	}
76519880Swollman#undef FROM_NADDR
76618316Swollman}
76718316Swollman
76818316Swollman
76918316Swollman/* Process a single input route.
77018316Swollman */
77118316Swollmanstatic void
77246303Smarkminput_route(naddr dst,			/* network order */
77318316Swollman	    naddr mask,
77446303Smarkm	    struct rt_spare *new,
77518316Swollman	    struct netinfo *n)
77618316Swollman{
77718316Swollman	int i;
77818316Swollman	struct rt_entry *rt;
77918316Swollman	struct rt_spare *rts, *rts0;
78018316Swollman	struct interface *ifp1;
78118316Swollman
78218316Swollman
78318316Swollman	/* See if the other guy is telling us to send our packets to him.
78418316Swollman	 * Sometimes network routes arrive over a point-to-point link for
78518316Swollman	 * the network containing the address(es) of the link.
78618316Swollman	 *
78718316Swollman	 * If our interface is broken, switch to using the other guy.
78818316Swollman	 */
78918316Swollman	ifp1 = ifwithaddr(dst, 1, 1);
79018316Swollman	if (ifp1 != 0
79119880Swollman	    && (!(ifp1->int_state & IS_BROKE)
79219880Swollman		|| (ifp1->int_state & IS_PASSIVE)))
79318316Swollman		return;
79418316Swollman
79518316Swollman	/* Look for the route in our table.
79618316Swollman	 */
79718316Swollman	rt = rtget(dst, mask);
79818316Swollman
79918316Swollman	/* Consider adding the route if we do not already have it.
80018316Swollman	 */
80118316Swollman	if (rt == 0) {
80218316Swollman		/* Ignore unknown routes being poisoned.
80318316Swollman		 */
80446303Smarkm		if (new->rts_metric == HOPCNT_INFINITY)
80518316Swollman			return;
80618316Swollman
80718316Swollman		/* Ignore the route if it points to us */
80818316Swollman		if (n->n_nhop != 0
80918316Swollman		    && 0 != ifwithaddr(n->n_nhop, 1, 0))
81018316Swollman			return;
81118316Swollman
81218316Swollman		/* If something has not gone crazy and tried to fill
81318316Swollman		 * our memory, accept the new route.
81418316Swollman		 */
81518316Swollman		if (total_routes < MAX_ROUTES)
81646303Smarkm			rtadd(dst, mask, 0, new);
81718316Swollman		return;
81818316Swollman	}
81918316Swollman
82018316Swollman	/* We already know about the route.  Consider this update.
82118316Swollman	 *
82218316Swollman	 * If (rt->rt_state & RS_NET_SYN), then this route
82318316Swollman	 * is the same as a network route we have inferred
82418316Swollman	 * for subnets we know, in order to tell RIPv1 routers
82518316Swollman	 * about the subnets.
82618316Swollman	 *
82718316Swollman	 * It is impossible to tell if the route is coming
82818316Swollman	 * from a distant RIPv2 router with the standard
82918316Swollman	 * netmask because that router knows about the entire
83018316Swollman	 * network, or if it is a round-about echo of a
83118316Swollman	 * synthetic, RIPv1 network route of our own.
83218316Swollman	 * The worst is that both kinds of routes might be
83318316Swollman	 * received, and the bad one might have the smaller
83418316Swollman	 * metric.  Partly solve this problem by never
83518316Swollman	 * aggregating into such a route.  Also keep it
83618316Swollman	 * around as long as the interface exists.
83718316Swollman	 */
83818316Swollman
83918316Swollman	rts0 = rt->rt_spares;
84018316Swollman	for (rts = rts0, i = NUM_SPARES; i != 0; i--, rts++) {
84146303Smarkm		if (rts->rts_router == new->rts_router)
84218316Swollman			break;
84318316Swollman		/* Note the worst slot to reuse,
84418316Swollman		 * other than the current slot.
84518316Swollman		 */
84618316Swollman		if (rts0 == rt->rt_spares
84718316Swollman		    || BETTER_LINK(rt, rts0, rts))
84818316Swollman			rts0 = rts;
84918316Swollman	}
85018316Swollman	if (i != 0) {
85146303Smarkm		/* Found a route from the router already in the table.
85218316Swollman		 */
85318316Swollman
85446303Smarkm		/* If the new route is a route broken down from an
85546303Smarkm		 * aggregated route, and if the previous route is either
85646303Smarkm		 * not a broken down route or was broken down from a finer
85746303Smarkm		 * netmask, and if the previous route is current,
85846303Smarkm		 * then forget this one.
85946303Smarkm		 */
86046303Smarkm		if (new->rts_de_ag > rts->rts_de_ag
86146303Smarkm		    && now_stale <= rts->rts_time)
86246303Smarkm			return;
86346303Smarkm
86418316Swollman		/* Keep poisoned routes around only long enough to pass
86546303Smarkm		 * the poison on.  Use a new timestamp for good routes.
86618316Swollman		 */
86746303Smarkm		if (rts->rts_metric == HOPCNT_INFINITY
86846303Smarkm		    && new->rts_metric == HOPCNT_INFINITY)
86946303Smarkm			new->rts_time = rts->rts_time;
87018316Swollman
87118316Swollman		/* If this is an update for the router we currently prefer,
87218316Swollman		 * then note it.
87318316Swollman		 */
87418316Swollman		if (i == NUM_SPARES) {
87546303Smarkm			rtchange(rt, rt->rt_state, new, 0);
87618316Swollman			/* If the route got worse, check for something better.
87718316Swollman			 */
87846303Smarkm			if (new->rts_metric > rts->rts_metric)
87918316Swollman				rtswitch(rt, 0);
88018316Swollman			return;
88118316Swollman		}
88218316Swollman
88318316Swollman		/* This is an update for a spare route.
88418316Swollman		 * Finished if the route is unchanged.
88518316Swollman		 */
88646303Smarkm		if (rts->rts_gate == new->rts_gate
88746303Smarkm		    && rts->rts_metric == new->rts_metric
88846303Smarkm		    && rts->rts_tag == new->rts_tag) {
88946303Smarkm			trace_upslot(rt, rts, new);
89046303Smarkm			*rts = *new;
89118316Swollman			return;
89218316Swollman		}
89346303Smarkm		/* Forget it if it has gone bad.
89446303Smarkm		 */
89546303Smarkm		if (new->rts_metric == HOPCNT_INFINITY) {
89646303Smarkm			rts_delete(rt, rts);
89746303Smarkm			return;
89846303Smarkm		}
89918316Swollman
90018316Swollman	} else {
90118316Swollman		/* The update is for a route we know about,
90218316Swollman		 * but not from a familiar router.
90318316Swollman		 *
90418316Swollman		 * Ignore the route if it points to us.
90518316Swollman		 */
90618316Swollman		if (n->n_nhop != 0
90718316Swollman		    && 0 != ifwithaddr(n->n_nhop, 1, 0))
90818316Swollman			return;
90918316Swollman
91046303Smarkm		/* the loop above set rts0=worst spare */
91118316Swollman		rts = rts0;
91218316Swollman
91318316Swollman		/* Save the route as a spare only if it has
91418316Swollman		 * a better metric than our worst spare.
91518316Swollman		 * This also ignores poisoned routes (those
91618316Swollman		 * received with metric HOPCNT_INFINITY).
91718316Swollman		 */
91846303Smarkm		if (new->rts_metric >= rts->rts_metric)
91918316Swollman			return;
92018316Swollman	}
92118316Swollman
92246303Smarkm	trace_upslot(rt, rts, new);
92346303Smarkm	*rts = *new;
92418316Swollman
92518316Swollman	/* try to switch to a better route */
92618316Swollman	rtswitch(rt, rts);
92718316Swollman}
92819880Swollman
92919880Swollman
93019880Swollmanstatic int				/* 0 if bad */
93119880Swollmanck_passwd(struct interface *aifp,
93219880Swollman	  struct rip *rip,
93319880Swollman	  void *lim,
93419880Swollman	  naddr from,
93519880Swollman	  struct msg_limit *use_authp)
93619880Swollman{
93719880Swollman#	define NA (rip->rip_auths)
93819880Swollman	struct netauth *na2;
93920339Swollman	struct auth *ap;
94019880Swollman	MD5_CTX md5_ctx;
94119880Swollman	u_char hash[RIP_AUTH_PW_LEN];
94246303Smarkm	int i, len;
94319880Swollman
944190718Sphk	assert(aifp != NULL);
94519880Swollman	if ((void *)NA >= lim || NA->a_family != RIP_AF_AUTH) {
94619880Swollman		msglim(use_authp, from, "missing password from %s",
94719880Swollman		       naddr_ntoa(from));
94819880Swollman		return 0;
94919880Swollman	}
95019880Swollman
95120339Swollman	/* accept any current (+/- 24 hours) password
95220339Swollman	 */
95320339Swollman	for (ap = aifp->int_auth, i = 0; i < MAX_AUTH_KEYS; i++, ap++) {
95420339Swollman		if (ap->type != NA->a_type
95520339Swollman		    || (u_long)ap->start > (u_long)clk.tv_sec+DAY
95620339Swollman		    || (u_long)ap->end+DAY < (u_long)clk.tv_sec)
95720339Swollman			continue;
95819880Swollman
95920339Swollman		if (NA->a_type == RIP_AUTH_PW) {
96046303Smarkm			if (!memcmp(NA->au.au_pw, ap->key, RIP_AUTH_PW_LEN))
96119880Swollman				return 1;
96219880Swollman
96320339Swollman		} else {
96420339Swollman			/* accept MD5 secret with the right key ID
96520339Swollman			 */
96620339Swollman			if (NA->au.a_md5.md5_keyid != ap->keyid)
96720339Swollman				continue;
96819880Swollman
96946303Smarkm			len = ntohs(NA->au.a_md5.md5_pkt_len);
97046303Smarkm			if ((len-sizeof(*rip)) % sizeof(*NA) != 0
97146303Smarkm			    || len != (char *)lim-(char*)rip-(int)sizeof(*NA)) {
97219880Swollman				msglim(use_authp, from,
97346303Smarkm				       "wrong MD5 RIPv2 packet length of %d"
97446303Smarkm				       " instead of %d from %s",
97546303Smarkm				       len, (int)((char *)lim-(char *)rip
97646303Smarkm						  -sizeof(*NA)),
97719880Swollman				       naddr_ntoa(from));
97819880Swollman				return 0;
97919880Swollman			}
98046303Smarkm			na2 = (struct netauth *)((char *)rip+len);
98146303Smarkm
98246303Smarkm			/* Given a good hash value, these are not security
98346303Smarkm			 * problems so be generous and accept the routes,
98446303Smarkm			 * after complaining.
98546303Smarkm			 */
98646303Smarkm			if (TRACEPACKETS) {
98746303Smarkm				if (NA->au.a_md5.md5_auth_len
988126250Sbms				    != RIP_AUTH_MD5_HASH_LEN)
98946303Smarkm					msglim(use_authp, from,
99046303Smarkm					       "unknown MD5 RIPv2 auth len %#x"
99146303Smarkm					       " instead of %#x from %s",
99246303Smarkm					       NA->au.a_md5.md5_auth_len,
993190745Sphk					       (unsigned)RIP_AUTH_MD5_HASH_LEN,
99446303Smarkm					       naddr_ntoa(from));
99546303Smarkm				if (na2->a_family != RIP_AF_AUTH)
99646303Smarkm					msglim(use_authp, from,
99746303Smarkm					       "unknown MD5 RIPv2 family %#x"
99846303Smarkm					       " instead of %#x from %s",
99946303Smarkm					       na2->a_family, RIP_AF_AUTH,
100046303Smarkm					       naddr_ntoa(from));
100146303Smarkm				if (na2->a_type != ntohs(1))
100246303Smarkm					msglim(use_authp, from,
100346303Smarkm					       "MD5 RIPv2 hash has %#x"
100446303Smarkm					       " instead of %#x from %s",
100546303Smarkm					       na2->a_type, ntohs(1),
100646303Smarkm					       naddr_ntoa(from));
100746303Smarkm			}
100846303Smarkm
100919880Swollman			MD5Init(&md5_ctx);
1010126250Sbms			MD5Update(&md5_ctx, (u_char *)rip,
1011126250Sbms				  len + RIP_AUTH_MD5_HASH_XTRA);
1012126250Sbms			MD5Update(&md5_ctx, ap->key, RIP_AUTH_MD5_KEY_LEN);
101319880Swollman			MD5Final(hash, &md5_ctx);
101446303Smarkm			if (!memcmp(hash, na2->au.au_pw, sizeof(hash)))
101546303Smarkm				return 1;
101619880Swollman		}
101719880Swollman	}
101819880Swollman
101919880Swollman	msglim(use_authp, from, "bad password from %s",
102019880Swollman	       naddr_ntoa(from));
102119880Swollman	return 0;
102219880Swollman#undef NA
102319880Swollman}
1024