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