1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 1999 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
33 */
34
35 /*
36 * Routing Table Management Daemon
37 */
38 #include "defs.h"
39
40 static char buf1[INET6_ADDRSTRLEN];
41 static char buf2[INET6_ADDRSTRLEN];
42
43 static void rip_input(struct sockaddr_in6 *from, int size, uint_t hopcount,
44 struct interface *ifp);
45
46 /*
47 * Return a pointer to the specified option buffer.
48 * If not found return NULL.
49 */
50 static void *
find_ancillary(struct msghdr * rmsg,int cmsg_type)51 find_ancillary(struct msghdr *rmsg, int cmsg_type)
52 {
53 struct cmsghdr *cmsg;
54
55 for (cmsg = CMSG_FIRSTHDR(rmsg); cmsg != NULL;
56 cmsg = CMSG_NXTHDR(rmsg, cmsg)) {
57 if (cmsg->cmsg_level == IPPROTO_IPV6 &&
58 cmsg->cmsg_type == cmsg_type) {
59 return (CMSG_DATA(cmsg));
60 }
61 }
62 return (NULL);
63 }
64
65 /*
66 * Read a packet and passes it to rip_input() for processing.
67 */
68 void
in_data(struct interface * ifp)69 in_data(struct interface *ifp)
70 {
71 struct sockaddr_in6 from;
72 int len;
73 struct msghdr rmsg;
74 struct iovec iov;
75 uchar_t *hopcntopt;
76
77 iov.iov_base = packet;
78 iov.iov_len = IPV6_MAX_PACKET;
79 rmsg.msg_name = &from;
80 rmsg.msg_namelen = (socklen_t)sizeof (from);
81 rmsg.msg_iov = &iov;
82 rmsg.msg_iovlen = 1;
83 rmsg.msg_control = control;
84 rmsg.msg_controllen = IPV6_MAX_PACKET;
85
86 if ((len = recvmsg(ifp->int_sock, &rmsg, 0)) < 0) {
87 /*
88 * Only syslog if a true error occurred.
89 */
90 if (errno != EINTR)
91 syslog(LOG_ERR, "in_data: recvmsg: %m");
92 return;
93 }
94 if (len == 0)
95 return;
96
97 if (tracing & INPUT_BIT) {
98 (void) inet_ntop(from.sin6_family, &from.sin6_addr, buf1,
99 sizeof (buf1));
100 }
101
102 /* Ignore packets > 64k or control buffers that don't fit */
103 if (rmsg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) {
104 if (tracing & INPUT_BIT) {
105 (void) fprintf(stderr,
106 "Truncated message: msg_flags 0x%x from %s\n",
107 rmsg.msg_flags, buf1);
108 }
109 return;
110 }
111
112 if ((hopcntopt = find_ancillary(&rmsg, IPV6_HOPLIMIT)) == NULL) {
113 if (tracing & INPUT_BIT) {
114 (void) fprintf(stderr, "Unknown hop limit from %s\n",
115 buf1);
116 }
117 return;
118 }
119 rip_input(&from, len, *(uint_t *)hopcntopt, ifp);
120 }
121
122 /*
123 * Process a newly received packet.
124 */
125 static void
rip_input(struct sockaddr_in6 * from,int size,uint_t hopcount,struct interface * ifp)126 rip_input(struct sockaddr_in6 *from, int size, uint_t hopcount,
127 struct interface *ifp)
128 {
129 struct rt_entry *rt;
130 struct netinfo6 *n;
131 int newsize;
132 boolean_t changes = _B_FALSE;
133 int answer = supplier;
134 struct in6_addr prefix;
135 struct in6_addr nexthop;
136 struct in6_addr *gate;
137 boolean_t foundnexthop = _B_FALSE;
138 struct sioc_addrreq sa;
139 struct sockaddr_in6 *sin6;
140
141 TRACE_INPUT(ifp, from, size);
142 if (tracing & INPUT_BIT) {
143 (void) inet_ntop(from->sin6_family, (void *)&from->sin6_addr,
144 buf1, sizeof (buf1));
145 }
146
147 /*
148 * If the packet is recevied on an interface with IFF_NORTEXCH flag set,
149 * we ignore the packet.
150 */
151 if (ifp->int_flags & RIP6_IFF_NORTEXCH) {
152 if (tracing & INPUT_BIT) {
153 (void) fprintf(ftrace,
154 "Ignore received RIPng packet on %s "
155 "(no route exchange on interface)\n",
156 ifp->int_name);
157 (void) fflush(ftrace);
158 }
159 return;
160 }
161 if (msg->rip6_vers != RIPVERSION6) {
162 if (tracing & INPUT_BIT) {
163 (void) fprintf(ftrace,
164 "Bad version number %d in packet from %s\n",
165 msg->rip6_vers, buf1);
166 (void) fflush(ftrace);
167 }
168 return;
169 }
170 if (ntohs(msg->rip6_res1) != 0) {
171 if (tracing & INPUT_BIT) {
172 (void) fprintf(ftrace,
173 "Non-zero reserved octets found in packet from "
174 "%s\n",
175 buf1);
176 (void) fflush(ftrace);
177 }
178 }
179
180 switch (msg->rip6_cmd) {
181
182 case RIPCMD6_REQUEST: /* multicasted request */
183 ifp->int_ipackets++;
184 newsize = 0;
185
186 /*
187 * Adjust size by the length of the command, version and
188 * reserved fields (which are in total 32-bit aligned).
189 */
190 size -= sizeof (msg->rip6_cmd) + sizeof (msg->rip6_vers) +
191 sizeof (msg->rip6_res1);
192
193 /*
194 * From section 2.4.1 of RFC 2080:
195 *
196 * If there is exactly one entry in the request with a
197 * destination prefix of zero, a prefix length of zero and
198 * an infinite metric, then supply the entire routing
199 * table.
200 */
201 n = msg->rip6_nets;
202 if (size == sizeof (struct netinfo6) &&
203 n->rip6_prefix_length == 0 &&
204 n->rip6_metric == HOPCNT_INFINITY) {
205 rtcreate_prefix(&n->rip6_prefix, &prefix,
206 n->rip6_prefix_length);
207 if (IN6_IS_ADDR_UNSPECIFIED(&prefix)) {
208 supply(from, ifp, 0,
209 from->sin6_port == rip6_port);
210 return;
211 }
212 }
213 for (; size >= sizeof (struct netinfo6);
214 size -= sizeof (struct netinfo6), n++) {
215 if (n->rip6_prefix_length > IPV6_ABITS) {
216 if (tracing & INPUT_BIT) {
217 (void) fprintf(ftrace,
218 "Bad prefix length %d in request "
219 "from %s\n",
220 n->rip6_prefix_length, buf1);
221 (void) fflush(ftrace);
222 }
223 continue;
224 }
225 if (IN6_IS_ADDR_LINKLOCAL(&n->rip6_prefix) ||
226 IN6_IS_ADDR_MULTICAST(&n->rip6_prefix)) {
227 if (tracing & INPUT_BIT) {
228 (void) fprintf(ftrace,
229 "Bad prefix %s in request from "
230 "%s\n",
231 inet_ntop(AF_INET6,
232 (void *)&n->rip6_prefix, buf2,
233 sizeof (buf2)),
234 buf1);
235 (void) fflush(ftrace);
236 }
237 continue;
238 }
239 rtcreate_prefix(&n->rip6_prefix, &prefix,
240 n->rip6_prefix_length);
241 rt = rtlookup(&prefix, n->rip6_prefix_length);
242
243 n->rip6_metric = (rt == NULL ?
244 HOPCNT_INFINITY :
245 min(rt->rt_metric, HOPCNT_INFINITY));
246 newsize += sizeof (struct netinfo6);
247 }
248 if (size > 0) {
249 if (tracing & INPUT_BIT) {
250 (void) fprintf(ftrace,
251 "Ignoring %d octets of trailing data in "
252 "request from %s\n",
253 size, buf1);
254 (void) fflush(ftrace);
255 }
256 }
257 if (answer && newsize > 0) {
258 /*
259 * Adjust newsize by the length of the command, version
260 * and reserved fields (which are in total 32-bit
261 * aligned).
262 */
263 msg->rip6_cmd = RIPCMD6_RESPONSE;
264 newsize += sizeof (msg->rip6_cmd) +
265 sizeof (msg->rip6_vers) + sizeof (msg->rip6_res1);
266 sendpacket(from, ifp, newsize, 0);
267 }
268 return;
269
270 case RIPCMD6_RESPONSE:
271 if (hopcount != IPV6_MAX_HOPS) {
272 if (tracing & INPUT_BIT) {
273 (void) fprintf(ftrace,
274 "Bad hop count %d in response from %s\n",
275 hopcount, buf1);
276 (void) fflush(ftrace);
277 }
278 return;
279 }
280
281 if (from->sin6_port != rip6_port) {
282 if (tracing & INPUT_BIT) {
283 (void) fprintf(ftrace,
284 "Bad source port %d in response from %s\n",
285 from->sin6_port, buf1);
286 (void) fflush(ftrace);
287 }
288 return;
289 }
290
291 if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) {
292 if (tracing & INPUT_BIT) {
293 (void) fprintf(ftrace,
294 "Bad source address (not link-local) in "
295 "response from %s\n", buf1);
296 (void) fflush(ftrace);
297 }
298 return;
299 }
300 ifp->int_ipackets++;
301
302 /*
303 * Adjust size by the length of the command, version and
304 * reserved fields (which are in total 32-bit aligned).
305 */
306 size -= sizeof (msg->rip6_cmd) + sizeof (msg->rip6_vers) +
307 sizeof (msg->rip6_res1);
308 for (n = msg->rip6_nets;
309 supplier && size >= sizeof (struct netinfo6);
310 size -= sizeof (struct netinfo6), n++) {
311 /*
312 * From section 2.1.1 of RFC 2080:
313 *
314 * This is a next hop RTE if n->rip6_metric is set to
315 * HOPCNT_NEXTHOP. If the next hop address (which is
316 * placed in the prefix field of this special RTE) is
317 * unspecified or is not a link-local address, then use
318 * the originator's address instead (effectively turning
319 * off next hop RTE processing.)
320 */
321 if (n->rip6_metric == HOPCNT_NEXTHOP) {
322 /*
323 * First check to see if the unspecified address
324 * was given as the next hop address. This is
325 * the correct way of specifying the end of use
326 * of a next hop address.
327 */
328 if (IN6_IS_ADDR_UNSPECIFIED(&n->rip6_prefix)) {
329 foundnexthop = _B_FALSE;
330 continue;
331 }
332 /*
333 * A next hop address that is not a link-local
334 * address is treated as the unspecified one.
335 * Trace this event if input tracing is enabled.
336 */
337 if (!IN6_IS_ADDR_LINKLOCAL(&n->rip6_prefix)) {
338 foundnexthop = _B_FALSE;
339 if (tracing & INPUT_BIT) {
340 (void) fprintf(ftrace,
341 "Bad next hop %s in "
342 "response from %s\n",
343 inet_ntop(AF_INET6,
344 (void *)&n->rip6_prefix,
345 buf2, sizeof (buf2)),
346 buf1);
347 }
348 continue;
349 }
350 /*
351 * Verify that the next hop address is not one
352 * of our own.
353 */
354 sin6 = (struct sockaddr_in6 *)&sa.sa_addr;
355 sin6->sin6_family = AF_INET6;
356 sin6->sin6_addr = n->rip6_prefix;
357 if (ioctl(iocsoc, SIOCTMYADDR,
358 (char *)&sa) < 0) {
359 syslog(LOG_ERR,
360 "rip_input: "
361 "ioctl (verify my address): %m");
362 return;
363 }
364 if (sa.sa_res != 0) {
365 foundnexthop = _B_FALSE;
366 if (tracing & INPUT_BIT) {
367 (void) fprintf(ftrace,
368 "Bad next hop %s is self "
369 "in response from %s\n",
370 inet_ntop(AF_INET6,
371 (void *)&n->rip6_prefix,
372 buf2, sizeof (buf2)),
373 buf1);
374 }
375 continue;
376 }
377 foundnexthop = _B_TRUE;
378 nexthop = n->rip6_prefix;
379 continue;
380 }
381 if (foundnexthop)
382 gate = &nexthop;
383 else
384 gate = &from->sin6_addr;
385
386 if (n->rip6_metric > HOPCNT_INFINITY ||
387 n->rip6_metric < 1) {
388 if (tracing & INPUT_BIT) {
389 (void) fprintf(ftrace,
390 "Bad metric %d in response from "
391 "%s\n",
392 n->rip6_metric, buf1);
393 (void) fflush(ftrace);
394 }
395 continue;
396 }
397 if (n->rip6_prefix_length > IPV6_ABITS) {
398 if (tracing & INPUT_BIT) {
399 (void) fprintf(ftrace,
400 "Bad prefix length %d in response "
401 "from %s\n",
402 n->rip6_prefix_length, buf1);
403 (void) fflush(ftrace);
404 }
405 continue;
406 }
407
408 if (IN6_IS_ADDR_LINKLOCAL(&n->rip6_prefix) ||
409 IN6_IS_ADDR_MULTICAST(&n->rip6_prefix)) {
410 if (tracing & INPUT_BIT) {
411
412 (void) fprintf(ftrace,
413 "Bad prefix %s in response from "
414 "%s\n",
415 inet_ntop(AF_INET6,
416 (void *)&n->rip6_prefix, buf2,
417 sizeof (buf2)),
418 buf1);
419 (void) fflush(ftrace);
420 }
421 continue;
422 }
423 /* Include metric for incoming interface */
424 n->rip6_metric += IFMETRIC(ifp);
425
426 rtcreate_prefix(&n->rip6_prefix, &prefix,
427 n->rip6_prefix_length);
428 rt = rtlookup(&prefix, n->rip6_prefix_length);
429 if (rt == NULL) {
430 if (n->rip6_metric < HOPCNT_INFINITY) {
431 rtadd(&prefix,
432 gate, n->rip6_prefix_length,
433 n->rip6_metric, n->rip6_route_tag,
434 _B_FALSE, ifp);
435 changes = _B_TRUE;
436 }
437 continue;
438 }
439
440 /*
441 * If the supplied metric is at least HOPCNT_INFINITY
442 * and the current metric of the route is
443 * HOPCNT_INFINITY, then this particular RTE is ignored.
444 */
445 if (n->rip6_metric >= HOPCNT_INFINITY &&
446 rt->rt_metric == HOPCNT_INFINITY)
447 continue;
448
449 /*
450 * From section 2.4.2 of RFC 2080:
451 *
452 * Update if any one of the following is true
453 *
454 * 1) From current gateway and a different metric.
455 * 2) From current gateway and a different index.
456 * 3) A shorter (smaller) metric.
457 * 4) Equivalent metric and an age at least
458 * one-half of EXPIRE_TIME.
459 *
460 * Otherwise, update timer for the interface on which
461 * the packet arrived.
462 */
463 if (IN6_ARE_ADDR_EQUAL(gate, &rt->rt_router)) {
464 if (n->rip6_metric != rt->rt_metric ||
465 rt->rt_ifp != ifp) {
466 rtchange(rt, gate, n->rip6_metric, ifp);
467 changes = _B_TRUE;
468 } else if (n->rip6_metric < HOPCNT_INFINITY) {
469 rt->rt_timer = 0;
470 }
471 } else if (n->rip6_metric < rt->rt_metric ||
472 (rt->rt_timer > (EXPIRE_TIME / 2) &&
473 rt->rt_metric == n->rip6_metric)) {
474 rtchange(rt, gate, n->rip6_metric, ifp);
475 changes = _B_TRUE;
476 }
477 }
478 if (changes && supplier)
479 dynamic_update(ifp);
480 return;
481
482 default:
483 if (tracing & INPUT_BIT) {
484 (void) fprintf(ftrace,
485 "Bad command %d in packet from %s\n",
486 msg->rip6_cmd, buf1);
487 (void) fflush(ftrace);
488 }
489 return;
490 }
491 }
492
493 /*
494 * If changes have occurred, and if we have not sent a multicast
495 * recently, send a dynamic update. This update is sent only
496 * on interfaces other than the one on which we received notice
497 * of the change. If we are within MIN_WAIT_TIME of a full update,
498 * don't bother sending; if we just sent a dynamic update
499 * and set a timer (nextmcast), delay until that time.
500 * If we just sent a full update, delay the dynamic update.
501 * Set a timer for a randomized value to suppress additional
502 * dynamic updates until it expires; if we delayed sending
503 * the current changes, set needupdate.
504 */
505 void
dynamic_update(struct interface * ifp)506 dynamic_update(struct interface *ifp)
507 {
508 int delay;
509
510 if (now.tv_sec - lastfullupdate.tv_sec >=
511 supplyinterval - MIN_WAIT_TIME)
512 return;
513
514 if (now.tv_sec - lastmcast.tv_sec >= MIN_WAIT_TIME &&
515 /* BEGIN CSTYLED */
516 timercmp(&nextmcast, &now, <)) {
517 /* END CSTYLED */
518 TRACE_ACTION("send dynamic update",
519 (struct rt_entry *)NULL);
520 supplyall(&allrouters, RTS_CHANGED, ifp, _B_TRUE);
521 lastmcast = now;
522 needupdate = _B_FALSE;
523 nextmcast.tv_sec = 0;
524 } else {
525 needupdate = _B_TRUE;
526 TRACE_ACTION("delay dynamic update",
527 (struct rt_entry *)NULL);
528 }
529
530 if (nextmcast.tv_sec == 0) {
531 delay = GET_RANDOM(MIN_WAIT_TIME * 1000000,
532 MAX_WAIT_TIME * 1000000);
533 if (tracing & ACTION_BIT) {
534 (void) fprintf(ftrace,
535 "inhibit dynamic update for %d msec\n",
536 delay / 1000);
537 (void) fflush(ftrace);
538 }
539 nextmcast.tv_sec = delay / 1000000;
540 nextmcast.tv_usec = delay % 1000000;
541 timevaladd(&nextmcast, &now);
542 /*
543 * If the next possibly dynamic update
544 * is within MIN_WAIT_TIME of the next full
545 * update, force the delay past the full
546 * update, or we might send a dynamic update
547 * just before the full update.
548 */
549 if (nextmcast.tv_sec >
550 lastfullupdate.tv_sec + supplyinterval - MIN_WAIT_TIME) {
551 nextmcast.tv_sec =
552 lastfullupdate.tv_sec + supplyinterval + 1;
553 }
554 }
555 }
556