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