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 * 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 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 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 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