xref: /netbsd-src/sbin/routed/input.c (revision cad376bd0d2637bc69e5e84a3ed8b96b4ea7996e)
1*cad376bdSchristos /*	$NetBSD: input.c,v 1.31 2009/10/26 02:53:15 christos Exp $	*/
20114e805Scgd 
361f28255Scgd /*
44c8599d3Smycroft  * Copyright (c) 1983, 1988, 1993
54c8599d3Smycroft  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
1561f28255Scgd  * 3. All advertising materials mentioning features or use of this software
1694b2d428Schristos  *    must display the following acknowledgment:
1761f28255Scgd  *	This product includes software developed by the University of
1861f28255Scgd  *	California, Berkeley and its contributors.
1961f28255Scgd  * 4. Neither the name of the University nor the names of its contributors
2061f28255Scgd  *    may be used to endorse or promote products derived from this software
2161f28255Scgd  *    without specific prior written permission.
2261f28255Scgd  *
2361f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2461f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2561f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2661f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2761f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2861f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2961f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3061f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3161f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3261f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3361f28255Scgd  * SUCH DAMAGE.
3461f28255Scgd  */
3561f28255Scgd 
3661f28255Scgd #include "defs.h"
37fc1a5246Sthorpej 
384fea751dSchristos #ifdef __NetBSD__
39*cad376bdSchristos __RCSID("$NetBSD: input.c,v 1.31 2009/10/26 02:53:15 christos Exp $");
404fea751dSchristos #elif defined(__FreeBSD__)
414fea751dSchristos __RCSID("$FreeBSD$");
424fea751dSchristos #else
43f93fe60aSchristos __RCSID("Revision: 2.26 ");
44f93fe60aSchristos #ident "Revision: 2.26 "
454fea751dSchristos #endif
464fea751dSchristos 
47e7512e5aSchristos static void input(struct sockaddr_in *, struct interface *, struct interface *,
48e7512e5aSchristos 		  struct rip *, int);
496d8ef4dfSthorpej static void input_route(naddr, naddr, struct rt_spare *, struct netinfo *);
50e7512e5aSchristos static int ck_passwd(struct interface *, struct rip *, void *,
51e7512e5aSchristos 		     naddr, struct msg_limit *);
5261f28255Scgd 
534841cf29Schristos 
54fc1a5246Sthorpej /* process RIP input
5561f28255Scgd  */
56e072e2aeScgd void
read_rip(int sock,struct interface * sifp)57fc1a5246Sthorpej read_rip(int sock,
58e7512e5aSchristos 	 struct interface *sifp)
5961f28255Scgd {
60fc1a5246Sthorpej 	struct sockaddr_in from;
61e7512e5aSchristos 	struct interface *aifp;
620c37c63eSmrg 	socklen_t fromlen;
630c37c63eSmrg 	int cc;
64e7512e5aSchristos #ifdef USE_PASSIFNAME
65e7512e5aSchristos 	static struct msg_limit  bad_name;
66e7512e5aSchristos 	struct {
67e7512e5aSchristos 		char	ifname[IFNAMSIZ];
68e7512e5aSchristos 		union pkt_buf pbuf;
69e7512e5aSchristos 	} inbuf;
70e7512e5aSchristos #else
71e7512e5aSchristos 	struct {
72e7512e5aSchristos 		union pkt_buf pbuf;
73e7512e5aSchristos 	} inbuf;
74e7512e5aSchristos #endif
7561f28255Scgd 
76fc1a5246Sthorpej 
77fc1a5246Sthorpej 	for (;;) {
78fc1a5246Sthorpej 		fromlen = sizeof(from);
79fc1a5246Sthorpej 		cc = recvfrom(sock, &inbuf, sizeof(inbuf), 0,
80fc1a5246Sthorpej 			      (struct sockaddr*)&from, &fromlen);
81fc1a5246Sthorpej 		if (cc <= 0) {
82fc1a5246Sthorpej 			if (cc < 0 && errno != EWOULDBLOCK)
83fc1a5246Sthorpej 				LOGERR("recvfrom(rip)");
84fc1a5246Sthorpej 			break;
85fc1a5246Sthorpej 		}
86fc1a5246Sthorpej 		if (fromlen != sizeof(struct sockaddr_in))
87fc1a5246Sthorpej 			logbad(1,"impossible recvfrom(rip) fromlen=%d",
88fc1a5246Sthorpej 			       fromlen);
89fc1a5246Sthorpej 
90e7512e5aSchristos 		/* aifp is the "authenticated" interface via which the packet
91e7512e5aSchristos 		 *	arrived.  In fact, it is only the interface on which
92e7512e5aSchristos 		 *	the packet should have arrived based on is source
93e7512e5aSchristos 		 *	address.
94e7512e5aSchristos 		 * sifp is interface associated with the socket through which
95e7512e5aSchristos 		 *	the packet was received.
96e7512e5aSchristos 		 */
97e7512e5aSchristos #ifdef USE_PASSIFNAME
98e7512e5aSchristos 		if ((cc -= sizeof(inbuf.ifname)) < 0)
99e7512e5aSchristos 			logbad(0,"missing USE_PASSIFNAME; only %d bytes",
100e7512e5aSchristos 			       cc+sizeof(inbuf.ifname));
101e7512e5aSchristos 
102e7512e5aSchristos 		/* check the remote interfaces first */
103e7512e5aSchristos 		for (aifp = remote_if; aifp; aifp = aifp->int_rlink) {
104e7512e5aSchristos 			if (aifp->int_addr == from.sin_addr.s_addr)
105e7512e5aSchristos 				break;
106e7512e5aSchristos 		}
107e7512e5aSchristos 		if (aifp == 0) {
108e7512e5aSchristos 			aifp = ifwithname(inbuf.ifname, 0);
109e7512e5aSchristos 			if (aifp == 0) {
110e7512e5aSchristos 				msglim(&bad_name, from.sin_addr.s_addr,
111e7512e5aSchristos 				       "impossible interface name %.*s",
112e7512e5aSchristos 				       IFNAMSIZ, inbuf.ifname);
113e7512e5aSchristos 			} else if (((aifp->int_if_flags & IFF_POINTOPOINT)
114e7512e5aSchristos 				    && aifp->int_dstaddr!=from.sin_addr.s_addr)
115e7512e5aSchristos 				   || (!(aifp->int_if_flags & IFF_POINTOPOINT)
116e7512e5aSchristos 				       && !on_net(from.sin_addr.s_addr,
117e7512e5aSchristos 						  aifp->int_net,
118e7512e5aSchristos 						  aifp->int_mask))) {
119e7512e5aSchristos 				/* If it came via the wrong interface, do not
120e7512e5aSchristos 				 * trust it.
121e7512e5aSchristos 				 */
122e7512e5aSchristos 				aifp = 0;
123e7512e5aSchristos 			}
124e7512e5aSchristos 		}
125e7512e5aSchristos #else
126e7512e5aSchristos 		aifp = iflookup(from.sin_addr.s_addr);
127e7512e5aSchristos #endif
128e7512e5aSchristos 		if (sifp == 0)
129e7512e5aSchristos 			sifp = aifp;
130e7512e5aSchristos 
131e7512e5aSchristos 		input(&from, sifp, aifp, &inbuf.pbuf.rip, cc);
132fc1a5246Sthorpej 	}
133fc1a5246Sthorpej }
134fc1a5246Sthorpej 
135fc1a5246Sthorpej 
136fc1a5246Sthorpej /* Process a RIP packet
137fc1a5246Sthorpej  */
138fc1a5246Sthorpej static void
input(struct sockaddr_in * from,struct interface * sifp,struct interface * aifp,struct rip * rip,int cc)139fc1a5246Sthorpej input(struct sockaddr_in *from,		/* received from this IP address */
140e7512e5aSchristos       struct interface *sifp,		/* interface of incoming socket */
141e7512e5aSchristos       struct interface *aifp,		/* "authenticated" interface */
142fc1a5246Sthorpej       struct rip *rip,
143e7512e5aSchristos       int cc)
144fc1a5246Sthorpej {
145fc1a5246Sthorpej #	define FROM_NADDR from->sin_addr.s_addr
146e7512e5aSchristos 	static struct msg_limit use_auth, bad_len, bad_mask;
147e7512e5aSchristos 	static struct msg_limit unk_router, bad_router, bad_nhop;
148fc1a5246Sthorpej 
149fc1a5246Sthorpej 	struct rt_entry *rt;
1506d8ef4dfSthorpej 	struct rt_spare new;
151fc1a5246Sthorpej 	struct netinfo *n, *lim;
152fc1a5246Sthorpej 	struct interface *ifp1;
1533f50343aSlukem 	naddr gate, mask, v1_mask, dst, ddst_h = 0;
154e7512e5aSchristos 	struct auth *ap;
1556d8ef4dfSthorpej 	struct tgate *tg = 0;
1566d8ef4dfSthorpej 	struct tgate_net *tn;
1576d8ef4dfSthorpej 	int i, j;
158fc1a5246Sthorpej 
159e7512e5aSchristos 	/* Notice when we hear from a remote gateway
160e7512e5aSchristos 	 */
161e7512e5aSchristos 	if (aifp != 0
162e7512e5aSchristos 	    && (aifp->int_state & IS_REMOTE))
163e7512e5aSchristos 		aifp->int_act_time = now.tv_sec;
164fc1a5246Sthorpej 
165e7512e5aSchristos 	trace_rip("Recv", "from", from, sifp, rip, cc);
166fc1a5246Sthorpej 
167fc1a5246Sthorpej 	if (rip->rip_vers == 0) {
168e7512e5aSchristos 		msglim(&bad_router, FROM_NADDR,
169e7512e5aSchristos 		       "RIP version 0, cmd %d, packet received from %s",
170fc1a5246Sthorpej 		       rip->rip_cmd, naddr_ntoa(FROM_NADDR));
17161f28255Scgd 		return;
1724d3fba59Schristos 	} else if (rip->rip_vers > RIPv2) {
1734d3fba59Schristos 		rip->rip_vers = RIPv2;
17461f28255Scgd 	}
175756b1291Schristos 	if (cc > (int)OVER_MAXPACKETSIZE) {
176e7512e5aSchristos 		msglim(&bad_router, FROM_NADDR,
177e7512e5aSchristos 		       "packet at least %d bytes too long received from %s",
178e7512e5aSchristos 		       cc-MAXPACKETSIZE, naddr_ntoa(FROM_NADDR));
179fc1a5246Sthorpej 		return;
180fc1a5246Sthorpej 	}
181fc1a5246Sthorpej 
182fc1a5246Sthorpej 	n = rip->rip_nets;
183e7512e5aSchristos 	lim = (struct netinfo *)((char*)rip + cc);
184fc1a5246Sthorpej 
185fc1a5246Sthorpej 	/* Notice authentication.
186fc1a5246Sthorpej 	 * As required by section 4.2 in RFC 1723, discard authenticated
187fc1a5246Sthorpej 	 * RIPv2 messages, but only if configured for that silliness.
188fc1a5246Sthorpej 	 *
189e7512e5aSchristos 	 * RIPv2 authentication is lame.  Why authenticate queries?
190fc1a5246Sthorpej 	 * Why should a RIPv2 implementation with authentication disabled
19194b2d428Schristos 	 * not be able to listen to RIPv2 packets with authentication, while
192fc1a5246Sthorpej 	 * RIPv1 systems will listen?  Crazy!
193fc1a5246Sthorpej 	 */
194fc1a5246Sthorpej 	if (!auth_ok
1954d3fba59Schristos 	    && rip->rip_vers == RIPv2
196fc1a5246Sthorpej 	    && n < lim && n->n_family == RIP_AF_AUTH) {
197e7512e5aSchristos 		msglim(&use_auth, FROM_NADDR,
198e7512e5aSchristos 		       "RIPv2 message with authentication from %s discarded",
199fc1a5246Sthorpej 		       naddr_ntoa(FROM_NADDR));
20061f28255Scgd 		return;
20161f28255Scgd 	}
2024841cf29Schristos 
20361f28255Scgd 	switch (rip->rip_cmd) {
20461f28255Scgd 	case RIPCMD_REQUEST:
205e7512e5aSchristos 		/* For mere requests, be a little sloppy about the source
206e7512e5aSchristos 		 */
207e7512e5aSchristos 		if (aifp == 0)
208e7512e5aSchristos 			aifp = sifp;
209e7512e5aSchristos 
210e7512e5aSchristos 		/* Are we talking to ourself or a remote gateway?
211e7512e5aSchristos 		 */
212e7512e5aSchristos 		ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
213e7512e5aSchristos 		if (ifp1) {
214e7512e5aSchristos 			if (ifp1->int_state & IS_REMOTE) {
215e7512e5aSchristos 				/* remote gateway */
216e7512e5aSchristos 				aifp = ifp1;
217e7512e5aSchristos 				if (check_remote(aifp)) {
218e7512e5aSchristos 					aifp->int_act_time = now.tv_sec;
219e7512e5aSchristos 					(void)if_ok(aifp, "remote ");
220e7512e5aSchristos 				}
221e7512e5aSchristos 			} else if (from->sin_port == htons(RIP_PORT)) {
222e7512e5aSchristos 				trace_pkt("    discard our own RIP request");
223e7512e5aSchristos 				return;
224e7512e5aSchristos 			}
225e7512e5aSchristos 		}
226e7512e5aSchristos 
227fc1a5246Sthorpej 		/* did the request come from a router?
228fc1a5246Sthorpej 		 */
229fc1a5246Sthorpej 		if (from->sin_port == htons(RIP_PORT)) {
230e7512e5aSchristos 			/* yes, ignore the request if RIP is off so that
231e7512e5aSchristos 			 * the router does not depend on us.
232fc1a5246Sthorpej 			 */
233e7512e5aSchristos 			if (rip_sock < 0
234e7512e5aSchristos 			    || (aifp != 0
235e7512e5aSchristos 				&& IS_RIP_OUT_OFF(aifp->int_state))) {
236e7512e5aSchristos 				trace_pkt("    discard request while RIP off");
237fc1a5246Sthorpej 				return;
238fc1a5246Sthorpej 			}
239fc1a5246Sthorpej 		}
240fc1a5246Sthorpej 
24194b2d428Schristos 		/* According to RFC 1723, we should ignore unauthenticated
242fc1a5246Sthorpej 		 * queries.  That is too silly to bother with.  Sheesh!
243e7512e5aSchristos 		 * Are forwarding tables supposed to be secret, when
244e7512e5aSchristos 		 * a bad guy can infer them with test traffic?  When RIP
245e7512e5aSchristos 		 * is still the most common router-discovery protocol
246e7512e5aSchristos 		 * and so hosts need to send queries that will be answered?
247e7512e5aSchristos 		 * What about `rtquery`?
248fc1a5246Sthorpej 		 * Maybe on firewalls you'd care, but not enough to
249fc1a5246Sthorpej 		 * give up the diagnostic facilities of remote probing.
250fc1a5246Sthorpej 		 */
251fc1a5246Sthorpej 
252e7512e5aSchristos 		if (n >= lim) {
253e7512e5aSchristos 			msglim(&bad_len, FROM_NADDR, "empty request from %s",
254e7512e5aSchristos 			       naddr_ntoa(FROM_NADDR));
255e7512e5aSchristos 			return;
256fc1a5246Sthorpej 		}
257e7512e5aSchristos 		if (cc%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
258e7512e5aSchristos 			msglim(&bad_len, FROM_NADDR,
259e7512e5aSchristos 			       "request of bad length (%d) from %s",
260e7512e5aSchristos 			       cc, naddr_ntoa(FROM_NADDR));
261e7512e5aSchristos 		}
262e7512e5aSchristos 
263e7512e5aSchristos 		if (rip->rip_vers == RIPv2
264e7512e5aSchristos 		    && (aifp == 0 || (aifp->int_state & IS_NO_RIPV1_OUT))) {
265e7512e5aSchristos 			v12buf.buf->rip_vers = RIPv2;
266e7512e5aSchristos 			/* If we have a secret but it is a cleartext secret,
267e7512e5aSchristos 			 * do not disclose our secret unless the other guy
268e7512e5aSchristos 			 * already knows it.
269e7512e5aSchristos 			 */
270e7512e5aSchristos 			ap = find_auth(aifp);
271e7512e5aSchristos 			if (ap != 0 && ap->type == RIP_AUTH_PW
272e7512e5aSchristos 			    && n->n_family == RIP_AF_AUTH
273e7512e5aSchristos 			    && !ck_passwd(aifp,rip,lim,FROM_NADDR,&use_auth))
274e7512e5aSchristos 				ap = 0;
275e7512e5aSchristos 		} else {
276e7512e5aSchristos 			v12buf.buf->rip_vers = RIPv1;
277e7512e5aSchristos 			ap = 0;
278e7512e5aSchristos 		}
279e7512e5aSchristos 		clr_ws_buf(&v12buf, ap);
280e7512e5aSchristos 
281e7512e5aSchristos 		do {
282*cad376bdSchristos 			n->n_metric = ntohl(n->n_metric);
283fc1a5246Sthorpej 
284fc1a5246Sthorpej 			/* A single entry with family RIP_AF_UNSPEC and
285fc1a5246Sthorpej 			 * metric HOPCNT_INFINITY means "all routes".
28661f28255Scgd 			 * We respond to routers only if we are acting
28761f28255Scgd 			 * as a supplier, or to anyone other than a router
288fc1a5246Sthorpej 			 * (i.e. a query).
28961f28255Scgd 			 */
290fc1a5246Sthorpej 			if (n->n_family == RIP_AF_UNSPEC
291e7512e5aSchristos 			    && n->n_metric == HOPCNT_INFINITY) {
2926d8ef4dfSthorpej 				/* Answer a query from a utility program
2936d8ef4dfSthorpej 				 * with all we know.
2944d3fba59Schristos 				 */
2956d8ef4dfSthorpej 				if (from->sin_port != htons(RIP_PORT)) {
296e7512e5aSchristos 					supply(from, aifp, OUT_QUERY, 0,
297e7512e5aSchristos 					       rip->rip_vers, ap != 0);
2984d3fba59Schristos 					return;
299fc1a5246Sthorpej 				}
300e7512e5aSchristos 
3014d3fba59Schristos 				/* A router trying to prime its tables.
3024d3fba59Schristos 				 * Filter the answer in the about same way
3034d3fba59Schristos 				 * broadcasts are filtered.
3044d3fba59Schristos 				 *
3054d3fba59Schristos 				 * Only answer a router if we are a supplier
3064d3fba59Schristos 				 * to keep an unwary host that is just starting
3076d8ef4dfSthorpej 				 * from picking us as a router.
3084d3fba59Schristos 				 */
309e7512e5aSchristos 				if (aifp == 0) {
310e7512e5aSchristos 					trace_pkt("ignore distant router");
3114d3fba59Schristos 					return;
312e7512e5aSchristos 				}
313e7512e5aSchristos 				if (!supplier
314e7512e5aSchristos 				    || IS_RIP_OFF(aifp->int_state)) {
315e7512e5aSchristos 					trace_pkt("ignore; not supplying");
316e7512e5aSchristos 					return;
317e7512e5aSchristos 				}
3184d3fba59Schristos 
3196d8ef4dfSthorpej 				/* Do not answer a RIPv1 router if
3206d8ef4dfSthorpej 				 * we are sending RIPv2.  But do offer
3216d8ef4dfSthorpej 				 * poor man's router discovery.
3226d8ef4dfSthorpej 				 */
3236d8ef4dfSthorpej 				if ((aifp->int_state & IS_NO_RIPV1_OUT)
3246d8ef4dfSthorpej 				    && rip->rip_vers == RIPv1) {
3256d8ef4dfSthorpej 					if (!(aifp->int_state & IS_PM_RDISC)) {
3266d8ef4dfSthorpej 					    trace_pkt("ignore; sending RIPv2");
3276d8ef4dfSthorpej 					    return;
3286d8ef4dfSthorpej 					}
3296d8ef4dfSthorpej 
3306d8ef4dfSthorpej 					v12buf.n->n_family = RIP_AF_INET;
3316d8ef4dfSthorpej 					v12buf.n->n_dst = RIP_DEFAULT;
3326d8ef4dfSthorpej 					i = aifp->int_d_metric;
333f93fe60aSchristos 					if (0 != (rt = rtget(RIP_DEFAULT, 0))) {
334f93fe60aSchristos 					    j = (rt->rt_metric
335f93fe60aSchristos 						 +aifp->int_metric
336f93fe60aSchristos 						 +aifp->int_adj_outmetric
337f93fe60aSchristos 						 +1);
338f93fe60aSchristos 					    if (i > j)
339f93fe60aSchristos 						i = j;
340f93fe60aSchristos 					}
3416d8ef4dfSthorpej 					v12buf.n->n_metric = htonl(i);
3426d8ef4dfSthorpej 					v12buf.n++;
3436d8ef4dfSthorpej 					break;
3446d8ef4dfSthorpej 				}
3456d8ef4dfSthorpej 
3466d8ef4dfSthorpej 				/* Respond with RIPv1 instead of RIPv2 if
3476d8ef4dfSthorpej 				 * that is what we are broadcasting on the
3486d8ef4dfSthorpej 				 * interface to keep the remote router from
3496d8ef4dfSthorpej 				 * getting the wrong initial idea of the
3506d8ef4dfSthorpej 				 * routes we send.
3516d8ef4dfSthorpej 				 */
3524d3fba59Schristos 				supply(from, aifp, OUT_UNICAST, 0,
3534d3fba59Schristos 				       (aifp->int_state & IS_NO_RIPV1_OUT)
354e7512e5aSchristos 				       ? RIPv2 : RIPv1,
355e7512e5aSchristos 				       ap != 0);
35661f28255Scgd 				return;
35761f28255Scgd 			}
358fc1a5246Sthorpej 
359e7512e5aSchristos 			/* Ignore authentication */
360e7512e5aSchristos 			if (n->n_family == RIP_AF_AUTH)
361e7512e5aSchristos 				continue;
362e7512e5aSchristos 
363fc1a5246Sthorpej 			if (n->n_family != RIP_AF_INET) {
364e7512e5aSchristos 				msglim(&bad_router, FROM_NADDR,
3656d8ef4dfSthorpej 				       "request from %s for unsupported"
3666d8ef4dfSthorpej 				       " (af %d) %s",
367fc1a5246Sthorpej 				       naddr_ntoa(FROM_NADDR),
368fc1a5246Sthorpej 				       ntohs(n->n_family),
369fc1a5246Sthorpej 				       naddr_ntoa(n->n_dst));
37068b7908bSchristos 				return;
3714841cf29Schristos 			}
372fc1a5246Sthorpej 
373e7512e5aSchristos 			/* We are being asked about a specific destination.
374e7512e5aSchristos 			 */
375fc1a5246Sthorpej 			dst = n->n_dst;
376fc1a5246Sthorpej 			if (!check_dst(dst)) {
377e7512e5aSchristos 				msglim(&bad_router, FROM_NADDR,
378e7512e5aSchristos 				       "bad queried destination %s from %s",
379fc1a5246Sthorpej 				       naddr_ntoa(dst),
380fc1a5246Sthorpej 				       naddr_ntoa(FROM_NADDR));
381fc1a5246Sthorpej 				return;
38261f28255Scgd 			}
383fc1a5246Sthorpej 
384e7512e5aSchristos 			/* decide what mask was intended */
385fc1a5246Sthorpej 			if (rip->rip_vers == RIPv1
386fc1a5246Sthorpej 			    || 0 == (mask = ntohl(n->n_mask))
387fc1a5246Sthorpej 			    || 0 != (ntohl(dst) & ~mask))
388e7512e5aSchristos 				mask = ripv1_mask_host(dst, aifp);
389fc1a5246Sthorpej 
390e7512e5aSchristos 			/* try to find the answer */
391fc1a5246Sthorpej 			rt = rtget(dst, mask);
392fc1a5246Sthorpej 			if (!rt && dst != RIP_DEFAULT)
393fc1a5246Sthorpej 				rt = rtfind(n->n_dst);
394fc1a5246Sthorpej 
395e7512e5aSchristos 			if (v12buf.buf->rip_vers != RIPv1)
396e7512e5aSchristos 				v12buf.n->n_mask = mask;
397fc1a5246Sthorpej 			if (rt == 0) {
398e7512e5aSchristos 				/* we do not have the answer */
399e7512e5aSchristos 				v12buf.n->n_metric = HOPCNT_INFINITY;
400fc1a5246Sthorpej 			} else {
401e7512e5aSchristos 				/* we have the answer, so compute the
402e7512e5aSchristos 				 * right metric and next hop.
403e7512e5aSchristos 				 */
404e7512e5aSchristos 				v12buf.n->n_family = RIP_AF_INET;
405e7512e5aSchristos 				v12buf.n->n_dst = dst;
406f93fe60aSchristos 				j = rt->rt_metric+1;
407f93fe60aSchristos 				if (!aifp)
408f93fe60aSchristos 					++j;
409f93fe60aSchristos 				else
410f93fe60aSchristos 					j += (aifp->int_metric
411f93fe60aSchristos 					      + aifp->int_adj_outmetric);
412f93fe60aSchristos 				if (j < HOPCNT_INFINITY)
413f93fe60aSchristos 					v12buf.n->n_metric = j;
414f93fe60aSchristos 				else
415e7512e5aSchristos 					v12buf.n->n_metric = HOPCNT_INFINITY;
416e7512e5aSchristos 				if (v12buf.buf->rip_vers != RIPv1) {
417e7512e5aSchristos 					v12buf.n->n_tag = rt->rt_tag;
418e7512e5aSchristos 					v12buf.n->n_mask = mask;
419e7512e5aSchristos 					if (aifp != 0
420fc1a5246Sthorpej 					    && on_net(rt->rt_gate,
421e7512e5aSchristos 						      aifp->int_net,
422e7512e5aSchristos 						      aifp->int_mask)
423e7512e5aSchristos 					    && rt->rt_gate != aifp->int_addr)
424e7512e5aSchristos 					    v12buf.n->n_nhop = rt->rt_gate;
425fc1a5246Sthorpej 				}
426fc1a5246Sthorpej 			}
427*cad376bdSchristos 			v12buf.n->n_metric = htonl(v12buf.n->n_metric);
428e7512e5aSchristos 
429e7512e5aSchristos 			/* Stop paying attention if we fill the output buffer.
430e7512e5aSchristos 			 */
431e7512e5aSchristos 			if (++v12buf.n >= v12buf.lim)
432e7512e5aSchristos 				break;
433e7512e5aSchristos 		} while (++n < lim);
434e7512e5aSchristos 
435e7512e5aSchristos 		/* Send the answer about specific routes.
436e7512e5aSchristos 		 */
437e7512e5aSchristos 		if (ap != 0 && ap->type == RIP_AUTH_MD5)
438e7512e5aSchristos 			end_md5_auth(&v12buf, ap);
439e7512e5aSchristos 
440e7512e5aSchristos 		if (from->sin_port != htons(RIP_PORT)) {
441e7512e5aSchristos 			/* query */
442e7512e5aSchristos 			(void)output(OUT_QUERY, from, aifp,
443e7512e5aSchristos 				     v12buf.buf,
444e7512e5aSchristos 				     ((char *)v12buf.n - (char*)v12buf.buf));
445e7512e5aSchristos 		} else if (supplier) {
446e7512e5aSchristos 			(void)output(OUT_UNICAST, from, aifp,
447e7512e5aSchristos 				     v12buf.buf,
448e7512e5aSchristos 				     ((char *)v12buf.n - (char*)v12buf.buf));
449e7512e5aSchristos 		} else {
450e7512e5aSchristos 			/* Only answer a router if we are a supplier
451fc1a5246Sthorpej 			 * to keep an unwary host that is just starting
452fc1a5246Sthorpej 			 * from picking us an a router.
453fc1a5246Sthorpej 			 */
454e7512e5aSchristos 			;
455fc1a5246Sthorpej 		}
45661f28255Scgd 		return;
45761f28255Scgd 
45861f28255Scgd 	case RIPCMD_TRACEON:
45961f28255Scgd 	case RIPCMD_TRACEOFF:
460d1c10b4cSchristos 		/* Notice that trace messages are turned off for all possible
461d1c10b4cSchristos 		 * abuse if _PATH_TRACE is undefined in pathnames.h.
462d1c10b4cSchristos 		 * Notice also that because of the way the trace file is
463d1c10b4cSchristos 		 * handled in trace.c, no abuse is plausible even if
464d1c10b4cSchristos 		 * _PATH_TRACE_ is defined.
465d1c10b4cSchristos 		 *
466d1c10b4cSchristos 		 * First verify message came from a privileged port. */
467fc1a5246Sthorpej 		if (ntohs(from->sin_port) > IPPORT_RESERVED) {
468fc1a5246Sthorpej 			msglog("trace command from untrusted port on %s",
469fc1a5246Sthorpej 			       naddr_ntoa(FROM_NADDR));
47061f28255Scgd 			return;
471fc1a5246Sthorpej 		}
4724d3fba59Schristos 		if (aifp == 0) {
473fc1a5246Sthorpej 			msglog("trace command from unknown router %s",
474fc1a5246Sthorpej 			       naddr_ntoa(FROM_NADDR));
4751f1b61fcSchristos 			return;
476fc1a5246Sthorpej 		}
477fc1a5246Sthorpej 		if (rip->rip_cmd == RIPCMD_TRACEON) {
478e7512e5aSchristos 			rip->rip_tracefile[cc-4] = '\0';
479756b1291Schristos #ifndef __NetBSD__
480e7512e5aSchristos 			set_tracefile((char*)rip->rip_tracefile,
481e7512e5aSchristos 				      "trace command: %s\n", 0);
482e24d8526Schristos #else
483e24d8526Schristos 			msglog("RIP_TRACEON for `%s' from %s ignored",
484e24d8526Schristos 			    (char *) rip->rip_tracefile,
485e24d8526Schristos 			    naddr_ntoa(FROM_NADDR));
486e24d8526Schristos #endif
487fc1a5246Sthorpej 		} else {
488756b1291Schristos #ifndef __NetBSD__
489e7512e5aSchristos 			trace_off("tracing turned off by %s",
490fc1a5246Sthorpej 				  naddr_ntoa(FROM_NADDR));
491e24d8526Schristos #else
492e24d8526Schristos 			msglog("RIP_TRACEOFF from %s ignored",
493e24d8526Schristos 			    naddr_ntoa(FROM_NADDR));
494e24d8526Schristos #endif
495fc1a5246Sthorpej 		}
49661f28255Scgd 		return;
49761f28255Scgd 
49861f28255Scgd 	case RIPCMD_RESPONSE:
499e7512e5aSchristos 		if (cc%sizeof(*n) != sizeof(struct rip)%sizeof(*n)) {
500e7512e5aSchristos 			msglim(&bad_len, FROM_NADDR,
501e7512e5aSchristos 			       "response of bad length (%d) from %s",
502e7512e5aSchristos 			       cc, naddr_ntoa(FROM_NADDR));
503fc1a5246Sthorpej 		}
504fc1a5246Sthorpej 
50561f28255Scgd 		/* verify message came from a router */
506fc1a5246Sthorpej 		if (from->sin_port != ntohs(RIP_PORT)) {
507e7512e5aSchristos 			msglim(&bad_router, FROM_NADDR,
508e7512e5aSchristos 			       "    discard RIP response from unknown port"
5094fea751dSchristos 			       " %d on %s",
5104fea751dSchristos 			       ntohs(from->sin_port), naddr_ntoa(FROM_NADDR));
51161f28255Scgd 			return;
51261f28255Scgd 		}
513fc1a5246Sthorpej 
514fc1a5246Sthorpej 		if (rip_sock < 0) {
515e7512e5aSchristos 			trace_pkt("    discard response while RIP off");
51661f28255Scgd 			return;
51761f28255Scgd 		}
5184841cf29Schristos 
519fc1a5246Sthorpej 		/* Are we talking to ourself or a remote gateway?
52061f28255Scgd 		 */
521fc1a5246Sthorpej 		ifp1 = ifwithaddr(FROM_NADDR, 0, 1);
522fc1a5246Sthorpej 		if (ifp1) {
523fc1a5246Sthorpej 			if (ifp1->int_state & IS_REMOTE) {
524e7512e5aSchristos 				/* remote gateway */
525e7512e5aSchristos 				aifp = ifp1;
526e7512e5aSchristos 				if (check_remote(aifp)) {
527e7512e5aSchristos 					aifp->int_act_time = now.tv_sec;
528e7512e5aSchristos 					(void)if_ok(aifp, "remote ");
52961f28255Scgd 				}
530fc1a5246Sthorpej 			} else {
531e7512e5aSchristos 				trace_pkt("    discard our own RIP response");
532fc1a5246Sthorpej 				return;
533fc1a5246Sthorpej 			}
534e7512e5aSchristos 		}
53561f28255Scgd 
536e7512e5aSchristos 		/* Accept routing packets from routers directly connected
537e7512e5aSchristos 		 * via broadcast or point-to-point networks, and from
538fc1a5246Sthorpej 		 * those listed in /etc/gateways.
53961f28255Scgd 		 */
540e7512e5aSchristos 		if (aifp == 0) {
541e7512e5aSchristos 			msglim(&unk_router, FROM_NADDR,
542e7512e5aSchristos 			       "   discard response from %s"
543e7512e5aSchristos 			       " via unexpected interface",
544fc1a5246Sthorpej 			       naddr_ntoa(FROM_NADDR));
545fc1a5246Sthorpej 			return;
546fc1a5246Sthorpej 		}
547e7512e5aSchristos 		if (IS_RIP_IN_OFF(aifp->int_state)) {
548e7512e5aSchristos 			trace_pkt("    discard RIPv%d response"
549e7512e5aSchristos 				  " via disabled interface %s",
550e7512e5aSchristos 				  rip->rip_vers, aifp->int_name);
551fc1a5246Sthorpej 			return;
552fc1a5246Sthorpej 		}
553fc1a5246Sthorpej 
554e7512e5aSchristos 		if (n >= lim) {
555e7512e5aSchristos 			msglim(&bad_len, FROM_NADDR, "empty response from %s",
556e7512e5aSchristos 			       naddr_ntoa(FROM_NADDR));
557e7512e5aSchristos 			return;
558e7512e5aSchristos 		}
559e7512e5aSchristos 
5604d3fba59Schristos 		if (((aifp->int_state & IS_NO_RIPV1_IN)
561fc1a5246Sthorpej 		     && rip->rip_vers == RIPv1)
5624d3fba59Schristos 		    || ((aifp->int_state & IS_NO_RIPV2_IN)
563fc1a5246Sthorpej 			&& rip->rip_vers != RIPv1)) {
564e7512e5aSchristos 			trace_pkt("    discard RIPv%d response",
565fc1a5246Sthorpej 				  rip->rip_vers);
566fc1a5246Sthorpej 			return;
567fc1a5246Sthorpej 		}
568fc1a5246Sthorpej 
569fc1a5246Sthorpej 		/* Ignore routes via dead interface.
570fc1a5246Sthorpej 		 */
5714d3fba59Schristos 		if (aifp->int_state & IS_BROKE) {
5726d8ef4dfSthorpej 			trace_pkt("discard response via broken interface %s",
5734d3fba59Schristos 				  aifp->int_name);
574fc1a5246Sthorpej 			return;
575fc1a5246Sthorpej 		}
576fc1a5246Sthorpej 
577e7512e5aSchristos 		/* If the interface cares, ignore bad routers.
578e7512e5aSchristos 		 * Trace but do not log this problem, because where it
579e7512e5aSchristos 		 * happens, it happens frequently.
580fc1a5246Sthorpej 		 */
581e7512e5aSchristos 		if (aifp->int_state & IS_DISTRUST) {
5826d8ef4dfSthorpej 			tg = tgates;
583e7512e5aSchristos 			while (tg->tgate_addr != FROM_NADDR) {
584e7512e5aSchristos 				tg = tg->tgate_next;
585e7512e5aSchristos 				if (tg == 0) {
586e7512e5aSchristos 					trace_pkt("    discard RIP response"
587e7512e5aSchristos 						  " from untrusted router %s",
588fc1a5246Sthorpej 						  naddr_ntoa(FROM_NADDR));
5894d3fba59Schristos 					return;
5904d3fba59Schristos 				}
591fc1a5246Sthorpej 			}
592e7512e5aSchristos 		}
593fc1a5246Sthorpej 
594e7512e5aSchristos 		/* Authenticate the packet if we have a secret.
595e7512e5aSchristos 		 * If we do not have any secrets, ignore the error in
596e7512e5aSchristos 		 * RFC 1723 and accept it regardless.
597e7512e5aSchristos 		 */
598e7512e5aSchristos 		if (aifp->int_auth[0].type != RIP_AUTH_NONE
599e7512e5aSchristos 		    && rip->rip_vers != RIPv1
600e7512e5aSchristos 		    && !ck_passwd(aifp,rip,lim,FROM_NADDR,&use_auth))
601e7512e5aSchristos 			return;
602fc1a5246Sthorpej 
603e7512e5aSchristos 		do {
604fc1a5246Sthorpej 			if (n->n_family == RIP_AF_AUTH)
605fc1a5246Sthorpej 				continue;
606fc1a5246Sthorpej 
607*cad376bdSchristos 			n->n_metric = ntohl(n->n_metric);
608fc1a5246Sthorpej 			dst = n->n_dst;
609fc1a5246Sthorpej 			if (n->n_family != RIP_AF_INET
610fc1a5246Sthorpej 			    && (n->n_family != RIP_AF_UNSPEC
611fc1a5246Sthorpej 				|| dst != RIP_DEFAULT)) {
612e7512e5aSchristos 				msglim(&bad_router, FROM_NADDR,
613e7512e5aSchristos 				       "route from %s to unsupported"
614e7512e5aSchristos 				       " address family=%d destination=%s",
615fc1a5246Sthorpej 				       naddr_ntoa(FROM_NADDR),
616fc1a5246Sthorpej 				       n->n_family,
617fc1a5246Sthorpej 				       naddr_ntoa(dst));
618fc1a5246Sthorpej 				continue;
619fc1a5246Sthorpej 			}
620fc1a5246Sthorpej 			if (!check_dst(dst)) {
621e7512e5aSchristos 				msglim(&bad_router, FROM_NADDR,
622e7512e5aSchristos 				       "bad destination %s from %s",
623fc1a5246Sthorpej 				       naddr_ntoa(dst),
624fc1a5246Sthorpej 				       naddr_ntoa(FROM_NADDR));
625fc1a5246Sthorpej 				return;
626fc1a5246Sthorpej 			}
627fc1a5246Sthorpej 			if (n->n_metric == 0
628fc1a5246Sthorpej 			    || n->n_metric > HOPCNT_INFINITY) {
629e7512e5aSchristos 				msglim(&bad_router, FROM_NADDR,
630e7512e5aSchristos 				       "bad metric %d from %s"
631fc1a5246Sthorpej 				       " for destination %s",
632fc1a5246Sthorpej 				       n->n_metric,
633fc1a5246Sthorpej 				       naddr_ntoa(FROM_NADDR),
634fc1a5246Sthorpej 				       naddr_ntoa(dst));
635fc1a5246Sthorpej 				return;
636fc1a5246Sthorpej 			}
637fc1a5246Sthorpej 
638fc1a5246Sthorpej 			/* Notice the next-hop.
639fc1a5246Sthorpej 			 */
640e7512e5aSchristos 			gate = FROM_NADDR;
6414d3fba59Schristos 			if (n->n_nhop != 0) {
64294b2d428Schristos 				if (rip->rip_vers == RIPv1) {
6434d3fba59Schristos 					n->n_nhop = 0;
6444d3fba59Schristos 				} else {
645fc1a5246Sthorpej 				    /* Use it only if it is valid. */
646fc1a5246Sthorpej 				    if (on_net(n->n_nhop,
6474d3fba59Schristos 					       aifp->int_net, aifp->int_mask)
648fc1a5246Sthorpej 					&& check_dst(n->n_nhop)) {
649fc1a5246Sthorpej 					    gate = n->n_nhop;
650fc1a5246Sthorpej 				    } else {
651e7512e5aSchristos 					    msglim(&bad_nhop, FROM_NADDR,
652e7512e5aSchristos 						   "router %s to %s"
653e7512e5aSchristos 						   " has bad next hop %s",
654fc1a5246Sthorpej 						   naddr_ntoa(FROM_NADDR),
655fc1a5246Sthorpej 						   naddr_ntoa(dst),
656fc1a5246Sthorpej 						   naddr_ntoa(n->n_nhop));
6574d3fba59Schristos 					    n->n_nhop = 0;
6584d3fba59Schristos 				    }
65961f28255Scgd 				}
66061f28255Scgd 			}
661fc1a5246Sthorpej 
662fc1a5246Sthorpej 			if (rip->rip_vers == RIPv1
663fc1a5246Sthorpej 			    || 0 == (mask = ntohl(n->n_mask))) {
6644d3fba59Schristos 				mask = ripv1_mask_host(dst,aifp);
665fc1a5246Sthorpej 			} else if ((ntohl(dst) & ~mask) != 0) {
666e7512e5aSchristos 				msglim(&bad_mask, FROM_NADDR,
667e7512e5aSchristos 				       "router %s sent bad netmask"
668756b1291Schristos 				       " %#lx with %s",
669fc1a5246Sthorpej 				       naddr_ntoa(FROM_NADDR),
670756b1291Schristos 				       (u_long)mask,
671fc1a5246Sthorpej 				       naddr_ntoa(dst));
672fc1a5246Sthorpej 				continue;
673fc1a5246Sthorpej 			}
674fc1a5246Sthorpej 			if (rip->rip_vers == RIPv1)
675fc1a5246Sthorpej 				n->n_tag = 0;
676fc1a5246Sthorpej 
677fc1a5246Sthorpej 			/* Adjust metric according to incoming interface..
678fc1a5246Sthorpej 			 */
679f93fe60aSchristos 			n->n_metric += (aifp->int_metric
680f93fe60aSchristos 					+ aifp->int_adj_inmetric);
681fc1a5246Sthorpej 			if (n->n_metric > HOPCNT_INFINITY)
682fc1a5246Sthorpej 				n->n_metric = HOPCNT_INFINITY;
683fc1a5246Sthorpej 
6846d8ef4dfSthorpej 			/* Should we trust this route from this router? */
6856d8ef4dfSthorpej 			if (tg && (tn = tg->tgate_nets)->mask != 0) {
6866d8ef4dfSthorpej 				for (i = 0; i < MAX_TGATE_NETS; i++, tn++) {
6876d8ef4dfSthorpej 					if (on_net(dst, tn->net, tn->mask)
6886d8ef4dfSthorpej 					    && tn->mask <= mask)
6896d8ef4dfSthorpej 					    break;
6906d8ef4dfSthorpej 				}
6916d8ef4dfSthorpej 				if (i >= MAX_TGATE_NETS || tn->mask == 0) {
6926d8ef4dfSthorpej 					trace_pkt("   ignored unauthorized %s",
6936d8ef4dfSthorpej 						  addrname(dst,mask,0));
6946d8ef4dfSthorpej 					continue;
6956d8ef4dfSthorpej 				}
6966d8ef4dfSthorpej 			}
6976d8ef4dfSthorpej 
698fc1a5246Sthorpej 			/* Recognize and ignore a default route we faked
699fc1a5246Sthorpej 			 * which is being sent back to us by a machine with
700fc1a5246Sthorpej 			 * broken split-horizon.
701fc1a5246Sthorpej 			 * Be a little more paranoid than that, and reject
702fc1a5246Sthorpej 			 * default routes with the same metric we advertised.
703fc1a5246Sthorpej 			 */
7044d3fba59Schristos 			if (aifp->int_d_metric != 0
705fc1a5246Sthorpej 			    && dst == RIP_DEFAULT
706756b1291Schristos 			    && (int)n->n_metric >= aifp->int_d_metric)
707fc1a5246Sthorpej 				continue;
708fc1a5246Sthorpej 
709fc1a5246Sthorpej 			/* We can receive aggregated RIPv2 routes that must
710fc1a5246Sthorpej 			 * be broken down before they are transmitted by
711fc1a5246Sthorpej 			 * RIPv1 via an interface on a subnet.
712fc1a5246Sthorpej 			 * We might also receive the same routes aggregated
713fc1a5246Sthorpej 			 * via other RIPv2 interfaces.
714fc1a5246Sthorpej 			 * This could cause duplicate routes to be sent on
715fc1a5246Sthorpej 			 * the RIPv1 interfaces.  "Longest matching variable
716fc1a5246Sthorpej 			 * length netmasks" lets RIPv2 listeners understand,
717fc1a5246Sthorpej 			 * but breaking down the aggregated routes for RIPv1
718fc1a5246Sthorpej 			 * listeners can produce duplicate routes.
719fc1a5246Sthorpej 			 *
720fc1a5246Sthorpej 			 * Breaking down aggregated routes here bloats
721fc1a5246Sthorpej 			 * the daemon table, but does not hurt the kernel
722fc1a5246Sthorpej 			 * table, since routes are always aggregated for
723fc1a5246Sthorpej 			 * the kernel.
724fc1a5246Sthorpej 			 *
725fc1a5246Sthorpej 			 * Notice that this does not break down network
726fc1a5246Sthorpej 			 * routes corresponding to subnets.  This is part
727fc1a5246Sthorpej 			 * of the defense against RS_NET_SYN.
728fc1a5246Sthorpej 			 */
729fc1a5246Sthorpej 			if (have_ripv1_out
730fc1a5246Sthorpej 			    && (((rt = rtget(dst,mask)) == 0
731e7512e5aSchristos 				 || !(rt->rt_state & RS_NET_SYN)))
732e7512e5aSchristos 			    && (v1_mask = ripv1_mask_net(dst,0)) > mask) {
733fc1a5246Sthorpej 				ddst_h = v1_mask & -v1_mask;
734fc1a5246Sthorpej 				i = (v1_mask & ~mask)/ddst_h;
7354d3fba59Schristos 				if (i >= 511) {
736fc1a5246Sthorpej 					/* Punt if we would have to generate
737fc1a5246Sthorpej 					 * an unreasonable number of routes.
738fc1a5246Sthorpej 					 */
7396d8ef4dfSthorpej 					if (TRACECONTENTS)
7406d8ef4dfSthorpej 					    trace_misc("accept %s-->%s as 1"
7414d3fba59Schristos 						       " instead of %d routes",
742fc1a5246Sthorpej 						       addrname(dst,mask,0),
7434d3fba59Schristos 						       naddr_ntoa(FROM_NADDR),
7444d3fba59Schristos 						       i+1);
745fc1a5246Sthorpej 					i = 0;
746fc1a5246Sthorpej 				} else {
747fc1a5246Sthorpej 					mask = v1_mask;
748fc1a5246Sthorpej 				}
749fc1a5246Sthorpej 			} else {
750fc1a5246Sthorpej 				i = 0;
751fc1a5246Sthorpej 			}
752fc1a5246Sthorpej 
7536d8ef4dfSthorpej 			new.rts_gate = gate;
7546d8ef4dfSthorpej 			new.rts_router = FROM_NADDR;
7556d8ef4dfSthorpej 			new.rts_metric = n->n_metric;
7566d8ef4dfSthorpej 			new.rts_tag = n->n_tag;
7576d8ef4dfSthorpej 			new.rts_time = now.tv_sec;
7586d8ef4dfSthorpej 			new.rts_ifp = aifp;
7596d8ef4dfSthorpej 			new.rts_de_ag = i;
7606d8ef4dfSthorpej 			j = 0;
761fc1a5246Sthorpej 			for (;;) {
7626d8ef4dfSthorpej 				input_route(dst, mask, &new, n);
7636d8ef4dfSthorpej 				if (++j > i)
764fc1a5246Sthorpej 					break;
765*cad376bdSchristos 				dst = ntohl(dst) + ddst_h;
766*cad376bdSchristos 				dst = htonl(dst);
767fc1a5246Sthorpej 			}
768e7512e5aSchristos 		} while (++n < lim);
769fc1a5246Sthorpej 		break;
770fc1a5246Sthorpej 	}
771e7512e5aSchristos #undef FROM_NADDR
772fc1a5246Sthorpej }
773fc1a5246Sthorpej 
774fc1a5246Sthorpej 
775fc1a5246Sthorpej /* Process a single input route.
776fc1a5246Sthorpej  */
777fc1a5246Sthorpej static void
input_route(naddr dst,naddr mask,struct rt_spare * new,struct netinfo * n)7786d8ef4dfSthorpej input_route(naddr dst,			/* network order */
779fc1a5246Sthorpej 	    naddr mask,
7806d8ef4dfSthorpej 	    struct rt_spare *new,
781fc1a5246Sthorpej 	    struct netinfo *n)
782fc1a5246Sthorpej {
783fc1a5246Sthorpej 	int i;
784fc1a5246Sthorpej 	struct rt_entry *rt;
785fc1a5246Sthorpej 	struct rt_spare *rts, *rts0;
786fc1a5246Sthorpej 	struct interface *ifp1;
787fc1a5246Sthorpej 
788fc1a5246Sthorpej 
789fc1a5246Sthorpej 	/* See if the other guy is telling us to send our packets to him.
790fc1a5246Sthorpej 	 * Sometimes network routes arrive over a point-to-point link for
791fc1a5246Sthorpej 	 * the network containing the address(es) of the link.
792fc1a5246Sthorpej 	 *
793fc1a5246Sthorpej 	 * If our interface is broken, switch to using the other guy.
794fc1a5246Sthorpej 	 */
795fc1a5246Sthorpej 	ifp1 = ifwithaddr(dst, 1, 1);
796fc1a5246Sthorpej 	if (ifp1 != 0
797e7512e5aSchristos 	    && (!(ifp1->int_state & IS_BROKE)
798e7512e5aSchristos 		|| (ifp1->int_state & IS_PASSIVE)))
799fc1a5246Sthorpej 		return;
800fc1a5246Sthorpej 
801fc1a5246Sthorpej 	/* Look for the route in our table.
802fc1a5246Sthorpej 	 */
803fc1a5246Sthorpej 	rt = rtget(dst, mask);
804fc1a5246Sthorpej 
805fc1a5246Sthorpej 	/* Consider adding the route if we do not already have it.
806fc1a5246Sthorpej 	 */
807fc1a5246Sthorpej 	if (rt == 0) {
808fc1a5246Sthorpej 		/* Ignore unknown routes being poisoned.
809fc1a5246Sthorpej 		 */
8106d8ef4dfSthorpej 		if (new->rts_metric == HOPCNT_INFINITY)
811fc1a5246Sthorpej 			return;
812fc1a5246Sthorpej 
8134d3fba59Schristos 		/* Ignore the route if it points to us */
8144d3fba59Schristos 		if (n->n_nhop != 0
8154d3fba59Schristos 		    && 0 != ifwithaddr(n->n_nhop, 1, 0))
8164d3fba59Schristos 			return;
8174d3fba59Schristos 
8184d3fba59Schristos 		/* If something has not gone crazy and tried to fill
8194d3fba59Schristos 		 * our memory, accept the new route.
8204d3fba59Schristos 		 */
8214d3fba59Schristos 		if (total_routes < MAX_ROUTES)
8226d8ef4dfSthorpej 			rtadd(dst, mask, 0, new);
823fc1a5246Sthorpej 		return;
824fc1a5246Sthorpej 	}
825fc1a5246Sthorpej 
826fc1a5246Sthorpej 	/* We already know about the route.  Consider this update.
827fc1a5246Sthorpej 	 *
828fc1a5246Sthorpej 	 * If (rt->rt_state & RS_NET_SYN), then this route
829fc1a5246Sthorpej 	 * is the same as a network route we have inferred
830fc1a5246Sthorpej 	 * for subnets we know, in order to tell RIPv1 routers
831fc1a5246Sthorpej 	 * about the subnets.
832fc1a5246Sthorpej 	 *
833fc1a5246Sthorpej 	 * It is impossible to tell if the route is coming
834fc1a5246Sthorpej 	 * from a distant RIPv2 router with the standard
835fc1a5246Sthorpej 	 * netmask because that router knows about the entire
836fc1a5246Sthorpej 	 * network, or if it is a round-about echo of a
837fc1a5246Sthorpej 	 * synthetic, RIPv1 network route of our own.
838fc1a5246Sthorpej 	 * The worst is that both kinds of routes might be
839fc1a5246Sthorpej 	 * received, and the bad one might have the smaller
8404d3fba59Schristos 	 * metric.  Partly solve this problem by never
8414d3fba59Schristos 	 * aggregating into such a route.  Also keep it
842fc1a5246Sthorpej 	 * around as long as the interface exists.
843fc1a5246Sthorpej 	 */
844fc1a5246Sthorpej 
845fc1a5246Sthorpej 	rts0 = rt->rt_spares;
846fc1a5246Sthorpej 	for (rts = rts0, i = NUM_SPARES; i != 0; i--, rts++) {
8476d8ef4dfSthorpej 		if (rts->rts_router == new->rts_router)
848fc1a5246Sthorpej 			break;
849fc1a5246Sthorpej 		/* Note the worst slot to reuse,
850fc1a5246Sthorpej 		 * other than the current slot.
851fc1a5246Sthorpej 		 */
852fc1a5246Sthorpej 		if (rts0 == rt->rt_spares
853fc1a5246Sthorpej 		    || BETTER_LINK(rt, rts0, rts))
854fc1a5246Sthorpej 			rts0 = rts;
855fc1a5246Sthorpej 	}
856fc1a5246Sthorpej 	if (i != 0) {
8576d8ef4dfSthorpej 		/* Found a route from the router already in the table.
858fc1a5246Sthorpej 		 */
8596d8ef4dfSthorpej 
8606d8ef4dfSthorpej 		/* If the new route is a route broken down from an
8616d8ef4dfSthorpej 		 * aggregated route, and if the previous route is either
8626d8ef4dfSthorpej 		 * not a broken down route or was broken down from a finer
8636d8ef4dfSthorpej 		 * netmask, and if the previous route is current,
8646d8ef4dfSthorpej 		 * then forget this one.
8656d8ef4dfSthorpej 		 */
8666d8ef4dfSthorpej 		if (new->rts_de_ag > rts->rts_de_ag
8676d8ef4dfSthorpej 		    && now_stale <= rts->rts_time)
8686d8ef4dfSthorpej 			return;
869fc1a5246Sthorpej 
8704d3fba59Schristos 		/* Keep poisoned routes around only long enough to pass
8716d8ef4dfSthorpej 		 * the poison on.  Use a new timestamp for good routes.
872fc1a5246Sthorpej 		 */
8736d8ef4dfSthorpej 		if (rts->rts_metric == HOPCNT_INFINITY
8746d8ef4dfSthorpej 		    && new->rts_metric == HOPCNT_INFINITY)
8756d8ef4dfSthorpej 			new->rts_time = rts->rts_time;
876fc1a5246Sthorpej 
877fc1a5246Sthorpej 		/* If this is an update for the router we currently prefer,
878fc1a5246Sthorpej 		 * then note it.
879fc1a5246Sthorpej 		 */
880fc1a5246Sthorpej 		if (i == NUM_SPARES) {
8816d8ef4dfSthorpej 			rtchange(rt, rt->rt_state, new, 0);
882fc1a5246Sthorpej 			/* If the route got worse, check for something better.
883fc1a5246Sthorpej 			 */
8846d8ef4dfSthorpej 			if (new->rts_metric > rts->rts_metric)
885fc1a5246Sthorpej 				rtswitch(rt, 0);
886fc1a5246Sthorpej 			return;
887fc1a5246Sthorpej 		}
888fc1a5246Sthorpej 
889fc1a5246Sthorpej 		/* This is an update for a spare route.
890fc1a5246Sthorpej 		 * Finished if the route is unchanged.
891fc1a5246Sthorpej 		 */
8926d8ef4dfSthorpej 		if (rts->rts_gate == new->rts_gate
8936d8ef4dfSthorpej 		    && rts->rts_metric == new->rts_metric
8946d8ef4dfSthorpej 		    && rts->rts_tag == new->rts_tag) {
8956d8ef4dfSthorpej 			trace_upslot(rt, rts, new);
8966d8ef4dfSthorpej 			*rts = *new;
897fc1a5246Sthorpej 			return;
8986d8ef4dfSthorpej 		}
8996d8ef4dfSthorpej 		/* Forget it if it has gone bad.
9006d8ef4dfSthorpej 		 */
9016d8ef4dfSthorpej 		if (new->rts_metric == HOPCNT_INFINITY) {
902e7512e5aSchristos 			rts_delete(rt, rts);
903e7512e5aSchristos 			return;
904fc1a5246Sthorpej 		}
905fc1a5246Sthorpej 
906fc1a5246Sthorpej 	} else {
907fc1a5246Sthorpej 		/* The update is for a route we know about,
908fc1a5246Sthorpej 		 * but not from a familiar router.
9094d3fba59Schristos 		 *
9104d3fba59Schristos 		 * Ignore the route if it points to us.
911fc1a5246Sthorpej 		 */
9124d3fba59Schristos 		if (n->n_nhop != 0
9134d3fba59Schristos 		    && 0 != ifwithaddr(n->n_nhop, 1, 0))
9144d3fba59Schristos 			return;
9154d3fba59Schristos 
9166d8ef4dfSthorpej 		/* the loop above set rts0=worst spare */
917fc1a5246Sthorpej 		rts = rts0;
918fc1a5246Sthorpej 
919fc1a5246Sthorpej 		/* Save the route as a spare only if it has
920fc1a5246Sthorpej 		 * a better metric than our worst spare.
921fc1a5246Sthorpej 		 * This also ignores poisoned routes (those
922fc1a5246Sthorpej 		 * received with metric HOPCNT_INFINITY).
923fc1a5246Sthorpej 		 */
9246d8ef4dfSthorpej 		if (new->rts_metric >= rts->rts_metric)
925fc1a5246Sthorpej 			return;
926fc1a5246Sthorpej 	}
927fc1a5246Sthorpej 
9286d8ef4dfSthorpej 	trace_upslot(rt, rts, new);
9296d8ef4dfSthorpej 	*rts = *new;
930fc1a5246Sthorpej 
931fc1a5246Sthorpej 	/* try to switch to a better route */
932fc1a5246Sthorpej 	rtswitch(rt, rts);
93361f28255Scgd }
934e7512e5aSchristos 
935e7512e5aSchristos 
936e7512e5aSchristos static int				/* 0 if bad */
ck_passwd(struct interface * aifp,struct rip * rip,void * lim,naddr from,struct msg_limit * use_authp)937e7512e5aSchristos ck_passwd(struct interface *aifp,
938e7512e5aSchristos 	  struct rip *rip,
939e7512e5aSchristos 	  void *lim,
940e7512e5aSchristos 	  naddr from,
941e7512e5aSchristos 	  struct msg_limit *use_authp)
942e7512e5aSchristos {
943e7512e5aSchristos #	define NA (rip->rip_auths)
944e7512e5aSchristos 	struct netauth *na2;
945e7512e5aSchristos 	struct auth *ap;
946e7512e5aSchristos 	MD5_CTX md5_ctx;
947e7512e5aSchristos 	u_char hash[RIP_AUTH_PW_LEN];
94894b2d428Schristos 	int i, len;
949e7512e5aSchristos 
950e7512e5aSchristos 
951e7512e5aSchristos 	if ((void *)NA >= lim || NA->a_family != RIP_AF_AUTH) {
952e7512e5aSchristos 		msglim(use_authp, from, "missing password from %s",
953e7512e5aSchristos 		       naddr_ntoa(from));
954e7512e5aSchristos 		return 0;
955e7512e5aSchristos 	}
956e7512e5aSchristos 
957e7512e5aSchristos 	/* accept any current (+/- 24 hours) password
958e7512e5aSchristos 	 */
959e7512e5aSchristos 	for (ap = aifp->int_auth, i = 0; i < MAX_AUTH_KEYS; i++, ap++) {
960e7512e5aSchristos 		if (ap->type != NA->a_type
961e7512e5aSchristos 		    || (u_long)ap->start > (u_long)clk.tv_sec+DAY
962e7512e5aSchristos 		    || (u_long)ap->end+DAY < (u_long)clk.tv_sec)
963e7512e5aSchristos 			continue;
964e7512e5aSchristos 
965e7512e5aSchristos 		if (NA->a_type == RIP_AUTH_PW) {
96694b2d428Schristos 			if (!memcmp(NA->au.au_pw, ap->key, RIP_AUTH_PW_LEN))
967e7512e5aSchristos 				return 1;
968e7512e5aSchristos 
969e7512e5aSchristos 		} else {
970e7512e5aSchristos 			/* accept MD5 secret with the right key ID
971e7512e5aSchristos 			 */
972e7512e5aSchristos 			if (NA->au.a_md5.md5_keyid != ap->keyid)
973e7512e5aSchristos 				continue;
974e7512e5aSchristos 
97594b2d428Schristos 			len = ntohs(NA->au.a_md5.md5_pkt_len);
97694b2d428Schristos 			if ((len-sizeof(*rip)) % sizeof(*NA) != 0
977756b1291Schristos 			    || len != (char *)lim-(char*)rip-(int)sizeof(*NA)) {
978e7512e5aSchristos 				msglim(use_authp, from,
97994b2d428Schristos 				       "wrong MD5 RIPv2 packet length of %d"
98094b2d428Schristos 				       " instead of %d from %s",
98194b2d428Schristos 				       len, (int)((char *)lim-(char *)rip
98294b2d428Schristos 						  -sizeof(*NA)),
983e7512e5aSchristos 				       naddr_ntoa(from));
984e7512e5aSchristos 				return 0;
985e7512e5aSchristos 			}
98694b2d428Schristos 			na2 = (struct netauth *)((char *)rip+len);
98794b2d428Schristos 
98894b2d428Schristos 			/* Given a good hash value, these are not security
98994b2d428Schristos 			 * problems so be generous and accept the routes,
99094b2d428Schristos 			 * after complaining.
99194b2d428Schristos 			 */
99294b2d428Schristos 			if (TRACEPACKETS) {
99394b2d428Schristos 				if (NA->au.a_md5.md5_auth_len
994f93fe60aSchristos 				    != RIP_AUTH_MD5_HASH_LEN)
99594b2d428Schristos 					msglim(use_authp, from,
99694b2d428Schristos 					       "unknown MD5 RIPv2 auth len %#x"
99719cc8c48Sagc 					       " instead of %#lx from %s",
99894b2d428Schristos 					       NA->au.a_md5.md5_auth_len,
99919cc8c48Sagc 					       (unsigned long) RIP_AUTH_MD5_HASH_LEN,
100094b2d428Schristos 					       naddr_ntoa(from));
100194b2d428Schristos 				if (na2->a_family != RIP_AF_AUTH)
100294b2d428Schristos 					msglim(use_authp, from,
100394b2d428Schristos 					       "unknown MD5 RIPv2 family %#x"
100494b2d428Schristos 					       " instead of %#x from %s",
100594b2d428Schristos 					       na2->a_family, RIP_AF_AUTH,
100694b2d428Schristos 					       naddr_ntoa(from));
100794b2d428Schristos 				if (na2->a_type != ntohs(1))
100894b2d428Schristos 					msglim(use_authp, from,
100994b2d428Schristos 					       "MD5 RIPv2 hash has %#x"
101094b2d428Schristos 					       " instead of %#x from %s",
101194b2d428Schristos 					       na2->a_type, ntohs(1),
101294b2d428Schristos 					       naddr_ntoa(from));
101394b2d428Schristos 			}
101494b2d428Schristos 
1015e7512e5aSchristos 			MD5Init(&md5_ctx);
1016f93fe60aSchristos 			MD5Update(&md5_ctx, (u_char *)rip,
1017f93fe60aSchristos 				  len + RIP_AUTH_MD5_HASH_XTRA);
1018f93fe60aSchristos 			MD5Update(&md5_ctx, ap->key, RIP_AUTH_MD5_KEY_LEN);
1019e7512e5aSchristos 			MD5Final(hash, &md5_ctx);
102094b2d428Schristos 			if (!memcmp(hash, na2->au.au_pw, sizeof(hash)))
1021e7512e5aSchristos 				return 1;
1022e7512e5aSchristos 		}
1023e7512e5aSchristos 	}
1024e7512e5aSchristos 
1025e7512e5aSchristos 	msglim(use_authp, from, "bad password from %s",
1026e7512e5aSchristos 	       naddr_ntoa(from));
1027e7512e5aSchristos 	return 0;
1028e7512e5aSchristos #undef NA
1029e7512e5aSchristos }
1030