10Sstevel@tonic-gate /* 2*3293Sapersson * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate * 50Sstevel@tonic-gate * Copyright (c) 1983, 1988, 1993 60Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 90Sstevel@tonic-gate * modification, are permitted provided that the following conditions 100Sstevel@tonic-gate * are met: 110Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 120Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 130Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 140Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 150Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 160Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 170Sstevel@tonic-gate * must display the following acknowledgment: 180Sstevel@tonic-gate * This product includes software developed by the University of 190Sstevel@tonic-gate * California, Berkeley and its contributors. 200Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors 210Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 220Sstevel@tonic-gate * without specific prior written permission. 230Sstevel@tonic-gate * 240Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 250Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 260Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 270Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 280Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 290Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 300Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 310Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 320Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 330Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 340Sstevel@tonic-gate * SUCH DAMAGE. 350Sstevel@tonic-gate * 360Sstevel@tonic-gate * $FreeBSD: src/sbin/routed/main.c,v 1.14 2000/08/11 08:24:38 sheldonh Exp $ 370Sstevel@tonic-gate * char copyright[] = "@(#) Copyright (c) 1983, 1988, 1993\n" 380Sstevel@tonic-gate * " The Regents of the University of California. All rights reserved.\n"; 390Sstevel@tonic-gate */ 400Sstevel@tonic-gate 410Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 420Sstevel@tonic-gate 430Sstevel@tonic-gate #include "defs.h" 440Sstevel@tonic-gate #include "pathnames.h" 450Sstevel@tonic-gate #include <signal.h> 460Sstevel@tonic-gate #include <fcntl.h> 470Sstevel@tonic-gate #include <sys/file.h> 480Sstevel@tonic-gate #include <userdefs.h> 490Sstevel@tonic-gate #include <sys/stat.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate #define IN_ROUTED_VERSION "2.22" 520Sstevel@tonic-gate 530Sstevel@tonic-gate int stopint; 540Sstevel@tonic-gate boolean_t supplier; /* supply or broadcast updates */ 550Sstevel@tonic-gate boolean_t supplier_set; 560Sstevel@tonic-gate /* -S option. _B_TRUE=treat all RIP speakers as default routers. */ 570Sstevel@tonic-gate boolean_t save_space = _B_FALSE; 580Sstevel@tonic-gate 590Sstevel@tonic-gate static boolean_t default_gateway; /* _B_TRUE=advertise default */ 600Sstevel@tonic-gate static boolean_t background = _B_TRUE; 610Sstevel@tonic-gate boolean_t ridhosts; /* _B_TRUE=reduce host routes */ 620Sstevel@tonic-gate boolean_t mhome; /* _B_TRUE=want multi-homed host route */ 630Sstevel@tonic-gate boolean_t advertise_mhome; /* _B_TRUE=must continue advertising it */ 640Sstevel@tonic-gate boolean_t auth_ok = _B_TRUE; /* _B_TRUE=ignore auth if we don't care */ 650Sstevel@tonic-gate boolean_t no_install; /* _B_TRUE=don't install in kernel */ 660Sstevel@tonic-gate 670Sstevel@tonic-gate struct timeval epoch; /* when started */ 680Sstevel@tonic-gate struct timeval clk; 690Sstevel@tonic-gate static struct timeval prev_clk; 700Sstevel@tonic-gate static int usec_fudge; 710Sstevel@tonic-gate struct timeval now; /* current idea of time */ 720Sstevel@tonic-gate /* If a route's rts_time is <= to now_stale, the route is stale. */ 730Sstevel@tonic-gate time_t now_stale; 740Sstevel@tonic-gate /* If a route's rts_time is <= to now_expire, the route is expired */ 750Sstevel@tonic-gate time_t now_expire; 760Sstevel@tonic-gate /* If a route's rts_time is <= to now_garbage, the route needs to be deleted */ 770Sstevel@tonic-gate time_t now_garbage; 780Sstevel@tonic-gate 790Sstevel@tonic-gate static struct timeval next_bcast; /* next general broadcast */ 800Sstevel@tonic-gate struct timeval no_flash = { /* inhibit flash update */ 810Sstevel@tonic-gate EPOCH+SUPPLY_INTERVAL, 0 820Sstevel@tonic-gate }; 830Sstevel@tonic-gate 840Sstevel@tonic-gate /* When now reaches this time, it's time to call sync_kern() */ 850Sstevel@tonic-gate static struct timeval sync_kern_timer; 860Sstevel@tonic-gate 870Sstevel@tonic-gate static fd_set fdbits; 880Sstevel@tonic-gate static int sock_max; 890Sstevel@tonic-gate int rip_sock = -1; /* RIP socket */ 900Sstevel@tonic-gate boolean_t rip_enabled; 910Sstevel@tonic-gate static boolean_t openlog_done; 920Sstevel@tonic-gate 930Sstevel@tonic-gate /* 940Sstevel@tonic-gate * The interface to which rip_sock is currently pointing for 950Sstevel@tonic-gate * output. 960Sstevel@tonic-gate */ 970Sstevel@tonic-gate struct interface *rip_sock_interface; 980Sstevel@tonic-gate 990Sstevel@tonic-gate int rt_sock; /* routing socket */ 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate static int open_rip_sock(); 1030Sstevel@tonic-gate static void timevalsub(struct timeval *, struct timeval *, struct timeval *); 1040Sstevel@tonic-gate static void sigalrm(int); 1050Sstevel@tonic-gate static void sigterm(int); 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate static int 1080Sstevel@tonic-gate daemon(boolean_t nochdir, boolean_t noclose) 1090Sstevel@tonic-gate { 1100Sstevel@tonic-gate int retv; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate if ((retv = fork()) == -1) 1130Sstevel@tonic-gate return (-1); 1140Sstevel@tonic-gate if (retv != 0) 1150Sstevel@tonic-gate _exit(EXIT_SUCCESS); 1160Sstevel@tonic-gate if (setsid() == -1) 1170Sstevel@tonic-gate return (-1); 1180Sstevel@tonic-gate if ((retv = fork()) == -1) 1190Sstevel@tonic-gate return (-1); 1200Sstevel@tonic-gate if (retv != 0) 1210Sstevel@tonic-gate _exit(EXIT_SUCCESS); 1220Sstevel@tonic-gate if (!nochdir && chdir("/") == -1) 1230Sstevel@tonic-gate return (-1); 1240Sstevel@tonic-gate if (!noclose) { 1250Sstevel@tonic-gate (void) close(0); 1260Sstevel@tonic-gate (void) close(1); 1270Sstevel@tonic-gate (void) close(2); 1280Sstevel@tonic-gate if ((retv = open("/dev/null", O_RDWR)) != -1) { 1290Sstevel@tonic-gate (void) dup2(retv, 1); 1300Sstevel@tonic-gate (void) dup2(retv, 2); 1310Sstevel@tonic-gate } 1320Sstevel@tonic-gate } 1330Sstevel@tonic-gate return (0); 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate int 1370Sstevel@tonic-gate main(int argc, char *argv[]) 1380Sstevel@tonic-gate { 1390Sstevel@tonic-gate int n, off; 1400Sstevel@tonic-gate char *p, *q; 1410Sstevel@tonic-gate const char *cp; 1420Sstevel@tonic-gate struct timeval select_timeout, result; 1430Sstevel@tonic-gate fd_set ibits; 1440Sstevel@tonic-gate in_addr_t p_net, p_mask; 1450Sstevel@tonic-gate struct parm parm; 1460Sstevel@tonic-gate char *tracename = NULL; 1470Sstevel@tonic-gate boolean_t vflag = _B_FALSE; 1480Sstevel@tonic-gate boolean_t version = _B_FALSE; 1490Sstevel@tonic-gate int sigerr = 0; 1500Sstevel@tonic-gate FILE *pidfp; 1510Sstevel@tonic-gate mode_t pidmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* 0644 */ 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 1560Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEXT" 1570Sstevel@tonic-gate #endif /* ! TEXT_DOMAIN */ 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate /* 1620Sstevel@tonic-gate * Some shells are badly broken and send SIGHUP to backgrounded 1630Sstevel@tonic-gate * processes. 1640Sstevel@tonic-gate */ 1650Sstevel@tonic-gate if (signal(SIGHUP, SIG_IGN) == SIG_ERR) 1660Sstevel@tonic-gate sigerr = errno; 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate ftrace = stdout; 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate if (gettimeofday(&clk, 0) == -1) { 1710Sstevel@tonic-gate logbad(_B_FALSE, "gettimeofday: %s", rip_strerror(errno)); 1720Sstevel@tonic-gate } 1730Sstevel@tonic-gate prev_clk = clk; 1740Sstevel@tonic-gate epoch = clk; 1750Sstevel@tonic-gate epoch.tv_sec -= EPOCH; 1760Sstevel@tonic-gate now.tv_sec = EPOCH; 1770Sstevel@tonic-gate now_stale = EPOCH - STALE_TIME; 1780Sstevel@tonic-gate now_expire = EPOCH - EXPIRE_TIME; 1790Sstevel@tonic-gate now_garbage = EPOCH - GARBAGE_TIME; 1800Sstevel@tonic-gate select_timeout.tv_sec = 0; 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate while ((n = getopt(argc, argv, "sSqdghmpAztVvnT:F:P:")) != -1) { 1830Sstevel@tonic-gate switch (n) { 1840Sstevel@tonic-gate case 'A': 1850Sstevel@tonic-gate /* 1860Sstevel@tonic-gate * Ignore authentication if we do not care. 1870Sstevel@tonic-gate * Crazy as it is, that is what RFC 2453 requires. 1880Sstevel@tonic-gate */ 1890Sstevel@tonic-gate auth_ok = _B_FALSE; 1900Sstevel@tonic-gate break; 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate case 't': 1930Sstevel@tonic-gate if (new_tracelevel < 2) 1940Sstevel@tonic-gate new_tracelevel = 2; 1950Sstevel@tonic-gate background = _B_FALSE; 1960Sstevel@tonic-gate break; 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate case 'd': /* put in.routed in foreground */ 1990Sstevel@tonic-gate background = _B_FALSE; 2000Sstevel@tonic-gate break; 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate case 'F': /* minimal routes for SLIP */ 2030Sstevel@tonic-gate n = FAKE_METRIC; 2040Sstevel@tonic-gate p = strchr(optarg, ','); 2050Sstevel@tonic-gate if (p != NULL) { 2060Sstevel@tonic-gate n = (int)strtoul(p+1, &q, 0); 2070Sstevel@tonic-gate if (*q == '\0' && p+1 != q && 2080Sstevel@tonic-gate n <= HOPCNT_INFINITY-1 && n >= 1) 2090Sstevel@tonic-gate *p = '\0'; 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate if (!getnet(optarg, &p_net, &p_mask)) { 2120Sstevel@tonic-gate if (p != NULL) 2130Sstevel@tonic-gate *p = ','; 2140Sstevel@tonic-gate msglog(gettext("bad network; \"-F %s\""), 2150Sstevel@tonic-gate optarg); 2160Sstevel@tonic-gate break; 2170Sstevel@tonic-gate } 2180Sstevel@tonic-gate (void) memset(&parm, 0, sizeof (parm)); 2190Sstevel@tonic-gate parm.parm_net = p_net; 2200Sstevel@tonic-gate parm.parm_mask = p_mask; 2210Sstevel@tonic-gate parm.parm_d_metric = n; 2220Sstevel@tonic-gate cp = insert_parm(&parm); 2230Sstevel@tonic-gate if (cp != NULL) 2240Sstevel@tonic-gate msglog(gettext("bad -F: %s"), cp); 2250Sstevel@tonic-gate break; 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate case 'g': 2280Sstevel@tonic-gate (void) memset(&parm, 0, sizeof (parm)); 2290Sstevel@tonic-gate parm.parm_d_metric = 1; 2300Sstevel@tonic-gate cp = insert_parm(&parm); 2310Sstevel@tonic-gate if (cp != NULL) 2320Sstevel@tonic-gate msglog(gettext("bad -g: %s"), cp); 2330Sstevel@tonic-gate else 2340Sstevel@tonic-gate default_gateway = _B_TRUE; 2350Sstevel@tonic-gate break; 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate case 'h': /* suppress extra host routes */ 2380Sstevel@tonic-gate ridhosts = _B_TRUE; 2390Sstevel@tonic-gate break; 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate case 'm': /* advertise host route */ 2420Sstevel@tonic-gate mhome = _B_TRUE; /* on multi-homed hosts */ 2430Sstevel@tonic-gate break; 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate case 'n': /* No-install mode */ 2460Sstevel@tonic-gate no_install = _B_TRUE; 2470Sstevel@tonic-gate break; 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate case 'P': 2500Sstevel@tonic-gate /* handle arbitrary parameters. */ 2510Sstevel@tonic-gate q = strdup(optarg); 2520Sstevel@tonic-gate if (q == NULL) 2530Sstevel@tonic-gate logbad(_B_FALSE, "strdup: %s", 2540Sstevel@tonic-gate rip_strerror(errno)); 2550Sstevel@tonic-gate cp = parse_parms(q, _B_FALSE); 2560Sstevel@tonic-gate if (cp != NULL) 2570Sstevel@tonic-gate msglog(gettext("%1$s in \"-P %2$s\""), cp, 2580Sstevel@tonic-gate optarg); 2590Sstevel@tonic-gate free(q); 2600Sstevel@tonic-gate break; 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate case 'q': 2630Sstevel@tonic-gate supplier = _B_FALSE; 2640Sstevel@tonic-gate supplier_set = _B_TRUE; 2650Sstevel@tonic-gate break; 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate case 's': 2680Sstevel@tonic-gate supplier = _B_TRUE; 2690Sstevel@tonic-gate supplier_set = _B_TRUE; 2700Sstevel@tonic-gate break; 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate case 'S': /* save-space option */ 2730Sstevel@tonic-gate save_space = _B_TRUE; 2740Sstevel@tonic-gate break; 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate case 'T': 2770Sstevel@tonic-gate tracename = optarg; 2780Sstevel@tonic-gate break; 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate case 'V': 2810Sstevel@tonic-gate /* display version */ 2820Sstevel@tonic-gate version = _B_TRUE; 2830Sstevel@tonic-gate msglog(gettext("version " IN_ROUTED_VERSION)); 2840Sstevel@tonic-gate break; 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate case 'v': 2870Sstevel@tonic-gate /* display route changes to supplied logfile */ 2880Sstevel@tonic-gate new_tracelevel = 1; 2890Sstevel@tonic-gate vflag = _B_TRUE; 2900Sstevel@tonic-gate break; 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate case 'z': /* increase debug-level */ 2930Sstevel@tonic-gate new_tracelevel++; 2940Sstevel@tonic-gate break; 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate default: 2970Sstevel@tonic-gate goto usage; 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate } 3000Sstevel@tonic-gate argc -= optind; 3010Sstevel@tonic-gate argv += optind; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate if (tracename == NULL && argc >= 1) { 3040Sstevel@tonic-gate tracename = *argv++; 3050Sstevel@tonic-gate argc--; 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate if (tracename != NULL && tracename[0] == '\0') 3080Sstevel@tonic-gate goto usage; 3090Sstevel@tonic-gate if (vflag && tracename == NULL) 3100Sstevel@tonic-gate goto usage; 3110Sstevel@tonic-gate if (argc != 0) { 3120Sstevel@tonic-gate usage: 3130Sstevel@tonic-gate (void) fprintf(stderr, 3140Sstevel@tonic-gate gettext("usage: in.routed [-AdghmnqsStVvz] " 3150Sstevel@tonic-gate "[-T <tracefile>]\n")); 3160Sstevel@tonic-gate (void) fprintf(stderr, 3170Sstevel@tonic-gate gettext("\t[-F <net>[/<mask>][,<metric>]] [-P <parms>]\n")); 3180Sstevel@tonic-gate logbad(_B_FALSE, gettext("excess arguments")); 3190Sstevel@tonic-gate } 3200Sstevel@tonic-gate if (geteuid() != 0) { 3210Sstevel@tonic-gate /* 3220Sstevel@tonic-gate * Regular users are allowed to run in.routed for the 3230Sstevel@tonic-gate * sole purpose of obtaining the version number. In 3240Sstevel@tonic-gate * that case, exit(EXIT_SUCCESS) without complaining. 3250Sstevel@tonic-gate */ 3260Sstevel@tonic-gate if (version) 3270Sstevel@tonic-gate exit(EXIT_SUCCESS); 3280Sstevel@tonic-gate logbad(_B_FALSE, gettext("requires UID 0")); 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate if (default_gateway) { 3320Sstevel@tonic-gate if (supplier_set && !supplier) { 3330Sstevel@tonic-gate msglog(gettext("-g and -q are incompatible")); 3340Sstevel@tonic-gate } else { 3350Sstevel@tonic-gate supplier = _B_TRUE; 3360Sstevel@tonic-gate supplier_set = _B_TRUE; 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate if (signal(SIGALRM, sigalrm) == SIG_ERR) 3410Sstevel@tonic-gate sigerr = errno; 3420Sstevel@tonic-gate /* SIGHUP fatal during debugging */ 3430Sstevel@tonic-gate if (!background) 3440Sstevel@tonic-gate if (signal(SIGHUP, sigterm) == SIG_ERR) 3450Sstevel@tonic-gate sigerr = errno; 3460Sstevel@tonic-gate if (signal(SIGTERM, sigterm) == SIG_ERR) 3470Sstevel@tonic-gate sigerr = errno; 3480Sstevel@tonic-gate if (signal(SIGINT, sigterm) == SIG_ERR) 3490Sstevel@tonic-gate sigerr = errno; 3500Sstevel@tonic-gate if (signal(SIGUSR1, sigtrace_more) == SIG_ERR) 3510Sstevel@tonic-gate sigerr = errno; 3520Sstevel@tonic-gate if (signal(SIGUSR2, sigtrace_less) == SIG_ERR) 3530Sstevel@tonic-gate sigerr = errno; 3540Sstevel@tonic-gate if (signal(SIGHUP, sigtrace_dump) == SIG_ERR) 3550Sstevel@tonic-gate sigerr = errno; 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate if (sigerr) 3580Sstevel@tonic-gate msglog("signal: %s", rip_strerror(sigerr)); 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate /* get into the background */ 3610Sstevel@tonic-gate if (background && daemon(_B_FALSE, _B_FALSE) < 0) 3620Sstevel@tonic-gate BADERR(_B_FALSE, "daemon()"); 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate /* Store our process id, blow away any existing file if it exists. */ 3650Sstevel@tonic-gate if ((pidfp = fopen(PATH_PID, "w")) == NULL) { 3660Sstevel@tonic-gate (void) fprintf(stderr, 3670Sstevel@tonic-gate gettext("in.routed: unable to open " PATH_PID ": %s\n"), 3680Sstevel@tonic-gate strerror(errno)); 3690Sstevel@tonic-gate } else { 3700Sstevel@tonic-gate (void) fprintf(pidfp, "%ld\n", getpid()); 3710Sstevel@tonic-gate (void) fclose(pidfp); 3720Sstevel@tonic-gate (void) chmod(PATH_PID, pidmode); 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate srandom((int)(clk.tv_sec ^ clk.tv_usec ^ getpid())); 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate /* allocate the interface tables */ 3780Sstevel@tonic-gate iftbl_alloc(); 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate /* prepare socket connected to the kernel. */ 3810Sstevel@tonic-gate rt_sock = socket(PF_ROUTE, SOCK_RAW, AF_INET); 3820Sstevel@tonic-gate if (rt_sock < 0) 3830Sstevel@tonic-gate BADERR(_B_TRUE, "rt_sock = socket()"); 3840Sstevel@tonic-gate if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1) 3850Sstevel@tonic-gate logbad(_B_TRUE, "fcntl(rt_sock) O_NONBLOCK: %s", 3860Sstevel@tonic-gate rip_strerror(errno)); 3870Sstevel@tonic-gate off = 0; 3880Sstevel@tonic-gate if (setsockopt(rt_sock, SOL_SOCKET, SO_USELOOPBACK, 3890Sstevel@tonic-gate &off, sizeof (off)) < 0) 3900Sstevel@tonic-gate LOGERR("setsockopt(SO_USELOOPBACK,0)"); 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate fix_select(); 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate if (tracename != NULL) { 3960Sstevel@tonic-gate (void) strlcpy(inittracename, tracename, 3970Sstevel@tonic-gate sizeof (inittracename)); 3980Sstevel@tonic-gate set_tracefile(inittracename, "%s", -1); 3990Sstevel@tonic-gate } else { 4000Sstevel@tonic-gate tracelevel_msg("%s", -1); /* turn on tracing to stdio */ 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate bufinit(); 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate /* initialize radix tree */ 4060Sstevel@tonic-gate rtinit(); 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate /* 4090Sstevel@tonic-gate * Pick a random part of the second for our output to minimize 4100Sstevel@tonic-gate * collisions. 4110Sstevel@tonic-gate * 4120Sstevel@tonic-gate * Start broadcasting after hearing from other routers, and 4130Sstevel@tonic-gate * at a random time so a bunch of systems do not get synchronized 4140Sstevel@tonic-gate * after a power failure. 4150Sstevel@tonic-gate * 4160Sstevel@tonic-gate * Since now is the number of seconds since epoch (this is initially 4170Sstevel@tonic-gate * EPOCH seconds), these times are really relative to now. 4180Sstevel@tonic-gate */ 4190Sstevel@tonic-gate intvl_random(&next_bcast, EPOCH+MIN_WAITTIME, EPOCH+SUPPLY_INTERVAL); 4200Sstevel@tonic-gate age_timer.tv_usec = next_bcast.tv_usec; 4210Sstevel@tonic-gate age_timer.tv_sec = EPOCH+MIN_WAITTIME; 4220Sstevel@tonic-gate rdisc_timer = next_bcast; 4230Sstevel@tonic-gate ifscan_timer.tv_usec = next_bcast.tv_usec; 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate /* 4260Sstevel@tonic-gate * Open the global rip socket. From now on, this socket can be 4270Sstevel@tonic-gate * assumed to be open. It will remain open until in.routed 4280Sstevel@tonic-gate * exits. 4290Sstevel@tonic-gate */ 4300Sstevel@tonic-gate rip_sock = open_rip_sock(); 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate /* 4330Sstevel@tonic-gate * Collect an initial view of the world by checking the interface 4340Sstevel@tonic-gate * configuration and the kludge file. 4350Sstevel@tonic-gate * 4360Sstevel@tonic-gate * gwkludge() could call addroutefordefault(), resulting in a call to 4370Sstevel@tonic-gate * iflookup, and thus ifscan() to find the physical interfaces. 4380Sstevel@tonic-gate * ifscan() will attempt to use the rip_sock in order to join 4390Sstevel@tonic-gate * mcast groups, so gwkludge *must* be called after opening 4400Sstevel@tonic-gate * the rip_sock. 4410Sstevel@tonic-gate */ 4420Sstevel@tonic-gate gwkludge(); 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate ifscan(); 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate /* Ask for routes */ 4470Sstevel@tonic-gate rip_query(); 4480Sstevel@tonic-gate rdisc_sol(); 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate /* Now turn off stdio if not tracing */ 4510Sstevel@tonic-gate if (new_tracelevel == 0) 4520Sstevel@tonic-gate trace_close(background); 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate /* Loop until a fatal error occurs, listening and broadcasting. */ 4550Sstevel@tonic-gate for (;;) { 4560Sstevel@tonic-gate prev_clk = clk; 4570Sstevel@tonic-gate if (gettimeofday(&clk, 0) == -1) { 4580Sstevel@tonic-gate logbad(_B_FALSE, "gettimeofday: %s", 4590Sstevel@tonic-gate rip_strerror(errno)); 4600Sstevel@tonic-gate } 4610Sstevel@tonic-gate if (prev_clk.tv_sec == clk.tv_sec && 4620Sstevel@tonic-gate prev_clk.tv_usec == clk.tv_usec+usec_fudge) { 4630Sstevel@tonic-gate /* 4640Sstevel@tonic-gate * Much of `in.routed` depends on time always advancing. 4650Sstevel@tonic-gate * On systems that do not guarantee that gettimeofday() 4660Sstevel@tonic-gate * produces unique timestamps even if called within 4670Sstevel@tonic-gate * a single tick, use trickery like that in classic 4680Sstevel@tonic-gate * BSD kernels. 4690Sstevel@tonic-gate */ 4700Sstevel@tonic-gate clk.tv_usec += ++usec_fudge; 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate } else { 4730Sstevel@tonic-gate time_t dt; 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate usec_fudge = 0; 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate timevalsub(&result, &clk, &prev_clk); 4780Sstevel@tonic-gate if (result.tv_sec < 0 || result.tv_sec > 4790Sstevel@tonic-gate select_timeout.tv_sec + 5) { 4800Sstevel@tonic-gate /* 4810Sstevel@tonic-gate * Deal with time changes before other 4820Sstevel@tonic-gate * housekeeping to keep everything straight. 4830Sstevel@tonic-gate */ 4840Sstevel@tonic-gate dt = result.tv_sec; 4850Sstevel@tonic-gate if (dt > 0) 4860Sstevel@tonic-gate dt -= select_timeout.tv_sec; 4870Sstevel@tonic-gate trace_act("time changed by %d sec", (int)dt); 4880Sstevel@tonic-gate epoch.tv_sec += dt; 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate timevalsub(&now, &clk, &epoch); 4920Sstevel@tonic-gate now_stale = now.tv_sec - STALE_TIME; 4930Sstevel@tonic-gate now_expire = now.tv_sec - EXPIRE_TIME; 4940Sstevel@tonic-gate now_garbage = now.tv_sec - GARBAGE_TIME; 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate /* deal with signals that should affect tracing */ 4970Sstevel@tonic-gate set_tracelevel(); 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate if (stopint != 0) { 5000Sstevel@tonic-gate trace_off("exiting with signal %d", stopint); 5010Sstevel@tonic-gate break; 5020Sstevel@tonic-gate } 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate /* look for new or dead interfaces */ 5050Sstevel@tonic-gate timevalsub(&select_timeout, &ifscan_timer, &now); 5060Sstevel@tonic-gate if (select_timeout.tv_sec <= 0) { 5070Sstevel@tonic-gate select_timeout.tv_sec = 0; 5080Sstevel@tonic-gate ifscan(); 5090Sstevel@tonic-gate rip_query(); 5100Sstevel@tonic-gate continue; 5110Sstevel@tonic-gate } 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate /* 5140Sstevel@tonic-gate * Check the kernel table occassionally for mysteriously 5150Sstevel@tonic-gate * evaporated routes 5160Sstevel@tonic-gate */ 5170Sstevel@tonic-gate timevalsub(&result, &sync_kern_timer, &now); 5180Sstevel@tonic-gate if (result.tv_sec <= 0) { 5190Sstevel@tonic-gate sync_kern(); 5200Sstevel@tonic-gate sync_kern_timer.tv_sec = (now.tv_sec 5210Sstevel@tonic-gate + CHECK_QUIET_INTERVAL); 5220Sstevel@tonic-gate continue; 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate if (timercmp(&result, &select_timeout, < /* */)) 5250Sstevel@tonic-gate select_timeout = result; 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate /* If it is time, then broadcast our routes. */ 5280Sstevel@tonic-gate if (should_supply(NULL) || advertise_mhome) { 5290Sstevel@tonic-gate timevalsub(&result, &next_bcast, &now); 5300Sstevel@tonic-gate if (result.tv_sec <= 0) { 5310Sstevel@tonic-gate /* 5320Sstevel@tonic-gate * Synchronize the aging and broadcast 5330Sstevel@tonic-gate * timers to minimize awakenings 5340Sstevel@tonic-gate */ 5350Sstevel@tonic-gate age(0); 5360Sstevel@tonic-gate age_peer_info(); 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate rip_bcast(0); 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate /* 5410Sstevel@tonic-gate * It is desirable to send routing updates 5420Sstevel@tonic-gate * regularly. So schedule the next update 5430Sstevel@tonic-gate * 30 seconds after the previous one was 5440Sstevel@tonic-gate * scheduled, instead of 30 seconds after 5450Sstevel@tonic-gate * the previous update was finished. 5460Sstevel@tonic-gate * Even if we just started after discovering 5470Sstevel@tonic-gate * a 2nd interface or were otherwise delayed, 5480Sstevel@tonic-gate * pick a 30-second aniversary of the 5490Sstevel@tonic-gate * original broadcast time. 5500Sstevel@tonic-gate */ 5510Sstevel@tonic-gate n = 1 + (0-result.tv_sec)/SUPPLY_INTERVAL; 5520Sstevel@tonic-gate next_bcast.tv_sec += n*SUPPLY_INTERVAL; 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate continue; 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate if (timercmp(&result, &select_timeout, < /* */)) 5580Sstevel@tonic-gate select_timeout = result; 5590Sstevel@tonic-gate } 5600Sstevel@tonic-gate 5610Sstevel@tonic-gate /* 5620Sstevel@tonic-gate * If we need a flash update, either do it now or 5630Sstevel@tonic-gate * set the delay to end when it is time. 5640Sstevel@tonic-gate * 5650Sstevel@tonic-gate * If we are within MIN_WAITTIME seconds of a full update, 5660Sstevel@tonic-gate * do not bother. 5670Sstevel@tonic-gate */ 5680Sstevel@tonic-gate if (need_flash && should_supply(NULL) && 5690Sstevel@tonic-gate no_flash.tv_sec+MIN_WAITTIME < next_bcast.tv_sec) { 5700Sstevel@tonic-gate /* accurate to the millisecond */ 5710Sstevel@tonic-gate if (!timercmp(&no_flash, &now, > /* */)) 5720Sstevel@tonic-gate rip_bcast(1); 5730Sstevel@tonic-gate timevalsub(&result, &no_flash, &now); 5740Sstevel@tonic-gate if (timercmp(&result, &select_timeout, < /* */)) 5750Sstevel@tonic-gate select_timeout = result; 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate /* trigger the main aging timer. */ 5790Sstevel@tonic-gate timevalsub(&result, &age_timer, &now); 5800Sstevel@tonic-gate if (result.tv_sec <= 0) { 5810Sstevel@tonic-gate age(0); 5820Sstevel@tonic-gate continue; 5830Sstevel@tonic-gate } 5840Sstevel@tonic-gate if (timercmp(&result, &select_timeout, < /* */)) 5850Sstevel@tonic-gate select_timeout = result; 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate /* update the kernel routing table */ 5880Sstevel@tonic-gate timevalsub(&result, &need_kern, &now); 5890Sstevel@tonic-gate if (result.tv_sec <= 0) { 5900Sstevel@tonic-gate age(0); 5910Sstevel@tonic-gate continue; 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate if (timercmp(&result, &select_timeout, < /* */)) 5940Sstevel@tonic-gate select_timeout = result; 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate /* 5970Sstevel@tonic-gate * take care of router discovery. We compare timeval 5980Sstevel@tonic-gate * structures here to have millisecond granularity. 5990Sstevel@tonic-gate */ 6000Sstevel@tonic-gate if (!timercmp(&rdisc_timer, &now, > /* */)) { 6010Sstevel@tonic-gate rdisc_age(0); 6020Sstevel@tonic-gate continue; 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate timevalsub(&result, &rdisc_timer, &now); 6050Sstevel@tonic-gate if (timercmp(&result, &select_timeout, < /* */)) 6060Sstevel@tonic-gate select_timeout = result; 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate /* 6090Sstevel@tonic-gate * Well-known bit of select(3c) silliness inherited 6100Sstevel@tonic-gate * from BSD: anything over 100 million seconds is 6110Sstevel@tonic-gate * considered an "error." Reset that to zero. 6120Sstevel@tonic-gate */ 6130Sstevel@tonic-gate if (select_timeout.tv_sec > 100000000) 6140Sstevel@tonic-gate select_timeout.tv_sec = 0; 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate /* wait for input or a timer to expire. */ 6170Sstevel@tonic-gate trace_flush(); 6180Sstevel@tonic-gate ibits = fdbits; 6190Sstevel@tonic-gate n = select(sock_max, &ibits, 0, 0, &select_timeout); 6200Sstevel@tonic-gate if (n <= 0) { 6210Sstevel@tonic-gate if (n < 0 && errno != EINTR && errno != EAGAIN) 6220Sstevel@tonic-gate BADERR(_B_TRUE, "select"); 6230Sstevel@tonic-gate continue; 6240Sstevel@tonic-gate } 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate if (FD_ISSET(rt_sock, &ibits)) { 6270Sstevel@tonic-gate read_rt(); 6280Sstevel@tonic-gate n--; 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate if (rdisc_sock >= 0 && FD_ISSET(rdisc_sock, &ibits)) { 6310Sstevel@tonic-gate read_d(); 6320Sstevel@tonic-gate n--; 6330Sstevel@tonic-gate } 634*3293Sapersson if (rdisc_mib_sock >= 0 && FD_ISSET(rdisc_mib_sock, &ibits)) { 635*3293Sapersson process_d_mib_sock(); 636*3293Sapersson n--; 637*3293Sapersson } 6380Sstevel@tonic-gate if (rip_sock >= 0 && FD_ISSET(rip_sock, &ibits)) { 6390Sstevel@tonic-gate if (read_rip() == -1) { 6400Sstevel@tonic-gate rip_enabled = _B_FALSE; 6410Sstevel@tonic-gate trace_off("main rip socket failed"); 6420Sstevel@tonic-gate (void) close(rip_sock); 6430Sstevel@tonic-gate rip_sock = -1; 6440Sstevel@tonic-gate fix_select(); 6450Sstevel@tonic-gate break; 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate n--; 6480Sstevel@tonic-gate } 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate rip_bcast(0); 6510Sstevel@tonic-gate rdisc_adv(_B_FALSE); 6520Sstevel@tonic-gate (void) unlink(PATH_PID); 6530Sstevel@tonic-gate return (stopint | 128); 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate static void 6580Sstevel@tonic-gate sigalrm(int sig) 6590Sstevel@tonic-gate { 6600Sstevel@tonic-gate /* 6610Sstevel@tonic-gate * Historically, SIGALRM would cause the daemon to check for 6620Sstevel@tonic-gate * new and broken interfaces. 6630Sstevel@tonic-gate */ 6640Sstevel@tonic-gate ifscan_timer.tv_sec = now.tv_sec; 6650Sstevel@tonic-gate trace_act("SIGALRM"); 6660Sstevel@tonic-gate if (signal(sig, sigalrm) == SIG_ERR) 6670Sstevel@tonic-gate msglog("signal: %s", rip_strerror(errno)); 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate /* watch for fatal signals */ 6720Sstevel@tonic-gate static void 6730Sstevel@tonic-gate sigterm(int sig) 6740Sstevel@tonic-gate { 6750Sstevel@tonic-gate stopint = sig; 6760Sstevel@tonic-gate if (signal(sig, SIG_DFL) == SIG_ERR) /* catch it only once */ 6770Sstevel@tonic-gate msglog("signal: %s", rip_strerror(errno)); 6780Sstevel@tonic-gate } 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate void 6820Sstevel@tonic-gate fix_select(void) 6830Sstevel@tonic-gate { 6840Sstevel@tonic-gate (void) FD_ZERO(&fdbits); 6850Sstevel@tonic-gate sock_max = 0; 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate FD_SET(rt_sock, &fdbits); 6880Sstevel@tonic-gate if (sock_max <= rt_sock) 6890Sstevel@tonic-gate sock_max = rt_sock+1; 6900Sstevel@tonic-gate if (rip_sock >= 0) { 6910Sstevel@tonic-gate FD_SET(rip_sock, &fdbits); 6920Sstevel@tonic-gate if (sock_max <= rip_sock) 6930Sstevel@tonic-gate sock_max = rip_sock+1; 6940Sstevel@tonic-gate } 6950Sstevel@tonic-gate if (rdisc_sock >= 0) { 6960Sstevel@tonic-gate FD_SET(rdisc_sock, &fdbits); 6970Sstevel@tonic-gate if (sock_max <= rdisc_sock) 6980Sstevel@tonic-gate sock_max = rdisc_sock+1; 699*3293Sapersson FD_SET(rdisc_mib_sock, &fdbits); 700*3293Sapersson if (sock_max <= rdisc_mib_sock) 701*3293Sapersson sock_max = rdisc_mib_sock+1; 7020Sstevel@tonic-gate } 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate void 7070Sstevel@tonic-gate fix_sock(int sock, 7080Sstevel@tonic-gate const char *name) 7090Sstevel@tonic-gate { 7100Sstevel@tonic-gate int on; 7110Sstevel@tonic-gate #define MIN_SOCKBUF (4*1024) 7120Sstevel@tonic-gate static int rbuf; 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) 7150Sstevel@tonic-gate logbad(_B_TRUE, "fcntl(%s) O_NONBLOCK: %s", name, 7160Sstevel@tonic-gate rip_strerror(errno)); 7170Sstevel@tonic-gate on = 1; 7180Sstevel@tonic-gate if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) 7190Sstevel@tonic-gate msglog("setsockopt(%s,SO_BROADCAST): %s", 7200Sstevel@tonic-gate name, rip_strerror(errno)); 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate if (rbuf >= MIN_SOCKBUF) { 7230Sstevel@tonic-gate if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 7240Sstevel@tonic-gate &rbuf, sizeof (rbuf)) < 0) 7250Sstevel@tonic-gate msglog("setsockopt(%s,SO_RCVBUF=%d): %s", 7260Sstevel@tonic-gate name, rbuf, rip_strerror(errno)); 7270Sstevel@tonic-gate } else { 7280Sstevel@tonic-gate for (rbuf = 60*1024; ; rbuf -= 4096) { 7290Sstevel@tonic-gate if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 7300Sstevel@tonic-gate &rbuf, sizeof (rbuf)) == 0) { 7310Sstevel@tonic-gate trace_act("RCVBUF=%d", rbuf); 7320Sstevel@tonic-gate break; 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate if (rbuf < MIN_SOCKBUF) { 7350Sstevel@tonic-gate msglog("setsockopt(%s,SO_RCVBUF = %d): %s", 7360Sstevel@tonic-gate name, rbuf, rip_strerror(errno)); 7370Sstevel@tonic-gate break; 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate } 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate /* 7450Sstevel@tonic-gate * Open and return the global rip socket. It is guaranteed to return 7460Sstevel@tonic-gate * a good file descriptor. 7470Sstevel@tonic-gate */ 7480Sstevel@tonic-gate static int 7490Sstevel@tonic-gate open_rip_sock() 7500Sstevel@tonic-gate { 7510Sstevel@tonic-gate struct sockaddr_in sin; 7520Sstevel@tonic-gate unsigned char ttl; 7530Sstevel@tonic-gate int s; 7540Sstevel@tonic-gate int on = 1; 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) 7580Sstevel@tonic-gate BADERR(_B_TRUE, "rip_sock = socket()"); 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate (void) memset(&sin, 0, sizeof (sin)); 7610Sstevel@tonic-gate sin.sin_family = AF_INET; 7620Sstevel@tonic-gate sin.sin_port = htons(RIP_PORT); 7630Sstevel@tonic-gate sin.sin_addr.s_addr = INADDR_ANY; 7640Sstevel@tonic-gate if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 7650Sstevel@tonic-gate BADERR(_B_FALSE, "bind(rip_sock)"); 7660Sstevel@tonic-gate } 7670Sstevel@tonic-gate fix_sock(s, "rip_sock"); 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate ttl = 1; 7700Sstevel@tonic-gate if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, 7710Sstevel@tonic-gate &ttl, sizeof (ttl)) < 0) 7720Sstevel@tonic-gate DBGERR(_B_TRUE, "rip_sock setsockopt(IP_MULTICAST_TTL)"); 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate if (setsockopt(s, IPPROTO_IP, IP_RECVIF, &on, sizeof (on))) 7750Sstevel@tonic-gate BADERR(_B_FALSE, "setsockopt(IP_RECVIF)"); 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate return (s); 7780Sstevel@tonic-gate } 7790Sstevel@tonic-gate 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate /* 7820Sstevel@tonic-gate * Disable RIP. Note that we don't close the global rip socket since 7830Sstevel@tonic-gate * it is used even when RIP is disabled to receive and answer certain 7840Sstevel@tonic-gate * queries. 7850Sstevel@tonic-gate */ 7860Sstevel@tonic-gate void 7870Sstevel@tonic-gate rip_off(void) 7880Sstevel@tonic-gate { 7890Sstevel@tonic-gate struct ip_mreq m; 7900Sstevel@tonic-gate struct interface *ifp; 7910Sstevel@tonic-gate char addrstr[INET_ADDRSTRLEN]; 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate if (rip_enabled && !mhome) { 7940Sstevel@tonic-gate trace_act("turn off RIP"); 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate /* 7970Sstevel@tonic-gate * Unsubscribe from the 224.0.0.9 RIP multicast 7980Sstevel@tonic-gate * group address 7990Sstevel@tonic-gate */ 8000Sstevel@tonic-gate for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) { 8010Sstevel@tonic-gate if ((ifp->int_if_flags & IFF_MULTICAST) && 8020Sstevel@tonic-gate !IS_IFF_QUIET(ifp->int_if_flags) && 8030Sstevel@tonic-gate !IS_RIP_IN_OFF(ifp->int_state) && 8040Sstevel@tonic-gate !(ifp->int_state & IS_DUP)) { 8050Sstevel@tonic-gate m.imr_multiaddr.s_addr = 8060Sstevel@tonic-gate htonl(INADDR_RIP_GROUP); 8070Sstevel@tonic-gate m.imr_interface.s_addr = 8080Sstevel@tonic-gate (ifp->int_if_flags & IFF_POINTOPOINT) ? 8090Sstevel@tonic-gate ifp->int_dstaddr : ifp->int_addr; 8100Sstevel@tonic-gate (void) strlcpy(addrstr, 8110Sstevel@tonic-gate inet_ntoa(m.imr_multiaddr), 8120Sstevel@tonic-gate sizeof (addrstr)); 8130Sstevel@tonic-gate if (setsockopt(rip_sock, IPPROTO_IP, 8140Sstevel@tonic-gate IP_DROP_MEMBERSHIP, &m, 8150Sstevel@tonic-gate sizeof (m)) < 0 && 8160Sstevel@tonic-gate errno != EADDRNOTAVAIL && errno != ENOENT) 8170Sstevel@tonic-gate writelog(LOG_WARNING, 8180Sstevel@tonic-gate "%s: setsockopt(IP_DROP_MEMBERSHIP " 8190Sstevel@tonic-gate "%s, %s): %s", ifp->int_name, 8200Sstevel@tonic-gate addrstr, inet_ntoa(m.imr_interface), 8210Sstevel@tonic-gate rip_strerror(errno)); 8220Sstevel@tonic-gate } 8230Sstevel@tonic-gate } 8240Sstevel@tonic-gate rip_enabled = _B_FALSE; 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate age(0); 8270Sstevel@tonic-gate } 8280Sstevel@tonic-gate } 8290Sstevel@tonic-gate 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate /* turn on RIP multicast input via an interface */ 8320Sstevel@tonic-gate void 8330Sstevel@tonic-gate rip_mcast_on(struct interface *ifp) 8340Sstevel@tonic-gate { 8350Sstevel@tonic-gate struct ip_mreq m; 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate if (!IS_RIP_IN_OFF(ifp->int_state) && 8380Sstevel@tonic-gate (ifp->int_if_flags & IFF_MULTICAST) && 8390Sstevel@tonic-gate !IS_IFF_QUIET(ifp->int_if_flags) && 8400Sstevel@tonic-gate !(ifp->int_state & IS_DUP)) { 8410Sstevel@tonic-gate m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); 8420Sstevel@tonic-gate m.imr_interface.s_addr = (ifp->int_if_flags & IFF_POINTOPOINT) ? 8430Sstevel@tonic-gate ifp->int_dstaddr : ifp->int_addr; 8440Sstevel@tonic-gate if ((setsockopt(rip_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 8450Sstevel@tonic-gate &m, sizeof (m)) < 0) && !(ifp->int_state & IS_BROKE)) 8460Sstevel@tonic-gate writelog(LOG_WARNING, 8470Sstevel@tonic-gate "Could not join 224.0.0.9 on interface %s: %s", 8480Sstevel@tonic-gate ifp->int_name, rip_strerror(errno)); 8490Sstevel@tonic-gate } 8500Sstevel@tonic-gate } 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate /* turn off RIP multicast input via an interface */ 8530Sstevel@tonic-gate void 8540Sstevel@tonic-gate rip_mcast_off(struct interface *ifp) 8550Sstevel@tonic-gate { 8560Sstevel@tonic-gate struct ip_mreq m; 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate if ((ifp->int_if_flags & IFF_MULTICAST) && 8590Sstevel@tonic-gate !IS_IFF_QUIET(ifp->int_if_flags) && rip_enabled) { 8600Sstevel@tonic-gate m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); 8610Sstevel@tonic-gate m.imr_interface.s_addr = (ifp->int_if_flags & IFF_POINTOPOINT) ? 8620Sstevel@tonic-gate ifp->int_dstaddr : ifp->int_addr; 8630Sstevel@tonic-gate if ((setsockopt(rip_sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, 8640Sstevel@tonic-gate &m, sizeof (m)) < 0) && errno != EADDRNOTAVAIL && 8650Sstevel@tonic-gate errno != ENOENT) 8660Sstevel@tonic-gate writelog(LOG_WARNING, 8670Sstevel@tonic-gate "setsockopt(IP_DROP_MEMBERSHIP RIP) for %s: %s", 8680Sstevel@tonic-gate ifp->int_name, rip_strerror(errno)); 8690Sstevel@tonic-gate } 8700Sstevel@tonic-gate } 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate /* enable RIP */ 8730Sstevel@tonic-gate void 8740Sstevel@tonic-gate rip_on(struct interface *ifp) 8750Sstevel@tonic-gate { 8760Sstevel@tonic-gate /* 8770Sstevel@tonic-gate * If RIP is already enabled, only start receiving 8780Sstevel@tonic-gate * multicasts for this interface. 8790Sstevel@tonic-gate */ 8800Sstevel@tonic-gate if (rip_enabled) { 8810Sstevel@tonic-gate if (ifp != NULL) 8820Sstevel@tonic-gate rip_mcast_on(ifp); 8830Sstevel@tonic-gate return; 8840Sstevel@tonic-gate } 8850Sstevel@tonic-gate 8860Sstevel@tonic-gate /* 8870Sstevel@tonic-gate * If RIP is disabled and it makes sense to enable it, then enable 8880Sstevel@tonic-gate * it on all of the interfaces. It makes sense if either router 8890Sstevel@tonic-gate * discovery is off, or if router discovery is on and at most one 8900Sstevel@tonic-gate * interface is doing RIP. 8910Sstevel@tonic-gate */ 8920Sstevel@tonic-gate if (rip_interfaces > 0 && (!rdisc_ok || rip_interfaces > 1)) { 8930Sstevel@tonic-gate trace_act("turn on RIP"); 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate rip_enabled = _B_TRUE; 8960Sstevel@tonic-gate rip_sock_interface = NULL; 8970Sstevel@tonic-gate 8980Sstevel@tonic-gate /* Do not advertise anything until we have heard something */ 8990Sstevel@tonic-gate if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME) 9000Sstevel@tonic-gate next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME; 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) { 9030Sstevel@tonic-gate ifp->int_query_time = NEVER; 9040Sstevel@tonic-gate rip_mcast_on(ifp); 9050Sstevel@tonic-gate } 9060Sstevel@tonic-gate ifscan_timer.tv_sec = now.tv_sec; 9070Sstevel@tonic-gate } 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate fix_select(); 9100Sstevel@tonic-gate } 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate 9130Sstevel@tonic-gate /* die if malloc(3) fails */ 9140Sstevel@tonic-gate void * 9150Sstevel@tonic-gate rtmalloc(size_t size, 9160Sstevel@tonic-gate const char *msg) 9170Sstevel@tonic-gate { 9180Sstevel@tonic-gate void *p = malloc(size); 9190Sstevel@tonic-gate if (p == NULL) 9200Sstevel@tonic-gate logbad(_B_TRUE, "malloc(%lu) failed in %s: %s", (ulong_t)size, 9210Sstevel@tonic-gate msg, rip_strerror(errno)); 9220Sstevel@tonic-gate return (p); 9230Sstevel@tonic-gate } 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate /* get a random instant in an interval */ 9270Sstevel@tonic-gate void 9280Sstevel@tonic-gate intvl_random(struct timeval *tp, /* put value here */ 9290Sstevel@tonic-gate ulong_t lo, /* value is after this second */ 9300Sstevel@tonic-gate ulong_t hi) /* and before this */ 9310Sstevel@tonic-gate { 9320Sstevel@tonic-gate tp->tv_sec = (time_t)(hi == lo ? lo : (lo + random() % ((hi - lo)))); 9330Sstevel@tonic-gate tp->tv_usec = random() % 1000000; 9340Sstevel@tonic-gate } 9350Sstevel@tonic-gate 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate void 9380Sstevel@tonic-gate timevaladd(struct timeval *t1, 9390Sstevel@tonic-gate struct timeval *t2) 9400Sstevel@tonic-gate { 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate t1->tv_sec += t2->tv_sec; 9430Sstevel@tonic-gate if ((t1->tv_usec += t2->tv_usec) >= 1000000) { 9440Sstevel@tonic-gate t1->tv_sec++; 9450Sstevel@tonic-gate t1->tv_usec -= 1000000; 9460Sstevel@tonic-gate } 9470Sstevel@tonic-gate } 9480Sstevel@tonic-gate 9490Sstevel@tonic-gate 9500Sstevel@tonic-gate /* t1 = t2 - t3 */ 9510Sstevel@tonic-gate static void 9520Sstevel@tonic-gate timevalsub(struct timeval *t1, 9530Sstevel@tonic-gate struct timeval *t2, 9540Sstevel@tonic-gate struct timeval *t3) 9550Sstevel@tonic-gate { 9560Sstevel@tonic-gate t1->tv_sec = t2->tv_sec - t3->tv_sec; 9570Sstevel@tonic-gate if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) { 9580Sstevel@tonic-gate t1->tv_sec--; 9590Sstevel@tonic-gate t1->tv_usec += 1000000; 9600Sstevel@tonic-gate } 9610Sstevel@tonic-gate } 9620Sstevel@tonic-gate 9630Sstevel@tonic-gate static void 9640Sstevel@tonic-gate do_openlog(void) 9650Sstevel@tonic-gate { 9660Sstevel@tonic-gate openlog_done = _B_TRUE; 9670Sstevel@tonic-gate openlog("in.routed", LOG_PID | LOG_ODELAY, LOG_DAEMON); 9680Sstevel@tonic-gate } 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate /* put a LOG_ERR message into the system log */ 9710Sstevel@tonic-gate void 9720Sstevel@tonic-gate msglog(const char *p, ...) 9730Sstevel@tonic-gate { 9740Sstevel@tonic-gate va_list args; 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate trace_flush(); 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate if (!openlog_done) 9790Sstevel@tonic-gate do_openlog(); 9800Sstevel@tonic-gate va_start(args, p); 9810Sstevel@tonic-gate vsyslog(LOG_ERR, p, args); 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate if (ftrace != 0) { 9840Sstevel@tonic-gate if (ftrace == stdout) 9850Sstevel@tonic-gate (void) fputs("in.routed: ", ftrace); 9860Sstevel@tonic-gate (void) vfprintf(ftrace, p, args); 9870Sstevel@tonic-gate (void) fputc('\n', ftrace); 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate } 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate 9920Sstevel@tonic-gate /* 9930Sstevel@tonic-gate * Put a message about a bad system into the system log if 9940Sstevel@tonic-gate * we have not complained about it recently. 9950Sstevel@tonic-gate * 9960Sstevel@tonic-gate * It is desirable to complain about all bad systems, but not too often. 9970Sstevel@tonic-gate * In the worst case, it is not practical to keep track of all bad systems. 9980Sstevel@tonic-gate * For example, there can be many systems with the wrong password. 9990Sstevel@tonic-gate */ 10000Sstevel@tonic-gate void 10010Sstevel@tonic-gate msglim(struct msg_limit *lim, in_addr_t addr, const char *p, ...) 10020Sstevel@tonic-gate { 10030Sstevel@tonic-gate va_list args; 10040Sstevel@tonic-gate int i; 10050Sstevel@tonic-gate struct msg_sub *ms1, *ms; 10060Sstevel@tonic-gate const char *p1; 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate va_start(args, p); 10090Sstevel@tonic-gate 10100Sstevel@tonic-gate /* 10110Sstevel@tonic-gate * look for the oldest slot in the table 10120Sstevel@tonic-gate * or the slot for the bad router. 10130Sstevel@tonic-gate */ 10140Sstevel@tonic-gate ms = ms1 = lim->subs; 10150Sstevel@tonic-gate for (i = MSG_SUBJECT_N; ; i--, ms1++) { 10160Sstevel@tonic-gate if (i == 0) { 10170Sstevel@tonic-gate /* Reuse a slot at most once every 10 minutes. */ 10180Sstevel@tonic-gate if (lim->reuse > now.tv_sec) { 10190Sstevel@tonic-gate ms = NULL; 10200Sstevel@tonic-gate } else { 10210Sstevel@tonic-gate lim->reuse = now.tv_sec + 10*60; 10220Sstevel@tonic-gate } 10230Sstevel@tonic-gate break; 10240Sstevel@tonic-gate } 10250Sstevel@tonic-gate if (ms->addr == addr) { 10260Sstevel@tonic-gate /* 10270Sstevel@tonic-gate * Repeat a complaint about a given system at 10280Sstevel@tonic-gate * most once an hour. 10290Sstevel@tonic-gate */ 10300Sstevel@tonic-gate if (ms->until > now.tv_sec) 10310Sstevel@tonic-gate ms = NULL; 10320Sstevel@tonic-gate break; 10330Sstevel@tonic-gate } 10340Sstevel@tonic-gate if (ms->until < ms1->until) 10350Sstevel@tonic-gate ms = ms1; 10360Sstevel@tonic-gate } 10370Sstevel@tonic-gate if (ms != NULL) { 10380Sstevel@tonic-gate ms->addr = addr; 10390Sstevel@tonic-gate ms->until = now.tv_sec + 60*60; /* 60 minutes */ 10400Sstevel@tonic-gate 10410Sstevel@tonic-gate if (!openlog_done) 10420Sstevel@tonic-gate do_openlog(); 10430Sstevel@tonic-gate trace_flush(); 10440Sstevel@tonic-gate for (p1 = p; *p1 == ' '; p1++) 10450Sstevel@tonic-gate continue; 10460Sstevel@tonic-gate vsyslog(LOG_ERR, p1, args); 10470Sstevel@tonic-gate } 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate /* always display the message if tracing */ 10500Sstevel@tonic-gate if (ftrace != 0) { 10510Sstevel@tonic-gate (void) vfprintf(ftrace, p, args); 10520Sstevel@tonic-gate (void) fputc('\n', ftrace); 10530Sstevel@tonic-gate } 10540Sstevel@tonic-gate } 10550Sstevel@tonic-gate 10560Sstevel@tonic-gate 10570Sstevel@tonic-gate void 10580Sstevel@tonic-gate logbad(boolean_t dump, const char *p, ...) 10590Sstevel@tonic-gate { 10600Sstevel@tonic-gate va_list args; 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate trace_flush(); 10630Sstevel@tonic-gate 10640Sstevel@tonic-gate if (!openlog_done) 10650Sstevel@tonic-gate do_openlog(); 10660Sstevel@tonic-gate va_start(args, p); 10670Sstevel@tonic-gate vsyslog(LOG_ERR, p, args); 10680Sstevel@tonic-gate 10690Sstevel@tonic-gate (void) fputs(gettext("in.routed: "), stderr); 10700Sstevel@tonic-gate (void) vfprintf(stderr, p, args); 10710Sstevel@tonic-gate (void) fputs(gettext("; giving up\n"), stderr); 10720Sstevel@tonic-gate (void) fflush(stderr); 10730Sstevel@tonic-gate 10740Sstevel@tonic-gate if (dump) 10750Sstevel@tonic-gate abort(); 10760Sstevel@tonic-gate exit(EXIT_FAILURE); 10770Sstevel@tonic-gate } 10780Sstevel@tonic-gate 10790Sstevel@tonic-gate /* put a message into the system log */ 10800Sstevel@tonic-gate void 10810Sstevel@tonic-gate writelog(int level, const char *p, ...) 10820Sstevel@tonic-gate { 10830Sstevel@tonic-gate va_list args; 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate trace_flush(); 10860Sstevel@tonic-gate 10870Sstevel@tonic-gate if (!openlog_done) 10880Sstevel@tonic-gate do_openlog(); 10890Sstevel@tonic-gate va_start(args, p); 10900Sstevel@tonic-gate vsyslog(level, p, args); 10910Sstevel@tonic-gate 10920Sstevel@tonic-gate if (ftrace != 0) { 10930Sstevel@tonic-gate if (ftrace == stdout) 10940Sstevel@tonic-gate (void) fputs("in.routed: ", ftrace); 10950Sstevel@tonic-gate (void) vfprintf(ftrace, p, args); 10960Sstevel@tonic-gate (void) fputc('\n', ftrace); 10970Sstevel@tonic-gate } 10980Sstevel@tonic-gate } 1099