118316Swollman/* 218316Swollman * Copyright (c) 1983, 1988, 1993 318316Swollman * The Regents of the University of California. All rights reserved. 418316Swollman * 518316Swollman * Redistribution and use in source and binary forms, with or without 618316Swollman * modification, are permitted provided that the following conditions 718316Swollman * are met: 818316Swollman * 1. Redistributions of source code must retain the above copyright 918316Swollman * notice, this list of conditions and the following disclaimer. 1018316Swollman * 2. Redistributions in binary form must reproduce the above copyright 1118316Swollman * notice, this list of conditions and the following disclaimer in the 1218316Swollman * documentation and/or other materials provided with the distribution. 1318316Swollman * 4. Neither the name of the University nor the names of its contributors 1418316Swollman * may be used to endorse or promote products derived from this software 1518316Swollman * without specific prior written permission. 1618316Swollman * 1718316Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1818316Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1918316Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2018316Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2118316Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2218316Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2318316Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2418316Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2518316Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2618316Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2718316Swollman * SUCH DAMAGE. 2846303Smarkm * 2950476Speter * $FreeBSD$ 3018316Swollman */ 3118316Swollman 3218316Swollman#include "defs.h" 3346303Smarkm#include "pathnames.h" 3418316Swollman#ifdef sgi 3518316Swollman#include "math.h" 3618316Swollman#endif 3746303Smarkm#include <signal.h> 3818316Swollman#include <fcntl.h> 3946303Smarkm#include <sys/file.h> 4018316Swollman 41190710Sphk__COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993 " 42126250Sbms "The Regents of the University of California." 43190710Sphk " All rights reserved."); 44126250Sbms#ifdef __NetBSD__ 4546303Smarkm__RCSID("$NetBSD$"); 46126250Sbms#include <util.h> 47126250Sbms#elif defined(__FreeBSD__) 48126250Sbms__RCSID("$FreeBSD$"); 49126250Sbms#else 50163999Strhodes__RCSID("$Revision: 2.31 $"); 51163999Strhodes#ident "$Revision: 2.31 $" 5246303Smarkm#endif 5346303Smarkm 5418316Swollmanpid_t mypid; 5518316Swollman 5618316Swollmannaddr myaddr; /* system address */ 57190715Sphkstatic char myname[MAXHOSTNAMELEN+1]; 5818316Swollman 59190715Sphkstatic int verbose; 6046303Smarkm 6118316Swollmanint supplier; /* supply or broadcast updates */ 6218316Swollmanint supplier_set; 63190715Sphkstatic int ipforwarding = 1; /* kernel forwarding on */ 6418316Swollman 65190715Sphkstatic int default_gateway; /* 1=advertise default */ 66190715Sphkstatic int background = 1; 6718316Swollmanint ridhosts; /* 1=reduce host routes */ 6818316Swollmanint mhome; /* 1=want multi-homed host route */ 6937908Scharnierint advertise_mhome; /* 1=must continue advertising it */ 7018316Swollmanint auth_ok = 1; /* 1=ignore auth if we do not care */ 7118316Swollman 7218316Swollmanstruct timeval epoch; /* when started */ 73190715Sphkstruct timeval clk; 74190715Sphkstatic struct timeval prev_clk; 7546303Smarkmstatic int usec_fudge; 7618316Swollmanstruct timeval now; /* current idea of time */ 7718316Swollmantime_t now_stale; 7818316Swollmantime_t now_expire; 7918316Swollmantime_t now_garbage; 8018316Swollman 81190715Sphkstatic struct timeval next_bcast; /* next general broadcast */ 8264131Ssheldonhstruct timeval no_flash = { /* inhibit flash update */ 8364131Ssheldonh EPOCH+SUPPLY_INTERVAL, 0 8464131Ssheldonh}; 8518316Swollman 86190715Sphkstatic struct timeval flush_kern_timer; 8746303Smarkm 88190715Sphkstatic fd_set fdbits; 89190715Sphkstatic int sock_max; 9018316Swollmanint rip_sock = -1; /* RIP socket */ 91190716Sphkconst struct interface *rip_sock_mcast; /* current multicast interface */ 9218316Swollmanint rt_sock; /* routing socket */ 9318316Swollmanint rt_sock_seqno; 9418316Swollman 9518316Swollman 9618316Swollmanstatic int get_rip_sock(naddr, int); 9718316Swollmanstatic void timevalsub(struct timeval *, struct timeval *, struct timeval *); 98190715Sphkstatic void sigalrm(int s UNUSED); 99190715Sphkstatic void sigterm(int sig); 10018316Swollman 10118316Swollmanint 10218316Swollmanmain(int argc, 10318316Swollman char *argv[]) 10418316Swollman{ 10518316Swollman int n, mib[4], off; 10618316Swollman size_t len; 10718316Swollman char *p, *q; 10846303Smarkm const char *cp; 10918316Swollman struct timeval wtime, t2; 11018316Swollman time_t dt; 11118316Swollman fd_set ibits; 11219896Swollman naddr p_net, p_mask; 11318316Swollman struct interface *ifp; 11418316Swollman struct parm parm; 11518316Swollman char *tracename = 0; 11618316Swollman 11718316Swollman 11819896Swollman /* Some shells are badly broken and send SIGHUP to backgrounded 11919896Swollman * processes. 12019896Swollman */ 12119896Swollman signal(SIGHUP, SIG_IGN); 12219896Swollman 123126250Sbms openlog("routed", LOG_PID, LOG_DAEMON); 12418316Swollman ftrace = stdout; 12518316Swollman 12618316Swollman gettimeofday(&clk, 0); 12718316Swollman prev_clk = clk; 12818316Swollman epoch = clk; 12918316Swollman epoch.tv_sec -= EPOCH; 13018316Swollman now.tv_sec = EPOCH; 13118316Swollman now_stale = EPOCH - STALE_TIME; 13218316Swollman now_expire = EPOCH - EXPIRE_TIME; 13318316Swollman now_garbage = EPOCH - GARBAGE_TIME; 13418316Swollman wtime.tv_sec = 0; 13518316Swollman 13618316Swollman (void)gethostname(myname, sizeof(myname)-1); 13718316Swollman (void)gethost(myname, &myaddr); 13818316Swollman 139163999Strhodes while ((n = getopt(argc, argv, "sqdghmAtvT:F:P:")) != -1) { 14018316Swollman switch (n) { 14118316Swollman case 's': 14218316Swollman supplier = 1; 14318316Swollman supplier_set = 1; 14418316Swollman break; 14518316Swollman 14618316Swollman case 'q': 14718316Swollman supplier = 0; 14818316Swollman supplier_set = 1; 14918316Swollman break; 15018316Swollman 15118316Swollman case 'd': 15218316Swollman background = 0; 15318316Swollman break; 15418316Swollman 15518316Swollman case 'g': 15646303Smarkm memset(&parm, 0, sizeof(parm)); 15718316Swollman parm.parm_d_metric = 1; 15846303Smarkm cp = check_parms(&parm); 15946303Smarkm if (cp != 0) 16046303Smarkm msglog("bad -g: %s", cp); 16118316Swollman else 16218316Swollman default_gateway = 1; 16318316Swollman break; 16418316Swollman 16518316Swollman case 'h': /* suppress extra host routes */ 16618316Swollman ridhosts = 1; 16718316Swollman break; 16818316Swollman 16918316Swollman case 'm': /* advertise host route */ 17018316Swollman mhome = 1; /* on multi-homed hosts */ 17118316Swollman break; 17218316Swollman 17318316Swollman case 'A': 17418316Swollman /* Ignore authentication if we do not care. 17518316Swollman * Crazy as it is, that is what RFC 1723 requires. 17618316Swollman */ 17718316Swollman auth_ok = 0; 17818316Swollman break; 17918316Swollman 18018316Swollman case 't': 18118316Swollman new_tracelevel++; 18218316Swollman break; 18318316Swollman 18418316Swollman case 'T': 18518316Swollman tracename = optarg; 18618316Swollman break; 18718316Swollman 18818316Swollman case 'F': /* minimal routes for SLIP */ 18919896Swollman n = FAKE_METRIC; 19018316Swollman p = strchr(optarg,','); 19118316Swollman if (p && *p != '\0') { 19218316Swollman n = (int)strtoul(p+1, &q, 0); 19318316Swollman if (*q == '\0' 19418316Swollman && n <= HOPCNT_INFINITY-1 19518316Swollman && n >= 1) 19618316Swollman *p = '\0'; 19718316Swollman } 19819896Swollman if (!getnet(optarg, &p_net, &p_mask)) { 19918316Swollman msglog("bad network; \"-F %s\"", 20018316Swollman optarg); 20118316Swollman break; 20218316Swollman } 20346303Smarkm memset(&parm, 0, sizeof(parm)); 20419896Swollman parm.parm_net = p_net; 20518316Swollman parm.parm_mask = p_mask; 20618316Swollman parm.parm_d_metric = n; 20746303Smarkm cp = check_parms(&parm); 20846303Smarkm if (cp != 0) 20946303Smarkm msglog("bad -F: %s", cp); 21018316Swollman break; 21118316Swollman 21218316Swollman case 'P': 21346303Smarkm /* handle arbitrary parameters. 21418316Swollman */ 21546303Smarkm q = strdup(optarg); 21646303Smarkm cp = parse_parms(q, 0); 21746303Smarkm if (cp != 0) 21846303Smarkm msglog("%s in \"-P %s\"", cp, optarg); 21946303Smarkm free(q); 22018316Swollman break; 22118316Swollman 22246303Smarkm case 'v': 22346303Smarkm /* display version */ 22446303Smarkm verbose++; 225163999Strhodes msglog("version 2.31"); 22646303Smarkm break; 22746303Smarkm 22818316Swollman default: 22918316Swollman goto usage; 23018316Swollman } 23118316Swollman } 23218316Swollman argc -= optind; 23318316Swollman argv += optind; 23418316Swollman 23518316Swollman if (tracename == 0 && argc >= 1) { 23618316Swollman tracename = *argv++; 23718316Swollman argc--; 23818316Swollman } 23920342Swollman if (tracename != 0 && tracename[0] == '\0') 24020342Swollman goto usage; 24118316Swollman if (argc != 0) { 24218316Swollmanusage: 243163999Strhodes logbad(0, "usage: routed [-sqdghmAtv] [-T tracefile]" 24446303Smarkm " [-F net[,metric]] [-P parms]"); 24518316Swollman } 24646303Smarkm if (geteuid() != 0) { 24746303Smarkm if (verbose) 24846303Smarkm exit(0); 24918316Swollman logbad(0, "requires UID 0"); 25046303Smarkm } 25118316Swollman 25218316Swollman mib[0] = CTL_NET; 25318316Swollman mib[1] = PF_INET; 25418316Swollman mib[2] = IPPROTO_IP; 25518316Swollman mib[3] = IPCTL_FORWARDING; 25618316Swollman len = sizeof(ipforwarding); 25718316Swollman if (sysctl(mib, 4, &ipforwarding, &len, 0, 0) < 0) 25818316Swollman LOGERR("sysctl(IPCTL_FORWARDING)"); 25918316Swollman 26018316Swollman if (!ipforwarding) { 26118316Swollman if (supplier) 26218316Swollman msglog("-s incompatible with ipforwarding=0"); 26318316Swollman if (default_gateway) { 26418316Swollman msglog("-g incompatible with ipforwarding=0"); 26518316Swollman default_gateway = 0; 26618316Swollman } 26718316Swollman supplier = 0; 26818316Swollman supplier_set = 1; 26918316Swollman } 27018316Swollman if (default_gateway) { 27118316Swollman if (supplier_set && !supplier) { 27218316Swollman msglog("-g and -q incompatible"); 27318316Swollman } else { 27418316Swollman supplier = 1; 27518316Swollman supplier_set = 1; 27618316Swollman } 27718316Swollman } 27818316Swollman 27918316Swollman 28018316Swollman signal(SIGALRM, sigalrm); 28118316Swollman if (!background) 28218316Swollman signal(SIGHUP, sigterm); /* SIGHUP fatal during debugging */ 28318316Swollman signal(SIGTERM, sigterm); 28418316Swollman signal(SIGINT, sigterm); 28518316Swollman signal(SIGUSR1, sigtrace_on); 28618316Swollman signal(SIGUSR2, sigtrace_off); 28718316Swollman 28818316Swollman /* get into the background */ 28918316Swollman#ifdef sgi 29020342Swollman if (0 > _daemonize(background ? 0 : (_DF_NOCHDIR|_DF_NOFORK), 29146303Smarkm STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)) 29220342Swollman BADERR(0, "_daemonize()"); 29318316Swollman#else 29446303Smarkm if (background && daemon(0, 1) < 0) 29520342Swollman BADERR(0,"daemon()"); 29618316Swollman#endif 29718316Swollman 298126250Sbms#if defined(__NetBSD__) 299126250Sbms pidfile(0); 300126250Sbms#endif 30118316Swollman mypid = getpid(); 302110670Sache#ifdef __FreeBSD__ 303110670Sache srandomdev(); 304110670Sache#else 30518316Swollman srandom((int)(clk.tv_sec ^ clk.tv_usec ^ mypid)); 306110670Sache#endif 30718316Swollman 30818316Swollman /* prepare socket connected to the kernel. 30918316Swollman */ 31018316Swollman rt_sock = socket(AF_ROUTE, SOCK_RAW, 0); 31118316Swollman if (rt_sock < 0) 31218316Swollman BADERR(1,"rt_sock = socket()"); 31318316Swollman if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1) 31418316Swollman logbad(1, "fcntl(rt_sock) O_NONBLOCK: %s", strerror(errno)); 31518316Swollman off = 0; 31618316Swollman if (setsockopt(rt_sock, SOL_SOCKET,SO_USELOOPBACK, 31718316Swollman &off,sizeof(off)) < 0) 31818316Swollman LOGERR("setsockopt(SO_USELOOPBACK,0)"); 31918316Swollman 32018316Swollman fix_select(); 32118316Swollman 32218316Swollman 32318316Swollman if (tracename != 0) { 32420342Swollman strncpy(inittracename, tracename, sizeof(inittracename)-1); 32546303Smarkm set_tracefile(inittracename, "%s", -1); 32620342Swollman } else { 32746303Smarkm tracelevel_msg("%s", -1); /* turn on tracing to stdio */ 32818316Swollman } 32918316Swollman 33019896Swollman bufinit(); 33119896Swollman 33218316Swollman /* initialize radix tree */ 33318316Swollman rtinit(); 33418316Swollman 33518316Swollman /* Pick a random part of the second for our output to minimize 33618316Swollman * collisions. 33718316Swollman * 33818316Swollman * Start broadcasting after hearing from other routers, and 33918316Swollman * at a random time so a bunch of systems do not get synchronized 34018316Swollman * after a power failure. 34118316Swollman */ 34218316Swollman intvl_random(&next_bcast, EPOCH+MIN_WAITTIME, EPOCH+SUPPLY_INTERVAL); 34318316Swollman age_timer.tv_usec = next_bcast.tv_usec; 34418316Swollman age_timer.tv_sec = EPOCH+MIN_WAITTIME; 34518316Swollman rdisc_timer = next_bcast; 34618316Swollman ifinit_timer.tv_usec = next_bcast.tv_usec; 34718316Swollman 34818316Swollman /* Collect an initial view of the world by checking the interface 34918316Swollman * configuration and the kludge file. 35018316Swollman */ 35118316Swollman gwkludge(); 35218316Swollman ifinit(); 35318316Swollman 35418316Swollman /* Ask for routes */ 35518316Swollman rip_query(); 35619896Swollman rdisc_sol(); 35718316Swollman 35846303Smarkm /* Now turn off stdio if not tracing */ 35946303Smarkm if (new_tracelevel == 0) 36046303Smarkm trace_close(background); 36146303Smarkm 36218316Swollman /* Loop forever, listening and broadcasting. 36318316Swollman */ 36418316Swollman for (;;) { 36518316Swollman prev_clk = clk; 36618316Swollman gettimeofday(&clk, 0); 36746303Smarkm if (prev_clk.tv_sec == clk.tv_sec 36846303Smarkm && prev_clk.tv_usec == clk.tv_usec+usec_fudge) { 36946303Smarkm /* Much of `routed` depends on time always advancing. 37046303Smarkm * On systems that do not guarantee that gettimeofday() 37146303Smarkm * produces unique timestamps even if called within 37246303Smarkm * a single tick, use trickery like that in classic 37346303Smarkm * BSD kernels. 37418316Swollman */ 37546303Smarkm clk.tv_usec += ++usec_fudge; 37646303Smarkm 37746303Smarkm } else { 37846303Smarkm usec_fudge = 0; 37946303Smarkm 38046303Smarkm timevalsub(&t2, &clk, &prev_clk); 38146303Smarkm if (t2.tv_sec < 0 38246303Smarkm || t2.tv_sec > wtime.tv_sec + 5) { 38346303Smarkm /* Deal with time changes before other 38446303Smarkm * housekeeping to keep everything straight. 38546303Smarkm */ 38646303Smarkm dt = t2.tv_sec; 38746303Smarkm if (dt > 0) 38846303Smarkm dt -= wtime.tv_sec; 38946303Smarkm trace_act("time changed by %d sec", (int)dt); 39046303Smarkm epoch.tv_sec += dt; 39146303Smarkm } 39218316Swollman } 39318316Swollman timevalsub(&now, &clk, &epoch); 39418316Swollman now_stale = now.tv_sec - STALE_TIME; 39518316Swollman now_expire = now.tv_sec - EXPIRE_TIME; 39618316Swollman now_garbage = now.tv_sec - GARBAGE_TIME; 39718316Swollman 39820342Swollman /* deal with signals that should affect tracing */ 39920342Swollman set_tracelevel(); 40018316Swollman 40118316Swollman if (stopint != 0) { 40219896Swollman rip_bcast(0); 40319896Swollman rdisc_adv(); 40446303Smarkm trace_off("exiting with signal %d", stopint); 40518316Swollman exit(stopint | 128); 40618316Swollman } 40718316Swollman 40818316Swollman /* look for new or dead interfaces */ 40918316Swollman timevalsub(&wtime, &ifinit_timer, &now); 41018316Swollman if (wtime.tv_sec <= 0) { 41118316Swollman wtime.tv_sec = 0; 41218316Swollman ifinit(); 41318316Swollman rip_query(); 41418316Swollman continue; 41518316Swollman } 41618316Swollman 417229778Suqs /* Check the kernel table occasionally for mysteriously 41846303Smarkm * evaporated routes 41946303Smarkm */ 42046303Smarkm timevalsub(&t2, &flush_kern_timer, &now); 42146303Smarkm if (t2.tv_sec <= 0) { 42246303Smarkm flush_kern(); 42346303Smarkm flush_kern_timer.tv_sec = (now.tv_sec 42446303Smarkm + CHECK_QUIET_INTERVAL); 42546303Smarkm continue; 42646303Smarkm } 42746303Smarkm if (timercmp(&t2, &wtime, <)) 42846303Smarkm wtime = t2; 42946303Smarkm 43018316Swollman /* If it is time, then broadcast our routes. 43118316Swollman */ 43218316Swollman if (supplier || advertise_mhome) { 43318316Swollman timevalsub(&t2, &next_bcast, &now); 43418316Swollman if (t2.tv_sec <= 0) { 43518316Swollman /* Synchronize the aging and broadcast 43618316Swollman * timers to minimize awakenings 43718316Swollman */ 43818316Swollman age(0); 43918316Swollman 44018316Swollman rip_bcast(0); 44118316Swollman 44218316Swollman /* It is desirable to send routing updates 44318316Swollman * regularly. So schedule the next update 44418316Swollman * 30 seconds after the previous one was 44529314Sdanny * scheduled, instead of 30 seconds after 44618316Swollman * the previous update was finished. 44718316Swollman * Even if we just started after discovering 44818316Swollman * a 2nd interface or were otherwise delayed, 449229778Suqs * pick a 30-second anniversary of the 45018316Swollman * original broadcast time. 45118316Swollman */ 45218316Swollman n = 1 + (0-t2.tv_sec)/SUPPLY_INTERVAL; 45318316Swollman next_bcast.tv_sec += n*SUPPLY_INTERVAL; 45418316Swollman 45518316Swollman continue; 45618316Swollman } 45718316Swollman 45818316Swollman if (timercmp(&t2, &wtime, <)) 45918316Swollman wtime = t2; 46018316Swollman } 46118316Swollman 46218316Swollman /* If we need a flash update, either do it now or 46318316Swollman * set the delay to end when it is time. 46418316Swollman * 46518316Swollman * If we are within MIN_WAITTIME seconds of a full update, 46618316Swollman * do not bother. 46718316Swollman */ 46818316Swollman if (need_flash 46918316Swollman && supplier 47018316Swollman && no_flash.tv_sec+MIN_WAITTIME < next_bcast.tv_sec) { 47118316Swollman /* accurate to the millisecond */ 47218316Swollman if (!timercmp(&no_flash, &now, >)) 47318316Swollman rip_bcast(1); 47418316Swollman timevalsub(&t2, &no_flash, &now); 47518316Swollman if (timercmp(&t2, &wtime, <)) 47618316Swollman wtime = t2; 47718316Swollman } 47818316Swollman 47918316Swollman /* trigger the main aging timer. 48018316Swollman */ 48118316Swollman timevalsub(&t2, &age_timer, &now); 48218316Swollman if (t2.tv_sec <= 0) { 48318316Swollman age(0); 48418316Swollman continue; 48518316Swollman } 48618316Swollman if (timercmp(&t2, &wtime, <)) 48718316Swollman wtime = t2; 48818316Swollman 48918316Swollman /* update the kernel routing table 49018316Swollman */ 49118316Swollman timevalsub(&t2, &need_kern, &now); 49218316Swollman if (t2.tv_sec <= 0) { 49318316Swollman age(0); 49418316Swollman continue; 49518316Swollman } 49618316Swollman if (timercmp(&t2, &wtime, <)) 49718316Swollman wtime = t2; 49818316Swollman 49918316Swollman /* take care of router discovery, 50046303Smarkm * but do it in the correct the millisecond 50118316Swollman */ 50218316Swollman if (!timercmp(&rdisc_timer, &now, >)) { 50318316Swollman rdisc_age(0); 50418316Swollman continue; 50518316Swollman } 50618316Swollman timevalsub(&t2, &rdisc_timer, &now); 50718316Swollman if (timercmp(&t2, &wtime, <)) 50818316Swollman wtime = t2; 50918316Swollman 51018316Swollman 51118316Swollman /* wait for input or a timer to expire. 51218316Swollman */ 51318316Swollman trace_flush(); 51418316Swollman ibits = fdbits; 51518316Swollman n = select(sock_max, &ibits, 0, 0, &wtime); 51618316Swollman if (n <= 0) { 51718316Swollman if (n < 0 && errno != EINTR && errno != EAGAIN) 51818316Swollman BADERR(1,"select"); 51918316Swollman continue; 52018316Swollman } 52118316Swollman 52218316Swollman if (FD_ISSET(rt_sock, &ibits)) { 52318316Swollman read_rt(); 52418316Swollman n--; 52518316Swollman } 52618316Swollman if (rdisc_sock >= 0 && FD_ISSET(rdisc_sock, &ibits)) { 52718316Swollman read_d(); 52818316Swollman n--; 52918316Swollman } 53018316Swollman if (rip_sock >= 0 && FD_ISSET(rip_sock, &ibits)) { 53118316Swollman read_rip(rip_sock, 0); 53218316Swollman n--; 53318316Swollman } 53418316Swollman 535190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 536190711Sphk if (n <= 0) 537190711Sphk break; 53818316Swollman if (ifp->int_rip_sock >= 0 53918316Swollman && FD_ISSET(ifp->int_rip_sock, &ibits)) { 54018316Swollman read_rip(ifp->int_rip_sock, ifp); 54118316Swollman n--; 54218316Swollman } 54318316Swollman } 54418316Swollman } 54518316Swollman} 54618316Swollman 54718316Swollman 54818316Swollman/* ARGSUSED */ 549190715Sphkstatic void 55046303Smarkmsigalrm(int s UNUSED) 55118316Swollman{ 55218316Swollman /* Historically, SIGALRM would cause the daemon to check for 55318316Swollman * new and broken interfaces. 55418316Swollman */ 55518316Swollman ifinit_timer.tv_sec = now.tv_sec; 55619896Swollman trace_act("SIGALRM"); 55718316Swollman} 55818316Swollman 55918316Swollman 56018316Swollman/* watch for fatal signals */ 561190715Sphkstatic void 56218316Swollmansigterm(int sig) 56318316Swollman{ 56418316Swollman stopint = sig; 56518316Swollman (void)signal(sig, SIG_DFL); /* catch it only once */ 56618316Swollman} 56718316Swollman 56818316Swollman 56918316Swollmanvoid 57018316Swollmanfix_select(void) 57118316Swollman{ 57218316Swollman struct interface *ifp; 57318316Swollman 57418316Swollman 57518316Swollman FD_ZERO(&fdbits); 57618316Swollman sock_max = 0; 57718316Swollman 57818316Swollman FD_SET(rt_sock, &fdbits); 57918316Swollman if (sock_max <= rt_sock) 58018316Swollman sock_max = rt_sock+1; 58118316Swollman if (rip_sock >= 0) { 58218316Swollman FD_SET(rip_sock, &fdbits); 58318316Swollman if (sock_max <= rip_sock) 58418316Swollman sock_max = rip_sock+1; 58518316Swollman } 586190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 58718316Swollman if (ifp->int_rip_sock >= 0) { 58818316Swollman FD_SET(ifp->int_rip_sock, &fdbits); 58918316Swollman if (sock_max <= ifp->int_rip_sock) 59018316Swollman sock_max = ifp->int_rip_sock+1; 59118316Swollman } 59218316Swollman } 59318316Swollman if (rdisc_sock >= 0) { 59418316Swollman FD_SET(rdisc_sock, &fdbits); 59518316Swollman if (sock_max <= rdisc_sock) 59618316Swollman sock_max = rdisc_sock+1; 59718316Swollman } 59818316Swollman} 59918316Swollman 60018316Swollman 60118316Swollmanvoid 60218316Swollmanfix_sock(int sock, 60346303Smarkm const char *name) 60418316Swollman{ 60518316Swollman int on; 60618316Swollman#define MIN_SOCKBUF (4*1024) 60718316Swollman static int rbuf; 60818316Swollman 60918316Swollman if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) 61018316Swollman logbad(1, "fcntl(%s) O_NONBLOCK: %s", 61118316Swollman name, strerror(errno)); 61218316Swollman on = 1; 61319896Swollman if (setsockopt(sock, SOL_SOCKET,SO_BROADCAST, &on,sizeof(on)) < 0) 61418316Swollman msglog("setsockopt(%s,SO_BROADCAST): %s", 61518316Swollman name, strerror(errno)); 61619896Swollman#ifdef USE_PASSIFNAME 61719896Swollman on = 1; 61819896Swollman if (setsockopt(sock, SOL_SOCKET, SO_PASSIFNAME, &on,sizeof(on)) < 0) 61919896Swollman msglog("setsockopt(%s,SO_PASSIFNAME): %s", 62019896Swollman name, strerror(errno)); 62119896Swollman#endif 62219896Swollman 62318316Swollman if (rbuf >= MIN_SOCKBUF) { 62418316Swollman if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 62518316Swollman &rbuf, sizeof(rbuf)) < 0) 62618316Swollman msglog("setsockopt(%s,SO_RCVBUF=%d): %s", 62718316Swollman name, rbuf, strerror(errno)); 62818316Swollman } else { 62918316Swollman for (rbuf = 60*1024; ; rbuf -= 4096) { 63018316Swollman if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 63118316Swollman &rbuf, sizeof(rbuf)) == 0) { 63219896Swollman trace_act("RCVBUF=%d", rbuf); 63318316Swollman break; 63418316Swollman } 63518316Swollman if (rbuf < MIN_SOCKBUF) { 63618316Swollman msglog("setsockopt(%s,SO_RCVBUF = %d): %s", 63718316Swollman name, rbuf, strerror(errno)); 63818316Swollman break; 63918316Swollman } 64018316Swollman } 64118316Swollman } 64218316Swollman} 64318316Swollman 64418316Swollman 64518316Swollman/* get a rip socket 64618316Swollman */ 64718316Swollmanstatic int /* <0 or file descriptor */ 64818316Swollmanget_rip_sock(naddr addr, 64918316Swollman int serious) /* 1=failure to bind is serious */ 65018316Swollman{ 651126250Sbms struct sockaddr_in rsin; 65218316Swollman unsigned char ttl; 65318316Swollman int s; 65418316Swollman 65518316Swollman 65618316Swollman if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 65718316Swollman BADERR(1,"rip_sock = socket()"); 65818316Swollman 659126250Sbms memset(&rsin, 0, sizeof(rsin)); 66018316Swollman#ifdef _HAVE_SIN_LEN 661126250Sbms rsin.sin_len = sizeof(rsin); 66218316Swollman#endif 663126250Sbms rsin.sin_family = AF_INET; 664126250Sbms rsin.sin_port = htons(RIP_PORT); 665126250Sbms rsin.sin_addr.s_addr = addr; 666126250Sbms if (bind(s, (struct sockaddr *)&rsin, sizeof(rsin)) < 0) { 66718316Swollman if (serious) 66818316Swollman BADERR(errno != EADDRINUSE, "bind(rip_sock)"); 66918316Swollman return -1; 67018316Swollman } 67118316Swollman fix_sock(s,"rip_sock"); 67218316Swollman 67318316Swollman ttl = 1; 67418316Swollman if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, 67518316Swollman &ttl, sizeof(ttl)) < 0) 67618316Swollman DBGERR(1,"rip_sock setsockopt(IP_MULTICAST_TTL)"); 67718316Swollman 67818316Swollman return s; 67918316Swollman} 68018316Swollman 68118316Swollman 68218316Swollman/* turn off main RIP socket */ 68318316Swollmanvoid 68418316Swollmanrip_off(void) 68518316Swollman{ 68618316Swollman struct interface *ifp; 68746303Smarkm naddr addr; 68818316Swollman 68918316Swollman 69018316Swollman if (rip_sock >= 0 && !mhome) { 69119896Swollman trace_act("turn off RIP"); 69218316Swollman 69318316Swollman (void)close(rip_sock); 69418316Swollman rip_sock = -1; 69518316Swollman 69618316Swollman /* get non-broadcast sockets to listen to queries. 69718316Swollman */ 698190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 69919896Swollman if (ifp->int_state & IS_REMOTE) 70019896Swollman continue; 70119896Swollman if (ifp->int_rip_sock < 0) { 70218316Swollman addr = ((ifp->int_if_flags & IFF_POINTOPOINT) 70318316Swollman ? ifp->int_dstaddr 70418316Swollman : ifp->int_addr); 70518316Swollman ifp->int_rip_sock = get_rip_sock(addr, 0); 70618316Swollman } 70718316Swollman } 70818316Swollman 70918316Swollman fix_select(); 71018316Swollman 71118316Swollman age(0); 71218316Swollman } 71318316Swollman} 71418316Swollman 71518316Swollman 71618316Swollman/* turn on RIP multicast input via an interface 71718316Swollman */ 71818316Swollmanstatic void 71918316Swollmanrip_mcast_on(struct interface *ifp) 72018316Swollman{ 721180993Sphk struct group_req gr; 722180993Sphk struct sockaddr_in *sin; 72318316Swollman 72418316Swollman if (!IS_RIP_IN_OFF(ifp->int_state) 72518316Swollman && (ifp->int_if_flags & IFF_MULTICAST) 72618316Swollman && !(ifp->int_state & IS_ALIAS)) { 727180993Sphk memset(&gr, 0, sizeof(gr)); 728180993Sphk gr.gr_interface = ifp->int_index; 729180993Sphk sin = (struct sockaddr_in *)&gr.gr_group; 730180993Sphk sin->sin_family = AF_INET; 731180993Sphk#ifdef _HAVE_SIN_LEN 732180993Sphk sin->sin_len = sizeof(struct sockaddr_in); 733126250Sbms#endif 734180993Sphk sin->sin_addr.s_addr = htonl(INADDR_RIP_GROUP); 735180993Sphk if (setsockopt(rip_sock, IPPROTO_IP, MCAST_JOIN_GROUP, 736180993Sphk &gr, sizeof(gr)) < 0) 737180993Sphk LOGERR("setsockopt(MCAST_JOIN_GROUP RIP)"); 73818316Swollman } 73918316Swollman} 74018316Swollman 74118316Swollman 74218316Swollman/* Prepare socket used for RIP. 74318316Swollman */ 74418316Swollmanvoid 74518316Swollmanrip_on(struct interface *ifp) 74618316Swollman{ 74718316Swollman /* If the main RIP socket is already alive, only start receiving 74818316Swollman * multicasts for this interface. 74918316Swollman */ 75018316Swollman if (rip_sock >= 0) { 75118316Swollman if (ifp != 0) 75218316Swollman rip_mcast_on(ifp); 75318316Swollman return; 75418316Swollman } 75518316Swollman 75619896Swollman /* If the main RIP socket is off and it makes sense to turn it on, 75719896Swollman * then turn it on for all of the interfaces. 75846303Smarkm * It makes sense if either router discovery is off, or if 75946303Smarkm * router discover is on and at most one interface is doing RIP. 76018316Swollman */ 76146303Smarkm if (rip_interfaces > 0 && (!rdisc_ok || rip_interfaces > 1)) { 76219896Swollman trace_act("turn on RIP"); 76318316Swollman 76418316Swollman /* Close all of the query sockets so that we can open 76518316Swollman * the main socket. SO_REUSEPORT is not a solution, 76618316Swollman * since that would let two daemons bind to the broadcast 76718316Swollman * socket. 76818316Swollman */ 769190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 77018316Swollman if (ifp->int_rip_sock >= 0) { 77118316Swollman (void)close(ifp->int_rip_sock); 77218316Swollman ifp->int_rip_sock = -1; 77318316Swollman } 77418316Swollman } 77518316Swollman 77618316Swollman rip_sock = get_rip_sock(INADDR_ANY, 1); 77718316Swollman rip_sock_mcast = 0; 77818316Swollman 77918316Swollman /* Do not advertise anything until we have heard something 78018316Swollman */ 78118316Swollman if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME) 78218316Swollman next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME; 78318316Swollman 784190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 78519896Swollman ifp->int_query_time = NEVER; 78618316Swollman rip_mcast_on(ifp); 78718316Swollman } 78818316Swollman ifinit_timer.tv_sec = now.tv_sec; 78918316Swollman 79018316Swollman } else if (ifp != 0 79119896Swollman && !(ifp->int_state & IS_REMOTE) 79219896Swollman && ifp->int_rip_sock < 0) { 79318316Swollman /* RIP is off, so ensure there are sockets on which 79418316Swollman * to listen for queries. 79518316Swollman */ 79618316Swollman ifp->int_rip_sock = get_rip_sock(ifp->int_addr, 0); 79719896Swollman } 79818316Swollman 79919896Swollman fix_select(); 80018316Swollman} 80118316Swollman 80218316Swollman 80318316Swollman/* die if malloc(3) fails 80418316Swollman */ 80518316Swollmanvoid * 80618316Swollmanrtmalloc(size_t size, 80746303Smarkm const char *msg) 80818316Swollman{ 80918316Swollman void *p = malloc(size); 81046303Smarkm if (p == 0) 81146303Smarkm logbad(1,"malloc(%lu) failed in %s", (u_long)size, msg); 81218316Swollman return p; 81318316Swollman} 81418316Swollman 81518316Swollman 81618316Swollman/* get a random instant in an interval 81718316Swollman */ 81818316Swollmanvoid 81918316Swollmanintvl_random(struct timeval *tp, /* put value here */ 82018316Swollman u_long lo, /* value is after this second */ 82118316Swollman u_long hi) /* and before this */ 82218316Swollman{ 82318316Swollman tp->tv_sec = (time_t)(hi == lo 82418316Swollman ? lo 82518316Swollman : (lo + random() % ((hi - lo)))); 82618316Swollman tp->tv_usec = random() % 1000000; 82718316Swollman} 82818316Swollman 82918316Swollman 83018316Swollmanvoid 83118316Swollmantimevaladd(struct timeval *t1, 83218316Swollman struct timeval *t2) 83318316Swollman{ 83418316Swollman 83518316Swollman t1->tv_sec += t2->tv_sec; 83637908Scharnier if ((t1->tv_usec += t2->tv_usec) >= 1000000) { 83718316Swollman t1->tv_sec++; 83818316Swollman t1->tv_usec -= 1000000; 83918316Swollman } 84018316Swollman} 84118316Swollman 84218316Swollman 84318316Swollman/* t1 = t2 - t3 84418316Swollman */ 84518316Swollmanstatic void 84618316Swollmantimevalsub(struct timeval *t1, 84718316Swollman struct timeval *t2, 84818316Swollman struct timeval *t3) 84918316Swollman{ 85018316Swollman t1->tv_sec = t2->tv_sec - t3->tv_sec; 85118316Swollman if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) { 85218316Swollman t1->tv_sec--; 85318316Swollman t1->tv_usec += 1000000; 85418316Swollman } 85518316Swollman} 85618316Swollman 85718316Swollman 85819896Swollman/* put a message into the system log 85919896Swollman */ 86018316Swollmanvoid 86146303Smarkmmsglog(const char *p, ...) 86218316Swollman{ 86318316Swollman va_list args; 86418316Swollman 86518316Swollman trace_flush(); 86618316Swollman 86718316Swollman va_start(args, p); 86818316Swollman vsyslog(LOG_ERR, p, args); 869163999Strhodes va_end(args); 87018316Swollman if (ftrace != 0) { 87118316Swollman if (ftrace == stdout) 87218316Swollman (void)fputs("routed: ", ftrace); 873163999Strhodes va_start(args, p); 87418316Swollman (void)vfprintf(ftrace, p, args); 875163999Strhodes va_end(args); 87618316Swollman (void)fputc('\n', ftrace); 87718316Swollman } 87818316Swollman} 87918316Swollman 88018316Swollman 88120342Swollman/* Put a message about a bad system into the system log if 88219896Swollman * we have not complained about it recently. 88320342Swollman * 88420342Swollman * It is desirable to complain about all bad systems, but not too often. 88520342Swollman * In the worst case, it is not practical to keep track of all bad systems. 88620342Swollman * For example, there can be many systems with the wrong password. 88719896Swollman */ 88818316Swollmanvoid 88946303Smarkmmsglim(struct msg_limit *lim, naddr addr, const char *p, ...) 89019896Swollman{ 89119896Swollman va_list args; 89220342Swollman int i; 89320342Swollman struct msg_sub *ms1, *ms; 89446303Smarkm const char *p1; 89519896Swollman 89620342Swollman /* look for the oldest slot in the table 89720342Swollman * or the slot for the bad router. 89820342Swollman */ 89920342Swollman ms = ms1 = lim->subs; 90020342Swollman for (i = MSG_SUBJECT_N; ; i--, ms1++) { 90120342Swollman if (i == 0) { 90220342Swollman /* Reuse a slot at most once every 10 minutes. 90320342Swollman */ 90420342Swollman if (lim->reuse > now.tv_sec) { 90520342Swollman ms = 0; 90620342Swollman } else { 90720342Swollman ms = ms1; 90820342Swollman lim->reuse = now.tv_sec + 10*60; 90920342Swollman } 91020342Swollman break; 91120342Swollman } 91220342Swollman if (ms->addr == addr) { 91320342Swollman /* Repeat a complaint about a given system at 91420342Swollman * most once an hour. 91520342Swollman */ 91620342Swollman if (ms->until > now.tv_sec) 91720342Swollman ms = 0; 91820342Swollman break; 91920342Swollman } 92020342Swollman if (ms->until < ms1->until) 92120342Swollman ms = ms1; 92220342Swollman } 92320342Swollman if (ms != 0) { 92420342Swollman ms->addr = addr; 92520342Swollman ms->until = now.tv_sec + 60*60; /* 60 minutes */ 92619896Swollman 92719896Swollman trace_flush(); 92819896Swollman for (p1 = p; *p1 == ' '; p1++) 92919896Swollman continue; 930163999Strhodes va_start(args, p); 93119896Swollman vsyslog(LOG_ERR, p1, args); 932163999Strhodes va_end(args); 93319896Swollman } 93419896Swollman 93520342Swollman /* always display the message if tracing */ 93619896Swollman if (ftrace != 0) { 937163999Strhodes va_start(args, p); 93819896Swollman (void)vfprintf(ftrace, p, args); 939163999Strhodes va_end(args); 94019896Swollman (void)fputc('\n', ftrace); 94119896Swollman } 94219896Swollman} 94319896Swollman 94419896Swollman 94519896Swollmanvoid 94646303Smarkmlogbad(int dump, const char *p, ...) 94718316Swollman{ 94818316Swollman va_list args; 94918316Swollman 95018316Swollman trace_flush(); 95118316Swollman 95218316Swollman va_start(args, p); 95318316Swollman vsyslog(LOG_ERR, p, args); 954163999Strhodes va_end(args); 95518316Swollman (void)fputs("routed: ", stderr); 956163999Strhodes va_start(args, p); 95718316Swollman (void)vfprintf(stderr, p, args); 958163999Strhodes va_end(args); 95918316Swollman (void)fputs("; giving up\n",stderr); 96018316Swollman (void)fflush(stderr); 96118316Swollman 96218316Swollman if (dump) 96318316Swollman abort(); 96418316Swollman exit(1); 96518316Swollman} 966