18a16b7a1SPedro F. Giffuni /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 47b6ab19dSGarrett Wollman * Copyright (c) 1983, 1988, 1993 57b6ab19dSGarrett Wollman * The Regents of the University of California. All rights reserved. 67b6ab19dSGarrett Wollman * 77b6ab19dSGarrett Wollman * Redistribution and use in source and binary forms, with or without 87b6ab19dSGarrett Wollman * modification, are permitted provided that the following conditions 97b6ab19dSGarrett Wollman * are met: 107b6ab19dSGarrett Wollman * 1. Redistributions of source code must retain the above copyright 117b6ab19dSGarrett Wollman * notice, this list of conditions and the following disclaimer. 127b6ab19dSGarrett Wollman * 2. Redistributions in binary form must reproduce the above copyright 137b6ab19dSGarrett Wollman * notice, this list of conditions and the following disclaimer in the 147b6ab19dSGarrett Wollman * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 167b6ab19dSGarrett Wollman * may be used to endorse or promote products derived from this software 177b6ab19dSGarrett Wollman * without specific prior written permission. 187b6ab19dSGarrett Wollman * 197b6ab19dSGarrett Wollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 207b6ab19dSGarrett Wollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 217b6ab19dSGarrett Wollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 227b6ab19dSGarrett Wollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 237b6ab19dSGarrett Wollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 247b6ab19dSGarrett Wollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 257b6ab19dSGarrett Wollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 267b6ab19dSGarrett Wollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 277b6ab19dSGarrett Wollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 287b6ab19dSGarrett Wollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 297b6ab19dSGarrett Wollman * SUCH DAMAGE. 30c90fe7dcSMark Murray * 317f3dea24SPeter Wemm * $FreeBSD$ 327b6ab19dSGarrett Wollman */ 337b6ab19dSGarrett Wollman 347b6ab19dSGarrett Wollman #include "defs.h" 357b6ab19dSGarrett Wollman #include "pathnames.h" 367b6ab19dSGarrett Wollman #ifdef sgi 377b6ab19dSGarrett Wollman #include "math.h" 387b6ab19dSGarrett Wollman #endif 397b6ab19dSGarrett Wollman #include <signal.h> 407b6ab19dSGarrett Wollman #include <fcntl.h> 417b6ab19dSGarrett Wollman #include <sys/file.h> 427b6ab19dSGarrett Wollman 433b3e61faSPoul-Henning Kamp __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993 " 44caa79e36SBruce M Simpson "The Regents of the University of California." 453b3e61faSPoul-Henning Kamp " All rights reserved."); 46caa79e36SBruce M Simpson #ifdef __NetBSD__ 472c7a9781SMark Murray __RCSID("$NetBSD$"); 48caa79e36SBruce M Simpson #include <util.h> 49caa79e36SBruce M Simpson #elif defined(__FreeBSD__) 50caa79e36SBruce M Simpson __RCSID("$FreeBSD$"); 51caa79e36SBruce M Simpson #else 52a4fff644STom Rhodes __RCSID("$Revision: 2.31 $"); 53a4fff644STom Rhodes #ident "$Revision: 2.31 $" 542c7a9781SMark Murray #endif 552c7a9781SMark Murray 567b6ab19dSGarrett Wollman pid_t mypid; 577b6ab19dSGarrett Wollman 587b6ab19dSGarrett Wollman naddr myaddr; /* system address */ 59f2ca6d8aSPoul-Henning Kamp static char myname[MAXHOSTNAMELEN+1]; 607b6ab19dSGarrett Wollman 61f2ca6d8aSPoul-Henning Kamp static int verbose; 622c7a9781SMark Murray 637b6ab19dSGarrett Wollman int supplier; /* supply or broadcast updates */ 647b6ab19dSGarrett Wollman int supplier_set; 65f2ca6d8aSPoul-Henning Kamp static int ipforwarding = 1; /* kernel forwarding on */ 667b6ab19dSGarrett Wollman 67f2ca6d8aSPoul-Henning Kamp static int default_gateway; /* 1=advertise default */ 68f2ca6d8aSPoul-Henning Kamp static int background = 1; 697b6ab19dSGarrett Wollman int ridhosts; /* 1=reduce host routes */ 707b6ab19dSGarrett Wollman int mhome; /* 1=want multi-homed host route */ 7190100551SPhilippe Charnier int advertise_mhome; /* 1=must continue advertising it */ 727b6ab19dSGarrett Wollman int auth_ok = 1; /* 1=ignore auth if we do not care */ 73b9f70cedSHiroki Sato int insecure; /* Reply to special queries or not */ 747b6ab19dSGarrett Wollman 757b6ab19dSGarrett Wollman struct timeval epoch; /* when started */ 76f2ca6d8aSPoul-Henning Kamp struct timeval clk; 77f2ca6d8aSPoul-Henning Kamp static struct timeval prev_clk; 782c7a9781SMark Murray static int usec_fudge; 797b6ab19dSGarrett Wollman struct timeval now; /* current idea of time */ 807b6ab19dSGarrett Wollman time_t now_stale; 817b6ab19dSGarrett Wollman time_t now_expire; 827b6ab19dSGarrett Wollman time_t now_garbage; 837b6ab19dSGarrett Wollman 84f2ca6d8aSPoul-Henning Kamp static struct timeval next_bcast; /* next general broadcast */ 85f7434bbdSSheldon Hearn struct timeval no_flash = { /* inhibit flash update */ 86f7434bbdSSheldon Hearn EPOCH+SUPPLY_INTERVAL, 0 87f7434bbdSSheldon Hearn }; 887b6ab19dSGarrett Wollman 89f2ca6d8aSPoul-Henning Kamp static struct timeval flush_kern_timer; 902c7a9781SMark Murray 91f2ca6d8aSPoul-Henning Kamp static fd_set fdbits; 92f2ca6d8aSPoul-Henning Kamp static int sock_max; 937b6ab19dSGarrett Wollman int rip_sock = -1; /* RIP socket */ 9449694c6dSPoul-Henning Kamp const struct interface *rip_sock_mcast; /* current multicast interface */ 957b6ab19dSGarrett Wollman int rt_sock; /* routing socket */ 967b6ab19dSGarrett Wollman int rt_sock_seqno; 977b6ab19dSGarrett Wollman 987b6ab19dSGarrett Wollman 997b6ab19dSGarrett Wollman static int get_rip_sock(naddr, int); 1007b6ab19dSGarrett Wollman static void timevalsub(struct timeval *, struct timeval *, struct timeval *); 101f2ca6d8aSPoul-Henning Kamp static void sigalrm(int s UNUSED); 102f2ca6d8aSPoul-Henning Kamp static void sigterm(int sig); 1037b6ab19dSGarrett Wollman 1047b6ab19dSGarrett Wollman int 1057b6ab19dSGarrett Wollman main(int argc, 1067b6ab19dSGarrett Wollman char *argv[]) 1077b6ab19dSGarrett Wollman { 1087b6ab19dSGarrett Wollman int n, mib[4], off; 1097b6ab19dSGarrett Wollman size_t len; 1107b6ab19dSGarrett Wollman char *p, *q; 1112c7a9781SMark Murray const char *cp; 1127b6ab19dSGarrett Wollman struct timeval wtime, t2; 1137b6ab19dSGarrett Wollman time_t dt; 1147b6ab19dSGarrett Wollman fd_set ibits; 1151608c04fSGarrett Wollman naddr p_net, p_mask; 1167b6ab19dSGarrett Wollman struct interface *ifp; 1177b6ab19dSGarrett Wollman struct parm parm; 1187b6ab19dSGarrett Wollman char *tracename = 0; 1197b6ab19dSGarrett Wollman 1207b6ab19dSGarrett Wollman 1211608c04fSGarrett Wollman /* Some shells are badly broken and send SIGHUP to backgrounded 1221608c04fSGarrett Wollman * processes. 1231608c04fSGarrett Wollman */ 1241608c04fSGarrett Wollman signal(SIGHUP, SIG_IGN); 1251608c04fSGarrett Wollman 126caa79e36SBruce M Simpson openlog("routed", LOG_PID, LOG_DAEMON); 1277b6ab19dSGarrett Wollman ftrace = stdout; 1287b6ab19dSGarrett Wollman 1297b6ab19dSGarrett Wollman gettimeofday(&clk, 0); 1307b6ab19dSGarrett Wollman prev_clk = clk; 1317b6ab19dSGarrett Wollman epoch = clk; 1327b6ab19dSGarrett Wollman epoch.tv_sec -= EPOCH; 1337b6ab19dSGarrett Wollman now.tv_sec = EPOCH; 1347b6ab19dSGarrett Wollman now_stale = EPOCH - STALE_TIME; 1357b6ab19dSGarrett Wollman now_expire = EPOCH - EXPIRE_TIME; 1367b6ab19dSGarrett Wollman now_garbage = EPOCH - GARBAGE_TIME; 1377b6ab19dSGarrett Wollman wtime.tv_sec = 0; 1387b6ab19dSGarrett Wollman 1397b6ab19dSGarrett Wollman (void)gethostname(myname, sizeof(myname)-1); 1407b6ab19dSGarrett Wollman (void)gethost(myname, &myaddr); 1417b6ab19dSGarrett Wollman 142b9f70cedSHiroki Sato while ((n = getopt(argc, argv, "isqdghmAtvT:F:P:")) != -1) { 1437b6ab19dSGarrett Wollman switch (n) { 144b9f70cedSHiroki Sato case 'i': 145b9f70cedSHiroki Sato insecure++; 146b9f70cedSHiroki Sato break; 1477b6ab19dSGarrett Wollman case 's': 1487b6ab19dSGarrett Wollman supplier = 1; 1497b6ab19dSGarrett Wollman supplier_set = 1; 1507b6ab19dSGarrett Wollman break; 1517b6ab19dSGarrett Wollman 1527b6ab19dSGarrett Wollman case 'q': 1537b6ab19dSGarrett Wollman supplier = 0; 1547b6ab19dSGarrett Wollman supplier_set = 1; 1557b6ab19dSGarrett Wollman break; 1567b6ab19dSGarrett Wollman 1577b6ab19dSGarrett Wollman case 'd': 1587b6ab19dSGarrett Wollman background = 0; 1597b6ab19dSGarrett Wollman break; 1607b6ab19dSGarrett Wollman 1617b6ab19dSGarrett Wollman case 'g': 1622c7a9781SMark Murray memset(&parm, 0, sizeof(parm)); 1637b6ab19dSGarrett Wollman parm.parm_d_metric = 1; 1642c7a9781SMark Murray cp = check_parms(&parm); 1652c7a9781SMark Murray if (cp != 0) 1662c7a9781SMark Murray msglog("bad -g: %s", cp); 1677b6ab19dSGarrett Wollman else 1687b6ab19dSGarrett Wollman default_gateway = 1; 1697b6ab19dSGarrett Wollman break; 1707b6ab19dSGarrett Wollman 1717b6ab19dSGarrett Wollman case 'h': /* suppress extra host routes */ 1727b6ab19dSGarrett Wollman ridhosts = 1; 1737b6ab19dSGarrett Wollman break; 1747b6ab19dSGarrett Wollman 1757b6ab19dSGarrett Wollman case 'm': /* advertise host route */ 1767b6ab19dSGarrett Wollman mhome = 1; /* on multi-homed hosts */ 1777b6ab19dSGarrett Wollman break; 1787b6ab19dSGarrett Wollman 1797b6ab19dSGarrett Wollman case 'A': 1807b6ab19dSGarrett Wollman /* Ignore authentication if we do not care. 1817b6ab19dSGarrett Wollman * Crazy as it is, that is what RFC 1723 requires. 1827b6ab19dSGarrett Wollman */ 1837b6ab19dSGarrett Wollman auth_ok = 0; 1847b6ab19dSGarrett Wollman break; 1857b6ab19dSGarrett Wollman 1867b6ab19dSGarrett Wollman case 't': 1877b6ab19dSGarrett Wollman new_tracelevel++; 1887b6ab19dSGarrett Wollman break; 1897b6ab19dSGarrett Wollman 1907b6ab19dSGarrett Wollman case 'T': 1917b6ab19dSGarrett Wollman tracename = optarg; 1927b6ab19dSGarrett Wollman break; 1937b6ab19dSGarrett Wollman 1947b6ab19dSGarrett Wollman case 'F': /* minimal routes for SLIP */ 1951608c04fSGarrett Wollman n = FAKE_METRIC; 1967b6ab19dSGarrett Wollman p = strchr(optarg,','); 1977b6ab19dSGarrett Wollman if (p && *p != '\0') { 1987b6ab19dSGarrett Wollman n = (int)strtoul(p+1, &q, 0); 1997b6ab19dSGarrett Wollman if (*q == '\0' 2007b6ab19dSGarrett Wollman && n <= HOPCNT_INFINITY-1 2017b6ab19dSGarrett Wollman && n >= 1) 2027b6ab19dSGarrett Wollman *p = '\0'; 2037b6ab19dSGarrett Wollman } 2041608c04fSGarrett Wollman if (!getnet(optarg, &p_net, &p_mask)) { 2057b6ab19dSGarrett Wollman msglog("bad network; \"-F %s\"", 2067b6ab19dSGarrett Wollman optarg); 2077b6ab19dSGarrett Wollman break; 2087b6ab19dSGarrett Wollman } 2092c7a9781SMark Murray memset(&parm, 0, sizeof(parm)); 2101608c04fSGarrett Wollman parm.parm_net = p_net; 2117b6ab19dSGarrett Wollman parm.parm_mask = p_mask; 2127b6ab19dSGarrett Wollman parm.parm_d_metric = n; 2132c7a9781SMark Murray cp = check_parms(&parm); 2142c7a9781SMark Murray if (cp != 0) 2152c7a9781SMark Murray msglog("bad -F: %s", cp); 2167b6ab19dSGarrett Wollman break; 2177b6ab19dSGarrett Wollman 2187b6ab19dSGarrett Wollman case 'P': 2192c7a9781SMark Murray /* handle arbitrary parameters. 2207b6ab19dSGarrett Wollman */ 2212c7a9781SMark Murray q = strdup(optarg); 2222c7a9781SMark Murray cp = parse_parms(q, 0); 2232c7a9781SMark Murray if (cp != 0) 2242c7a9781SMark Murray msglog("%s in \"-P %s\"", cp, optarg); 2252c7a9781SMark Murray free(q); 2262c7a9781SMark Murray break; 2272c7a9781SMark Murray 2282c7a9781SMark Murray case 'v': 2292c7a9781SMark Murray /* display version */ 2302c7a9781SMark Murray verbose++; 231a4fff644STom Rhodes msglog("version 2.31"); 2327b6ab19dSGarrett Wollman break; 2337b6ab19dSGarrett Wollman 2347b6ab19dSGarrett Wollman default: 2357b6ab19dSGarrett Wollman goto usage; 2367b6ab19dSGarrett Wollman } 2377b6ab19dSGarrett Wollman } 2387b6ab19dSGarrett Wollman argc -= optind; 2397b6ab19dSGarrett Wollman argv += optind; 2407b6ab19dSGarrett Wollman 2417b6ab19dSGarrett Wollman if (tracename == 0 && argc >= 1) { 2427b6ab19dSGarrett Wollman tracename = *argv++; 2437b6ab19dSGarrett Wollman argc--; 2447b6ab19dSGarrett Wollman } 245a30febecSGarrett Wollman if (tracename != 0 && tracename[0] == '\0') 246a30febecSGarrett Wollman goto usage; 2477b6ab19dSGarrett Wollman if (argc != 0) { 2487b6ab19dSGarrett Wollman usage: 249a4fff644STom Rhodes logbad(0, "usage: routed [-sqdghmAtv] [-T tracefile]" 2507b6ab19dSGarrett Wollman " [-F net[,metric]] [-P parms]"); 2517b6ab19dSGarrett Wollman } 2522c7a9781SMark Murray if (geteuid() != 0) { 2532c7a9781SMark Murray if (verbose) 2542c7a9781SMark Murray exit(0); 2557b6ab19dSGarrett Wollman logbad(0, "requires UID 0"); 2562c7a9781SMark Murray } 2577b6ab19dSGarrett Wollman 2587b6ab19dSGarrett Wollman mib[0] = CTL_NET; 2597b6ab19dSGarrett Wollman mib[1] = PF_INET; 2607b6ab19dSGarrett Wollman mib[2] = IPPROTO_IP; 2617b6ab19dSGarrett Wollman mib[3] = IPCTL_FORWARDING; 2627b6ab19dSGarrett Wollman len = sizeof(ipforwarding); 2637b6ab19dSGarrett Wollman if (sysctl(mib, 4, &ipforwarding, &len, 0, 0) < 0) 2647b6ab19dSGarrett Wollman LOGERR("sysctl(IPCTL_FORWARDING)"); 2657b6ab19dSGarrett Wollman 2667b6ab19dSGarrett Wollman if (!ipforwarding) { 2677b6ab19dSGarrett Wollman if (supplier) 2687b6ab19dSGarrett Wollman msglog("-s incompatible with ipforwarding=0"); 2697b6ab19dSGarrett Wollman if (default_gateway) { 2707b6ab19dSGarrett Wollman msglog("-g incompatible with ipforwarding=0"); 2717b6ab19dSGarrett Wollman default_gateway = 0; 2727b6ab19dSGarrett Wollman } 2737b6ab19dSGarrett Wollman supplier = 0; 2747b6ab19dSGarrett Wollman supplier_set = 1; 2757b6ab19dSGarrett Wollman } 2767b6ab19dSGarrett Wollman if (default_gateway) { 2777b6ab19dSGarrett Wollman if (supplier_set && !supplier) { 2787b6ab19dSGarrett Wollman msglog("-g and -q incompatible"); 2797b6ab19dSGarrett Wollman } else { 2807b6ab19dSGarrett Wollman supplier = 1; 2817b6ab19dSGarrett Wollman supplier_set = 1; 2827b6ab19dSGarrett Wollman } 2837b6ab19dSGarrett Wollman } 2847b6ab19dSGarrett Wollman 2857b6ab19dSGarrett Wollman 2867b6ab19dSGarrett Wollman signal(SIGALRM, sigalrm); 2877b6ab19dSGarrett Wollman if (!background) 2887b6ab19dSGarrett Wollman signal(SIGHUP, sigterm); /* SIGHUP fatal during debugging */ 2897b6ab19dSGarrett Wollman signal(SIGTERM, sigterm); 2907b6ab19dSGarrett Wollman signal(SIGINT, sigterm); 2917b6ab19dSGarrett Wollman signal(SIGUSR1, sigtrace_on); 2927b6ab19dSGarrett Wollman signal(SIGUSR2, sigtrace_off); 2937b6ab19dSGarrett Wollman 2947b6ab19dSGarrett Wollman /* get into the background */ 2957b6ab19dSGarrett Wollman #ifdef sgi 296a30febecSGarrett Wollman if (0 > _daemonize(background ? 0 : (_DF_NOCHDIR|_DF_NOFORK), 2972c7a9781SMark Murray STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)) 2987b6ab19dSGarrett Wollman BADERR(0, "_daemonize()"); 2997b6ab19dSGarrett Wollman #else 3002c7a9781SMark Murray if (background && daemon(0, 1) < 0) 3017b6ab19dSGarrett Wollman BADERR(0,"daemon()"); 3027b6ab19dSGarrett Wollman #endif 3037b6ab19dSGarrett Wollman 304caa79e36SBruce M Simpson #if defined(__NetBSD__) 305caa79e36SBruce M Simpson pidfile(0); 306caa79e36SBruce M Simpson #endif 3077b6ab19dSGarrett Wollman mypid = getpid(); 3087b6ab19dSGarrett Wollman 3097b6ab19dSGarrett Wollman /* prepare socket connected to the kernel. 3107b6ab19dSGarrett Wollman */ 3117b6ab19dSGarrett Wollman rt_sock = socket(AF_ROUTE, SOCK_RAW, 0); 3127b6ab19dSGarrett Wollman if (rt_sock < 0) 3137b6ab19dSGarrett Wollman BADERR(1,"rt_sock = socket()"); 3147b6ab19dSGarrett Wollman if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1) 3157b6ab19dSGarrett Wollman logbad(1, "fcntl(rt_sock) O_NONBLOCK: %s", strerror(errno)); 3167b6ab19dSGarrett Wollman off = 0; 3177b6ab19dSGarrett Wollman if (setsockopt(rt_sock, SOL_SOCKET,SO_USELOOPBACK, 3187b6ab19dSGarrett Wollman &off,sizeof(off)) < 0) 3197b6ab19dSGarrett Wollman LOGERR("setsockopt(SO_USELOOPBACK,0)"); 3207b6ab19dSGarrett Wollman 3217b6ab19dSGarrett Wollman fix_select(); 3227b6ab19dSGarrett Wollman 3237b6ab19dSGarrett Wollman 3247b6ab19dSGarrett Wollman if (tracename != 0) { 325a30febecSGarrett Wollman strncpy(inittracename, tracename, sizeof(inittracename)-1); 3262c7a9781SMark Murray set_tracefile(inittracename, "%s", -1); 327a30febecSGarrett Wollman } else { 3282c7a9781SMark Murray tracelevel_msg("%s", -1); /* turn on tracing to stdio */ 3297b6ab19dSGarrett Wollman } 3301608c04fSGarrett Wollman 3311608c04fSGarrett Wollman bufinit(); 3327b6ab19dSGarrett Wollman 3337b6ab19dSGarrett Wollman /* initialize radix tree */ 3347b6ab19dSGarrett Wollman rtinit(); 3357b6ab19dSGarrett Wollman 3367b6ab19dSGarrett Wollman /* Pick a random part of the second for our output to minimize 3377b6ab19dSGarrett Wollman * collisions. 3387b6ab19dSGarrett Wollman * 3397b6ab19dSGarrett Wollman * Start broadcasting after hearing from other routers, and 3407b6ab19dSGarrett Wollman * at a random time so a bunch of systems do not get synchronized 3417b6ab19dSGarrett Wollman * after a power failure. 3427b6ab19dSGarrett Wollman */ 3437b6ab19dSGarrett Wollman intvl_random(&next_bcast, EPOCH+MIN_WAITTIME, EPOCH+SUPPLY_INTERVAL); 3447b6ab19dSGarrett Wollman age_timer.tv_usec = next_bcast.tv_usec; 3457b6ab19dSGarrett Wollman age_timer.tv_sec = EPOCH+MIN_WAITTIME; 3467b6ab19dSGarrett Wollman rdisc_timer = next_bcast; 3477b6ab19dSGarrett Wollman ifinit_timer.tv_usec = next_bcast.tv_usec; 3487b6ab19dSGarrett Wollman 3497b6ab19dSGarrett Wollman /* Collect an initial view of the world by checking the interface 3507b6ab19dSGarrett Wollman * configuration and the kludge file. 3517b6ab19dSGarrett Wollman */ 3527b6ab19dSGarrett Wollman gwkludge(); 3537b6ab19dSGarrett Wollman ifinit(); 3547b6ab19dSGarrett Wollman 3557b6ab19dSGarrett Wollman /* Ask for routes */ 3567b6ab19dSGarrett Wollman rip_query(); 3577b6ab19dSGarrett Wollman rdisc_sol(); 3587b6ab19dSGarrett Wollman 3592c7a9781SMark Murray /* Now turn off stdio if not tracing */ 3602c7a9781SMark Murray if (new_tracelevel == 0) 3612c7a9781SMark Murray trace_close(background); 3622c7a9781SMark Murray 3637b6ab19dSGarrett Wollman /* Loop forever, listening and broadcasting. 3647b6ab19dSGarrett Wollman */ 3657b6ab19dSGarrett Wollman for (;;) { 3667b6ab19dSGarrett Wollman prev_clk = clk; 3677b6ab19dSGarrett Wollman gettimeofday(&clk, 0); 3682c7a9781SMark Murray if (prev_clk.tv_sec == clk.tv_sec 3692c7a9781SMark Murray && prev_clk.tv_usec == clk.tv_usec+usec_fudge) { 3702c7a9781SMark Murray /* Much of `routed` depends on time always advancing. 3712c7a9781SMark Murray * On systems that do not guarantee that gettimeofday() 3722c7a9781SMark Murray * produces unique timestamps even if called within 3732c7a9781SMark Murray * a single tick, use trickery like that in classic 3742c7a9781SMark Murray * BSD kernels. 3752c7a9781SMark Murray */ 3762c7a9781SMark Murray clk.tv_usec += ++usec_fudge; 3772c7a9781SMark Murray 3782c7a9781SMark Murray } else { 3792c7a9781SMark Murray usec_fudge = 0; 3802c7a9781SMark Murray 3817b6ab19dSGarrett Wollman timevalsub(&t2, &clk, &prev_clk); 3827b6ab19dSGarrett Wollman if (t2.tv_sec < 0 3837b6ab19dSGarrett Wollman || t2.tv_sec > wtime.tv_sec + 5) { 3842c7a9781SMark Murray /* Deal with time changes before other 3852c7a9781SMark Murray * housekeeping to keep everything straight. 3867b6ab19dSGarrett Wollman */ 3877b6ab19dSGarrett Wollman dt = t2.tv_sec; 3887b6ab19dSGarrett Wollman if (dt > 0) 3897b6ab19dSGarrett Wollman dt -= wtime.tv_sec; 3902c7a9781SMark Murray trace_act("time changed by %d sec", (int)dt); 3917b6ab19dSGarrett Wollman epoch.tv_sec += dt; 3927b6ab19dSGarrett Wollman } 3932c7a9781SMark Murray } 3947b6ab19dSGarrett Wollman timevalsub(&now, &clk, &epoch); 3957b6ab19dSGarrett Wollman now_stale = now.tv_sec - STALE_TIME; 3967b6ab19dSGarrett Wollman now_expire = now.tv_sec - EXPIRE_TIME; 3977b6ab19dSGarrett Wollman now_garbage = now.tv_sec - GARBAGE_TIME; 3987b6ab19dSGarrett Wollman 399a30febecSGarrett Wollman /* deal with signals that should affect tracing */ 400a30febecSGarrett Wollman set_tracelevel(); 4017b6ab19dSGarrett Wollman 4027b6ab19dSGarrett Wollman if (stopint != 0) { 4037b6ab19dSGarrett Wollman rip_bcast(0); 4047b6ab19dSGarrett Wollman rdisc_adv(); 4052c7a9781SMark Murray trace_off("exiting with signal %d", stopint); 4067b6ab19dSGarrett Wollman exit(stopint | 128); 4077b6ab19dSGarrett Wollman } 4087b6ab19dSGarrett Wollman 4097b6ab19dSGarrett Wollman /* look for new or dead interfaces */ 4107b6ab19dSGarrett Wollman timevalsub(&wtime, &ifinit_timer, &now); 4117b6ab19dSGarrett Wollman if (wtime.tv_sec <= 0) { 4127b6ab19dSGarrett Wollman wtime.tv_sec = 0; 4137b6ab19dSGarrett Wollman ifinit(); 4147b6ab19dSGarrett Wollman rip_query(); 4157b6ab19dSGarrett Wollman continue; 4167b6ab19dSGarrett Wollman } 4177b6ab19dSGarrett Wollman 4184b85a12fSUlrich Spörlein /* Check the kernel table occasionally for mysteriously 4192c7a9781SMark Murray * evaporated routes 4202c7a9781SMark Murray */ 4212c7a9781SMark Murray timevalsub(&t2, &flush_kern_timer, &now); 4222c7a9781SMark Murray if (t2.tv_sec <= 0) { 4232c7a9781SMark Murray flush_kern(); 4242c7a9781SMark Murray flush_kern_timer.tv_sec = (now.tv_sec 4252c7a9781SMark Murray + CHECK_QUIET_INTERVAL); 4262c7a9781SMark Murray continue; 4272c7a9781SMark Murray } 4282c7a9781SMark Murray if (timercmp(&t2, &wtime, <)) 4292c7a9781SMark Murray wtime = t2; 4302c7a9781SMark Murray 4317b6ab19dSGarrett Wollman /* If it is time, then broadcast our routes. 4327b6ab19dSGarrett Wollman */ 4337b6ab19dSGarrett Wollman if (supplier || advertise_mhome) { 4347b6ab19dSGarrett Wollman timevalsub(&t2, &next_bcast, &now); 4357b6ab19dSGarrett Wollman if (t2.tv_sec <= 0) { 4367b6ab19dSGarrett Wollman /* Synchronize the aging and broadcast 4377b6ab19dSGarrett Wollman * timers to minimize awakenings 4387b6ab19dSGarrett Wollman */ 4397b6ab19dSGarrett Wollman age(0); 4407b6ab19dSGarrett Wollman 4417b6ab19dSGarrett Wollman rip_bcast(0); 4427b6ab19dSGarrett Wollman 4437b6ab19dSGarrett Wollman /* It is desirable to send routing updates 4447b6ab19dSGarrett Wollman * regularly. So schedule the next update 4457b6ab19dSGarrett Wollman * 30 seconds after the previous one was 4466f1edd29SDaniel O'Callaghan * scheduled, instead of 30 seconds after 4477b6ab19dSGarrett Wollman * the previous update was finished. 4487b6ab19dSGarrett Wollman * Even if we just started after discovering 4497b6ab19dSGarrett Wollman * a 2nd interface or were otherwise delayed, 4504b85a12fSUlrich Spörlein * pick a 30-second anniversary of the 4517b6ab19dSGarrett Wollman * original broadcast time. 4527b6ab19dSGarrett Wollman */ 4537b6ab19dSGarrett Wollman n = 1 + (0-t2.tv_sec)/SUPPLY_INTERVAL; 4547b6ab19dSGarrett Wollman next_bcast.tv_sec += n*SUPPLY_INTERVAL; 4557b6ab19dSGarrett Wollman 4567b6ab19dSGarrett Wollman continue; 4577b6ab19dSGarrett Wollman } 4587b6ab19dSGarrett Wollman 4597b6ab19dSGarrett Wollman if (timercmp(&t2, &wtime, <)) 4607b6ab19dSGarrett Wollman wtime = t2; 4617b6ab19dSGarrett Wollman } 4627b6ab19dSGarrett Wollman 4637b6ab19dSGarrett Wollman /* If we need a flash update, either do it now or 4647b6ab19dSGarrett Wollman * set the delay to end when it is time. 4657b6ab19dSGarrett Wollman * 4667b6ab19dSGarrett Wollman * If we are within MIN_WAITTIME seconds of a full update, 4677b6ab19dSGarrett Wollman * do not bother. 4687b6ab19dSGarrett Wollman */ 4697b6ab19dSGarrett Wollman if (need_flash 4707b6ab19dSGarrett Wollman && supplier 4717b6ab19dSGarrett Wollman && no_flash.tv_sec+MIN_WAITTIME < next_bcast.tv_sec) { 4727b6ab19dSGarrett Wollman /* accurate to the millisecond */ 4737b6ab19dSGarrett Wollman if (!timercmp(&no_flash, &now, >)) 4747b6ab19dSGarrett Wollman rip_bcast(1); 4757b6ab19dSGarrett Wollman timevalsub(&t2, &no_flash, &now); 4767b6ab19dSGarrett Wollman if (timercmp(&t2, &wtime, <)) 4777b6ab19dSGarrett Wollman wtime = t2; 4787b6ab19dSGarrett Wollman } 4797b6ab19dSGarrett Wollman 4807b6ab19dSGarrett Wollman /* trigger the main aging timer. 4817b6ab19dSGarrett Wollman */ 4827b6ab19dSGarrett Wollman timevalsub(&t2, &age_timer, &now); 4837b6ab19dSGarrett Wollman if (t2.tv_sec <= 0) { 4847b6ab19dSGarrett Wollman age(0); 4857b6ab19dSGarrett Wollman continue; 4867b6ab19dSGarrett Wollman } 4877b6ab19dSGarrett Wollman if (timercmp(&t2, &wtime, <)) 4887b6ab19dSGarrett Wollman wtime = t2; 4897b6ab19dSGarrett Wollman 4907b6ab19dSGarrett Wollman /* update the kernel routing table 4917b6ab19dSGarrett Wollman */ 4927b6ab19dSGarrett Wollman timevalsub(&t2, &need_kern, &now); 4937b6ab19dSGarrett Wollman if (t2.tv_sec <= 0) { 4947b6ab19dSGarrett Wollman age(0); 4957b6ab19dSGarrett Wollman continue; 4967b6ab19dSGarrett Wollman } 4977b6ab19dSGarrett Wollman if (timercmp(&t2, &wtime, <)) 4987b6ab19dSGarrett Wollman wtime = t2; 4997b6ab19dSGarrett Wollman 5007b6ab19dSGarrett Wollman /* take care of router discovery, 5012c7a9781SMark Murray * but do it in the correct the millisecond 5027b6ab19dSGarrett Wollman */ 5037b6ab19dSGarrett Wollman if (!timercmp(&rdisc_timer, &now, >)) { 5047b6ab19dSGarrett Wollman rdisc_age(0); 5057b6ab19dSGarrett Wollman continue; 5067b6ab19dSGarrett Wollman } 5077b6ab19dSGarrett Wollman timevalsub(&t2, &rdisc_timer, &now); 5087b6ab19dSGarrett Wollman if (timercmp(&t2, &wtime, <)) 5097b6ab19dSGarrett Wollman wtime = t2; 5107b6ab19dSGarrett Wollman 5117b6ab19dSGarrett Wollman 5127b6ab19dSGarrett Wollman /* wait for input or a timer to expire. 5137b6ab19dSGarrett Wollman */ 5147b6ab19dSGarrett Wollman trace_flush(); 5157b6ab19dSGarrett Wollman ibits = fdbits; 5167b6ab19dSGarrett Wollman n = select(sock_max, &ibits, 0, 0, &wtime); 5177b6ab19dSGarrett Wollman if (n <= 0) { 5187b6ab19dSGarrett Wollman if (n < 0 && errno != EINTR && errno != EAGAIN) 5197b6ab19dSGarrett Wollman BADERR(1,"select"); 5207b6ab19dSGarrett Wollman continue; 5217b6ab19dSGarrett Wollman } 5227b6ab19dSGarrett Wollman 5237b6ab19dSGarrett Wollman if (FD_ISSET(rt_sock, &ibits)) { 5247b6ab19dSGarrett Wollman read_rt(); 5257b6ab19dSGarrett Wollman n--; 5267b6ab19dSGarrett Wollman } 5277b6ab19dSGarrett Wollman if (rdisc_sock >= 0 && FD_ISSET(rdisc_sock, &ibits)) { 5287b6ab19dSGarrett Wollman read_d(); 5297b6ab19dSGarrett Wollman n--; 5307b6ab19dSGarrett Wollman } 5317b6ab19dSGarrett Wollman if (rip_sock >= 0 && FD_ISSET(rip_sock, &ibits)) { 5327b6ab19dSGarrett Wollman read_rip(rip_sock, 0); 5337b6ab19dSGarrett Wollman n--; 5347b6ab19dSGarrett Wollman } 5357b6ab19dSGarrett Wollman 53638ae6523SPoul-Henning Kamp LIST_FOREACH(ifp, &ifnet, int_list) { 53738ae6523SPoul-Henning Kamp if (n <= 0) 53838ae6523SPoul-Henning Kamp break; 5397b6ab19dSGarrett Wollman if (ifp->int_rip_sock >= 0 5407b6ab19dSGarrett Wollman && FD_ISSET(ifp->int_rip_sock, &ibits)) { 5417b6ab19dSGarrett Wollman read_rip(ifp->int_rip_sock, ifp); 5427b6ab19dSGarrett Wollman n--; 5437b6ab19dSGarrett Wollman } 5447b6ab19dSGarrett Wollman } 5457b6ab19dSGarrett Wollman } 5467b6ab19dSGarrett Wollman } 5477b6ab19dSGarrett Wollman 5487b6ab19dSGarrett Wollman 5497b6ab19dSGarrett Wollman /* ARGSUSED */ 550f2ca6d8aSPoul-Henning Kamp static void 5512c7a9781SMark Murray sigalrm(int s UNUSED) 5527b6ab19dSGarrett Wollman { 5537b6ab19dSGarrett Wollman /* Historically, SIGALRM would cause the daemon to check for 5547b6ab19dSGarrett Wollman * new and broken interfaces. 5557b6ab19dSGarrett Wollman */ 5567b6ab19dSGarrett Wollman ifinit_timer.tv_sec = now.tv_sec; 5571608c04fSGarrett Wollman trace_act("SIGALRM"); 5587b6ab19dSGarrett Wollman } 5597b6ab19dSGarrett Wollman 5607b6ab19dSGarrett Wollman 5617b6ab19dSGarrett Wollman /* watch for fatal signals */ 562f2ca6d8aSPoul-Henning Kamp static void 5637b6ab19dSGarrett Wollman sigterm(int sig) 5647b6ab19dSGarrett Wollman { 5657b6ab19dSGarrett Wollman stopint = sig; 5667b6ab19dSGarrett Wollman (void)signal(sig, SIG_DFL); /* catch it only once */ 5677b6ab19dSGarrett Wollman } 5687b6ab19dSGarrett Wollman 5697b6ab19dSGarrett Wollman 5707b6ab19dSGarrett Wollman void 5717b6ab19dSGarrett Wollman fix_select(void) 5727b6ab19dSGarrett Wollman { 5737b6ab19dSGarrett Wollman struct interface *ifp; 5747b6ab19dSGarrett Wollman 5757b6ab19dSGarrett Wollman 5767b6ab19dSGarrett Wollman FD_ZERO(&fdbits); 5777b6ab19dSGarrett Wollman sock_max = 0; 5787b6ab19dSGarrett Wollman 5797b6ab19dSGarrett Wollman FD_SET(rt_sock, &fdbits); 5807b6ab19dSGarrett Wollman if (sock_max <= rt_sock) 5817b6ab19dSGarrett Wollman sock_max = rt_sock+1; 5827b6ab19dSGarrett Wollman if (rip_sock >= 0) { 5837b6ab19dSGarrett Wollman FD_SET(rip_sock, &fdbits); 5847b6ab19dSGarrett Wollman if (sock_max <= rip_sock) 5857b6ab19dSGarrett Wollman sock_max = rip_sock+1; 5867b6ab19dSGarrett Wollman } 58738ae6523SPoul-Henning Kamp LIST_FOREACH(ifp, &ifnet, int_list) { 5887b6ab19dSGarrett Wollman if (ifp->int_rip_sock >= 0) { 5897b6ab19dSGarrett Wollman FD_SET(ifp->int_rip_sock, &fdbits); 5907b6ab19dSGarrett Wollman if (sock_max <= ifp->int_rip_sock) 5917b6ab19dSGarrett Wollman sock_max = ifp->int_rip_sock+1; 5927b6ab19dSGarrett Wollman } 5937b6ab19dSGarrett Wollman } 5947b6ab19dSGarrett Wollman if (rdisc_sock >= 0) { 5957b6ab19dSGarrett Wollman FD_SET(rdisc_sock, &fdbits); 5967b6ab19dSGarrett Wollman if (sock_max <= rdisc_sock) 5977b6ab19dSGarrett Wollman sock_max = rdisc_sock+1; 5987b6ab19dSGarrett Wollman } 5997b6ab19dSGarrett Wollman } 6007b6ab19dSGarrett Wollman 6017b6ab19dSGarrett Wollman 6027b6ab19dSGarrett Wollman void 6037b6ab19dSGarrett Wollman fix_sock(int sock, 6042c7a9781SMark Murray const char *name) 6057b6ab19dSGarrett Wollman { 6067b6ab19dSGarrett Wollman int on; 6077b6ab19dSGarrett Wollman #define MIN_SOCKBUF (4*1024) 6087b6ab19dSGarrett Wollman static int rbuf; 6097b6ab19dSGarrett Wollman 6107b6ab19dSGarrett Wollman if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) 6117b6ab19dSGarrett Wollman logbad(1, "fcntl(%s) O_NONBLOCK: %s", 6127b6ab19dSGarrett Wollman name, strerror(errno)); 6137b6ab19dSGarrett Wollman on = 1; 6141608c04fSGarrett Wollman if (setsockopt(sock, SOL_SOCKET,SO_BROADCAST, &on,sizeof(on)) < 0) 6157b6ab19dSGarrett Wollman msglog("setsockopt(%s,SO_BROADCAST): %s", 6167b6ab19dSGarrett Wollman name, strerror(errno)); 6171608c04fSGarrett Wollman #ifdef USE_PASSIFNAME 6181608c04fSGarrett Wollman on = 1; 6191608c04fSGarrett Wollman if (setsockopt(sock, SOL_SOCKET, SO_PASSIFNAME, &on,sizeof(on)) < 0) 6201608c04fSGarrett Wollman msglog("setsockopt(%s,SO_PASSIFNAME): %s", 6211608c04fSGarrett Wollman name, strerror(errno)); 6221608c04fSGarrett Wollman #endif 6231608c04fSGarrett Wollman 6247b6ab19dSGarrett Wollman if (rbuf >= MIN_SOCKBUF) { 6257b6ab19dSGarrett Wollman if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 6267b6ab19dSGarrett Wollman &rbuf, sizeof(rbuf)) < 0) 6277b6ab19dSGarrett Wollman msglog("setsockopt(%s,SO_RCVBUF=%d): %s", 6287b6ab19dSGarrett Wollman name, rbuf, strerror(errno)); 6297b6ab19dSGarrett Wollman } else { 6307b6ab19dSGarrett Wollman for (rbuf = 60*1024; ; rbuf -= 4096) { 6317b6ab19dSGarrett Wollman if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 6327b6ab19dSGarrett Wollman &rbuf, sizeof(rbuf)) == 0) { 6331608c04fSGarrett Wollman trace_act("RCVBUF=%d", rbuf); 6347b6ab19dSGarrett Wollman break; 6357b6ab19dSGarrett Wollman } 6367b6ab19dSGarrett Wollman if (rbuf < MIN_SOCKBUF) { 6377b6ab19dSGarrett Wollman msglog("setsockopt(%s,SO_RCVBUF = %d): %s", 6387b6ab19dSGarrett Wollman name, rbuf, strerror(errno)); 6397b6ab19dSGarrett Wollman break; 6407b6ab19dSGarrett Wollman } 6417b6ab19dSGarrett Wollman } 6427b6ab19dSGarrett Wollman } 6437b6ab19dSGarrett Wollman } 6447b6ab19dSGarrett Wollman 6457b6ab19dSGarrett Wollman 6467b6ab19dSGarrett Wollman /* get a rip socket 6477b6ab19dSGarrett Wollman */ 6487b6ab19dSGarrett Wollman static int /* <0 or file descriptor */ 6497b6ab19dSGarrett Wollman get_rip_sock(naddr addr, 6507b6ab19dSGarrett Wollman int serious) /* 1=failure to bind is serious */ 6517b6ab19dSGarrett Wollman { 652caa79e36SBruce M Simpson struct sockaddr_in rsin; 6537b6ab19dSGarrett Wollman unsigned char ttl; 6547b6ab19dSGarrett Wollman int s; 6557b6ab19dSGarrett Wollman 6567b6ab19dSGarrett Wollman 6577b6ab19dSGarrett Wollman if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 6587b6ab19dSGarrett Wollman BADERR(1,"rip_sock = socket()"); 6597b6ab19dSGarrett Wollman 660caa79e36SBruce M Simpson memset(&rsin, 0, sizeof(rsin)); 6617b6ab19dSGarrett Wollman #ifdef _HAVE_SIN_LEN 662caa79e36SBruce M Simpson rsin.sin_len = sizeof(rsin); 6637b6ab19dSGarrett Wollman #endif 664caa79e36SBruce M Simpson rsin.sin_family = AF_INET; 665caa79e36SBruce M Simpson rsin.sin_port = htons(RIP_PORT); 666caa79e36SBruce M Simpson rsin.sin_addr.s_addr = addr; 667caa79e36SBruce M Simpson if (bind(s, (struct sockaddr *)&rsin, sizeof(rsin)) < 0) { 6687b6ab19dSGarrett Wollman if (serious) 6697b6ab19dSGarrett Wollman BADERR(errno != EADDRINUSE, "bind(rip_sock)"); 670*5539da56SWarner Losh close(s); 6717b6ab19dSGarrett Wollman return -1; 6727b6ab19dSGarrett Wollman } 6737b6ab19dSGarrett Wollman fix_sock(s,"rip_sock"); 6747b6ab19dSGarrett Wollman 6757b6ab19dSGarrett Wollman ttl = 1; 6767b6ab19dSGarrett Wollman if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, 6777b6ab19dSGarrett Wollman &ttl, sizeof(ttl)) < 0) 6787b6ab19dSGarrett Wollman DBGERR(1,"rip_sock setsockopt(IP_MULTICAST_TTL)"); 6797b6ab19dSGarrett Wollman 6807b6ab19dSGarrett Wollman return s; 6817b6ab19dSGarrett Wollman } 6827b6ab19dSGarrett Wollman 6837b6ab19dSGarrett Wollman 6847b6ab19dSGarrett Wollman /* turn off main RIP socket */ 6857b6ab19dSGarrett Wollman void 6867b6ab19dSGarrett Wollman rip_off(void) 6877b6ab19dSGarrett Wollman { 6887b6ab19dSGarrett Wollman struct interface *ifp; 6892c7a9781SMark Murray naddr addr; 6907b6ab19dSGarrett Wollman 6917b6ab19dSGarrett Wollman 6927b6ab19dSGarrett Wollman if (rip_sock >= 0 && !mhome) { 6931608c04fSGarrett Wollman trace_act("turn off RIP"); 6947b6ab19dSGarrett Wollman 6957b6ab19dSGarrett Wollman (void)close(rip_sock); 6967b6ab19dSGarrett Wollman rip_sock = -1; 6977b6ab19dSGarrett Wollman 6987b6ab19dSGarrett Wollman /* get non-broadcast sockets to listen to queries. 6997b6ab19dSGarrett Wollman */ 70038ae6523SPoul-Henning Kamp LIST_FOREACH(ifp, &ifnet, int_list) { 7011608c04fSGarrett Wollman if (ifp->int_state & IS_REMOTE) 7021608c04fSGarrett Wollman continue; 7031608c04fSGarrett Wollman if (ifp->int_rip_sock < 0) { 7047b6ab19dSGarrett Wollman addr = ((ifp->int_if_flags & IFF_POINTOPOINT) 7057b6ab19dSGarrett Wollman ? ifp->int_dstaddr 7067b6ab19dSGarrett Wollman : ifp->int_addr); 7077b6ab19dSGarrett Wollman ifp->int_rip_sock = get_rip_sock(addr, 0); 7087b6ab19dSGarrett Wollman } 7097b6ab19dSGarrett Wollman } 7107b6ab19dSGarrett Wollman 7117b6ab19dSGarrett Wollman fix_select(); 7127b6ab19dSGarrett Wollman 7137b6ab19dSGarrett Wollman age(0); 7147b6ab19dSGarrett Wollman } 7157b6ab19dSGarrett Wollman } 7167b6ab19dSGarrett Wollman 7177b6ab19dSGarrett Wollman 7187b6ab19dSGarrett Wollman /* turn on RIP multicast input via an interface 7197b6ab19dSGarrett Wollman */ 7207b6ab19dSGarrett Wollman static void 7217b6ab19dSGarrett Wollman rip_mcast_on(struct interface *ifp) 7227b6ab19dSGarrett Wollman { 72368b22388SPoul-Henning Kamp struct group_req gr; 72468b22388SPoul-Henning Kamp struct sockaddr_in *sin; 7257b6ab19dSGarrett Wollman 7267b6ab19dSGarrett Wollman if (!IS_RIP_IN_OFF(ifp->int_state) 7277b6ab19dSGarrett Wollman && (ifp->int_if_flags & IFF_MULTICAST) 7287b6ab19dSGarrett Wollman && !(ifp->int_state & IS_ALIAS)) { 72968b22388SPoul-Henning Kamp memset(&gr, 0, sizeof(gr)); 73068b22388SPoul-Henning Kamp gr.gr_interface = ifp->int_index; 73168b22388SPoul-Henning Kamp sin = (struct sockaddr_in *)&gr.gr_group; 73268b22388SPoul-Henning Kamp sin->sin_family = AF_INET; 73368b22388SPoul-Henning Kamp #ifdef _HAVE_SIN_LEN 73468b22388SPoul-Henning Kamp sin->sin_len = sizeof(struct sockaddr_in); 735caa79e36SBruce M Simpson #endif 73668b22388SPoul-Henning Kamp sin->sin_addr.s_addr = htonl(INADDR_RIP_GROUP); 73768b22388SPoul-Henning Kamp if (setsockopt(rip_sock, IPPROTO_IP, MCAST_JOIN_GROUP, 73868b22388SPoul-Henning Kamp &gr, sizeof(gr)) < 0) 73968b22388SPoul-Henning Kamp LOGERR("setsockopt(MCAST_JOIN_GROUP RIP)"); 7407b6ab19dSGarrett Wollman } 7417b6ab19dSGarrett Wollman } 7427b6ab19dSGarrett Wollman 7437b6ab19dSGarrett Wollman 7447b6ab19dSGarrett Wollman /* Prepare socket used for RIP. 7457b6ab19dSGarrett Wollman */ 7467b6ab19dSGarrett Wollman void 7477b6ab19dSGarrett Wollman rip_on(struct interface *ifp) 7487b6ab19dSGarrett Wollman { 7497b6ab19dSGarrett Wollman /* If the main RIP socket is already alive, only start receiving 7507b6ab19dSGarrett Wollman * multicasts for this interface. 7517b6ab19dSGarrett Wollman */ 7527b6ab19dSGarrett Wollman if (rip_sock >= 0) { 753562c5a82SPedro F. Giffuni if (ifp != NULL) 7547b6ab19dSGarrett Wollman rip_mcast_on(ifp); 7557b6ab19dSGarrett Wollman return; 7567b6ab19dSGarrett Wollman } 7577b6ab19dSGarrett Wollman 7581608c04fSGarrett Wollman /* If the main RIP socket is off and it makes sense to turn it on, 7591608c04fSGarrett Wollman * then turn it on for all of the interfaces. 7602c7a9781SMark Murray * It makes sense if either router discovery is off, or if 7612c7a9781SMark Murray * router discover is on and at most one interface is doing RIP. 7627b6ab19dSGarrett Wollman */ 7632c7a9781SMark Murray if (rip_interfaces > 0 && (!rdisc_ok || rip_interfaces > 1)) { 7641608c04fSGarrett Wollman trace_act("turn on RIP"); 7657b6ab19dSGarrett Wollman 7667b6ab19dSGarrett Wollman /* Close all of the query sockets so that we can open 7677b6ab19dSGarrett Wollman * the main socket. SO_REUSEPORT is not a solution, 7687b6ab19dSGarrett Wollman * since that would let two daemons bind to the broadcast 7697b6ab19dSGarrett Wollman * socket. 7707b6ab19dSGarrett Wollman */ 77138ae6523SPoul-Henning Kamp LIST_FOREACH(ifp, &ifnet, int_list) { 7727b6ab19dSGarrett Wollman if (ifp->int_rip_sock >= 0) { 7737b6ab19dSGarrett Wollman (void)close(ifp->int_rip_sock); 7747b6ab19dSGarrett Wollman ifp->int_rip_sock = -1; 7757b6ab19dSGarrett Wollman } 7767b6ab19dSGarrett Wollman } 7777b6ab19dSGarrett Wollman 7787b6ab19dSGarrett Wollman rip_sock = get_rip_sock(INADDR_ANY, 1); 779562c5a82SPedro F. Giffuni rip_sock_mcast = NULL; 7807b6ab19dSGarrett Wollman 7817b6ab19dSGarrett Wollman /* Do not advertise anything until we have heard something 7827b6ab19dSGarrett Wollman */ 7837b6ab19dSGarrett Wollman if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME) 7847b6ab19dSGarrett Wollman next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME; 7857b6ab19dSGarrett Wollman 78638ae6523SPoul-Henning Kamp LIST_FOREACH(ifp, &ifnet, int_list) { 7871608c04fSGarrett Wollman ifp->int_query_time = NEVER; 7887b6ab19dSGarrett Wollman rip_mcast_on(ifp); 7897b6ab19dSGarrett Wollman } 7907b6ab19dSGarrett Wollman ifinit_timer.tv_sec = now.tv_sec; 7917b6ab19dSGarrett Wollman 792562c5a82SPedro F. Giffuni } else if (ifp != NULL 7931608c04fSGarrett Wollman && !(ifp->int_state & IS_REMOTE) 7941608c04fSGarrett Wollman && ifp->int_rip_sock < 0) { 7957b6ab19dSGarrett Wollman /* RIP is off, so ensure there are sockets on which 7967b6ab19dSGarrett Wollman * to listen for queries. 7977b6ab19dSGarrett Wollman */ 7987b6ab19dSGarrett Wollman ifp->int_rip_sock = get_rip_sock(ifp->int_addr, 0); 7991608c04fSGarrett Wollman } 8007b6ab19dSGarrett Wollman 8017b6ab19dSGarrett Wollman fix_select(); 8027b6ab19dSGarrett Wollman } 8037b6ab19dSGarrett Wollman 8047b6ab19dSGarrett Wollman 8057b6ab19dSGarrett Wollman /* die if malloc(3) fails 8067b6ab19dSGarrett Wollman */ 8077b6ab19dSGarrett Wollman void * 8087b6ab19dSGarrett Wollman rtmalloc(size_t size, 8092c7a9781SMark Murray const char *msg) 8107b6ab19dSGarrett Wollman { 8117b6ab19dSGarrett Wollman void *p = malloc(size); 812562c5a82SPedro F. Giffuni if (p == NULL) 8132c7a9781SMark Murray logbad(1,"malloc(%lu) failed in %s", (u_long)size, msg); 8147b6ab19dSGarrett Wollman return p; 8157b6ab19dSGarrett Wollman } 8167b6ab19dSGarrett Wollman 8177b6ab19dSGarrett Wollman 8187b6ab19dSGarrett Wollman /* get a random instant in an interval 8197b6ab19dSGarrett Wollman */ 8207b6ab19dSGarrett Wollman void 8217b6ab19dSGarrett Wollman intvl_random(struct timeval *tp, /* put value here */ 8227b6ab19dSGarrett Wollman u_long lo, /* value is after this second */ 8237b6ab19dSGarrett Wollman u_long hi) /* and before this */ 8247b6ab19dSGarrett Wollman { 8257b6ab19dSGarrett Wollman tp->tv_sec = (time_t)(hi == lo 8267b6ab19dSGarrett Wollman ? lo 827bdfd68dcSPedro F. Giffuni : (lo + arc4random_uniform(1 + hi - lo))); 828bdfd68dcSPedro F. Giffuni tp->tv_usec = arc4random_uniform(1000000); 8297b6ab19dSGarrett Wollman } 8307b6ab19dSGarrett Wollman 8317b6ab19dSGarrett Wollman 8327b6ab19dSGarrett Wollman void 8337b6ab19dSGarrett Wollman timevaladd(struct timeval *t1, 8347b6ab19dSGarrett Wollman struct timeval *t2) 8357b6ab19dSGarrett Wollman { 8367b6ab19dSGarrett Wollman 8377b6ab19dSGarrett Wollman t1->tv_sec += t2->tv_sec; 83890100551SPhilippe Charnier if ((t1->tv_usec += t2->tv_usec) >= 1000000) { 8397b6ab19dSGarrett Wollman t1->tv_sec++; 8407b6ab19dSGarrett Wollman t1->tv_usec -= 1000000; 8417b6ab19dSGarrett Wollman } 8427b6ab19dSGarrett Wollman } 8437b6ab19dSGarrett Wollman 8447b6ab19dSGarrett Wollman 8457b6ab19dSGarrett Wollman /* t1 = t2 - t3 8467b6ab19dSGarrett Wollman */ 8477b6ab19dSGarrett Wollman static void 8487b6ab19dSGarrett Wollman timevalsub(struct timeval *t1, 8497b6ab19dSGarrett Wollman struct timeval *t2, 8507b6ab19dSGarrett Wollman struct timeval *t3) 8517b6ab19dSGarrett Wollman { 8527b6ab19dSGarrett Wollman t1->tv_sec = t2->tv_sec - t3->tv_sec; 8537b6ab19dSGarrett Wollman if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) { 8547b6ab19dSGarrett Wollman t1->tv_sec--; 8557b6ab19dSGarrett Wollman t1->tv_usec += 1000000; 8567b6ab19dSGarrett Wollman } 8577b6ab19dSGarrett Wollman } 8587b6ab19dSGarrett Wollman 8597b6ab19dSGarrett Wollman 8601608c04fSGarrett Wollman /* put a message into the system log 8611608c04fSGarrett Wollman */ 8627b6ab19dSGarrett Wollman void 8632c7a9781SMark Murray msglog(const char *p, ...) 8647b6ab19dSGarrett Wollman { 8657b6ab19dSGarrett Wollman va_list args; 8667b6ab19dSGarrett Wollman 8677b6ab19dSGarrett Wollman trace_flush(); 8687b6ab19dSGarrett Wollman 8697b6ab19dSGarrett Wollman va_start(args, p); 8707b6ab19dSGarrett Wollman vsyslog(LOG_ERR, p, args); 871a4fff644STom Rhodes va_end(args); 872562c5a82SPedro F. Giffuni if (ftrace != NULL) { 8737b6ab19dSGarrett Wollman if (ftrace == stdout) 8747b6ab19dSGarrett Wollman (void)fputs("routed: ", ftrace); 875a4fff644STom Rhodes va_start(args, p); 8767b6ab19dSGarrett Wollman (void)vfprintf(ftrace, p, args); 877a4fff644STom Rhodes va_end(args); 8787b6ab19dSGarrett Wollman (void)fputc('\n', ftrace); 8797b6ab19dSGarrett Wollman } 8807b6ab19dSGarrett Wollman } 8817b6ab19dSGarrett Wollman 8827b6ab19dSGarrett Wollman 883a30febecSGarrett Wollman /* Put a message about a bad system into the system log if 8841608c04fSGarrett Wollman * we have not complained about it recently. 885a30febecSGarrett Wollman * 886a30febecSGarrett Wollman * It is desirable to complain about all bad systems, but not too often. 887a30febecSGarrett Wollman * In the worst case, it is not practical to keep track of all bad systems. 888a30febecSGarrett Wollman * For example, there can be many systems with the wrong password. 8891608c04fSGarrett Wollman */ 8901608c04fSGarrett Wollman void 8912c7a9781SMark Murray msglim(struct msg_limit *lim, naddr addr, const char *p, ...) 8921608c04fSGarrett Wollman { 8931608c04fSGarrett Wollman va_list args; 894a30febecSGarrett Wollman int i; 895a30febecSGarrett Wollman struct msg_sub *ms1, *ms; 8962c7a9781SMark Murray const char *p1; 8971608c04fSGarrett Wollman 898a30febecSGarrett Wollman /* look for the oldest slot in the table 899a30febecSGarrett Wollman * or the slot for the bad router. 900a30febecSGarrett Wollman */ 901a30febecSGarrett Wollman ms = ms1 = lim->subs; 902a30febecSGarrett Wollman for (i = MSG_SUBJECT_N; ; i--, ms1++) { 903a30febecSGarrett Wollman if (i == 0) { 904a30febecSGarrett Wollman /* Reuse a slot at most once every 10 minutes. 905a30febecSGarrett Wollman */ 906a30febecSGarrett Wollman if (lim->reuse > now.tv_sec) { 907562c5a82SPedro F. Giffuni ms = NULL; 908a30febecSGarrett Wollman } else { 909a30febecSGarrett Wollman ms = ms1; 910a30febecSGarrett Wollman lim->reuse = now.tv_sec + 10*60; 911a30febecSGarrett Wollman } 912a30febecSGarrett Wollman break; 913a30febecSGarrett Wollman } 914a30febecSGarrett Wollman if (ms->addr == addr) { 915a30febecSGarrett Wollman /* Repeat a complaint about a given system at 916a30febecSGarrett Wollman * most once an hour. 917a30febecSGarrett Wollman */ 918a30febecSGarrett Wollman if (ms->until > now.tv_sec) 919562c5a82SPedro F. Giffuni ms = NULL; 920a30febecSGarrett Wollman break; 921a30febecSGarrett Wollman } 922a30febecSGarrett Wollman if (ms->until < ms1->until) 923a30febecSGarrett Wollman ms = ms1; 924a30febecSGarrett Wollman } 925562c5a82SPedro F. Giffuni if (ms != NULL) { 926a30febecSGarrett Wollman ms->addr = addr; 927a30febecSGarrett Wollman ms->until = now.tv_sec + 60*60; /* 60 minutes */ 9281608c04fSGarrett Wollman 9291608c04fSGarrett Wollman trace_flush(); 9301608c04fSGarrett Wollman for (p1 = p; *p1 == ' '; p1++) 9311608c04fSGarrett Wollman continue; 932a4fff644STom Rhodes va_start(args, p); 9331608c04fSGarrett Wollman vsyslog(LOG_ERR, p1, args); 934a4fff644STom Rhodes va_end(args); 9351608c04fSGarrett Wollman } 9361608c04fSGarrett Wollman 937a30febecSGarrett Wollman /* always display the message if tracing */ 938562c5a82SPedro F. Giffuni if (ftrace != NULL) { 939a4fff644STom Rhodes va_start(args, p); 9401608c04fSGarrett Wollman (void)vfprintf(ftrace, p, args); 941a4fff644STom Rhodes va_end(args); 9421608c04fSGarrett Wollman (void)fputc('\n', ftrace); 9431608c04fSGarrett Wollman } 9441608c04fSGarrett Wollman } 9451608c04fSGarrett Wollman 9461608c04fSGarrett Wollman 9477b6ab19dSGarrett Wollman void 9482c7a9781SMark Murray logbad(int dump, const char *p, ...) 9497b6ab19dSGarrett Wollman { 9507b6ab19dSGarrett Wollman va_list args; 9517b6ab19dSGarrett Wollman 9527b6ab19dSGarrett Wollman trace_flush(); 9537b6ab19dSGarrett Wollman 9547b6ab19dSGarrett Wollman va_start(args, p); 9557b6ab19dSGarrett Wollman vsyslog(LOG_ERR, p, args); 956a4fff644STom Rhodes va_end(args); 9577b6ab19dSGarrett Wollman (void)fputs("routed: ", stderr); 958a4fff644STom Rhodes va_start(args, p); 9597b6ab19dSGarrett Wollman (void)vfprintf(stderr, p, args); 960a4fff644STom Rhodes va_end(args); 9617b6ab19dSGarrett Wollman (void)fputs("; giving up\n",stderr); 9627b6ab19dSGarrett Wollman (void)fflush(stderr); 9637b6ab19dSGarrett Wollman 9647b6ab19dSGarrett Wollman if (dump) 9657b6ab19dSGarrett Wollman abort(); 9667b6ab19dSGarrett Wollman exit(1); 9677b6ab19dSGarrett Wollman } 968