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