17c478bd9Sstevel@tonic-gate /* 2*44991a1cSVladimir Kotal * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate * 57c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1988, 1993 67c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 97c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions 107c478bd9Sstevel@tonic-gate * are met: 117c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 127c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 137c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 147c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 157c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 167c478bd9Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 177c478bd9Sstevel@tonic-gate * must display the following acknowledgment: 187c478bd9Sstevel@tonic-gate * This product includes software developed by the University of 197c478bd9Sstevel@tonic-gate * California, Berkeley and its contributors. 207c478bd9Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors 217c478bd9Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 227c478bd9Sstevel@tonic-gate * without specific prior written permission. 237c478bd9Sstevel@tonic-gate * 247c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 257c478bd9Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 267c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 277c478bd9Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 287c478bd9Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 297c478bd9Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 307c478bd9Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 317c478bd9Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 327c478bd9Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 337c478bd9Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 347c478bd9Sstevel@tonic-gate * SUCH DAMAGE. 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * $FreeBSD: src/sbin/routed/main.c,v 1.14 2000/08/11 08:24:38 sheldonh Exp $ 377c478bd9Sstevel@tonic-gate * char copyright[] = "@(#) Copyright (c) 1983, 1988, 1993\n" 387c478bd9Sstevel@tonic-gate * " The Regents of the University of California. All rights reserved.\n"; 397c478bd9Sstevel@tonic-gate */ 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #include "defs.h" 427c478bd9Sstevel@tonic-gate #include "pathnames.h" 437c478bd9Sstevel@tonic-gate #include <signal.h> 447c478bd9Sstevel@tonic-gate #include <fcntl.h> 457c478bd9Sstevel@tonic-gate #include <sys/file.h> 467c478bd9Sstevel@tonic-gate #include <userdefs.h> 477c478bd9Sstevel@tonic-gate #include <sys/stat.h> 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #define IN_ROUTED_VERSION "2.22" 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate int stopint; 527c478bd9Sstevel@tonic-gate boolean_t supplier; /* supply or broadcast updates */ 537c478bd9Sstevel@tonic-gate boolean_t supplier_set; 547c478bd9Sstevel@tonic-gate /* -S option. _B_TRUE=treat all RIP speakers as default routers. */ 557c478bd9Sstevel@tonic-gate boolean_t save_space = _B_FALSE; 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate static boolean_t default_gateway; /* _B_TRUE=advertise default */ 587c478bd9Sstevel@tonic-gate static boolean_t background = _B_TRUE; 597c478bd9Sstevel@tonic-gate boolean_t ridhosts; /* _B_TRUE=reduce host routes */ 607c478bd9Sstevel@tonic-gate boolean_t mhome; /* _B_TRUE=want multi-homed host route */ 617c478bd9Sstevel@tonic-gate boolean_t advertise_mhome; /* _B_TRUE=must continue advertising it */ 627c478bd9Sstevel@tonic-gate boolean_t auth_ok = _B_TRUE; /* _B_TRUE=ignore auth if we don't care */ 637c478bd9Sstevel@tonic-gate boolean_t no_install; /* _B_TRUE=don't install in kernel */ 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate struct timeval epoch; /* when started */ 667c478bd9Sstevel@tonic-gate struct timeval clk; 677c478bd9Sstevel@tonic-gate static struct timeval prev_clk; 687c478bd9Sstevel@tonic-gate static int usec_fudge; 697c478bd9Sstevel@tonic-gate struct timeval now; /* current idea of time */ 707c478bd9Sstevel@tonic-gate /* If a route's rts_time is <= to now_stale, the route is stale. */ 717c478bd9Sstevel@tonic-gate time_t now_stale; 727c478bd9Sstevel@tonic-gate /* If a route's rts_time is <= to now_expire, the route is expired */ 737c478bd9Sstevel@tonic-gate time_t now_expire; 747c478bd9Sstevel@tonic-gate /* If a route's rts_time is <= to now_garbage, the route needs to be deleted */ 757c478bd9Sstevel@tonic-gate time_t now_garbage; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate static struct timeval next_bcast; /* next general broadcast */ 787c478bd9Sstevel@tonic-gate struct timeval no_flash = { /* inhibit flash update */ 797c478bd9Sstevel@tonic-gate EPOCH+SUPPLY_INTERVAL, 0 807c478bd9Sstevel@tonic-gate }; 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /* When now reaches this time, it's time to call sync_kern() */ 837c478bd9Sstevel@tonic-gate static struct timeval sync_kern_timer; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate static fd_set fdbits; 867c478bd9Sstevel@tonic-gate static int sock_max; 877c478bd9Sstevel@tonic-gate int rip_sock = -1; /* RIP socket */ 887c478bd9Sstevel@tonic-gate boolean_t rip_enabled; 897c478bd9Sstevel@tonic-gate static boolean_t openlog_done; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate /* 927c478bd9Sstevel@tonic-gate * The interface to which rip_sock is currently pointing for 937c478bd9Sstevel@tonic-gate * output. 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate struct interface *rip_sock_interface; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate int rt_sock; /* routing socket */ 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate static int open_rip_sock(); 1017c478bd9Sstevel@tonic-gate static void timevalsub(struct timeval *, struct timeval *, struct timeval *); 1027c478bd9Sstevel@tonic-gate static void sigalrm(int); 1037c478bd9Sstevel@tonic-gate static void sigterm(int); 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate int 1067c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 1077c478bd9Sstevel@tonic-gate { 1087c478bd9Sstevel@tonic-gate int n, off; 1097c478bd9Sstevel@tonic-gate char *p, *q; 1107c478bd9Sstevel@tonic-gate const char *cp; 1117c478bd9Sstevel@tonic-gate struct timeval select_timeout, result; 1127c478bd9Sstevel@tonic-gate fd_set ibits; 1137c478bd9Sstevel@tonic-gate in_addr_t p_net, p_mask; 1147c478bd9Sstevel@tonic-gate struct parm parm; 1157c478bd9Sstevel@tonic-gate char *tracename = NULL; 1167c478bd9Sstevel@tonic-gate boolean_t vflag = _B_FALSE; 1177c478bd9Sstevel@tonic-gate boolean_t version = _B_FALSE; 1187c478bd9Sstevel@tonic-gate int sigerr = 0; 1197c478bd9Sstevel@tonic-gate FILE *pidfp; 1207c478bd9Sstevel@tonic-gate mode_t pidmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* 0644 */ 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 1257c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEXT" 1267c478bd9Sstevel@tonic-gate #endif /* ! TEXT_DOMAIN */ 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate /* 1317c478bd9Sstevel@tonic-gate * Some shells are badly broken and send SIGHUP to backgrounded 1327c478bd9Sstevel@tonic-gate * processes. 1337c478bd9Sstevel@tonic-gate */ 1347c478bd9Sstevel@tonic-gate if (signal(SIGHUP, SIG_IGN) == SIG_ERR) 1357c478bd9Sstevel@tonic-gate sigerr = errno; 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate ftrace = stdout; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate if (gettimeofday(&clk, 0) == -1) { 1407c478bd9Sstevel@tonic-gate logbad(_B_FALSE, "gettimeofday: %s", rip_strerror(errno)); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate prev_clk = clk; 1437c478bd9Sstevel@tonic-gate epoch = clk; 1447c478bd9Sstevel@tonic-gate epoch.tv_sec -= EPOCH; 1457c478bd9Sstevel@tonic-gate now.tv_sec = EPOCH; 1467c478bd9Sstevel@tonic-gate now_stale = EPOCH - STALE_TIME; 1477c478bd9Sstevel@tonic-gate now_expire = EPOCH - EXPIRE_TIME; 1487c478bd9Sstevel@tonic-gate now_garbage = EPOCH - GARBAGE_TIME; 1497c478bd9Sstevel@tonic-gate select_timeout.tv_sec = 0; 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate while ((n = getopt(argc, argv, "sSqdghmpAztVvnT:F:P:")) != -1) { 1527c478bd9Sstevel@tonic-gate switch (n) { 1537c478bd9Sstevel@tonic-gate case 'A': 1547c478bd9Sstevel@tonic-gate /* 1557c478bd9Sstevel@tonic-gate * Ignore authentication if we do not care. 1567c478bd9Sstevel@tonic-gate * Crazy as it is, that is what RFC 2453 requires. 1577c478bd9Sstevel@tonic-gate */ 1587c478bd9Sstevel@tonic-gate auth_ok = _B_FALSE; 1597c478bd9Sstevel@tonic-gate break; 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate case 't': 1627c478bd9Sstevel@tonic-gate if (new_tracelevel < 2) 1637c478bd9Sstevel@tonic-gate new_tracelevel = 2; 1647c478bd9Sstevel@tonic-gate background = _B_FALSE; 1657c478bd9Sstevel@tonic-gate break; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate case 'd': /* put in.routed in foreground */ 1687c478bd9Sstevel@tonic-gate background = _B_FALSE; 1697c478bd9Sstevel@tonic-gate break; 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate case 'F': /* minimal routes for SLIP */ 1727c478bd9Sstevel@tonic-gate n = FAKE_METRIC; 1737c478bd9Sstevel@tonic-gate p = strchr(optarg, ','); 1747c478bd9Sstevel@tonic-gate if (p != NULL) { 1757c478bd9Sstevel@tonic-gate n = (int)strtoul(p+1, &q, 0); 1767c478bd9Sstevel@tonic-gate if (*q == '\0' && p+1 != q && 1777c478bd9Sstevel@tonic-gate n <= HOPCNT_INFINITY-1 && n >= 1) 1787c478bd9Sstevel@tonic-gate *p = '\0'; 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate if (!getnet(optarg, &p_net, &p_mask)) { 1817c478bd9Sstevel@tonic-gate if (p != NULL) 1827c478bd9Sstevel@tonic-gate *p = ','; 1837c478bd9Sstevel@tonic-gate msglog(gettext("bad network; \"-F %s\""), 1847c478bd9Sstevel@tonic-gate optarg); 1857c478bd9Sstevel@tonic-gate break; 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate (void) memset(&parm, 0, sizeof (parm)); 1887c478bd9Sstevel@tonic-gate parm.parm_net = p_net; 1897c478bd9Sstevel@tonic-gate parm.parm_mask = p_mask; 1907c478bd9Sstevel@tonic-gate parm.parm_d_metric = n; 1917c478bd9Sstevel@tonic-gate cp = insert_parm(&parm); 1927c478bd9Sstevel@tonic-gate if (cp != NULL) 1937c478bd9Sstevel@tonic-gate msglog(gettext("bad -F: %s"), cp); 1947c478bd9Sstevel@tonic-gate break; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate case 'g': 1977c478bd9Sstevel@tonic-gate (void) memset(&parm, 0, sizeof (parm)); 1987c478bd9Sstevel@tonic-gate parm.parm_d_metric = 1; 1997c478bd9Sstevel@tonic-gate cp = insert_parm(&parm); 2007c478bd9Sstevel@tonic-gate if (cp != NULL) 2017c478bd9Sstevel@tonic-gate msglog(gettext("bad -g: %s"), cp); 2027c478bd9Sstevel@tonic-gate else 2037c478bd9Sstevel@tonic-gate default_gateway = _B_TRUE; 2047c478bd9Sstevel@tonic-gate break; 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate case 'h': /* suppress extra host routes */ 2077c478bd9Sstevel@tonic-gate ridhosts = _B_TRUE; 2087c478bd9Sstevel@tonic-gate break; 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate case 'm': /* advertise host route */ 2117c478bd9Sstevel@tonic-gate mhome = _B_TRUE; /* on multi-homed hosts */ 2127c478bd9Sstevel@tonic-gate break; 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate case 'n': /* No-install mode */ 2157c478bd9Sstevel@tonic-gate no_install = _B_TRUE; 2167c478bd9Sstevel@tonic-gate break; 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate case 'P': 2197c478bd9Sstevel@tonic-gate /* handle arbitrary parameters. */ 2207c478bd9Sstevel@tonic-gate q = strdup(optarg); 2217c478bd9Sstevel@tonic-gate if (q == NULL) 2227c478bd9Sstevel@tonic-gate logbad(_B_FALSE, "strdup: %s", 2237c478bd9Sstevel@tonic-gate rip_strerror(errno)); 2247c478bd9Sstevel@tonic-gate cp = parse_parms(q, _B_FALSE); 2257c478bd9Sstevel@tonic-gate if (cp != NULL) 2267c478bd9Sstevel@tonic-gate msglog(gettext("%1$s in \"-P %2$s\""), cp, 2277c478bd9Sstevel@tonic-gate optarg); 2287c478bd9Sstevel@tonic-gate free(q); 2297c478bd9Sstevel@tonic-gate break; 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate case 'q': 2327c478bd9Sstevel@tonic-gate supplier = _B_FALSE; 2337c478bd9Sstevel@tonic-gate supplier_set = _B_TRUE; 2347c478bd9Sstevel@tonic-gate break; 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate case 's': 2377c478bd9Sstevel@tonic-gate supplier = _B_TRUE; 2387c478bd9Sstevel@tonic-gate supplier_set = _B_TRUE; 2397c478bd9Sstevel@tonic-gate break; 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate case 'S': /* save-space option */ 2427c478bd9Sstevel@tonic-gate save_space = _B_TRUE; 2437c478bd9Sstevel@tonic-gate break; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate case 'T': 2467c478bd9Sstevel@tonic-gate tracename = optarg; 2477c478bd9Sstevel@tonic-gate break; 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate case 'V': 2507c478bd9Sstevel@tonic-gate /* display version */ 2517c478bd9Sstevel@tonic-gate version = _B_TRUE; 2527c478bd9Sstevel@tonic-gate msglog(gettext("version " IN_ROUTED_VERSION)); 2537c478bd9Sstevel@tonic-gate break; 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate case 'v': 2567c478bd9Sstevel@tonic-gate /* display route changes to supplied logfile */ 2577c478bd9Sstevel@tonic-gate new_tracelevel = 1; 2587c478bd9Sstevel@tonic-gate vflag = _B_TRUE; 2597c478bd9Sstevel@tonic-gate break; 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate case 'z': /* increase debug-level */ 2627c478bd9Sstevel@tonic-gate new_tracelevel++; 2637c478bd9Sstevel@tonic-gate break; 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate default: 2667c478bd9Sstevel@tonic-gate goto usage; 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate argc -= optind; 2707c478bd9Sstevel@tonic-gate argv += optind; 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate if (tracename == NULL && argc >= 1) { 2737c478bd9Sstevel@tonic-gate tracename = *argv++; 2747c478bd9Sstevel@tonic-gate argc--; 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate if (tracename != NULL && tracename[0] == '\0') 2777c478bd9Sstevel@tonic-gate goto usage; 2787c478bd9Sstevel@tonic-gate if (vflag && tracename == NULL) 2797c478bd9Sstevel@tonic-gate goto usage; 2807c478bd9Sstevel@tonic-gate if (argc != 0) { 2817c478bd9Sstevel@tonic-gate usage: 282*44991a1cSVladimir Kotal (void) fprintf(stderr, gettext( 283*44991a1cSVladimir Kotal "usage: in.routed [-AdghmnqsStVvz] " 2847c478bd9Sstevel@tonic-gate "[-T <tracefile>]\n")); 2857c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2867c478bd9Sstevel@tonic-gate gettext("\t[-F <net>[/<mask>][,<metric>]] [-P <parms>]\n")); 2877c478bd9Sstevel@tonic-gate logbad(_B_FALSE, gettext("excess arguments")); 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate if (geteuid() != 0) { 2907c478bd9Sstevel@tonic-gate /* 2917c478bd9Sstevel@tonic-gate * Regular users are allowed to run in.routed for the 2927c478bd9Sstevel@tonic-gate * sole purpose of obtaining the version number. In 2937c478bd9Sstevel@tonic-gate * that case, exit(EXIT_SUCCESS) without complaining. 2947c478bd9Sstevel@tonic-gate */ 2957c478bd9Sstevel@tonic-gate if (version) 2967c478bd9Sstevel@tonic-gate exit(EXIT_SUCCESS); 2977c478bd9Sstevel@tonic-gate logbad(_B_FALSE, gettext("requires UID 0")); 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate if (default_gateway) { 3017c478bd9Sstevel@tonic-gate if (supplier_set && !supplier) { 3027c478bd9Sstevel@tonic-gate msglog(gettext("-g and -q are incompatible")); 3037c478bd9Sstevel@tonic-gate } else { 3047c478bd9Sstevel@tonic-gate supplier = _B_TRUE; 3057c478bd9Sstevel@tonic-gate supplier_set = _B_TRUE; 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate if (signal(SIGALRM, sigalrm) == SIG_ERR) 3107c478bd9Sstevel@tonic-gate sigerr = errno; 3117c478bd9Sstevel@tonic-gate /* SIGHUP fatal during debugging */ 3127c478bd9Sstevel@tonic-gate if (!background) 3137c478bd9Sstevel@tonic-gate if (signal(SIGHUP, sigterm) == SIG_ERR) 3147c478bd9Sstevel@tonic-gate sigerr = errno; 3157c478bd9Sstevel@tonic-gate if (signal(SIGTERM, sigterm) == SIG_ERR) 3167c478bd9Sstevel@tonic-gate sigerr = errno; 3177c478bd9Sstevel@tonic-gate if (signal(SIGINT, sigterm) == SIG_ERR) 3187c478bd9Sstevel@tonic-gate sigerr = errno; 3197c478bd9Sstevel@tonic-gate if (signal(SIGUSR1, sigtrace_more) == SIG_ERR) 3207c478bd9Sstevel@tonic-gate sigerr = errno; 3217c478bd9Sstevel@tonic-gate if (signal(SIGUSR2, sigtrace_less) == SIG_ERR) 3227c478bd9Sstevel@tonic-gate sigerr = errno; 3237c478bd9Sstevel@tonic-gate if (signal(SIGHUP, sigtrace_dump) == SIG_ERR) 3247c478bd9Sstevel@tonic-gate sigerr = errno; 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate if (sigerr) 3277c478bd9Sstevel@tonic-gate msglog("signal: %s", rip_strerror(sigerr)); 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* get into the background */ 330*44991a1cSVladimir Kotal if (background && daemon(0, 0) < 0) 3317c478bd9Sstevel@tonic-gate BADERR(_B_FALSE, "daemon()"); 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate /* Store our process id, blow away any existing file if it exists. */ 3347c478bd9Sstevel@tonic-gate if ((pidfp = fopen(PATH_PID, "w")) == NULL) { 3357c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3367c478bd9Sstevel@tonic-gate gettext("in.routed: unable to open " PATH_PID ": %s\n"), 3377c478bd9Sstevel@tonic-gate strerror(errno)); 3387c478bd9Sstevel@tonic-gate } else { 3397c478bd9Sstevel@tonic-gate (void) fprintf(pidfp, "%ld\n", getpid()); 3407c478bd9Sstevel@tonic-gate (void) fclose(pidfp); 3417c478bd9Sstevel@tonic-gate (void) chmod(PATH_PID, pidmode); 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate srandom((int)(clk.tv_sec ^ clk.tv_usec ^ getpid())); 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate /* allocate the interface tables */ 3477c478bd9Sstevel@tonic-gate iftbl_alloc(); 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate /* prepare socket connected to the kernel. */ 3507c478bd9Sstevel@tonic-gate rt_sock = socket(PF_ROUTE, SOCK_RAW, AF_INET); 3517c478bd9Sstevel@tonic-gate if (rt_sock < 0) 3527c478bd9Sstevel@tonic-gate BADERR(_B_TRUE, "rt_sock = socket()"); 3537c478bd9Sstevel@tonic-gate if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1) 3547c478bd9Sstevel@tonic-gate logbad(_B_TRUE, "fcntl(rt_sock) O_NONBLOCK: %s", 3557c478bd9Sstevel@tonic-gate rip_strerror(errno)); 3567c478bd9Sstevel@tonic-gate off = 0; 3577c478bd9Sstevel@tonic-gate if (setsockopt(rt_sock, SOL_SOCKET, SO_USELOOPBACK, 3587c478bd9Sstevel@tonic-gate &off, sizeof (off)) < 0) 3597c478bd9Sstevel@tonic-gate LOGERR("setsockopt(SO_USELOOPBACK,0)"); 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate fix_select(); 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate if (tracename != NULL) { 3657c478bd9Sstevel@tonic-gate (void) strlcpy(inittracename, tracename, 3667c478bd9Sstevel@tonic-gate sizeof (inittracename)); 3677c478bd9Sstevel@tonic-gate set_tracefile(inittracename, "%s", -1); 3687c478bd9Sstevel@tonic-gate } else { 3697c478bd9Sstevel@tonic-gate tracelevel_msg("%s", -1); /* turn on tracing to stdio */ 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate bufinit(); 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* initialize radix tree */ 3757c478bd9Sstevel@tonic-gate rtinit(); 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate /* 3787c478bd9Sstevel@tonic-gate * Pick a random part of the second for our output to minimize 3797c478bd9Sstevel@tonic-gate * collisions. 3807c478bd9Sstevel@tonic-gate * 3817c478bd9Sstevel@tonic-gate * Start broadcasting after hearing from other routers, and 3827c478bd9Sstevel@tonic-gate * at a random time so a bunch of systems do not get synchronized 3837c478bd9Sstevel@tonic-gate * after a power failure. 3847c478bd9Sstevel@tonic-gate * 3857c478bd9Sstevel@tonic-gate * Since now is the number of seconds since epoch (this is initially 3867c478bd9Sstevel@tonic-gate * EPOCH seconds), these times are really relative to now. 3877c478bd9Sstevel@tonic-gate */ 3887c478bd9Sstevel@tonic-gate intvl_random(&next_bcast, EPOCH+MIN_WAITTIME, EPOCH+SUPPLY_INTERVAL); 3897c478bd9Sstevel@tonic-gate age_timer.tv_usec = next_bcast.tv_usec; 3907c478bd9Sstevel@tonic-gate age_timer.tv_sec = EPOCH+MIN_WAITTIME; 3917c478bd9Sstevel@tonic-gate rdisc_timer = next_bcast; 3927c478bd9Sstevel@tonic-gate ifscan_timer.tv_usec = next_bcast.tv_usec; 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate /* 3957c478bd9Sstevel@tonic-gate * Open the global rip socket. From now on, this socket can be 3967c478bd9Sstevel@tonic-gate * assumed to be open. It will remain open until in.routed 3977c478bd9Sstevel@tonic-gate * exits. 3987c478bd9Sstevel@tonic-gate */ 3997c478bd9Sstevel@tonic-gate rip_sock = open_rip_sock(); 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate /* 4027c478bd9Sstevel@tonic-gate * Collect an initial view of the world by checking the interface 4037c478bd9Sstevel@tonic-gate * configuration and the kludge file. 4047c478bd9Sstevel@tonic-gate * 4057c478bd9Sstevel@tonic-gate * gwkludge() could call addroutefordefault(), resulting in a call to 4067c478bd9Sstevel@tonic-gate * iflookup, and thus ifscan() to find the physical interfaces. 4077c478bd9Sstevel@tonic-gate * ifscan() will attempt to use the rip_sock in order to join 4087c478bd9Sstevel@tonic-gate * mcast groups, so gwkludge *must* be called after opening 4097c478bd9Sstevel@tonic-gate * the rip_sock. 4107c478bd9Sstevel@tonic-gate */ 4117c478bd9Sstevel@tonic-gate gwkludge(); 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate ifscan(); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate /* Ask for routes */ 4167c478bd9Sstevel@tonic-gate rip_query(); 4177c478bd9Sstevel@tonic-gate rdisc_sol(); 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate /* Now turn off stdio if not tracing */ 4207c478bd9Sstevel@tonic-gate if (new_tracelevel == 0) 4217c478bd9Sstevel@tonic-gate trace_close(background); 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate /* Loop until a fatal error occurs, listening and broadcasting. */ 4247c478bd9Sstevel@tonic-gate for (;;) { 4257c478bd9Sstevel@tonic-gate prev_clk = clk; 4267c478bd9Sstevel@tonic-gate if (gettimeofday(&clk, 0) == -1) { 4277c478bd9Sstevel@tonic-gate logbad(_B_FALSE, "gettimeofday: %s", 4287c478bd9Sstevel@tonic-gate rip_strerror(errno)); 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate if (prev_clk.tv_sec == clk.tv_sec && 4317c478bd9Sstevel@tonic-gate prev_clk.tv_usec == clk.tv_usec+usec_fudge) { 4327c478bd9Sstevel@tonic-gate /* 4337c478bd9Sstevel@tonic-gate * Much of `in.routed` depends on time always advancing. 4347c478bd9Sstevel@tonic-gate * On systems that do not guarantee that gettimeofday() 4357c478bd9Sstevel@tonic-gate * produces unique timestamps even if called within 4367c478bd9Sstevel@tonic-gate * a single tick, use trickery like that in classic 4377c478bd9Sstevel@tonic-gate * BSD kernels. 4387c478bd9Sstevel@tonic-gate */ 4397c478bd9Sstevel@tonic-gate clk.tv_usec += ++usec_fudge; 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate } else { 4427c478bd9Sstevel@tonic-gate time_t dt; 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate usec_fudge = 0; 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate timevalsub(&result, &clk, &prev_clk); 4477c478bd9Sstevel@tonic-gate if (result.tv_sec < 0 || result.tv_sec > 4487c478bd9Sstevel@tonic-gate select_timeout.tv_sec + 5) { 4497c478bd9Sstevel@tonic-gate /* 4507c478bd9Sstevel@tonic-gate * Deal with time changes before other 4517c478bd9Sstevel@tonic-gate * housekeeping to keep everything straight. 4527c478bd9Sstevel@tonic-gate */ 4537c478bd9Sstevel@tonic-gate dt = result.tv_sec; 4547c478bd9Sstevel@tonic-gate if (dt > 0) 4557c478bd9Sstevel@tonic-gate dt -= select_timeout.tv_sec; 4567c478bd9Sstevel@tonic-gate trace_act("time changed by %d sec", (int)dt); 4577c478bd9Sstevel@tonic-gate epoch.tv_sec += dt; 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate timevalsub(&now, &clk, &epoch); 4617c478bd9Sstevel@tonic-gate now_stale = now.tv_sec - STALE_TIME; 4627c478bd9Sstevel@tonic-gate now_expire = now.tv_sec - EXPIRE_TIME; 4637c478bd9Sstevel@tonic-gate now_garbage = now.tv_sec - GARBAGE_TIME; 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate /* deal with signals that should affect tracing */ 4667c478bd9Sstevel@tonic-gate set_tracelevel(); 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate if (stopint != 0) { 4697c478bd9Sstevel@tonic-gate trace_off("exiting with signal %d", stopint); 4707c478bd9Sstevel@tonic-gate break; 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate /* look for new or dead interfaces */ 4747c478bd9Sstevel@tonic-gate timevalsub(&select_timeout, &ifscan_timer, &now); 4757c478bd9Sstevel@tonic-gate if (select_timeout.tv_sec <= 0) { 4767c478bd9Sstevel@tonic-gate select_timeout.tv_sec = 0; 4777c478bd9Sstevel@tonic-gate ifscan(); 4787c478bd9Sstevel@tonic-gate rip_query(); 4797c478bd9Sstevel@tonic-gate continue; 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate /* 4837c478bd9Sstevel@tonic-gate * Check the kernel table occassionally for mysteriously 4847c478bd9Sstevel@tonic-gate * evaporated routes 4857c478bd9Sstevel@tonic-gate */ 4867c478bd9Sstevel@tonic-gate timevalsub(&result, &sync_kern_timer, &now); 4877c478bd9Sstevel@tonic-gate if (result.tv_sec <= 0) { 4887c478bd9Sstevel@tonic-gate sync_kern(); 4897c478bd9Sstevel@tonic-gate sync_kern_timer.tv_sec = (now.tv_sec 4907c478bd9Sstevel@tonic-gate + CHECK_QUIET_INTERVAL); 4917c478bd9Sstevel@tonic-gate continue; 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate if (timercmp(&result, &select_timeout, < /* */)) 4947c478bd9Sstevel@tonic-gate select_timeout = result; 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate /* If it is time, then broadcast our routes. */ 4977c478bd9Sstevel@tonic-gate if (should_supply(NULL) || advertise_mhome) { 4987c478bd9Sstevel@tonic-gate timevalsub(&result, &next_bcast, &now); 4997c478bd9Sstevel@tonic-gate if (result.tv_sec <= 0) { 5007c478bd9Sstevel@tonic-gate /* 5017c478bd9Sstevel@tonic-gate * Synchronize the aging and broadcast 5027c478bd9Sstevel@tonic-gate * timers to minimize awakenings 5037c478bd9Sstevel@tonic-gate */ 5047c478bd9Sstevel@tonic-gate age(0); 5057c478bd9Sstevel@tonic-gate age_peer_info(); 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate rip_bcast(0); 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate /* 5107c478bd9Sstevel@tonic-gate * It is desirable to send routing updates 5117c478bd9Sstevel@tonic-gate * regularly. So schedule the next update 5127c478bd9Sstevel@tonic-gate * 30 seconds after the previous one was 5137c478bd9Sstevel@tonic-gate * scheduled, instead of 30 seconds after 5147c478bd9Sstevel@tonic-gate * the previous update was finished. 5157c478bd9Sstevel@tonic-gate * Even if we just started after discovering 5167c478bd9Sstevel@tonic-gate * a 2nd interface or were otherwise delayed, 5177c478bd9Sstevel@tonic-gate * pick a 30-second aniversary of the 5187c478bd9Sstevel@tonic-gate * original broadcast time. 5197c478bd9Sstevel@tonic-gate */ 5207c478bd9Sstevel@tonic-gate n = 1 + (0-result.tv_sec)/SUPPLY_INTERVAL; 5217c478bd9Sstevel@tonic-gate next_bcast.tv_sec += n*SUPPLY_INTERVAL; 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate continue; 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate if (timercmp(&result, &select_timeout, < /* */)) 5277c478bd9Sstevel@tonic-gate select_timeout = result; 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate /* 5317c478bd9Sstevel@tonic-gate * If we need a flash update, either do it now or 5327c478bd9Sstevel@tonic-gate * set the delay to end when it is time. 5337c478bd9Sstevel@tonic-gate * 5347c478bd9Sstevel@tonic-gate * If we are within MIN_WAITTIME seconds of a full update, 5357c478bd9Sstevel@tonic-gate * do not bother. 5367c478bd9Sstevel@tonic-gate */ 5377c478bd9Sstevel@tonic-gate if (need_flash && should_supply(NULL) && 5387c478bd9Sstevel@tonic-gate no_flash.tv_sec+MIN_WAITTIME < next_bcast.tv_sec) { 5397c478bd9Sstevel@tonic-gate /* accurate to the millisecond */ 5407c478bd9Sstevel@tonic-gate if (!timercmp(&no_flash, &now, > /* */)) 5417c478bd9Sstevel@tonic-gate rip_bcast(1); 5427c478bd9Sstevel@tonic-gate timevalsub(&result, &no_flash, &now); 5437c478bd9Sstevel@tonic-gate if (timercmp(&result, &select_timeout, < /* */)) 5447c478bd9Sstevel@tonic-gate select_timeout = result; 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate /* trigger the main aging timer. */ 5487c478bd9Sstevel@tonic-gate timevalsub(&result, &age_timer, &now); 5497c478bd9Sstevel@tonic-gate if (result.tv_sec <= 0) { 5507c478bd9Sstevel@tonic-gate age(0); 5517c478bd9Sstevel@tonic-gate continue; 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate if (timercmp(&result, &select_timeout, < /* */)) 5547c478bd9Sstevel@tonic-gate select_timeout = result; 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate /* update the kernel routing table */ 5577c478bd9Sstevel@tonic-gate timevalsub(&result, &need_kern, &now); 5587c478bd9Sstevel@tonic-gate if (result.tv_sec <= 0) { 5597c478bd9Sstevel@tonic-gate age(0); 5607c478bd9Sstevel@tonic-gate continue; 5617c478bd9Sstevel@tonic-gate } 5627c478bd9Sstevel@tonic-gate if (timercmp(&result, &select_timeout, < /* */)) 5637c478bd9Sstevel@tonic-gate select_timeout = result; 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate /* 5667c478bd9Sstevel@tonic-gate * take care of router discovery. We compare timeval 5677c478bd9Sstevel@tonic-gate * structures here to have millisecond granularity. 5687c478bd9Sstevel@tonic-gate */ 5697c478bd9Sstevel@tonic-gate if (!timercmp(&rdisc_timer, &now, > /* */)) { 5707c478bd9Sstevel@tonic-gate rdisc_age(0); 5717c478bd9Sstevel@tonic-gate continue; 5727c478bd9Sstevel@tonic-gate } 5737c478bd9Sstevel@tonic-gate timevalsub(&result, &rdisc_timer, &now); 5747c478bd9Sstevel@tonic-gate if (timercmp(&result, &select_timeout, < /* */)) 5757c478bd9Sstevel@tonic-gate select_timeout = result; 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate /* 5787c478bd9Sstevel@tonic-gate * Well-known bit of select(3c) silliness inherited 5797c478bd9Sstevel@tonic-gate * from BSD: anything over 100 million seconds is 5807c478bd9Sstevel@tonic-gate * considered an "error." Reset that to zero. 5817c478bd9Sstevel@tonic-gate */ 5827c478bd9Sstevel@tonic-gate if (select_timeout.tv_sec > 100000000) 5837c478bd9Sstevel@tonic-gate select_timeout.tv_sec = 0; 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate /* wait for input or a timer to expire. */ 5867c478bd9Sstevel@tonic-gate trace_flush(); 5877c478bd9Sstevel@tonic-gate ibits = fdbits; 5887c478bd9Sstevel@tonic-gate n = select(sock_max, &ibits, 0, 0, &select_timeout); 5897c478bd9Sstevel@tonic-gate if (n <= 0) { 5907c478bd9Sstevel@tonic-gate if (n < 0 && errno != EINTR && errno != EAGAIN) 5917c478bd9Sstevel@tonic-gate BADERR(_B_TRUE, "select"); 5927c478bd9Sstevel@tonic-gate continue; 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate if (FD_ISSET(rt_sock, &ibits)) { 5967c478bd9Sstevel@tonic-gate read_rt(); 5977c478bd9Sstevel@tonic-gate n--; 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate if (rdisc_sock >= 0 && FD_ISSET(rdisc_sock, &ibits)) { 6007c478bd9Sstevel@tonic-gate read_d(); 6017c478bd9Sstevel@tonic-gate n--; 6027c478bd9Sstevel@tonic-gate } 60365d6e08aSapersson if (rdisc_mib_sock >= 0 && FD_ISSET(rdisc_mib_sock, &ibits)) { 60465d6e08aSapersson process_d_mib_sock(); 60565d6e08aSapersson n--; 60665d6e08aSapersson } 6077c478bd9Sstevel@tonic-gate if (rip_sock >= 0 && FD_ISSET(rip_sock, &ibits)) { 6087c478bd9Sstevel@tonic-gate if (read_rip() == -1) { 6097c478bd9Sstevel@tonic-gate rip_enabled = _B_FALSE; 6107c478bd9Sstevel@tonic-gate trace_off("main rip socket failed"); 6117c478bd9Sstevel@tonic-gate (void) close(rip_sock); 6127c478bd9Sstevel@tonic-gate rip_sock = -1; 6137c478bd9Sstevel@tonic-gate fix_select(); 6147c478bd9Sstevel@tonic-gate break; 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate n--; 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate rip_bcast(0); 6207c478bd9Sstevel@tonic-gate rdisc_adv(_B_FALSE); 6217c478bd9Sstevel@tonic-gate (void) unlink(PATH_PID); 6227c478bd9Sstevel@tonic-gate return (stopint | 128); 6237c478bd9Sstevel@tonic-gate } 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate static void 6277c478bd9Sstevel@tonic-gate sigalrm(int sig) 6287c478bd9Sstevel@tonic-gate { 6297c478bd9Sstevel@tonic-gate /* 6307c478bd9Sstevel@tonic-gate * Historically, SIGALRM would cause the daemon to check for 6317c478bd9Sstevel@tonic-gate * new and broken interfaces. 6327c478bd9Sstevel@tonic-gate */ 6337c478bd9Sstevel@tonic-gate ifscan_timer.tv_sec = now.tv_sec; 6347c478bd9Sstevel@tonic-gate trace_act("SIGALRM"); 6357c478bd9Sstevel@tonic-gate if (signal(sig, sigalrm) == SIG_ERR) 6367c478bd9Sstevel@tonic-gate msglog("signal: %s", rip_strerror(errno)); 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate /* watch for fatal signals */ 6417c478bd9Sstevel@tonic-gate static void 6427c478bd9Sstevel@tonic-gate sigterm(int sig) 6437c478bd9Sstevel@tonic-gate { 6447c478bd9Sstevel@tonic-gate stopint = sig; 6457c478bd9Sstevel@tonic-gate if (signal(sig, SIG_DFL) == SIG_ERR) /* catch it only once */ 6467c478bd9Sstevel@tonic-gate msglog("signal: %s", rip_strerror(errno)); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate void 6517c478bd9Sstevel@tonic-gate fix_select(void) 6527c478bd9Sstevel@tonic-gate { 6537c478bd9Sstevel@tonic-gate (void) FD_ZERO(&fdbits); 6547c478bd9Sstevel@tonic-gate sock_max = 0; 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate FD_SET(rt_sock, &fdbits); 6577c478bd9Sstevel@tonic-gate if (sock_max <= rt_sock) 6587c478bd9Sstevel@tonic-gate sock_max = rt_sock+1; 6597c478bd9Sstevel@tonic-gate if (rip_sock >= 0) { 6607c478bd9Sstevel@tonic-gate FD_SET(rip_sock, &fdbits); 6617c478bd9Sstevel@tonic-gate if (sock_max <= rip_sock) 6627c478bd9Sstevel@tonic-gate sock_max = rip_sock+1; 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate if (rdisc_sock >= 0) { 6657c478bd9Sstevel@tonic-gate FD_SET(rdisc_sock, &fdbits); 6667c478bd9Sstevel@tonic-gate if (sock_max <= rdisc_sock) 6677c478bd9Sstevel@tonic-gate sock_max = rdisc_sock+1; 66865d6e08aSapersson FD_SET(rdisc_mib_sock, &fdbits); 66965d6e08aSapersson if (sock_max <= rdisc_mib_sock) 67065d6e08aSapersson sock_max = rdisc_mib_sock+1; 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate } 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate void 6767c478bd9Sstevel@tonic-gate fix_sock(int sock, 6777c478bd9Sstevel@tonic-gate const char *name) 6787c478bd9Sstevel@tonic-gate { 6797c478bd9Sstevel@tonic-gate int on; 6807c478bd9Sstevel@tonic-gate #define MIN_SOCKBUF (4*1024) 6817c478bd9Sstevel@tonic-gate static int rbuf; 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) 6847c478bd9Sstevel@tonic-gate logbad(_B_TRUE, "fcntl(%s) O_NONBLOCK: %s", name, 6857c478bd9Sstevel@tonic-gate rip_strerror(errno)); 6867c478bd9Sstevel@tonic-gate on = 1; 6877c478bd9Sstevel@tonic-gate if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) 6887c478bd9Sstevel@tonic-gate msglog("setsockopt(%s,SO_BROADCAST): %s", 6897c478bd9Sstevel@tonic-gate name, rip_strerror(errno)); 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate if (rbuf >= MIN_SOCKBUF) { 6927c478bd9Sstevel@tonic-gate if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 6937c478bd9Sstevel@tonic-gate &rbuf, sizeof (rbuf)) < 0) 6947c478bd9Sstevel@tonic-gate msglog("setsockopt(%s,SO_RCVBUF=%d): %s", 6957c478bd9Sstevel@tonic-gate name, rbuf, rip_strerror(errno)); 6967c478bd9Sstevel@tonic-gate } else { 6977c478bd9Sstevel@tonic-gate for (rbuf = 60*1024; ; rbuf -= 4096) { 6987c478bd9Sstevel@tonic-gate if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 6997c478bd9Sstevel@tonic-gate &rbuf, sizeof (rbuf)) == 0) { 7007c478bd9Sstevel@tonic-gate trace_act("RCVBUF=%d", rbuf); 7017c478bd9Sstevel@tonic-gate break; 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate if (rbuf < MIN_SOCKBUF) { 7047c478bd9Sstevel@tonic-gate msglog("setsockopt(%s,SO_RCVBUF = %d): %s", 7057c478bd9Sstevel@tonic-gate name, rbuf, rip_strerror(errno)); 7067c478bd9Sstevel@tonic-gate break; 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate } 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate /* 7147c478bd9Sstevel@tonic-gate * Open and return the global rip socket. It is guaranteed to return 7157c478bd9Sstevel@tonic-gate * a good file descriptor. 7167c478bd9Sstevel@tonic-gate */ 7177c478bd9Sstevel@tonic-gate static int 7187c478bd9Sstevel@tonic-gate open_rip_sock() 7197c478bd9Sstevel@tonic-gate { 7207c478bd9Sstevel@tonic-gate struct sockaddr_in sin; 7217c478bd9Sstevel@tonic-gate unsigned char ttl; 7227c478bd9Sstevel@tonic-gate int s; 7237c478bd9Sstevel@tonic-gate int on = 1; 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) 7277c478bd9Sstevel@tonic-gate BADERR(_B_TRUE, "rip_sock = socket()"); 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate (void) memset(&sin, 0, sizeof (sin)); 7307c478bd9Sstevel@tonic-gate sin.sin_family = AF_INET; 7317c478bd9Sstevel@tonic-gate sin.sin_port = htons(RIP_PORT); 7327c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = INADDR_ANY; 7337c478bd9Sstevel@tonic-gate if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 7347c478bd9Sstevel@tonic-gate BADERR(_B_FALSE, "bind(rip_sock)"); 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate fix_sock(s, "rip_sock"); 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate ttl = 1; 7397c478bd9Sstevel@tonic-gate if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, 7407c478bd9Sstevel@tonic-gate &ttl, sizeof (ttl)) < 0) 7417c478bd9Sstevel@tonic-gate DBGERR(_B_TRUE, "rip_sock setsockopt(IP_MULTICAST_TTL)"); 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate if (setsockopt(s, IPPROTO_IP, IP_RECVIF, &on, sizeof (on))) 7447c478bd9Sstevel@tonic-gate BADERR(_B_FALSE, "setsockopt(IP_RECVIF)"); 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate return (s); 7477c478bd9Sstevel@tonic-gate } 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate /* 7517c478bd9Sstevel@tonic-gate * Disable RIP. Note that we don't close the global rip socket since 7527c478bd9Sstevel@tonic-gate * it is used even when RIP is disabled to receive and answer certain 7537c478bd9Sstevel@tonic-gate * queries. 7547c478bd9Sstevel@tonic-gate */ 7557c478bd9Sstevel@tonic-gate void 7567c478bd9Sstevel@tonic-gate rip_off(void) 7577c478bd9Sstevel@tonic-gate { 7587c478bd9Sstevel@tonic-gate struct ip_mreq m; 7597c478bd9Sstevel@tonic-gate struct interface *ifp; 7607c478bd9Sstevel@tonic-gate char addrstr[INET_ADDRSTRLEN]; 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate if (rip_enabled && !mhome) { 7637c478bd9Sstevel@tonic-gate trace_act("turn off RIP"); 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate /* 7667c478bd9Sstevel@tonic-gate * Unsubscribe from the 224.0.0.9 RIP multicast 7677c478bd9Sstevel@tonic-gate * group address 7687c478bd9Sstevel@tonic-gate */ 7697c478bd9Sstevel@tonic-gate for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) { 7707c478bd9Sstevel@tonic-gate if ((ifp->int_if_flags & IFF_MULTICAST) && 7717c478bd9Sstevel@tonic-gate !IS_IFF_QUIET(ifp->int_if_flags) && 7727c478bd9Sstevel@tonic-gate !IS_RIP_IN_OFF(ifp->int_state) && 7737c478bd9Sstevel@tonic-gate !(ifp->int_state & IS_DUP)) { 7747c478bd9Sstevel@tonic-gate m.imr_multiaddr.s_addr = 7757c478bd9Sstevel@tonic-gate htonl(INADDR_RIP_GROUP); 7767c478bd9Sstevel@tonic-gate m.imr_interface.s_addr = 7777c478bd9Sstevel@tonic-gate (ifp->int_if_flags & IFF_POINTOPOINT) ? 7787c478bd9Sstevel@tonic-gate ifp->int_dstaddr : ifp->int_addr; 7797c478bd9Sstevel@tonic-gate (void) strlcpy(addrstr, 7807c478bd9Sstevel@tonic-gate inet_ntoa(m.imr_multiaddr), 7817c478bd9Sstevel@tonic-gate sizeof (addrstr)); 7827c478bd9Sstevel@tonic-gate if (setsockopt(rip_sock, IPPROTO_IP, 7837c478bd9Sstevel@tonic-gate IP_DROP_MEMBERSHIP, &m, 7847c478bd9Sstevel@tonic-gate sizeof (m)) < 0 && 7857c478bd9Sstevel@tonic-gate errno != EADDRNOTAVAIL && errno != ENOENT) 7867c478bd9Sstevel@tonic-gate writelog(LOG_WARNING, 7877c478bd9Sstevel@tonic-gate "%s: setsockopt(IP_DROP_MEMBERSHIP " 7887c478bd9Sstevel@tonic-gate "%s, %s): %s", ifp->int_name, 7897c478bd9Sstevel@tonic-gate addrstr, inet_ntoa(m.imr_interface), 7907c478bd9Sstevel@tonic-gate rip_strerror(errno)); 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate } 7937c478bd9Sstevel@tonic-gate rip_enabled = _B_FALSE; 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate age(0); 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate } 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate /* turn on RIP multicast input via an interface */ 8017c478bd9Sstevel@tonic-gate void 8027c478bd9Sstevel@tonic-gate rip_mcast_on(struct interface *ifp) 8037c478bd9Sstevel@tonic-gate { 8047c478bd9Sstevel@tonic-gate struct ip_mreq m; 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate if (!IS_RIP_IN_OFF(ifp->int_state) && 8077c478bd9Sstevel@tonic-gate (ifp->int_if_flags & IFF_MULTICAST) && 8087c478bd9Sstevel@tonic-gate !IS_IFF_QUIET(ifp->int_if_flags) && 8097c478bd9Sstevel@tonic-gate !(ifp->int_state & IS_DUP)) { 8107c478bd9Sstevel@tonic-gate m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); 8117c478bd9Sstevel@tonic-gate m.imr_interface.s_addr = (ifp->int_if_flags & IFF_POINTOPOINT) ? 8127c478bd9Sstevel@tonic-gate ifp->int_dstaddr : ifp->int_addr; 8137c478bd9Sstevel@tonic-gate if ((setsockopt(rip_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 8147c478bd9Sstevel@tonic-gate &m, sizeof (m)) < 0) && !(ifp->int_state & IS_BROKE)) 8157c478bd9Sstevel@tonic-gate writelog(LOG_WARNING, 8167c478bd9Sstevel@tonic-gate "Could not join 224.0.0.9 on interface %s: %s", 8177c478bd9Sstevel@tonic-gate ifp->int_name, rip_strerror(errno)); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate /* turn off RIP multicast input via an interface */ 8227c478bd9Sstevel@tonic-gate void 8237c478bd9Sstevel@tonic-gate rip_mcast_off(struct interface *ifp) 8247c478bd9Sstevel@tonic-gate { 8257c478bd9Sstevel@tonic-gate struct ip_mreq m; 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate if ((ifp->int_if_flags & IFF_MULTICAST) && 8287c478bd9Sstevel@tonic-gate !IS_IFF_QUIET(ifp->int_if_flags) && rip_enabled) { 8297c478bd9Sstevel@tonic-gate m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); 8307c478bd9Sstevel@tonic-gate m.imr_interface.s_addr = (ifp->int_if_flags & IFF_POINTOPOINT) ? 8317c478bd9Sstevel@tonic-gate ifp->int_dstaddr : ifp->int_addr; 8327c478bd9Sstevel@tonic-gate if ((setsockopt(rip_sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, 8337c478bd9Sstevel@tonic-gate &m, sizeof (m)) < 0) && errno != EADDRNOTAVAIL && 8347c478bd9Sstevel@tonic-gate errno != ENOENT) 8357c478bd9Sstevel@tonic-gate writelog(LOG_WARNING, 8367c478bd9Sstevel@tonic-gate "setsockopt(IP_DROP_MEMBERSHIP RIP) for %s: %s", 8377c478bd9Sstevel@tonic-gate ifp->int_name, rip_strerror(errno)); 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate /* enable RIP */ 8427c478bd9Sstevel@tonic-gate void 8437c478bd9Sstevel@tonic-gate rip_on(struct interface *ifp) 8447c478bd9Sstevel@tonic-gate { 8457c478bd9Sstevel@tonic-gate /* 8467c478bd9Sstevel@tonic-gate * If RIP is already enabled, only start receiving 8477c478bd9Sstevel@tonic-gate * multicasts for this interface. 8487c478bd9Sstevel@tonic-gate */ 8497c478bd9Sstevel@tonic-gate if (rip_enabled) { 8507c478bd9Sstevel@tonic-gate if (ifp != NULL) 8517c478bd9Sstevel@tonic-gate rip_mcast_on(ifp); 8527c478bd9Sstevel@tonic-gate return; 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate /* 8567c478bd9Sstevel@tonic-gate * If RIP is disabled and it makes sense to enable it, then enable 8577c478bd9Sstevel@tonic-gate * it on all of the interfaces. It makes sense if either router 8587c478bd9Sstevel@tonic-gate * discovery is off, or if router discovery is on and at most one 8597c478bd9Sstevel@tonic-gate * interface is doing RIP. 8607c478bd9Sstevel@tonic-gate */ 8617c478bd9Sstevel@tonic-gate if (rip_interfaces > 0 && (!rdisc_ok || rip_interfaces > 1)) { 8627c478bd9Sstevel@tonic-gate trace_act("turn on RIP"); 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate rip_enabled = _B_TRUE; 8657c478bd9Sstevel@tonic-gate rip_sock_interface = NULL; 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate /* Do not advertise anything until we have heard something */ 8687c478bd9Sstevel@tonic-gate if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME) 8697c478bd9Sstevel@tonic-gate next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME; 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) { 8727c478bd9Sstevel@tonic-gate ifp->int_query_time = NEVER; 8737c478bd9Sstevel@tonic-gate rip_mcast_on(ifp); 8747c478bd9Sstevel@tonic-gate } 8757c478bd9Sstevel@tonic-gate ifscan_timer.tv_sec = now.tv_sec; 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate fix_select(); 8797c478bd9Sstevel@tonic-gate } 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate /* die if malloc(3) fails */ 8837c478bd9Sstevel@tonic-gate void * 8847c478bd9Sstevel@tonic-gate rtmalloc(size_t size, 8857c478bd9Sstevel@tonic-gate const char *msg) 8867c478bd9Sstevel@tonic-gate { 8877c478bd9Sstevel@tonic-gate void *p = malloc(size); 8887c478bd9Sstevel@tonic-gate if (p == NULL) 8897c478bd9Sstevel@tonic-gate logbad(_B_TRUE, "malloc(%lu) failed in %s: %s", (ulong_t)size, 8907c478bd9Sstevel@tonic-gate msg, rip_strerror(errno)); 8917c478bd9Sstevel@tonic-gate return (p); 8927c478bd9Sstevel@tonic-gate } 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate /* get a random instant in an interval */ 8967c478bd9Sstevel@tonic-gate void 8977c478bd9Sstevel@tonic-gate intvl_random(struct timeval *tp, /* put value here */ 8987c478bd9Sstevel@tonic-gate ulong_t lo, /* value is after this second */ 8997c478bd9Sstevel@tonic-gate ulong_t hi) /* and before this */ 9007c478bd9Sstevel@tonic-gate { 9017c478bd9Sstevel@tonic-gate tp->tv_sec = (time_t)(hi == lo ? lo : (lo + random() % ((hi - lo)))); 9027c478bd9Sstevel@tonic-gate tp->tv_usec = random() % 1000000; 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate void 9077c478bd9Sstevel@tonic-gate timevaladd(struct timeval *t1, 9087c478bd9Sstevel@tonic-gate struct timeval *t2) 9097c478bd9Sstevel@tonic-gate { 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate t1->tv_sec += t2->tv_sec; 9127c478bd9Sstevel@tonic-gate if ((t1->tv_usec += t2->tv_usec) >= 1000000) { 9137c478bd9Sstevel@tonic-gate t1->tv_sec++; 9147c478bd9Sstevel@tonic-gate t1->tv_usec -= 1000000; 9157c478bd9Sstevel@tonic-gate } 9167c478bd9Sstevel@tonic-gate } 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate /* t1 = t2 - t3 */ 9207c478bd9Sstevel@tonic-gate static void 9217c478bd9Sstevel@tonic-gate timevalsub(struct timeval *t1, 9227c478bd9Sstevel@tonic-gate struct timeval *t2, 9237c478bd9Sstevel@tonic-gate struct timeval *t3) 9247c478bd9Sstevel@tonic-gate { 9257c478bd9Sstevel@tonic-gate t1->tv_sec = t2->tv_sec - t3->tv_sec; 9267c478bd9Sstevel@tonic-gate if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) { 9277c478bd9Sstevel@tonic-gate t1->tv_sec--; 9287c478bd9Sstevel@tonic-gate t1->tv_usec += 1000000; 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate static void 9337c478bd9Sstevel@tonic-gate do_openlog(void) 9347c478bd9Sstevel@tonic-gate { 9357c478bd9Sstevel@tonic-gate openlog_done = _B_TRUE; 9367c478bd9Sstevel@tonic-gate openlog("in.routed", LOG_PID | LOG_ODELAY, LOG_DAEMON); 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate /* put a LOG_ERR message into the system log */ 9407c478bd9Sstevel@tonic-gate void 9417c478bd9Sstevel@tonic-gate msglog(const char *p, ...) 9427c478bd9Sstevel@tonic-gate { 9437c478bd9Sstevel@tonic-gate va_list args; 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate trace_flush(); 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate if (!openlog_done) 9487c478bd9Sstevel@tonic-gate do_openlog(); 9497c478bd9Sstevel@tonic-gate va_start(args, p); 9507c478bd9Sstevel@tonic-gate vsyslog(LOG_ERR, p, args); 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate if (ftrace != 0) { 9537c478bd9Sstevel@tonic-gate if (ftrace == stdout) 9547c478bd9Sstevel@tonic-gate (void) fputs("in.routed: ", ftrace); 9557c478bd9Sstevel@tonic-gate (void) vfprintf(ftrace, p, args); 9567c478bd9Sstevel@tonic-gate (void) fputc('\n', ftrace); 9577c478bd9Sstevel@tonic-gate } 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate /* 9627c478bd9Sstevel@tonic-gate * Put a message about a bad system into the system log if 9637c478bd9Sstevel@tonic-gate * we have not complained about it recently. 9647c478bd9Sstevel@tonic-gate * 9657c478bd9Sstevel@tonic-gate * It is desirable to complain about all bad systems, but not too often. 9667c478bd9Sstevel@tonic-gate * In the worst case, it is not practical to keep track of all bad systems. 9677c478bd9Sstevel@tonic-gate * For example, there can be many systems with the wrong password. 9687c478bd9Sstevel@tonic-gate */ 9697c478bd9Sstevel@tonic-gate void 9707c478bd9Sstevel@tonic-gate msglim(struct msg_limit *lim, in_addr_t addr, const char *p, ...) 9717c478bd9Sstevel@tonic-gate { 9727c478bd9Sstevel@tonic-gate va_list args; 9737c478bd9Sstevel@tonic-gate int i; 9747c478bd9Sstevel@tonic-gate struct msg_sub *ms1, *ms; 9757c478bd9Sstevel@tonic-gate const char *p1; 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate va_start(args, p); 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate /* 9807c478bd9Sstevel@tonic-gate * look for the oldest slot in the table 9817c478bd9Sstevel@tonic-gate * or the slot for the bad router. 9827c478bd9Sstevel@tonic-gate */ 9837c478bd9Sstevel@tonic-gate ms = ms1 = lim->subs; 9847c478bd9Sstevel@tonic-gate for (i = MSG_SUBJECT_N; ; i--, ms1++) { 9857c478bd9Sstevel@tonic-gate if (i == 0) { 9867c478bd9Sstevel@tonic-gate /* Reuse a slot at most once every 10 minutes. */ 9877c478bd9Sstevel@tonic-gate if (lim->reuse > now.tv_sec) { 9887c478bd9Sstevel@tonic-gate ms = NULL; 9897c478bd9Sstevel@tonic-gate } else { 9907c478bd9Sstevel@tonic-gate lim->reuse = now.tv_sec + 10*60; 9917c478bd9Sstevel@tonic-gate } 9927c478bd9Sstevel@tonic-gate break; 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate if (ms->addr == addr) { 9957c478bd9Sstevel@tonic-gate /* 9967c478bd9Sstevel@tonic-gate * Repeat a complaint about a given system at 9977c478bd9Sstevel@tonic-gate * most once an hour. 9987c478bd9Sstevel@tonic-gate */ 9997c478bd9Sstevel@tonic-gate if (ms->until > now.tv_sec) 10007c478bd9Sstevel@tonic-gate ms = NULL; 10017c478bd9Sstevel@tonic-gate break; 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate if (ms->until < ms1->until) 10047c478bd9Sstevel@tonic-gate ms = ms1; 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate if (ms != NULL) { 10077c478bd9Sstevel@tonic-gate ms->addr = addr; 10087c478bd9Sstevel@tonic-gate ms->until = now.tv_sec + 60*60; /* 60 minutes */ 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate if (!openlog_done) 10117c478bd9Sstevel@tonic-gate do_openlog(); 10127c478bd9Sstevel@tonic-gate trace_flush(); 10137c478bd9Sstevel@tonic-gate for (p1 = p; *p1 == ' '; p1++) 10147c478bd9Sstevel@tonic-gate continue; 10157c478bd9Sstevel@tonic-gate vsyslog(LOG_ERR, p1, args); 10167c478bd9Sstevel@tonic-gate } 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate /* always display the message if tracing */ 10197c478bd9Sstevel@tonic-gate if (ftrace != 0) { 10207c478bd9Sstevel@tonic-gate (void) vfprintf(ftrace, p, args); 10217c478bd9Sstevel@tonic-gate (void) fputc('\n', ftrace); 10227c478bd9Sstevel@tonic-gate } 10237c478bd9Sstevel@tonic-gate } 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate void 10277c478bd9Sstevel@tonic-gate logbad(boolean_t dump, const char *p, ...) 10287c478bd9Sstevel@tonic-gate { 10297c478bd9Sstevel@tonic-gate va_list args; 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate trace_flush(); 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate if (!openlog_done) 10347c478bd9Sstevel@tonic-gate do_openlog(); 10357c478bd9Sstevel@tonic-gate va_start(args, p); 10367c478bd9Sstevel@tonic-gate vsyslog(LOG_ERR, p, args); 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate (void) fputs(gettext("in.routed: "), stderr); 10397c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, p, args); 10407c478bd9Sstevel@tonic-gate (void) fputs(gettext("; giving up\n"), stderr); 10417c478bd9Sstevel@tonic-gate (void) fflush(stderr); 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate if (dump) 10447c478bd9Sstevel@tonic-gate abort(); 10457c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 10467c478bd9Sstevel@tonic-gate } 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate /* put a message into the system log */ 10497c478bd9Sstevel@tonic-gate void 10507c478bd9Sstevel@tonic-gate writelog(int level, const char *p, ...) 10517c478bd9Sstevel@tonic-gate { 10527c478bd9Sstevel@tonic-gate va_list args; 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate trace_flush(); 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate if (!openlog_done) 10577c478bd9Sstevel@tonic-gate do_openlog(); 10587c478bd9Sstevel@tonic-gate va_start(args, p); 10597c478bd9Sstevel@tonic-gate vsyslog(level, p, args); 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate if (ftrace != 0) { 10627c478bd9Sstevel@tonic-gate if (ftrace == stdout) 10637c478bd9Sstevel@tonic-gate (void) fputs("in.routed: ", ftrace); 10647c478bd9Sstevel@tonic-gate (void) vfprintf(ftrace, p, args); 10657c478bd9Sstevel@tonic-gate (void) fputc('\n', ftrace); 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate } 1068