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 }