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