main.c revision 126250
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 * 3. All advertising materials mentioning features or use of this software 1446303Smarkm * must display the following acknowledgment: 1518316Swollman * This product includes software developed by the University of 1618316Swollman * California, Berkeley and its contributors. 1718316Swollman * 4. Neither the name of the University nor the names of its contributors 1818316Swollman * may be used to endorse or promote products derived from this software 1918316Swollman * without specific prior written permission. 2018316Swollman * 2118316Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2218316Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2318316Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2418316Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2518316Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2618316Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2718316Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2818316Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2918316Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3018316Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3118316Swollman * SUCH DAMAGE. 3246303Smarkm * 3350476Speter * $FreeBSD: head/sbin/routed/main.c 126250 2004-02-25 23:45:57Z bms $ 3418316Swollman */ 3518316Swollman 3618316Swollman#include "defs.h" 3746303Smarkm#include "pathnames.h" 3818316Swollman#ifdef sgi 3918316Swollman#include "math.h" 4018316Swollman#endif 4146303Smarkm#include <signal.h> 4218316Swollman#include <fcntl.h> 4346303Smarkm#include <sys/file.h> 4418316Swollman 45126250Sbms__COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993\n" 46126250Sbms "The Regents of the University of California." 47126250Sbms " All rights reserved.\n"); 48126250Sbms#ifdef __NetBSD__ 4946303Smarkm__RCSID("$NetBSD$"); 50126250Sbms#include <util.h> 51126250Sbms#elif defined(__FreeBSD__) 52126250Sbms__RCSID("$FreeBSD: head/sbin/routed/main.c 126250 2004-02-25 23:45:57Z bms $"); 53126250Sbms#else 54126250Sbms__RCSID("$Revision: 2.27 $"); 55126250Sbms#ident "$Revision: 2.27 $" 5646303Smarkm#endif 5750969Speter#ident "$FreeBSD: head/sbin/routed/main.c 126250 2004-02-25 23:45:57Z bms $" 5846303Smarkm 5918316Swollmanpid_t mypid; 6018316Swollman 6118316Swollmannaddr myaddr; /* system address */ 6218316Swollmanchar myname[MAXHOSTNAMELEN+1]; 6318316Swollman 6446303Smarkmint verbose; 6546303Smarkm 6618316Swollmanint supplier; /* supply or broadcast updates */ 6718316Swollmanint supplier_set; 6818316Swollmanint ipforwarding = 1; /* kernel forwarding on */ 6918316Swollman 7018316Swollmanint default_gateway; /* 1=advertise default */ 7118316Swollmanint background = 1; 7218316Swollmanint ridhosts; /* 1=reduce host routes */ 7318316Swollmanint mhome; /* 1=want multi-homed host route */ 7437908Scharnierint advertise_mhome; /* 1=must continue advertising it */ 7518316Swollmanint auth_ok = 1; /* 1=ignore auth if we do not care */ 7618316Swollman 7718316Swollmanstruct timeval epoch; /* when started */ 7818316Swollmanstruct timeval clk, prev_clk; 7946303Smarkmstatic int usec_fudge; 8018316Swollmanstruct timeval now; /* current idea of time */ 8118316Swollmantime_t now_stale; 8218316Swollmantime_t now_expire; 8318316Swollmantime_t now_garbage; 8418316Swollman 8518316Swollmanstruct timeval next_bcast; /* next general broadcast */ 8664131Ssheldonhstruct timeval no_flash = { /* inhibit flash update */ 8764131Ssheldonh EPOCH+SUPPLY_INTERVAL, 0 8864131Ssheldonh}; 8918316Swollman 9046303Smarkmstruct timeval flush_kern_timer; 9146303Smarkm 9218316Swollmanfd_set fdbits; 9318316Swollmanint sock_max; 9418316Swollmanint rip_sock = -1; /* RIP socket */ 9518316Swollmanstruct interface *rip_sock_mcast; /* current multicast interface */ 9618316Swollmanint rt_sock; /* routing socket */ 9718316Swollmanint rt_sock_seqno; 9818316Swollman 9918316Swollman 10018316Swollmanstatic int get_rip_sock(naddr, int); 10118316Swollmanstatic void timevalsub(struct timeval *, struct timeval *, struct timeval *); 10218316Swollman 10318316Swollmanint 10418316Swollmanmain(int argc, 10518316Swollman char *argv[]) 10618316Swollman{ 10718316Swollman int n, mib[4], off; 10818316Swollman size_t len; 10918316Swollman char *p, *q; 11046303Smarkm const char *cp; 11118316Swollman struct timeval wtime, t2; 11218316Swollman time_t dt; 11318316Swollman fd_set ibits; 11419896Swollman naddr p_net, p_mask; 11518316Swollman struct interface *ifp; 11618316Swollman struct parm parm; 11718316Swollman char *tracename = 0; 11818316Swollman 11918316Swollman 12019896Swollman /* Some shells are badly broken and send SIGHUP to backgrounded 12119896Swollman * processes. 12219896Swollman */ 12319896Swollman signal(SIGHUP, SIG_IGN); 12419896Swollman 125126250Sbms openlog("routed", LOG_PID, LOG_DAEMON); 12618316Swollman ftrace = stdout; 12718316Swollman 12818316Swollman gettimeofday(&clk, 0); 12918316Swollman prev_clk = clk; 13018316Swollman epoch = clk; 13118316Swollman epoch.tv_sec -= EPOCH; 13218316Swollman now.tv_sec = EPOCH; 13318316Swollman now_stale = EPOCH - STALE_TIME; 13418316Swollman now_expire = EPOCH - EXPIRE_TIME; 13518316Swollman now_garbage = EPOCH - GARBAGE_TIME; 13618316Swollman wtime.tv_sec = 0; 13718316Swollman 13818316Swollman (void)gethostname(myname, sizeof(myname)-1); 13918316Swollman (void)gethost(myname, &myaddr); 14018316Swollman 14146303Smarkm while ((n = getopt(argc, argv, "sqdghmpAtvT:F:P:")) != -1) { 14218316Swollman switch (n) { 14318316Swollman case 's': 14418316Swollman supplier = 1; 14518316Swollman supplier_set = 1; 14618316Swollman break; 14718316Swollman 14818316Swollman case 'q': 14918316Swollman supplier = 0; 15018316Swollman supplier_set = 1; 15118316Swollman break; 15218316Swollman 15318316Swollman case 'd': 15418316Swollman background = 0; 15518316Swollman break; 15618316Swollman 15718316Swollman case 'g': 15846303Smarkm memset(&parm, 0, sizeof(parm)); 15918316Swollman parm.parm_d_metric = 1; 16046303Smarkm cp = check_parms(&parm); 16146303Smarkm if (cp != 0) 16246303Smarkm msglog("bad -g: %s", cp); 16318316Swollman else 16418316Swollman default_gateway = 1; 16518316Swollman break; 16618316Swollman 16718316Swollman case 'h': /* suppress extra host routes */ 16818316Swollman ridhosts = 1; 16918316Swollman break; 17018316Swollman 17118316Swollman case 'm': /* advertise host route */ 17218316Swollman mhome = 1; /* on multi-homed hosts */ 17318316Swollman break; 17418316Swollman 17518316Swollman case 'A': 17618316Swollman /* Ignore authentication if we do not care. 17718316Swollman * Crazy as it is, that is what RFC 1723 requires. 17818316Swollman */ 17918316Swollman auth_ok = 0; 18018316Swollman break; 18118316Swollman 18218316Swollman case 't': 18318316Swollman new_tracelevel++; 18418316Swollman break; 18518316Swollman 18618316Swollman case 'T': 18718316Swollman tracename = optarg; 18818316Swollman break; 18918316Swollman 19018316Swollman case 'F': /* minimal routes for SLIP */ 19119896Swollman n = FAKE_METRIC; 19218316Swollman p = strchr(optarg,','); 19318316Swollman if (p && *p != '\0') { 19418316Swollman n = (int)strtoul(p+1, &q, 0); 19518316Swollman if (*q == '\0' 19618316Swollman && n <= HOPCNT_INFINITY-1 19718316Swollman && n >= 1) 19818316Swollman *p = '\0'; 19918316Swollman } 20019896Swollman if (!getnet(optarg, &p_net, &p_mask)) { 20118316Swollman msglog("bad network; \"-F %s\"", 20218316Swollman optarg); 20318316Swollman break; 20418316Swollman } 20546303Smarkm memset(&parm, 0, sizeof(parm)); 20619896Swollman parm.parm_net = p_net; 20718316Swollman parm.parm_mask = p_mask; 20818316Swollman parm.parm_d_metric = n; 20946303Smarkm cp = check_parms(&parm); 21046303Smarkm if (cp != 0) 21146303Smarkm msglog("bad -F: %s", cp); 21218316Swollman break; 21318316Swollman 21418316Swollman case 'P': 21546303Smarkm /* handle arbitrary parameters. 21618316Swollman */ 21746303Smarkm q = strdup(optarg); 21846303Smarkm cp = parse_parms(q, 0); 21946303Smarkm if (cp != 0) 22046303Smarkm msglog("%s in \"-P %s\"", cp, optarg); 22146303Smarkm free(q); 22218316Swollman break; 22318316Swollman 22446303Smarkm case 'v': 22546303Smarkm /* display version */ 22646303Smarkm verbose++; 227126250Sbms msglog("version 2.25"); 22846303Smarkm break; 22946303Smarkm 23018316Swollman default: 23118316Swollman goto usage; 23218316Swollman } 23318316Swollman } 23418316Swollman argc -= optind; 23518316Swollman argv += optind; 23618316Swollman 23718316Swollman if (tracename == 0 && argc >= 1) { 23818316Swollman tracename = *argv++; 23918316Swollman argc--; 24018316Swollman } 24120342Swollman if (tracename != 0 && tracename[0] == '\0') 24220342Swollman goto usage; 24318316Swollman if (argc != 0) { 24418316Swollmanusage: 24546303Smarkm logbad(0, "usage: routed [-sqdghmpAtv] [-T tracefile]" 24646303Smarkm " [-F net[,metric]] [-P parms]"); 24718316Swollman } 24846303Smarkm if (geteuid() != 0) { 24946303Smarkm if (verbose) 25046303Smarkm exit(0); 25118316Swollman logbad(0, "requires UID 0"); 25246303Smarkm } 25318316Swollman 25418316Swollman mib[0] = CTL_NET; 25518316Swollman mib[1] = PF_INET; 25618316Swollman mib[2] = IPPROTO_IP; 25718316Swollman mib[3] = IPCTL_FORWARDING; 25818316Swollman len = sizeof(ipforwarding); 25918316Swollman if (sysctl(mib, 4, &ipforwarding, &len, 0, 0) < 0) 26018316Swollman LOGERR("sysctl(IPCTL_FORWARDING)"); 26118316Swollman 26218316Swollman if (!ipforwarding) { 26318316Swollman if (supplier) 26418316Swollman msglog("-s incompatible with ipforwarding=0"); 26518316Swollman if (default_gateway) { 26618316Swollman msglog("-g incompatible with ipforwarding=0"); 26718316Swollman default_gateway = 0; 26818316Swollman } 26918316Swollman supplier = 0; 27018316Swollman supplier_set = 1; 27118316Swollman } 27218316Swollman if (default_gateway) { 27318316Swollman if (supplier_set && !supplier) { 27418316Swollman msglog("-g and -q incompatible"); 27518316Swollman } else { 27618316Swollman supplier = 1; 27718316Swollman supplier_set = 1; 27818316Swollman } 27918316Swollman } 28018316Swollman 28118316Swollman 28218316Swollman signal(SIGALRM, sigalrm); 28318316Swollman if (!background) 28418316Swollman signal(SIGHUP, sigterm); /* SIGHUP fatal during debugging */ 28518316Swollman signal(SIGTERM, sigterm); 28618316Swollman signal(SIGINT, sigterm); 28718316Swollman signal(SIGUSR1, sigtrace_on); 28818316Swollman signal(SIGUSR2, sigtrace_off); 28918316Swollman 29018316Swollman /* get into the background */ 29118316Swollman#ifdef sgi 29220342Swollman if (0 > _daemonize(background ? 0 : (_DF_NOCHDIR|_DF_NOFORK), 29346303Smarkm STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)) 29420342Swollman BADERR(0, "_daemonize()"); 29518316Swollman#else 29646303Smarkm if (background && daemon(0, 1) < 0) 29720342Swollman BADERR(0,"daemon()"); 29818316Swollman#endif 29918316Swollman 300126250Sbms#if defined(__NetBSD__) 301126250Sbms pidfile(0); 302126250Sbms#endif 30318316Swollman mypid = getpid(); 304110670Sache#ifdef __FreeBSD__ 305110670Sache srandomdev(); 306110670Sache#else 30718316Swollman srandom((int)(clk.tv_sec ^ clk.tv_usec ^ mypid)); 308110670Sache#endif 30918316Swollman 31018316Swollman /* prepare socket connected to the kernel. 31118316Swollman */ 31218316Swollman rt_sock = socket(AF_ROUTE, SOCK_RAW, 0); 31318316Swollman if (rt_sock < 0) 31418316Swollman BADERR(1,"rt_sock = socket()"); 31518316Swollman if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1) 31618316Swollman logbad(1, "fcntl(rt_sock) O_NONBLOCK: %s", strerror(errno)); 31718316Swollman off = 0; 31818316Swollman if (setsockopt(rt_sock, SOL_SOCKET,SO_USELOOPBACK, 31918316Swollman &off,sizeof(off)) < 0) 32018316Swollman LOGERR("setsockopt(SO_USELOOPBACK,0)"); 32118316Swollman 32218316Swollman fix_select(); 32318316Swollman 32418316Swollman 32518316Swollman if (tracename != 0) { 32620342Swollman strncpy(inittracename, tracename, sizeof(inittracename)-1); 32746303Smarkm set_tracefile(inittracename, "%s", -1); 32820342Swollman } else { 32946303Smarkm tracelevel_msg("%s", -1); /* turn on tracing to stdio */ 33018316Swollman } 33118316Swollman 33219896Swollman bufinit(); 33319896Swollman 33418316Swollman /* initialize radix tree */ 33518316Swollman rtinit(); 33618316Swollman 33718316Swollman /* Pick a random part of the second for our output to minimize 33818316Swollman * collisions. 33918316Swollman * 34018316Swollman * Start broadcasting after hearing from other routers, and 34118316Swollman * at a random time so a bunch of systems do not get synchronized 34218316Swollman * after a power failure. 34318316Swollman */ 34418316Swollman intvl_random(&next_bcast, EPOCH+MIN_WAITTIME, EPOCH+SUPPLY_INTERVAL); 34518316Swollman age_timer.tv_usec = next_bcast.tv_usec; 34618316Swollman age_timer.tv_sec = EPOCH+MIN_WAITTIME; 34718316Swollman rdisc_timer = next_bcast; 34818316Swollman ifinit_timer.tv_usec = next_bcast.tv_usec; 34918316Swollman 35018316Swollman /* Collect an initial view of the world by checking the interface 35118316Swollman * configuration and the kludge file. 35218316Swollman */ 35318316Swollman gwkludge(); 35418316Swollman ifinit(); 35518316Swollman 35618316Swollman /* Ask for routes */ 35718316Swollman rip_query(); 35819896Swollman rdisc_sol(); 35918316Swollman 36046303Smarkm /* Now turn off stdio if not tracing */ 36146303Smarkm if (new_tracelevel == 0) 36246303Smarkm trace_close(background); 36346303Smarkm 36418316Swollman /* Loop forever, listening and broadcasting. 36518316Swollman */ 36618316Swollman for (;;) { 36718316Swollman prev_clk = clk; 36818316Swollman gettimeofday(&clk, 0); 36946303Smarkm if (prev_clk.tv_sec == clk.tv_sec 37046303Smarkm && prev_clk.tv_usec == clk.tv_usec+usec_fudge) { 37146303Smarkm /* Much of `routed` depends on time always advancing. 37246303Smarkm * On systems that do not guarantee that gettimeofday() 37346303Smarkm * produces unique timestamps even if called within 37446303Smarkm * a single tick, use trickery like that in classic 37546303Smarkm * BSD kernels. 37618316Swollman */ 37746303Smarkm clk.tv_usec += ++usec_fudge; 37846303Smarkm 37946303Smarkm } else { 38046303Smarkm usec_fudge = 0; 38146303Smarkm 38246303Smarkm timevalsub(&t2, &clk, &prev_clk); 38346303Smarkm if (t2.tv_sec < 0 38446303Smarkm || t2.tv_sec > wtime.tv_sec + 5) { 38546303Smarkm /* Deal with time changes before other 38646303Smarkm * housekeeping to keep everything straight. 38746303Smarkm */ 38846303Smarkm dt = t2.tv_sec; 38946303Smarkm if (dt > 0) 39046303Smarkm dt -= wtime.tv_sec; 39146303Smarkm trace_act("time changed by %d sec", (int)dt); 39246303Smarkm epoch.tv_sec += dt; 39346303Smarkm } 39418316Swollman } 39518316Swollman timevalsub(&now, &clk, &epoch); 39618316Swollman now_stale = now.tv_sec - STALE_TIME; 39718316Swollman now_expire = now.tv_sec - EXPIRE_TIME; 39818316Swollman now_garbage = now.tv_sec - GARBAGE_TIME; 39918316Swollman 40020342Swollman /* deal with signals that should affect tracing */ 40120342Swollman set_tracelevel(); 40218316Swollman 40318316Swollman if (stopint != 0) { 40419896Swollman rip_bcast(0); 40519896Swollman rdisc_adv(); 40646303Smarkm trace_off("exiting with signal %d", stopint); 40718316Swollman exit(stopint | 128); 40818316Swollman } 40918316Swollman 41018316Swollman /* look for new or dead interfaces */ 41118316Swollman timevalsub(&wtime, &ifinit_timer, &now); 41218316Swollman if (wtime.tv_sec <= 0) { 41318316Swollman wtime.tv_sec = 0; 41418316Swollman ifinit(); 41518316Swollman rip_query(); 41618316Swollman continue; 41718316Swollman } 41818316Swollman 41946303Smarkm /* Check the kernel table occassionally for mysteriously 42046303Smarkm * evaporated routes 42146303Smarkm */ 42246303Smarkm timevalsub(&t2, &flush_kern_timer, &now); 42346303Smarkm if (t2.tv_sec <= 0) { 42446303Smarkm flush_kern(); 42546303Smarkm flush_kern_timer.tv_sec = (now.tv_sec 42646303Smarkm + CHECK_QUIET_INTERVAL); 42746303Smarkm continue; 42846303Smarkm } 42946303Smarkm if (timercmp(&t2, &wtime, <)) 43046303Smarkm wtime = t2; 43146303Smarkm 43218316Swollman /* If it is time, then broadcast our routes. 43318316Swollman */ 43418316Swollman if (supplier || advertise_mhome) { 43518316Swollman timevalsub(&t2, &next_bcast, &now); 43618316Swollman if (t2.tv_sec <= 0) { 43718316Swollman /* Synchronize the aging and broadcast 43818316Swollman * timers to minimize awakenings 43918316Swollman */ 44018316Swollman age(0); 44118316Swollman 44218316Swollman rip_bcast(0); 44318316Swollman 44418316Swollman /* It is desirable to send routing updates 44518316Swollman * regularly. So schedule the next update 44618316Swollman * 30 seconds after the previous one was 44729314Sdanny * scheduled, instead of 30 seconds after 44818316Swollman * the previous update was finished. 44918316Swollman * Even if we just started after discovering 45018316Swollman * a 2nd interface or were otherwise delayed, 45118316Swollman * pick a 30-second aniversary of the 45218316Swollman * original broadcast time. 45318316Swollman */ 45418316Swollman n = 1 + (0-t2.tv_sec)/SUPPLY_INTERVAL; 45518316Swollman next_bcast.tv_sec += n*SUPPLY_INTERVAL; 45618316Swollman 45718316Swollman continue; 45818316Swollman } 45918316Swollman 46018316Swollman if (timercmp(&t2, &wtime, <)) 46118316Swollman wtime = t2; 46218316Swollman } 46318316Swollman 46418316Swollman /* If we need a flash update, either do it now or 46518316Swollman * set the delay to end when it is time. 46618316Swollman * 46718316Swollman * If we are within MIN_WAITTIME seconds of a full update, 46818316Swollman * do not bother. 46918316Swollman */ 47018316Swollman if (need_flash 47118316Swollman && supplier 47218316Swollman && no_flash.tv_sec+MIN_WAITTIME < next_bcast.tv_sec) { 47318316Swollman /* accurate to the millisecond */ 47418316Swollman if (!timercmp(&no_flash, &now, >)) 47518316Swollman rip_bcast(1); 47618316Swollman timevalsub(&t2, &no_flash, &now); 47718316Swollman if (timercmp(&t2, &wtime, <)) 47818316Swollman wtime = t2; 47918316Swollman } 48018316Swollman 48118316Swollman /* trigger the main aging timer. 48218316Swollman */ 48318316Swollman timevalsub(&t2, &age_timer, &now); 48418316Swollman if (t2.tv_sec <= 0) { 48518316Swollman age(0); 48618316Swollman continue; 48718316Swollman } 48818316Swollman if (timercmp(&t2, &wtime, <)) 48918316Swollman wtime = t2; 49018316Swollman 49118316Swollman /* update the kernel routing table 49218316Swollman */ 49318316Swollman timevalsub(&t2, &need_kern, &now); 49418316Swollman if (t2.tv_sec <= 0) { 49518316Swollman age(0); 49618316Swollman continue; 49718316Swollman } 49818316Swollman if (timercmp(&t2, &wtime, <)) 49918316Swollman wtime = t2; 50018316Swollman 50118316Swollman /* take care of router discovery, 50246303Smarkm * but do it in the correct the millisecond 50318316Swollman */ 50418316Swollman if (!timercmp(&rdisc_timer, &now, >)) { 50518316Swollman rdisc_age(0); 50618316Swollman continue; 50718316Swollman } 50818316Swollman timevalsub(&t2, &rdisc_timer, &now); 50918316Swollman if (timercmp(&t2, &wtime, <)) 51018316Swollman wtime = t2; 51118316Swollman 51218316Swollman 51318316Swollman /* wait for input or a timer to expire. 51418316Swollman */ 51518316Swollman trace_flush(); 51618316Swollman ibits = fdbits; 51718316Swollman n = select(sock_max, &ibits, 0, 0, &wtime); 51818316Swollman if (n <= 0) { 51918316Swollman if (n < 0 && errno != EINTR && errno != EAGAIN) 52018316Swollman BADERR(1,"select"); 52118316Swollman continue; 52218316Swollman } 52318316Swollman 52418316Swollman if (FD_ISSET(rt_sock, &ibits)) { 52518316Swollman read_rt(); 52618316Swollman n--; 52718316Swollman } 52818316Swollman if (rdisc_sock >= 0 && FD_ISSET(rdisc_sock, &ibits)) { 52918316Swollman read_d(); 53018316Swollman n--; 53118316Swollman } 53218316Swollman if (rip_sock >= 0 && FD_ISSET(rip_sock, &ibits)) { 53318316Swollman read_rip(rip_sock, 0); 53418316Swollman n--; 53518316Swollman } 53618316Swollman 53718316Swollman for (ifp = ifnet; n > 0 && 0 != ifp; ifp = ifp->int_next) { 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 */ 54918316Swollmanvoid 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 */ 56118316Swollmanvoid 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 } 58618316Swollman for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { 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 */ 69818316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 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{ 72118316Swollman struct ip_mreq m; 72218316Swollman 72318316Swollman if (!IS_RIP_IN_OFF(ifp->int_state) 72418316Swollman && (ifp->int_if_flags & IFF_MULTICAST) 72518316Swollman#ifdef MCAST_PPP_BUG 72618316Swollman && !(ifp->int_if_flags & IFF_POINTOPOINT) 72718316Swollman#endif 72818316Swollman && !(ifp->int_state & IS_ALIAS)) { 72918316Swollman m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); 730126250Sbms#ifdef MCAST_IFINDEX 731126250Sbms m.imr_interface.s_addr = htonl(ifp->int_index); 732126250Sbms#else 73318316Swollman m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) 73418316Swollman ? ifp->int_dstaddr 73518316Swollman : ifp->int_addr); 736126250Sbms#endif 73718316Swollman if (setsockopt(rip_sock,IPPROTO_IP, IP_ADD_MEMBERSHIP, 73818316Swollman &m, sizeof(m)) < 0) 73918316Swollman LOGERR("setsockopt(IP_ADD_MEMBERSHIP RIP)"); 74018316Swollman } 74118316Swollman} 74218316Swollman 74318316Swollman 74418316Swollman/* Prepare socket used for RIP. 74518316Swollman */ 74618316Swollmanvoid 74718316Swollmanrip_on(struct interface *ifp) 74818316Swollman{ 74918316Swollman /* If the main RIP socket is already alive, only start receiving 75018316Swollman * multicasts for this interface. 75118316Swollman */ 75218316Swollman if (rip_sock >= 0) { 75318316Swollman if (ifp != 0) 75418316Swollman rip_mcast_on(ifp); 75518316Swollman return; 75618316Swollman } 75718316Swollman 75819896Swollman /* If the main RIP socket is off and it makes sense to turn it on, 75919896Swollman * then turn it on for all of the interfaces. 76046303Smarkm * It makes sense if either router discovery is off, or if 76146303Smarkm * router discover is on and at most one interface is doing RIP. 76218316Swollman */ 76346303Smarkm if (rip_interfaces > 0 && (!rdisc_ok || rip_interfaces > 1)) { 76419896Swollman trace_act("turn on RIP"); 76518316Swollman 76618316Swollman /* Close all of the query sockets so that we can open 76718316Swollman * the main socket. SO_REUSEPORT is not a solution, 76818316Swollman * since that would let two daemons bind to the broadcast 76918316Swollman * socket. 77018316Swollman */ 77118316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 77218316Swollman if (ifp->int_rip_sock >= 0) { 77318316Swollman (void)close(ifp->int_rip_sock); 77418316Swollman ifp->int_rip_sock = -1; 77518316Swollman } 77618316Swollman } 77718316Swollman 77818316Swollman rip_sock = get_rip_sock(INADDR_ANY, 1); 77918316Swollman rip_sock_mcast = 0; 78018316Swollman 78118316Swollman /* Do not advertise anything until we have heard something 78218316Swollman */ 78318316Swollman if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME) 78418316Swollman next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME; 78518316Swollman 78618316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 78719896Swollman ifp->int_query_time = NEVER; 78818316Swollman rip_mcast_on(ifp); 78918316Swollman } 79018316Swollman ifinit_timer.tv_sec = now.tv_sec; 79118316Swollman 79218316Swollman } else if (ifp != 0 79319896Swollman && !(ifp->int_state & IS_REMOTE) 79419896Swollman && ifp->int_rip_sock < 0) { 79518316Swollman /* RIP is off, so ensure there are sockets on which 79618316Swollman * to listen for queries. 79718316Swollman */ 79818316Swollman ifp->int_rip_sock = get_rip_sock(ifp->int_addr, 0); 79919896Swollman } 80018316Swollman 80119896Swollman fix_select(); 80218316Swollman} 80318316Swollman 80418316Swollman 80518316Swollman/* die if malloc(3) fails 80618316Swollman */ 80718316Swollmanvoid * 80818316Swollmanrtmalloc(size_t size, 80946303Smarkm const char *msg) 81018316Swollman{ 81118316Swollman void *p = malloc(size); 81246303Smarkm if (p == 0) 81346303Smarkm logbad(1,"malloc(%lu) failed in %s", (u_long)size, msg); 81418316Swollman return p; 81518316Swollman} 81618316Swollman 81718316Swollman 81818316Swollman/* get a random instant in an interval 81918316Swollman */ 82018316Swollmanvoid 82118316Swollmanintvl_random(struct timeval *tp, /* put value here */ 82218316Swollman u_long lo, /* value is after this second */ 82318316Swollman u_long hi) /* and before this */ 82418316Swollman{ 82518316Swollman tp->tv_sec = (time_t)(hi == lo 82618316Swollman ? lo 82718316Swollman : (lo + random() % ((hi - lo)))); 82818316Swollman tp->tv_usec = random() % 1000000; 82918316Swollman} 83018316Swollman 83118316Swollman 83218316Swollmanvoid 83318316Swollmantimevaladd(struct timeval *t1, 83418316Swollman struct timeval *t2) 83518316Swollman{ 83618316Swollman 83718316Swollman t1->tv_sec += t2->tv_sec; 83837908Scharnier if ((t1->tv_usec += t2->tv_usec) >= 1000000) { 83918316Swollman t1->tv_sec++; 84018316Swollman t1->tv_usec -= 1000000; 84118316Swollman } 84218316Swollman} 84318316Swollman 84418316Swollman 84518316Swollman/* t1 = t2 - t3 84618316Swollman */ 84718316Swollmanstatic void 84818316Swollmantimevalsub(struct timeval *t1, 84918316Swollman struct timeval *t2, 85018316Swollman struct timeval *t3) 85118316Swollman{ 85218316Swollman t1->tv_sec = t2->tv_sec - t3->tv_sec; 85318316Swollman if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) { 85418316Swollman t1->tv_sec--; 85518316Swollman t1->tv_usec += 1000000; 85618316Swollman } 85718316Swollman} 85818316Swollman 85918316Swollman 86019896Swollman/* put a message into the system log 86119896Swollman */ 86218316Swollmanvoid 86346303Smarkmmsglog(const char *p, ...) 86418316Swollman{ 86518316Swollman va_list args; 86618316Swollman 86718316Swollman trace_flush(); 86818316Swollman 86918316Swollman va_start(args, p); 87018316Swollman vsyslog(LOG_ERR, p, args); 87118316Swollman 87218316Swollman if (ftrace != 0) { 87318316Swollman if (ftrace == stdout) 87418316Swollman (void)fputs("routed: ", ftrace); 87518316Swollman (void)vfprintf(ftrace, p, args); 87618316Swollman (void)fputc('\n', ftrace); 87718316Swollman } 878126250Sbms va_end(args); 87918316Swollman} 88018316Swollman 88118316Swollman 88220342Swollman/* Put a message about a bad system into the system log if 88319896Swollman * we have not complained about it recently. 88420342Swollman * 88520342Swollman * It is desirable to complain about all bad systems, but not too often. 88620342Swollman * In the worst case, it is not practical to keep track of all bad systems. 88720342Swollman * For example, there can be many systems with the wrong password. 88819896Swollman */ 88918316Swollmanvoid 89046303Smarkmmsglim(struct msg_limit *lim, naddr addr, const char *p, ...) 89119896Swollman{ 89219896Swollman va_list args; 89320342Swollman int i; 89420342Swollman struct msg_sub *ms1, *ms; 89546303Smarkm const char *p1; 89619896Swollman 89719896Swollman va_start(args, p); 89819896Swollman 89920342Swollman /* look for the oldest slot in the table 90020342Swollman * or the slot for the bad router. 90120342Swollman */ 90220342Swollman ms = ms1 = lim->subs; 90320342Swollman for (i = MSG_SUBJECT_N; ; i--, ms1++) { 90420342Swollman if (i == 0) { 90520342Swollman /* Reuse a slot at most once every 10 minutes. 90620342Swollman */ 90720342Swollman if (lim->reuse > now.tv_sec) { 90820342Swollman ms = 0; 90920342Swollman } else { 91020342Swollman ms = ms1; 91120342Swollman lim->reuse = now.tv_sec + 10*60; 91220342Swollman } 91320342Swollman break; 91420342Swollman } 91520342Swollman if (ms->addr == addr) { 91620342Swollman /* Repeat a complaint about a given system at 91720342Swollman * most once an hour. 91820342Swollman */ 91920342Swollman if (ms->until > now.tv_sec) 92020342Swollman ms = 0; 92120342Swollman break; 92220342Swollman } 92320342Swollman if (ms->until < ms1->until) 92420342Swollman ms = ms1; 92520342Swollman } 92620342Swollman if (ms != 0) { 92720342Swollman ms->addr = addr; 92820342Swollman ms->until = now.tv_sec + 60*60; /* 60 minutes */ 92919896Swollman 93019896Swollman trace_flush(); 93119896Swollman for (p1 = p; *p1 == ' '; p1++) 93219896Swollman continue; 93319896Swollman vsyslog(LOG_ERR, p1, args); 93419896Swollman } 93519896Swollman 93620342Swollman /* always display the message if tracing */ 93719896Swollman if (ftrace != 0) { 93819896Swollman (void)vfprintf(ftrace, p, args); 93919896Swollman (void)fputc('\n', ftrace); 94019896Swollman } 941126250Sbms va_end(args); 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); 95418316Swollman 95518316Swollman (void)fputs("routed: ", stderr); 95618316Swollman (void)vfprintf(stderr, p, args); 95718316Swollman (void)fputs("; giving up\n",stderr); 95818316Swollman (void)fflush(stderr); 959126250Sbms va_end(args); 96018316Swollman 96118316Swollman if (dump) 96218316Swollman abort(); 96318316Swollman exit(1); 96418316Swollman} 965