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