1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 * 5 * Copyright (c) 1983, 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgment: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * $FreeBSD: src/sbin/routed/main.c,v 1.14 2000/08/11 08:24:38 sheldonh Exp $ 37 * char copyright[] = "@(#) Copyright (c) 1983, 1988, 1993\n" 38 * " The Regents of the University of California. All rights reserved.\n"; 39 */ 40 41 #include "defs.h" 42 #include "pathnames.h" 43 #include <signal.h> 44 #include <fcntl.h> 45 #include <sys/file.h> 46 #include <userdefs.h> 47 #include <sys/stat.h> 48 49 #define IN_ROUTED_VERSION "2.22" 50 51 int stopint; 52 boolean_t supplier; /* supply or broadcast updates */ 53 boolean_t supplier_set; 54 /* -S option. _B_TRUE=treat all RIP speakers as default routers. */ 55 boolean_t save_space = _B_FALSE; 56 57 static boolean_t default_gateway; /* _B_TRUE=advertise default */ 58 static boolean_t background = _B_TRUE; 59 boolean_t ridhosts; /* _B_TRUE=reduce host routes */ 60 boolean_t mhome; /* _B_TRUE=want multi-homed host route */ 61 boolean_t advertise_mhome; /* _B_TRUE=must continue advertising it */ 62 boolean_t auth_ok = _B_TRUE; /* _B_TRUE=ignore auth if we don't care */ 63 boolean_t no_install; /* _B_TRUE=don't install in kernel */ 64 65 struct timeval epoch; /* when started */ 66 struct timeval clk; 67 static struct timeval prev_clk; 68 static int usec_fudge; 69 struct timeval now; /* current idea of time */ 70 /* If a route's rts_time is <= to now_stale, the route is stale. */ 71 time_t now_stale; 72 /* If a route's rts_time is <= to now_expire, the route is expired */ 73 time_t now_expire; 74 /* If a route's rts_time is <= to now_garbage, the route needs to be deleted */ 75 time_t now_garbage; 76 77 static struct timeval next_bcast; /* next general broadcast */ 78 struct timeval no_flash = { /* inhibit flash update */ 79 EPOCH+SUPPLY_INTERVAL, 0 80 }; 81 82 /* When now reaches this time, it's time to call sync_kern() */ 83 static struct timeval sync_kern_timer; 84 85 static fd_set fdbits; 86 static int sock_max; 87 int rip_sock = -1; /* RIP socket */ 88 boolean_t rip_enabled; 89 static boolean_t openlog_done; 90 91 /* 92 * The interface to which rip_sock is currently pointing for 93 * output. 94 */ 95 struct interface *rip_sock_interface; 96 97 int rt_sock; /* routing socket */ 98 99 100 static int open_rip_sock(); 101 static void timevalsub(struct timeval *, struct timeval *, struct timeval *); 102 static void sigalrm(int); 103 static void sigterm(int); 104 105 int 106 main(int argc, char *argv[]) 107 { 108 int n, off; 109 char *p, *q; 110 const char *cp; 111 struct timeval select_timeout, result; 112 fd_set ibits; 113 in_addr_t p_net, p_mask; 114 struct parm parm; 115 char *tracename = NULL; 116 boolean_t vflag = _B_FALSE; 117 boolean_t version = _B_FALSE; 118 int sigerr = 0; 119 FILE *pidfp; 120 mode_t pidmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* 0644 */ 121 122 (void) setlocale(LC_ALL, ""); 123 124 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 125 #define TEXT_DOMAIN "SYS_TEXT" 126 #endif /* ! TEXT_DOMAIN */ 127 128 (void) textdomain(TEXT_DOMAIN); 129 130 /* 131 * Some shells are badly broken and send SIGHUP to backgrounded 132 * processes. 133 */ 134 if (signal(SIGHUP, SIG_IGN) == SIG_ERR) 135 sigerr = errno; 136 137 ftrace = stdout; 138 139 if (gettimeofday(&clk, 0) == -1) { 140 logbad(_B_FALSE, "gettimeofday: %s", rip_strerror(errno)); 141 } 142 prev_clk = clk; 143 epoch = clk; 144 epoch.tv_sec -= EPOCH; 145 now.tv_sec = EPOCH; 146 now_stale = EPOCH - STALE_TIME; 147 now_expire = EPOCH - EXPIRE_TIME; 148 now_garbage = EPOCH - GARBAGE_TIME; 149 select_timeout.tv_sec = 0; 150 151 while ((n = getopt(argc, argv, "sSqdghmpAztVvnT:F:P:")) != -1) { 152 switch (n) { 153 case 'A': 154 /* 155 * Ignore authentication if we do not care. 156 * Crazy as it is, that is what RFC 2453 requires. 157 */ 158 auth_ok = _B_FALSE; 159 break; 160 161 case 't': 162 if (new_tracelevel < 2) 163 new_tracelevel = 2; 164 background = _B_FALSE; 165 break; 166 167 case 'd': /* put in.routed in foreground */ 168 background = _B_FALSE; 169 break; 170 171 case 'F': /* minimal routes for SLIP */ 172 n = FAKE_METRIC; 173 p = strchr(optarg, ','); 174 if (p != NULL) { 175 n = (int)strtoul(p+1, &q, 0); 176 if (*q == '\0' && p+1 != q && 177 n <= HOPCNT_INFINITY-1 && n >= 1) 178 *p = '\0'; 179 } 180 if (!getnet(optarg, &p_net, &p_mask)) { 181 if (p != NULL) 182 *p = ','; 183 msglog(gettext("bad network; \"-F %s\""), 184 optarg); 185 break; 186 } 187 (void) memset(&parm, 0, sizeof (parm)); 188 parm.parm_net = p_net; 189 parm.parm_mask = p_mask; 190 parm.parm_d_metric = n; 191 cp = insert_parm(&parm); 192 if (cp != NULL) 193 msglog(gettext("bad -F: %s"), cp); 194 break; 195 196 case 'g': 197 (void) memset(&parm, 0, sizeof (parm)); 198 parm.parm_d_metric = 1; 199 cp = insert_parm(&parm); 200 if (cp != NULL) 201 msglog(gettext("bad -g: %s"), cp); 202 else 203 default_gateway = _B_TRUE; 204 break; 205 206 case 'h': /* suppress extra host routes */ 207 ridhosts = _B_TRUE; 208 break; 209 210 case 'm': /* advertise host route */ 211 mhome = _B_TRUE; /* on multi-homed hosts */ 212 break; 213 214 case 'n': /* No-install mode */ 215 no_install = _B_TRUE; 216 break; 217 218 case 'P': 219 /* handle arbitrary parameters. */ 220 q = strdup(optarg); 221 if (q == NULL) 222 logbad(_B_FALSE, "strdup: %s", 223 rip_strerror(errno)); 224 cp = parse_parms(q, _B_FALSE); 225 if (cp != NULL) 226 msglog(gettext("%1$s in \"-P %2$s\""), cp, 227 optarg); 228 free(q); 229 break; 230 231 case 'q': 232 supplier = _B_FALSE; 233 supplier_set = _B_TRUE; 234 break; 235 236 case 's': 237 supplier = _B_TRUE; 238 supplier_set = _B_TRUE; 239 break; 240 241 case 'S': /* save-space option */ 242 save_space = _B_TRUE; 243 break; 244 245 case 'T': 246 tracename = optarg; 247 break; 248 249 case 'V': 250 /* display version */ 251 version = _B_TRUE; 252 msglog(gettext("version " IN_ROUTED_VERSION)); 253 break; 254 255 case 'v': 256 /* display route changes to supplied logfile */ 257 new_tracelevel = 1; 258 vflag = _B_TRUE; 259 break; 260 261 case 'z': /* increase debug-level */ 262 new_tracelevel++; 263 break; 264 265 default: 266 goto usage; 267 } 268 } 269 argc -= optind; 270 argv += optind; 271 272 if (tracename == NULL && argc >= 1) { 273 tracename = *argv++; 274 argc--; 275 } 276 if (tracename != NULL && tracename[0] == '\0') 277 goto usage; 278 if (vflag && tracename == NULL) 279 goto usage; 280 if (argc != 0) { 281 usage: 282 (void) fprintf(stderr, gettext( 283 "usage: in.routed [-AdghmnqsStVvz] " 284 "[-T <tracefile>]\n")); 285 (void) fprintf(stderr, 286 gettext("\t[-F <net>[/<mask>][,<metric>]] [-P <parms>]\n")); 287 logbad(_B_FALSE, gettext("excess arguments")); 288 } 289 if (geteuid() != 0) { 290 /* 291 * Regular users are allowed to run in.routed for the 292 * sole purpose of obtaining the version number. In 293 * that case, exit(EXIT_SUCCESS) without complaining. 294 */ 295 if (version) 296 exit(EXIT_SUCCESS); 297 logbad(_B_FALSE, gettext("requires UID 0")); 298 } 299 300 if (default_gateway) { 301 if (supplier_set && !supplier) { 302 msglog(gettext("-g and -q are incompatible")); 303 } else { 304 supplier = _B_TRUE; 305 supplier_set = _B_TRUE; 306 } 307 } 308 309 if (signal(SIGALRM, sigalrm) == SIG_ERR) 310 sigerr = errno; 311 /* SIGHUP fatal during debugging */ 312 if (!background) 313 if (signal(SIGHUP, sigterm) == SIG_ERR) 314 sigerr = errno; 315 if (signal(SIGTERM, sigterm) == SIG_ERR) 316 sigerr = errno; 317 if (signal(SIGINT, sigterm) == SIG_ERR) 318 sigerr = errno; 319 if (signal(SIGUSR1, sigtrace_more) == SIG_ERR) 320 sigerr = errno; 321 if (signal(SIGUSR2, sigtrace_less) == SIG_ERR) 322 sigerr = errno; 323 if (signal(SIGHUP, sigtrace_dump) == SIG_ERR) 324 sigerr = errno; 325 326 if (sigerr) 327 msglog("signal: %s", rip_strerror(sigerr)); 328 329 /* get into the background */ 330 if (background && daemon(0, 0) < 0) 331 BADERR(_B_FALSE, "daemon()"); 332 333 /* Store our process id, blow away any existing file if it exists. */ 334 if ((pidfp = fopen(PATH_PID, "w")) == NULL) { 335 (void) fprintf(stderr, 336 gettext("in.routed: unable to open " PATH_PID ": %s\n"), 337 strerror(errno)); 338 } else { 339 (void) fprintf(pidfp, "%ld\n", getpid()); 340 (void) fclose(pidfp); 341 (void) chmod(PATH_PID, pidmode); 342 } 343 344 srandom((int)(clk.tv_sec ^ clk.tv_usec ^ getpid())); 345 346 /* allocate the interface tables */ 347 iftbl_alloc(); 348 349 /* prepare socket connected to the kernel. */ 350 rt_sock = socket(PF_ROUTE, SOCK_RAW, AF_INET); 351 if (rt_sock < 0) 352 BADERR(_B_TRUE, "rt_sock = socket()"); 353 if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1) 354 logbad(_B_TRUE, "fcntl(rt_sock) O_NONBLOCK: %s", 355 rip_strerror(errno)); 356 off = 0; 357 if (setsockopt(rt_sock, SOL_SOCKET, SO_USELOOPBACK, 358 &off, sizeof (off)) < 0) 359 LOGERR("setsockopt(SO_USELOOPBACK,0)"); 360 361 fix_select(); 362 363 364 if (tracename != NULL) { 365 (void) strlcpy(inittracename, tracename, 366 sizeof (inittracename)); 367 set_tracefile(inittracename, "%s", -1); 368 } else { 369 tracelevel_msg("%s", -1); /* turn on tracing to stdio */ 370 } 371 372 bufinit(); 373 374 /* initialize radix tree */ 375 rtinit(); 376 377 /* 378 * Pick a random part of the second for our output to minimize 379 * collisions. 380 * 381 * Start broadcasting after hearing from other routers, and 382 * at a random time so a bunch of systems do not get synchronized 383 * after a power failure. 384 * 385 * Since now is the number of seconds since epoch (this is initially 386 * EPOCH seconds), these times are really relative to now. 387 */ 388 intvl_random(&next_bcast, EPOCH+MIN_WAITTIME, EPOCH+SUPPLY_INTERVAL); 389 age_timer.tv_usec = next_bcast.tv_usec; 390 age_timer.tv_sec = EPOCH+MIN_WAITTIME; 391 rdisc_timer = next_bcast; 392 ifscan_timer.tv_usec = next_bcast.tv_usec; 393 394 /* 395 * Open the global rip socket. From now on, this socket can be 396 * assumed to be open. It will remain open until in.routed 397 * exits. 398 */ 399 rip_sock = open_rip_sock(); 400 401 /* 402 * Collect an initial view of the world by checking the interface 403 * configuration and the kludge file. 404 * 405 * gwkludge() could call addroutefordefault(), resulting in a call to 406 * iflookup, and thus ifscan() to find the physical interfaces. 407 * ifscan() will attempt to use the rip_sock in order to join 408 * mcast groups, so gwkludge *must* be called after opening 409 * the rip_sock. 410 */ 411 gwkludge(); 412 413 ifscan(); 414 415 /* Ask for routes */ 416 rip_query(); 417 rdisc_sol(); 418 419 /* Now turn off stdio if not tracing */ 420 if (new_tracelevel == 0) 421 trace_close(background); 422 423 /* Loop until a fatal error occurs, listening and broadcasting. */ 424 for (;;) { 425 prev_clk = clk; 426 if (gettimeofday(&clk, 0) == -1) { 427 logbad(_B_FALSE, "gettimeofday: %s", 428 rip_strerror(errno)); 429 } 430 if (prev_clk.tv_sec == clk.tv_sec && 431 prev_clk.tv_usec == clk.tv_usec+usec_fudge) { 432 /* 433 * Much of `in.routed` depends on time always advancing. 434 * On systems that do not guarantee that gettimeofday() 435 * produces unique timestamps even if called within 436 * a single tick, use trickery like that in classic 437 * BSD kernels. 438 */ 439 clk.tv_usec += ++usec_fudge; 440 441 } else { 442 time_t dt; 443 444 usec_fudge = 0; 445 446 timevalsub(&result, &clk, &prev_clk); 447 if (result.tv_sec < 0 || result.tv_sec > 448 select_timeout.tv_sec + 5) { 449 /* 450 * Deal with time changes before other 451 * housekeeping to keep everything straight. 452 */ 453 dt = result.tv_sec; 454 if (dt > 0) 455 dt -= select_timeout.tv_sec; 456 trace_act("time changed by %d sec", (int)dt); 457 epoch.tv_sec += dt; 458 } 459 } 460 timevalsub(&now, &clk, &epoch); 461 now_stale = now.tv_sec - STALE_TIME; 462 now_expire = now.tv_sec - EXPIRE_TIME; 463 now_garbage = now.tv_sec - GARBAGE_TIME; 464 465 /* deal with signals that should affect tracing */ 466 set_tracelevel(); 467 468 if (stopint != 0) { 469 trace_off("exiting with signal %d", stopint); 470 break; 471 } 472 473 /* look for new or dead interfaces */ 474 timevalsub(&select_timeout, &ifscan_timer, &now); 475 if (select_timeout.tv_sec <= 0) { 476 select_timeout.tv_sec = 0; 477 ifscan(); 478 rip_query(); 479 continue; 480 } 481 482 /* 483 * Check the kernel table occassionally for mysteriously 484 * evaporated routes 485 */ 486 timevalsub(&result, &sync_kern_timer, &now); 487 if (result.tv_sec <= 0) { 488 sync_kern(); 489 sync_kern_timer.tv_sec = (now.tv_sec 490 + CHECK_QUIET_INTERVAL); 491 continue; 492 } 493 if (timercmp(&result, &select_timeout, < /* */)) 494 select_timeout = result; 495 496 /* If it is time, then broadcast our routes. */ 497 if (should_supply(NULL) || advertise_mhome) { 498 timevalsub(&result, &next_bcast, &now); 499 if (result.tv_sec <= 0) { 500 /* 501 * Synchronize the aging and broadcast 502 * timers to minimize awakenings 503 */ 504 age(0); 505 age_peer_info(); 506 507 rip_bcast(0); 508 509 /* 510 * It is desirable to send routing updates 511 * regularly. So schedule the next update 512 * 30 seconds after the previous one was 513 * scheduled, instead of 30 seconds after 514 * the previous update was finished. 515 * Even if we just started after discovering 516 * a 2nd interface or were otherwise delayed, 517 * pick a 30-second aniversary of the 518 * original broadcast time. 519 */ 520 n = 1 + (0-result.tv_sec)/SUPPLY_INTERVAL; 521 next_bcast.tv_sec += n*SUPPLY_INTERVAL; 522 523 continue; 524 } 525 526 if (timercmp(&result, &select_timeout, < /* */)) 527 select_timeout = result; 528 } 529 530 /* 531 * If we need a flash update, either do it now or 532 * set the delay to end when it is time. 533 * 534 * If we are within MIN_WAITTIME seconds of a full update, 535 * do not bother. 536 */ 537 if (need_flash && should_supply(NULL) && 538 no_flash.tv_sec+MIN_WAITTIME < next_bcast.tv_sec) { 539 /* accurate to the millisecond */ 540 if (!timercmp(&no_flash, &now, > /* */)) 541 rip_bcast(1); 542 timevalsub(&result, &no_flash, &now); 543 if (timercmp(&result, &select_timeout, < /* */)) 544 select_timeout = result; 545 } 546 547 /* trigger the main aging timer. */ 548 timevalsub(&result, &age_timer, &now); 549 if (result.tv_sec <= 0) { 550 age(0); 551 continue; 552 } 553 if (timercmp(&result, &select_timeout, < /* */)) 554 select_timeout = result; 555 556 /* update the kernel routing table */ 557 timevalsub(&result, &need_kern, &now); 558 if (result.tv_sec <= 0) { 559 age(0); 560 continue; 561 } 562 if (timercmp(&result, &select_timeout, < /* */)) 563 select_timeout = result; 564 565 /* 566 * take care of router discovery. We compare timeval 567 * structures here to have millisecond granularity. 568 */ 569 if (!timercmp(&rdisc_timer, &now, > /* */)) { 570 rdisc_age(0); 571 continue; 572 } 573 timevalsub(&result, &rdisc_timer, &now); 574 if (timercmp(&result, &select_timeout, < /* */)) 575 select_timeout = result; 576 577 /* 578 * Well-known bit of select(3c) silliness inherited 579 * from BSD: anything over 100 million seconds is 580 * considered an "error." Reset that to zero. 581 */ 582 if (select_timeout.tv_sec > 100000000) 583 select_timeout.tv_sec = 0; 584 585 /* wait for input or a timer to expire. */ 586 trace_flush(); 587 ibits = fdbits; 588 n = select(sock_max, &ibits, 0, 0, &select_timeout); 589 if (n <= 0) { 590 if (n < 0 && errno != EINTR && errno != EAGAIN) 591 BADERR(_B_TRUE, "select"); 592 continue; 593 } 594 595 if (FD_ISSET(rt_sock, &ibits)) { 596 read_rt(); 597 n--; 598 } 599 if (rdisc_sock >= 0 && FD_ISSET(rdisc_sock, &ibits)) { 600 read_d(); 601 n--; 602 } 603 if (rdisc_mib_sock >= 0 && FD_ISSET(rdisc_mib_sock, &ibits)) { 604 process_d_mib_sock(); 605 n--; 606 } 607 if (rip_sock >= 0 && FD_ISSET(rip_sock, &ibits)) { 608 if (read_rip() == -1) { 609 rip_enabled = _B_FALSE; 610 trace_off("main rip socket failed"); 611 (void) close(rip_sock); 612 rip_sock = -1; 613 fix_select(); 614 break; 615 } 616 n--; 617 } 618 } 619 rip_bcast(0); 620 rdisc_adv(_B_FALSE); 621 (void) unlink(PATH_PID); 622 return (stopint | 128); 623 } 624 625 626 static void 627 sigalrm(int sig) 628 { 629 /* 630 * Historically, SIGALRM would cause the daemon to check for 631 * new and broken interfaces. 632 */ 633 ifscan_timer.tv_sec = now.tv_sec; 634 trace_act("SIGALRM"); 635 if (signal(sig, sigalrm) == SIG_ERR) 636 msglog("signal: %s", rip_strerror(errno)); 637 } 638 639 640 /* watch for fatal signals */ 641 static void 642 sigterm(int sig) 643 { 644 stopint = sig; 645 if (signal(sig, SIG_DFL) == SIG_ERR) /* catch it only once */ 646 msglog("signal: %s", rip_strerror(errno)); 647 } 648 649 650 void 651 fix_select(void) 652 { 653 (void) FD_ZERO(&fdbits); 654 sock_max = 0; 655 656 FD_SET(rt_sock, &fdbits); 657 if (sock_max <= rt_sock) 658 sock_max = rt_sock+1; 659 if (rip_sock >= 0) { 660 FD_SET(rip_sock, &fdbits); 661 if (sock_max <= rip_sock) 662 sock_max = rip_sock+1; 663 } 664 if (rdisc_sock >= 0) { 665 FD_SET(rdisc_sock, &fdbits); 666 if (sock_max <= rdisc_sock) 667 sock_max = rdisc_sock+1; 668 FD_SET(rdisc_mib_sock, &fdbits); 669 if (sock_max <= rdisc_mib_sock) 670 sock_max = rdisc_mib_sock+1; 671 } 672 } 673 674 675 void 676 fix_sock(int sock, 677 const char *name) 678 { 679 int on; 680 #define MIN_SOCKBUF (4*1024) 681 static int rbuf; 682 683 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) 684 logbad(_B_TRUE, "fcntl(%s) O_NONBLOCK: %s", name, 685 rip_strerror(errno)); 686 on = 1; 687 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) 688 msglog("setsockopt(%s,SO_BROADCAST): %s", 689 name, rip_strerror(errno)); 690 691 if (rbuf >= MIN_SOCKBUF) { 692 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 693 &rbuf, sizeof (rbuf)) < 0) 694 msglog("setsockopt(%s,SO_RCVBUF=%d): %s", 695 name, rbuf, rip_strerror(errno)); 696 } else { 697 for (rbuf = 60*1024; ; rbuf -= 4096) { 698 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 699 &rbuf, sizeof (rbuf)) == 0) { 700 trace_act("RCVBUF=%d", rbuf); 701 break; 702 } 703 if (rbuf < MIN_SOCKBUF) { 704 msglog("setsockopt(%s,SO_RCVBUF = %d): %s", 705 name, rbuf, rip_strerror(errno)); 706 break; 707 } 708 } 709 } 710 } 711 712 713 /* 714 * Open and return the global rip socket. It is guaranteed to return 715 * a good file descriptor. 716 */ 717 static int 718 open_rip_sock() 719 { 720 struct sockaddr_in sin; 721 unsigned char ttl; 722 int s; 723 int on = 1; 724 725 726 if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) 727 BADERR(_B_TRUE, "rip_sock = socket()"); 728 729 (void) memset(&sin, 0, sizeof (sin)); 730 sin.sin_family = AF_INET; 731 sin.sin_port = htons(RIP_PORT); 732 sin.sin_addr.s_addr = INADDR_ANY; 733 if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 734 BADERR(_B_FALSE, "bind(rip_sock)"); 735 } 736 fix_sock(s, "rip_sock"); 737 738 ttl = 1; 739 if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, 740 &ttl, sizeof (ttl)) < 0) 741 DBGERR(_B_TRUE, "rip_sock setsockopt(IP_MULTICAST_TTL)"); 742 743 if (setsockopt(s, IPPROTO_IP, IP_RECVIF, &on, sizeof (on))) 744 BADERR(_B_FALSE, "setsockopt(IP_RECVIF)"); 745 746 return (s); 747 } 748 749 750 /* 751 * Disable RIP. Note that we don't close the global rip socket since 752 * it is used even when RIP is disabled to receive and answer certain 753 * queries. 754 */ 755 void 756 rip_off(void) 757 { 758 struct ip_mreq m; 759 struct interface *ifp; 760 char addrstr[INET_ADDRSTRLEN]; 761 762 if (rip_enabled && !mhome) { 763 trace_act("turn off RIP"); 764 765 /* 766 * Unsubscribe from the 224.0.0.9 RIP multicast 767 * group address 768 */ 769 for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) { 770 if ((ifp->int_if_flags & IFF_MULTICAST) && 771 !IS_IFF_QUIET(ifp->int_if_flags) && 772 !IS_RIP_IN_OFF(ifp->int_state) && 773 !(ifp->int_state & IS_DUP)) { 774 m.imr_multiaddr.s_addr = 775 htonl(INADDR_RIP_GROUP); 776 m.imr_interface.s_addr = 777 (ifp->int_if_flags & IFF_POINTOPOINT) ? 778 ifp->int_dstaddr : ifp->int_addr; 779 (void) strlcpy(addrstr, 780 inet_ntoa(m.imr_multiaddr), 781 sizeof (addrstr)); 782 if (setsockopt(rip_sock, IPPROTO_IP, 783 IP_DROP_MEMBERSHIP, &m, 784 sizeof (m)) < 0 && 785 errno != EADDRNOTAVAIL && errno != ENOENT) 786 writelog(LOG_WARNING, 787 "%s: setsockopt(IP_DROP_MEMBERSHIP " 788 "%s, %s): %s", ifp->int_name, 789 addrstr, inet_ntoa(m.imr_interface), 790 rip_strerror(errno)); 791 } 792 } 793 rip_enabled = _B_FALSE; 794 795 age(0); 796 } 797 } 798 799 800 /* turn on RIP multicast input via an interface */ 801 void 802 rip_mcast_on(struct interface *ifp) 803 { 804 struct ip_mreq m; 805 806 if (!IS_RIP_IN_OFF(ifp->int_state) && 807 (ifp->int_if_flags & IFF_MULTICAST) && 808 !IS_IFF_QUIET(ifp->int_if_flags) && 809 !(ifp->int_state & IS_DUP)) { 810 m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); 811 m.imr_interface.s_addr = (ifp->int_if_flags & IFF_POINTOPOINT) ? 812 ifp->int_dstaddr : ifp->int_addr; 813 if ((setsockopt(rip_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 814 &m, sizeof (m)) < 0) && !(ifp->int_state & IS_BROKE)) 815 writelog(LOG_WARNING, 816 "Could not join 224.0.0.9 on interface %s: %s", 817 ifp->int_name, rip_strerror(errno)); 818 } 819 } 820 821 /* turn off RIP multicast input via an interface */ 822 void 823 rip_mcast_off(struct interface *ifp) 824 { 825 struct ip_mreq m; 826 827 if ((ifp->int_if_flags & IFF_MULTICAST) && 828 !IS_IFF_QUIET(ifp->int_if_flags) && rip_enabled) { 829 m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); 830 m.imr_interface.s_addr = (ifp->int_if_flags & IFF_POINTOPOINT) ? 831 ifp->int_dstaddr : ifp->int_addr; 832 if ((setsockopt(rip_sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, 833 &m, sizeof (m)) < 0) && errno != EADDRNOTAVAIL && 834 errno != ENOENT) 835 writelog(LOG_WARNING, 836 "setsockopt(IP_DROP_MEMBERSHIP RIP) for %s: %s", 837 ifp->int_name, rip_strerror(errno)); 838 } 839 } 840 841 /* enable RIP */ 842 void 843 rip_on(struct interface *ifp) 844 { 845 /* 846 * If RIP is already enabled, only start receiving 847 * multicasts for this interface. 848 */ 849 if (rip_enabled) { 850 if (ifp != NULL) 851 rip_mcast_on(ifp); 852 return; 853 } 854 855 /* 856 * If RIP is disabled and it makes sense to enable it, then enable 857 * it on all of the interfaces. It makes sense if either router 858 * discovery is off, or if router discovery is on and at most one 859 * interface is doing RIP. 860 */ 861 if (rip_interfaces > 0 && (!rdisc_ok || rip_interfaces > 1)) { 862 trace_act("turn on RIP"); 863 864 rip_enabled = _B_TRUE; 865 rip_sock_interface = NULL; 866 867 /* Do not advertise anything until we have heard something */ 868 if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME) 869 next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME; 870 871 for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) { 872 ifp->int_query_time = NEVER; 873 rip_mcast_on(ifp); 874 } 875 ifscan_timer.tv_sec = now.tv_sec; 876 } 877 878 fix_select(); 879 } 880 881 882 /* die if malloc(3) fails */ 883 void * 884 rtmalloc(size_t size, 885 const char *msg) 886 { 887 void *p = malloc(size); 888 if (p == NULL) 889 logbad(_B_TRUE, "malloc(%lu) failed in %s: %s", (ulong_t)size, 890 msg, rip_strerror(errno)); 891 return (p); 892 } 893 894 895 /* get a random instant in an interval */ 896 void 897 intvl_random(struct timeval *tp, /* put value here */ 898 ulong_t lo, /* value is after this second */ 899 ulong_t hi) /* and before this */ 900 { 901 tp->tv_sec = (time_t)(hi == lo ? lo : (lo + random() % ((hi - lo)))); 902 tp->tv_usec = random() % 1000000; 903 } 904 905 906 void 907 timevaladd(struct timeval *t1, 908 struct timeval *t2) 909 { 910 911 t1->tv_sec += t2->tv_sec; 912 if ((t1->tv_usec += t2->tv_usec) >= 1000000) { 913 t1->tv_sec++; 914 t1->tv_usec -= 1000000; 915 } 916 } 917 918 919 /* t1 = t2 - t3 */ 920 static void 921 timevalsub(struct timeval *t1, 922 struct timeval *t2, 923 struct timeval *t3) 924 { 925 t1->tv_sec = t2->tv_sec - t3->tv_sec; 926 if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) { 927 t1->tv_sec--; 928 t1->tv_usec += 1000000; 929 } 930 } 931 932 static void 933 do_openlog(void) 934 { 935 openlog_done = _B_TRUE; 936 openlog("in.routed", LOG_PID | LOG_ODELAY, LOG_DAEMON); 937 } 938 939 /* put a LOG_ERR message into the system log */ 940 void 941 msglog(const char *p, ...) 942 { 943 va_list args; 944 945 trace_flush(); 946 947 if (!openlog_done) 948 do_openlog(); 949 va_start(args, p); 950 vsyslog(LOG_ERR, p, args); 951 952 if (ftrace != 0) { 953 if (ftrace == stdout) 954 (void) fputs("in.routed: ", ftrace); 955 (void) vfprintf(ftrace, p, args); 956 (void) fputc('\n', ftrace); 957 } 958 } 959 960 961 /* 962 * Put a message about a bad system into the system log if 963 * we have not complained about it recently. 964 * 965 * It is desirable to complain about all bad systems, but not too often. 966 * In the worst case, it is not practical to keep track of all bad systems. 967 * For example, there can be many systems with the wrong password. 968 */ 969 void 970 msglim(struct msg_limit *lim, in_addr_t addr, const char *p, ...) 971 { 972 va_list args; 973 int i; 974 struct msg_sub *ms1, *ms; 975 const char *p1; 976 977 va_start(args, p); 978 979 /* 980 * look for the oldest slot in the table 981 * or the slot for the bad router. 982 */ 983 ms = ms1 = lim->subs; 984 for (i = MSG_SUBJECT_N; ; i--, ms1++) { 985 if (i == 0) { 986 /* Reuse a slot at most once every 10 minutes. */ 987 if (lim->reuse > now.tv_sec) { 988 ms = NULL; 989 } else { 990 lim->reuse = now.tv_sec + 10*60; 991 } 992 break; 993 } 994 if (ms->addr == addr) { 995 /* 996 * Repeat a complaint about a given system at 997 * most once an hour. 998 */ 999 if (ms->until > now.tv_sec) 1000 ms = NULL; 1001 break; 1002 } 1003 if (ms->until < ms1->until) 1004 ms = ms1; 1005 } 1006 if (ms != NULL) { 1007 ms->addr = addr; 1008 ms->until = now.tv_sec + 60*60; /* 60 minutes */ 1009 1010 if (!openlog_done) 1011 do_openlog(); 1012 trace_flush(); 1013 for (p1 = p; *p1 == ' '; p1++) 1014 continue; 1015 vsyslog(LOG_ERR, p1, args); 1016 } 1017 1018 /* always display the message if tracing */ 1019 if (ftrace != 0) { 1020 (void) vfprintf(ftrace, p, args); 1021 (void) fputc('\n', ftrace); 1022 } 1023 } 1024 1025 1026 void 1027 logbad(boolean_t dump, const char *p, ...) 1028 { 1029 va_list args; 1030 1031 trace_flush(); 1032 1033 if (!openlog_done) 1034 do_openlog(); 1035 va_start(args, p); 1036 vsyslog(LOG_ERR, p, args); 1037 1038 (void) fputs(gettext("in.routed: "), stderr); 1039 (void) vfprintf(stderr, p, args); 1040 (void) fputs(gettext("; giving up\n"), stderr); 1041 (void) fflush(stderr); 1042 1043 if (dump) 1044 abort(); 1045 exit(EXIT_FAILURE); 1046 } 1047 1048 /* put a message into the system log */ 1049 void 1050 writelog(int level, const char *p, ...) 1051 { 1052 va_list args; 1053 1054 trace_flush(); 1055 1056 if (!openlog_done) 1057 do_openlog(); 1058 va_start(args, p); 1059 vsyslog(level, p, args); 1060 1061 if (ftrace != 0) { 1062 if (ftrace == stdout) 1063 (void) fputs("in.routed: ", ftrace); 1064 (void) vfprintf(ftrace, p, args); 1065 (void) fputc('\n', ftrace); 1066 } 1067 }