main.c revision 163999
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: head/sbin/routed/main.c 163999 2006-11-05 14:49:47Z trhodes $ 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 41126250Sbms__COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993\n" 42126250Sbms "The Regents of the University of California." 43126250Sbms " All rights reserved.\n"); 44126250Sbms#ifdef __NetBSD__ 4546303Smarkm__RCSID("$NetBSD$"); 46126250Sbms#include <util.h> 47126250Sbms#elif defined(__FreeBSD__) 48126250Sbms__RCSID("$FreeBSD: head/sbin/routed/main.c 163999 2006-11-05 14:49:47Z trhodes $"); 49126250Sbms#else 50163999Strhodes__RCSID("$Revision: 2.31 $"); 51163999Strhodes#ident "$Revision: 2.31 $" 5246303Smarkm#endif 5346303Smarkm 5418316Swollmanpid_t mypid; 5518316Swollman 5618316Swollmannaddr myaddr; /* system address */ 5718316Swollmanchar myname[MAXHOSTNAMELEN+1]; 5818316Swollman 5946303Smarkmint verbose; 6046303Smarkm 6118316Swollmanint supplier; /* supply or broadcast updates */ 6218316Swollmanint supplier_set; 6318316Swollmanint ipforwarding = 1; /* kernel forwarding on */ 6418316Swollman 6518316Swollmanint default_gateway; /* 1=advertise default */ 6618316Swollmanint 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 */ 7318316Swollmanstruct timeval clk, prev_clk; 7446303Smarkmstatic int usec_fudge; 7518316Swollmanstruct timeval now; /* current idea of time */ 7618316Swollmantime_t now_stale; 7718316Swollmantime_t now_expire; 7818316Swollmantime_t now_garbage; 7918316Swollman 8018316Swollmanstruct timeval next_bcast; /* next general broadcast */ 8164131Ssheldonhstruct timeval no_flash = { /* inhibit flash update */ 8264131Ssheldonh EPOCH+SUPPLY_INTERVAL, 0 8364131Ssheldonh}; 8418316Swollman 8546303Smarkmstruct timeval flush_kern_timer; 8646303Smarkm 8718316Swollmanfd_set fdbits; 8818316Swollmanint sock_max; 8918316Swollmanint rip_sock = -1; /* RIP socket */ 9018316Swollmanstruct interface *rip_sock_mcast; /* current multicast interface */ 9118316Swollmanint rt_sock; /* routing socket */ 9218316Swollmanint rt_sock_seqno; 9318316Swollman 9418316Swollman 9518316Swollmanstatic int get_rip_sock(naddr, int); 9618316Swollmanstatic void timevalsub(struct timeval *, struct timeval *, struct timeval *); 9718316Swollman 9818316Swollmanint 9918316Swollmanmain(int argc, 10018316Swollman char *argv[]) 10118316Swollman{ 10218316Swollman int n, mib[4], off; 10318316Swollman size_t len; 10418316Swollman char *p, *q; 10546303Smarkm const char *cp; 10618316Swollman struct timeval wtime, t2; 10718316Swollman time_t dt; 10818316Swollman fd_set ibits; 10919896Swollman naddr p_net, p_mask; 11018316Swollman struct interface *ifp; 11118316Swollman struct parm parm; 11218316Swollman char *tracename = 0; 11318316Swollman 11418316Swollman 11519896Swollman /* Some shells are badly broken and send SIGHUP to backgrounded 11619896Swollman * processes. 11719896Swollman */ 11819896Swollman signal(SIGHUP, SIG_IGN); 11919896Swollman 120126250Sbms openlog("routed", LOG_PID, LOG_DAEMON); 12118316Swollman ftrace = stdout; 12218316Swollman 12318316Swollman gettimeofday(&clk, 0); 12418316Swollman prev_clk = clk; 12518316Swollman epoch = clk; 12618316Swollman epoch.tv_sec -= EPOCH; 12718316Swollman now.tv_sec = EPOCH; 12818316Swollman now_stale = EPOCH - STALE_TIME; 12918316Swollman now_expire = EPOCH - EXPIRE_TIME; 13018316Swollman now_garbage = EPOCH - GARBAGE_TIME; 13118316Swollman wtime.tv_sec = 0; 13218316Swollman 13318316Swollman (void)gethostname(myname, sizeof(myname)-1); 13418316Swollman (void)gethost(myname, &myaddr); 13518316Swollman 136163999Strhodes while ((n = getopt(argc, argv, "sqdghmAtvT:F:P:")) != -1) { 13718316Swollman switch (n) { 13818316Swollman case 's': 13918316Swollman supplier = 1; 14018316Swollman supplier_set = 1; 14118316Swollman break; 14218316Swollman 14318316Swollman case 'q': 14418316Swollman supplier = 0; 14518316Swollman supplier_set = 1; 14618316Swollman break; 14718316Swollman 14818316Swollman case 'd': 14918316Swollman background = 0; 15018316Swollman break; 15118316Swollman 15218316Swollman case 'g': 15346303Smarkm memset(&parm, 0, sizeof(parm)); 15418316Swollman parm.parm_d_metric = 1; 15546303Smarkm cp = check_parms(&parm); 15646303Smarkm if (cp != 0) 15746303Smarkm msglog("bad -g: %s", cp); 15818316Swollman else 15918316Swollman default_gateway = 1; 16018316Swollman break; 16118316Swollman 16218316Swollman case 'h': /* suppress extra host routes */ 16318316Swollman ridhosts = 1; 16418316Swollman break; 16518316Swollman 16618316Swollman case 'm': /* advertise host route */ 16718316Swollman mhome = 1; /* on multi-homed hosts */ 16818316Swollman break; 16918316Swollman 17018316Swollman case 'A': 17118316Swollman /* Ignore authentication if we do not care. 17218316Swollman * Crazy as it is, that is what RFC 1723 requires. 17318316Swollman */ 17418316Swollman auth_ok = 0; 17518316Swollman break; 17618316Swollman 17718316Swollman case 't': 17818316Swollman new_tracelevel++; 17918316Swollman break; 18018316Swollman 18118316Swollman case 'T': 18218316Swollman tracename = optarg; 18318316Swollman break; 18418316Swollman 18518316Swollman case 'F': /* minimal routes for SLIP */ 18619896Swollman n = FAKE_METRIC; 18718316Swollman p = strchr(optarg,','); 18818316Swollman if (p && *p != '\0') { 18918316Swollman n = (int)strtoul(p+1, &q, 0); 19018316Swollman if (*q == '\0' 19118316Swollman && n <= HOPCNT_INFINITY-1 19218316Swollman && n >= 1) 19318316Swollman *p = '\0'; 19418316Swollman } 19519896Swollman if (!getnet(optarg, &p_net, &p_mask)) { 19618316Swollman msglog("bad network; \"-F %s\"", 19718316Swollman optarg); 19818316Swollman break; 19918316Swollman } 20046303Smarkm memset(&parm, 0, sizeof(parm)); 20119896Swollman parm.parm_net = p_net; 20218316Swollman parm.parm_mask = p_mask; 20318316Swollman parm.parm_d_metric = n; 20446303Smarkm cp = check_parms(&parm); 20546303Smarkm if (cp != 0) 20646303Smarkm msglog("bad -F: %s", cp); 20718316Swollman break; 20818316Swollman 20918316Swollman case 'P': 21046303Smarkm /* handle arbitrary parameters. 21118316Swollman */ 21246303Smarkm q = strdup(optarg); 21346303Smarkm cp = parse_parms(q, 0); 21446303Smarkm if (cp != 0) 21546303Smarkm msglog("%s in \"-P %s\"", cp, optarg); 21646303Smarkm free(q); 21718316Swollman break; 21818316Swollman 21946303Smarkm case 'v': 22046303Smarkm /* display version */ 22146303Smarkm verbose++; 222163999Strhodes msglog("version 2.31"); 22346303Smarkm break; 22446303Smarkm 22518316Swollman default: 22618316Swollman goto usage; 22718316Swollman } 22818316Swollman } 22918316Swollman argc -= optind; 23018316Swollman argv += optind; 23118316Swollman 23218316Swollman if (tracename == 0 && argc >= 1) { 23318316Swollman tracename = *argv++; 23418316Swollman argc--; 23518316Swollman } 23620342Swollman if (tracename != 0 && tracename[0] == '\0') 23720342Swollman goto usage; 23818316Swollman if (argc != 0) { 23918316Swollmanusage: 240163999Strhodes logbad(0, "usage: routed [-sqdghmAtv] [-T tracefile]" 24146303Smarkm " [-F net[,metric]] [-P parms]"); 24218316Swollman } 24346303Smarkm if (geteuid() != 0) { 24446303Smarkm if (verbose) 24546303Smarkm exit(0); 24618316Swollman logbad(0, "requires UID 0"); 24746303Smarkm } 24818316Swollman 24918316Swollman mib[0] = CTL_NET; 25018316Swollman mib[1] = PF_INET; 25118316Swollman mib[2] = IPPROTO_IP; 25218316Swollman mib[3] = IPCTL_FORWARDING; 25318316Swollman len = sizeof(ipforwarding); 25418316Swollman if (sysctl(mib, 4, &ipforwarding, &len, 0, 0) < 0) 25518316Swollman LOGERR("sysctl(IPCTL_FORWARDING)"); 25618316Swollman 25718316Swollman if (!ipforwarding) { 25818316Swollman if (supplier) 25918316Swollman msglog("-s incompatible with ipforwarding=0"); 26018316Swollman if (default_gateway) { 26118316Swollman msglog("-g incompatible with ipforwarding=0"); 26218316Swollman default_gateway = 0; 26318316Swollman } 26418316Swollman supplier = 0; 26518316Swollman supplier_set = 1; 26618316Swollman } 26718316Swollman if (default_gateway) { 26818316Swollman if (supplier_set && !supplier) { 26918316Swollman msglog("-g and -q incompatible"); 27018316Swollman } else { 27118316Swollman supplier = 1; 27218316Swollman supplier_set = 1; 27318316Swollman } 27418316Swollman } 27518316Swollman 27618316Swollman 27718316Swollman signal(SIGALRM, sigalrm); 27818316Swollman if (!background) 27918316Swollman signal(SIGHUP, sigterm); /* SIGHUP fatal during debugging */ 28018316Swollman signal(SIGTERM, sigterm); 28118316Swollman signal(SIGINT, sigterm); 28218316Swollman signal(SIGUSR1, sigtrace_on); 28318316Swollman signal(SIGUSR2, sigtrace_off); 28418316Swollman 28518316Swollman /* get into the background */ 28618316Swollman#ifdef sgi 28720342Swollman if (0 > _daemonize(background ? 0 : (_DF_NOCHDIR|_DF_NOFORK), 28846303Smarkm STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)) 28920342Swollman BADERR(0, "_daemonize()"); 29018316Swollman#else 29146303Smarkm if (background && daemon(0, 1) < 0) 29220342Swollman BADERR(0,"daemon()"); 29318316Swollman#endif 29418316Swollman 295126250Sbms#if defined(__NetBSD__) 296126250Sbms pidfile(0); 297126250Sbms#endif 29818316Swollman mypid = getpid(); 299110670Sache#ifdef __FreeBSD__ 300110670Sache srandomdev(); 301110670Sache#else 30218316Swollman srandom((int)(clk.tv_sec ^ clk.tv_usec ^ mypid)); 303110670Sache#endif 30418316Swollman 30518316Swollman /* prepare socket connected to the kernel. 30618316Swollman */ 30718316Swollman rt_sock = socket(AF_ROUTE, SOCK_RAW, 0); 30818316Swollman if (rt_sock < 0) 30918316Swollman BADERR(1,"rt_sock = socket()"); 31018316Swollman if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1) 31118316Swollman logbad(1, "fcntl(rt_sock) O_NONBLOCK: %s", strerror(errno)); 31218316Swollman off = 0; 31318316Swollman if (setsockopt(rt_sock, SOL_SOCKET,SO_USELOOPBACK, 31418316Swollman &off,sizeof(off)) < 0) 31518316Swollman LOGERR("setsockopt(SO_USELOOPBACK,0)"); 31618316Swollman 31718316Swollman fix_select(); 31818316Swollman 31918316Swollman 32018316Swollman if (tracename != 0) { 32120342Swollman strncpy(inittracename, tracename, sizeof(inittracename)-1); 32246303Smarkm set_tracefile(inittracename, "%s", -1); 32320342Swollman } else { 32446303Smarkm tracelevel_msg("%s", -1); /* turn on tracing to stdio */ 32518316Swollman } 32618316Swollman 32719896Swollman bufinit(); 32819896Swollman 32918316Swollman /* initialize radix tree */ 33018316Swollman rtinit(); 33118316Swollman 33218316Swollman /* Pick a random part of the second for our output to minimize 33318316Swollman * collisions. 33418316Swollman * 33518316Swollman * Start broadcasting after hearing from other routers, and 33618316Swollman * at a random time so a bunch of systems do not get synchronized 33718316Swollman * after a power failure. 33818316Swollman */ 33918316Swollman intvl_random(&next_bcast, EPOCH+MIN_WAITTIME, EPOCH+SUPPLY_INTERVAL); 34018316Swollman age_timer.tv_usec = next_bcast.tv_usec; 34118316Swollman age_timer.tv_sec = EPOCH+MIN_WAITTIME; 34218316Swollman rdisc_timer = next_bcast; 34318316Swollman ifinit_timer.tv_usec = next_bcast.tv_usec; 34418316Swollman 34518316Swollman /* Collect an initial view of the world by checking the interface 34618316Swollman * configuration and the kludge file. 34718316Swollman */ 34818316Swollman gwkludge(); 34918316Swollman ifinit(); 35018316Swollman 35118316Swollman /* Ask for routes */ 35218316Swollman rip_query(); 35319896Swollman rdisc_sol(); 35418316Swollman 35546303Smarkm /* Now turn off stdio if not tracing */ 35646303Smarkm if (new_tracelevel == 0) 35746303Smarkm trace_close(background); 35846303Smarkm 35918316Swollman /* Loop forever, listening and broadcasting. 36018316Swollman */ 36118316Swollman for (;;) { 36218316Swollman prev_clk = clk; 36318316Swollman gettimeofday(&clk, 0); 36446303Smarkm if (prev_clk.tv_sec == clk.tv_sec 36546303Smarkm && prev_clk.tv_usec == clk.tv_usec+usec_fudge) { 36646303Smarkm /* Much of `routed` depends on time always advancing. 36746303Smarkm * On systems that do not guarantee that gettimeofday() 36846303Smarkm * produces unique timestamps even if called within 36946303Smarkm * a single tick, use trickery like that in classic 37046303Smarkm * BSD kernels. 37118316Swollman */ 37246303Smarkm clk.tv_usec += ++usec_fudge; 37346303Smarkm 37446303Smarkm } else { 37546303Smarkm usec_fudge = 0; 37646303Smarkm 37746303Smarkm timevalsub(&t2, &clk, &prev_clk); 37846303Smarkm if (t2.tv_sec < 0 37946303Smarkm || t2.tv_sec > wtime.tv_sec + 5) { 38046303Smarkm /* Deal with time changes before other 38146303Smarkm * housekeeping to keep everything straight. 38246303Smarkm */ 38346303Smarkm dt = t2.tv_sec; 38446303Smarkm if (dt > 0) 38546303Smarkm dt -= wtime.tv_sec; 38646303Smarkm trace_act("time changed by %d sec", (int)dt); 38746303Smarkm epoch.tv_sec += dt; 38846303Smarkm } 38918316Swollman } 39018316Swollman timevalsub(&now, &clk, &epoch); 39118316Swollman now_stale = now.tv_sec - STALE_TIME; 39218316Swollman now_expire = now.tv_sec - EXPIRE_TIME; 39318316Swollman now_garbage = now.tv_sec - GARBAGE_TIME; 39418316Swollman 39520342Swollman /* deal with signals that should affect tracing */ 39620342Swollman set_tracelevel(); 39718316Swollman 39818316Swollman if (stopint != 0) { 39919896Swollman rip_bcast(0); 40019896Swollman rdisc_adv(); 40146303Smarkm trace_off("exiting with signal %d", stopint); 40218316Swollman exit(stopint | 128); 40318316Swollman } 40418316Swollman 40518316Swollman /* look for new or dead interfaces */ 40618316Swollman timevalsub(&wtime, &ifinit_timer, &now); 40718316Swollman if (wtime.tv_sec <= 0) { 40818316Swollman wtime.tv_sec = 0; 40918316Swollman ifinit(); 41018316Swollman rip_query(); 41118316Swollman continue; 41218316Swollman } 41318316Swollman 41446303Smarkm /* Check the kernel table occassionally for mysteriously 41546303Smarkm * evaporated routes 41646303Smarkm */ 41746303Smarkm timevalsub(&t2, &flush_kern_timer, &now); 41846303Smarkm if (t2.tv_sec <= 0) { 41946303Smarkm flush_kern(); 42046303Smarkm flush_kern_timer.tv_sec = (now.tv_sec 42146303Smarkm + CHECK_QUIET_INTERVAL); 42246303Smarkm continue; 42346303Smarkm } 42446303Smarkm if (timercmp(&t2, &wtime, <)) 42546303Smarkm wtime = t2; 42646303Smarkm 42718316Swollman /* If it is time, then broadcast our routes. 42818316Swollman */ 42918316Swollman if (supplier || advertise_mhome) { 43018316Swollman timevalsub(&t2, &next_bcast, &now); 43118316Swollman if (t2.tv_sec <= 0) { 43218316Swollman /* Synchronize the aging and broadcast 43318316Swollman * timers to minimize awakenings 43418316Swollman */ 43518316Swollman age(0); 43618316Swollman 43718316Swollman rip_bcast(0); 43818316Swollman 43918316Swollman /* It is desirable to send routing updates 44018316Swollman * regularly. So schedule the next update 44118316Swollman * 30 seconds after the previous one was 44229314Sdanny * scheduled, instead of 30 seconds after 44318316Swollman * the previous update was finished. 44418316Swollman * Even if we just started after discovering 44518316Swollman * a 2nd interface or were otherwise delayed, 44618316Swollman * pick a 30-second aniversary of the 44718316Swollman * original broadcast time. 44818316Swollman */ 44918316Swollman n = 1 + (0-t2.tv_sec)/SUPPLY_INTERVAL; 45018316Swollman next_bcast.tv_sec += n*SUPPLY_INTERVAL; 45118316Swollman 45218316Swollman continue; 45318316Swollman } 45418316Swollman 45518316Swollman if (timercmp(&t2, &wtime, <)) 45618316Swollman wtime = t2; 45718316Swollman } 45818316Swollman 45918316Swollman /* If we need a flash update, either do it now or 46018316Swollman * set the delay to end when it is time. 46118316Swollman * 46218316Swollman * If we are within MIN_WAITTIME seconds of a full update, 46318316Swollman * do not bother. 46418316Swollman */ 46518316Swollman if (need_flash 46618316Swollman && supplier 46718316Swollman && no_flash.tv_sec+MIN_WAITTIME < next_bcast.tv_sec) { 46818316Swollman /* accurate to the millisecond */ 46918316Swollman if (!timercmp(&no_flash, &now, >)) 47018316Swollman rip_bcast(1); 47118316Swollman timevalsub(&t2, &no_flash, &now); 47218316Swollman if (timercmp(&t2, &wtime, <)) 47318316Swollman wtime = t2; 47418316Swollman } 47518316Swollman 47618316Swollman /* trigger the main aging timer. 47718316Swollman */ 47818316Swollman timevalsub(&t2, &age_timer, &now); 47918316Swollman if (t2.tv_sec <= 0) { 48018316Swollman age(0); 48118316Swollman continue; 48218316Swollman } 48318316Swollman if (timercmp(&t2, &wtime, <)) 48418316Swollman wtime = t2; 48518316Swollman 48618316Swollman /* update the kernel routing table 48718316Swollman */ 48818316Swollman timevalsub(&t2, &need_kern, &now); 48918316Swollman if (t2.tv_sec <= 0) { 49018316Swollman age(0); 49118316Swollman continue; 49218316Swollman } 49318316Swollman if (timercmp(&t2, &wtime, <)) 49418316Swollman wtime = t2; 49518316Swollman 49618316Swollman /* take care of router discovery, 49746303Smarkm * but do it in the correct the millisecond 49818316Swollman */ 49918316Swollman if (!timercmp(&rdisc_timer, &now, >)) { 50018316Swollman rdisc_age(0); 50118316Swollman continue; 50218316Swollman } 50318316Swollman timevalsub(&t2, &rdisc_timer, &now); 50418316Swollman if (timercmp(&t2, &wtime, <)) 50518316Swollman wtime = t2; 50618316Swollman 50718316Swollman 50818316Swollman /* wait for input or a timer to expire. 50918316Swollman */ 51018316Swollman trace_flush(); 51118316Swollman ibits = fdbits; 51218316Swollman n = select(sock_max, &ibits, 0, 0, &wtime); 51318316Swollman if (n <= 0) { 51418316Swollman if (n < 0 && errno != EINTR && errno != EAGAIN) 51518316Swollman BADERR(1,"select"); 51618316Swollman continue; 51718316Swollman } 51818316Swollman 51918316Swollman if (FD_ISSET(rt_sock, &ibits)) { 52018316Swollman read_rt(); 52118316Swollman n--; 52218316Swollman } 52318316Swollman if (rdisc_sock >= 0 && FD_ISSET(rdisc_sock, &ibits)) { 52418316Swollman read_d(); 52518316Swollman n--; 52618316Swollman } 52718316Swollman if (rip_sock >= 0 && FD_ISSET(rip_sock, &ibits)) { 52818316Swollman read_rip(rip_sock, 0); 52918316Swollman n--; 53018316Swollman } 53118316Swollman 53218316Swollman for (ifp = ifnet; n > 0 && 0 != ifp; ifp = ifp->int_next) { 53318316Swollman if (ifp->int_rip_sock >= 0 53418316Swollman && FD_ISSET(ifp->int_rip_sock, &ibits)) { 53518316Swollman read_rip(ifp->int_rip_sock, ifp); 53618316Swollman n--; 53718316Swollman } 53818316Swollman } 53918316Swollman } 54018316Swollman} 54118316Swollman 54218316Swollman 54318316Swollman/* ARGSUSED */ 54418316Swollmanvoid 54546303Smarkmsigalrm(int s UNUSED) 54618316Swollman{ 54718316Swollman /* Historically, SIGALRM would cause the daemon to check for 54818316Swollman * new and broken interfaces. 54918316Swollman */ 55018316Swollman ifinit_timer.tv_sec = now.tv_sec; 55119896Swollman trace_act("SIGALRM"); 55218316Swollman} 55318316Swollman 55418316Swollman 55518316Swollman/* watch for fatal signals */ 55618316Swollmanvoid 55718316Swollmansigterm(int sig) 55818316Swollman{ 55918316Swollman stopint = sig; 56018316Swollman (void)signal(sig, SIG_DFL); /* catch it only once */ 56118316Swollman} 56218316Swollman 56318316Swollman 56418316Swollmanvoid 56518316Swollmanfix_select(void) 56618316Swollman{ 56718316Swollman struct interface *ifp; 56818316Swollman 56918316Swollman 57018316Swollman FD_ZERO(&fdbits); 57118316Swollman sock_max = 0; 57218316Swollman 57318316Swollman FD_SET(rt_sock, &fdbits); 57418316Swollman if (sock_max <= rt_sock) 57518316Swollman sock_max = rt_sock+1; 57618316Swollman if (rip_sock >= 0) { 57718316Swollman FD_SET(rip_sock, &fdbits); 57818316Swollman if (sock_max <= rip_sock) 57918316Swollman sock_max = rip_sock+1; 58018316Swollman } 58118316Swollman for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { 58218316Swollman if (ifp->int_rip_sock >= 0) { 58318316Swollman FD_SET(ifp->int_rip_sock, &fdbits); 58418316Swollman if (sock_max <= ifp->int_rip_sock) 58518316Swollman sock_max = ifp->int_rip_sock+1; 58618316Swollman } 58718316Swollman } 58818316Swollman if (rdisc_sock >= 0) { 58918316Swollman FD_SET(rdisc_sock, &fdbits); 59018316Swollman if (sock_max <= rdisc_sock) 59118316Swollman sock_max = rdisc_sock+1; 59218316Swollman } 59318316Swollman} 59418316Swollman 59518316Swollman 59618316Swollmanvoid 59718316Swollmanfix_sock(int sock, 59846303Smarkm const char *name) 59918316Swollman{ 60018316Swollman int on; 60118316Swollman#define MIN_SOCKBUF (4*1024) 60218316Swollman static int rbuf; 60318316Swollman 60418316Swollman if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) 60518316Swollman logbad(1, "fcntl(%s) O_NONBLOCK: %s", 60618316Swollman name, strerror(errno)); 60718316Swollman on = 1; 60819896Swollman if (setsockopt(sock, SOL_SOCKET,SO_BROADCAST, &on,sizeof(on)) < 0) 60918316Swollman msglog("setsockopt(%s,SO_BROADCAST): %s", 61018316Swollman name, strerror(errno)); 61119896Swollman#ifdef USE_PASSIFNAME 61219896Swollman on = 1; 61319896Swollman if (setsockopt(sock, SOL_SOCKET, SO_PASSIFNAME, &on,sizeof(on)) < 0) 61419896Swollman msglog("setsockopt(%s,SO_PASSIFNAME): %s", 61519896Swollman name, strerror(errno)); 61619896Swollman#endif 61719896Swollman 61818316Swollman if (rbuf >= MIN_SOCKBUF) { 61918316Swollman if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 62018316Swollman &rbuf, sizeof(rbuf)) < 0) 62118316Swollman msglog("setsockopt(%s,SO_RCVBUF=%d): %s", 62218316Swollman name, rbuf, strerror(errno)); 62318316Swollman } else { 62418316Swollman for (rbuf = 60*1024; ; rbuf -= 4096) { 62518316Swollman if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 62618316Swollman &rbuf, sizeof(rbuf)) == 0) { 62719896Swollman trace_act("RCVBUF=%d", rbuf); 62818316Swollman break; 62918316Swollman } 63018316Swollman if (rbuf < MIN_SOCKBUF) { 63118316Swollman msglog("setsockopt(%s,SO_RCVBUF = %d): %s", 63218316Swollman name, rbuf, strerror(errno)); 63318316Swollman break; 63418316Swollman } 63518316Swollman } 63618316Swollman } 63718316Swollman} 63818316Swollman 63918316Swollman 64018316Swollman/* get a rip socket 64118316Swollman */ 64218316Swollmanstatic int /* <0 or file descriptor */ 64318316Swollmanget_rip_sock(naddr addr, 64418316Swollman int serious) /* 1=failure to bind is serious */ 64518316Swollman{ 646126250Sbms struct sockaddr_in rsin; 64718316Swollman unsigned char ttl; 64818316Swollman int s; 64918316Swollman 65018316Swollman 65118316Swollman if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 65218316Swollman BADERR(1,"rip_sock = socket()"); 65318316Swollman 654126250Sbms memset(&rsin, 0, sizeof(rsin)); 65518316Swollman#ifdef _HAVE_SIN_LEN 656126250Sbms rsin.sin_len = sizeof(rsin); 65718316Swollman#endif 658126250Sbms rsin.sin_family = AF_INET; 659126250Sbms rsin.sin_port = htons(RIP_PORT); 660126250Sbms rsin.sin_addr.s_addr = addr; 661126250Sbms if (bind(s, (struct sockaddr *)&rsin, sizeof(rsin)) < 0) { 66218316Swollman if (serious) 66318316Swollman BADERR(errno != EADDRINUSE, "bind(rip_sock)"); 66418316Swollman return -1; 66518316Swollman } 66618316Swollman fix_sock(s,"rip_sock"); 66718316Swollman 66818316Swollman ttl = 1; 66918316Swollman if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, 67018316Swollman &ttl, sizeof(ttl)) < 0) 67118316Swollman DBGERR(1,"rip_sock setsockopt(IP_MULTICAST_TTL)"); 67218316Swollman 67318316Swollman return s; 67418316Swollman} 67518316Swollman 67618316Swollman 67718316Swollman/* turn off main RIP socket */ 67818316Swollmanvoid 67918316Swollmanrip_off(void) 68018316Swollman{ 68118316Swollman struct interface *ifp; 68246303Smarkm naddr addr; 68318316Swollman 68418316Swollman 68518316Swollman if (rip_sock >= 0 && !mhome) { 68619896Swollman trace_act("turn off RIP"); 68718316Swollman 68818316Swollman (void)close(rip_sock); 68918316Swollman rip_sock = -1; 69018316Swollman 69118316Swollman /* get non-broadcast sockets to listen to queries. 69218316Swollman */ 69318316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 69419896Swollman if (ifp->int_state & IS_REMOTE) 69519896Swollman continue; 69619896Swollman if (ifp->int_rip_sock < 0) { 69718316Swollman addr = ((ifp->int_if_flags & IFF_POINTOPOINT) 69818316Swollman ? ifp->int_dstaddr 69918316Swollman : ifp->int_addr); 70018316Swollman ifp->int_rip_sock = get_rip_sock(addr, 0); 70118316Swollman } 70218316Swollman } 70318316Swollman 70418316Swollman fix_select(); 70518316Swollman 70618316Swollman age(0); 70718316Swollman } 70818316Swollman} 70918316Swollman 71018316Swollman 71118316Swollman/* turn on RIP multicast input via an interface 71218316Swollman */ 71318316Swollmanstatic void 71418316Swollmanrip_mcast_on(struct interface *ifp) 71518316Swollman{ 71618316Swollman struct ip_mreq m; 71718316Swollman 71818316Swollman if (!IS_RIP_IN_OFF(ifp->int_state) 71918316Swollman && (ifp->int_if_flags & IFF_MULTICAST) 72018316Swollman#ifdef MCAST_PPP_BUG 72118316Swollman && !(ifp->int_if_flags & IFF_POINTOPOINT) 72218316Swollman#endif 72318316Swollman && !(ifp->int_state & IS_ALIAS)) { 72418316Swollman m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); 725126250Sbms#ifdef MCAST_IFINDEX 726126250Sbms m.imr_interface.s_addr = htonl(ifp->int_index); 727126250Sbms#else 72818316Swollman m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) 72918316Swollman ? ifp->int_dstaddr 73018316Swollman : ifp->int_addr); 731126250Sbms#endif 73218316Swollman if (setsockopt(rip_sock,IPPROTO_IP, IP_ADD_MEMBERSHIP, 73318316Swollman &m, sizeof(m)) < 0) 73418316Swollman LOGERR("setsockopt(IP_ADD_MEMBERSHIP RIP)"); 73518316Swollman } 73618316Swollman} 73718316Swollman 73818316Swollman 73918316Swollman/* Prepare socket used for RIP. 74018316Swollman */ 74118316Swollmanvoid 74218316Swollmanrip_on(struct interface *ifp) 74318316Swollman{ 74418316Swollman /* If the main RIP socket is already alive, only start receiving 74518316Swollman * multicasts for this interface. 74618316Swollman */ 74718316Swollman if (rip_sock >= 0) { 74818316Swollman if (ifp != 0) 74918316Swollman rip_mcast_on(ifp); 75018316Swollman return; 75118316Swollman } 75218316Swollman 75319896Swollman /* If the main RIP socket is off and it makes sense to turn it on, 75419896Swollman * then turn it on for all of the interfaces. 75546303Smarkm * It makes sense if either router discovery is off, or if 75646303Smarkm * router discover is on and at most one interface is doing RIP. 75718316Swollman */ 75846303Smarkm if (rip_interfaces > 0 && (!rdisc_ok || rip_interfaces > 1)) { 75919896Swollman trace_act("turn on RIP"); 76018316Swollman 76118316Swollman /* Close all of the query sockets so that we can open 76218316Swollman * the main socket. SO_REUSEPORT is not a solution, 76318316Swollman * since that would let two daemons bind to the broadcast 76418316Swollman * socket. 76518316Swollman */ 76618316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 76718316Swollman if (ifp->int_rip_sock >= 0) { 76818316Swollman (void)close(ifp->int_rip_sock); 76918316Swollman ifp->int_rip_sock = -1; 77018316Swollman } 77118316Swollman } 77218316Swollman 77318316Swollman rip_sock = get_rip_sock(INADDR_ANY, 1); 77418316Swollman rip_sock_mcast = 0; 77518316Swollman 77618316Swollman /* Do not advertise anything until we have heard something 77718316Swollman */ 77818316Swollman if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME) 77918316Swollman next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME; 78018316Swollman 78118316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 78219896Swollman ifp->int_query_time = NEVER; 78318316Swollman rip_mcast_on(ifp); 78418316Swollman } 78518316Swollman ifinit_timer.tv_sec = now.tv_sec; 78618316Swollman 78718316Swollman } else if (ifp != 0 78819896Swollman && !(ifp->int_state & IS_REMOTE) 78919896Swollman && ifp->int_rip_sock < 0) { 79018316Swollman /* RIP is off, so ensure there are sockets on which 79118316Swollman * to listen for queries. 79218316Swollman */ 79318316Swollman ifp->int_rip_sock = get_rip_sock(ifp->int_addr, 0); 79419896Swollman } 79518316Swollman 79619896Swollman fix_select(); 79718316Swollman} 79818316Swollman 79918316Swollman 80018316Swollman/* die if malloc(3) fails 80118316Swollman */ 80218316Swollmanvoid * 80318316Swollmanrtmalloc(size_t size, 80446303Smarkm const char *msg) 80518316Swollman{ 80618316Swollman void *p = malloc(size); 80746303Smarkm if (p == 0) 80846303Smarkm logbad(1,"malloc(%lu) failed in %s", (u_long)size, msg); 80918316Swollman return p; 81018316Swollman} 81118316Swollman 81218316Swollman 81318316Swollman/* get a random instant in an interval 81418316Swollman */ 81518316Swollmanvoid 81618316Swollmanintvl_random(struct timeval *tp, /* put value here */ 81718316Swollman u_long lo, /* value is after this second */ 81818316Swollman u_long hi) /* and before this */ 81918316Swollman{ 82018316Swollman tp->tv_sec = (time_t)(hi == lo 82118316Swollman ? lo 82218316Swollman : (lo + random() % ((hi - lo)))); 82318316Swollman tp->tv_usec = random() % 1000000; 82418316Swollman} 82518316Swollman 82618316Swollman 82718316Swollmanvoid 82818316Swollmantimevaladd(struct timeval *t1, 82918316Swollman struct timeval *t2) 83018316Swollman{ 83118316Swollman 83218316Swollman t1->tv_sec += t2->tv_sec; 83337908Scharnier if ((t1->tv_usec += t2->tv_usec) >= 1000000) { 83418316Swollman t1->tv_sec++; 83518316Swollman t1->tv_usec -= 1000000; 83618316Swollman } 83718316Swollman} 83818316Swollman 83918316Swollman 84018316Swollman/* t1 = t2 - t3 84118316Swollman */ 84218316Swollmanstatic void 84318316Swollmantimevalsub(struct timeval *t1, 84418316Swollman struct timeval *t2, 84518316Swollman struct timeval *t3) 84618316Swollman{ 84718316Swollman t1->tv_sec = t2->tv_sec - t3->tv_sec; 84818316Swollman if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) { 84918316Swollman t1->tv_sec--; 85018316Swollman t1->tv_usec += 1000000; 85118316Swollman } 85218316Swollman} 85318316Swollman 85418316Swollman 85519896Swollman/* put a message into the system log 85619896Swollman */ 85718316Swollmanvoid 85846303Smarkmmsglog(const char *p, ...) 85918316Swollman{ 86018316Swollman va_list args; 86118316Swollman 86218316Swollman trace_flush(); 86318316Swollman 86418316Swollman va_start(args, p); 86518316Swollman vsyslog(LOG_ERR, p, args); 866163999Strhodes va_end(args); 86718316Swollman if (ftrace != 0) { 86818316Swollman if (ftrace == stdout) 86918316Swollman (void)fputs("routed: ", ftrace); 870163999Strhodes va_start(args, p); 87118316Swollman (void)vfprintf(ftrace, p, args); 872163999Strhodes va_end(args); 87318316Swollman (void)fputc('\n', ftrace); 87418316Swollman } 87518316Swollman} 87618316Swollman 87718316Swollman 87820342Swollman/* Put a message about a bad system into the system log if 87919896Swollman * we have not complained about it recently. 88020342Swollman * 88120342Swollman * It is desirable to complain about all bad systems, but not too often. 88220342Swollman * In the worst case, it is not practical to keep track of all bad systems. 88320342Swollman * For example, there can be many systems with the wrong password. 88419896Swollman */ 88518316Swollmanvoid 88646303Smarkmmsglim(struct msg_limit *lim, naddr addr, const char *p, ...) 88719896Swollman{ 88819896Swollman va_list args; 88920342Swollman int i; 89020342Swollman struct msg_sub *ms1, *ms; 89146303Smarkm const char *p1; 89219896Swollman 89320342Swollman /* look for the oldest slot in the table 89420342Swollman * or the slot for the bad router. 89520342Swollman */ 89620342Swollman ms = ms1 = lim->subs; 89720342Swollman for (i = MSG_SUBJECT_N; ; i--, ms1++) { 89820342Swollman if (i == 0) { 89920342Swollman /* Reuse a slot at most once every 10 minutes. 90020342Swollman */ 90120342Swollman if (lim->reuse > now.tv_sec) { 90220342Swollman ms = 0; 90320342Swollman } else { 90420342Swollman ms = ms1; 90520342Swollman lim->reuse = now.tv_sec + 10*60; 90620342Swollman } 90720342Swollman break; 90820342Swollman } 90920342Swollman if (ms->addr == addr) { 91020342Swollman /* Repeat a complaint about a given system at 91120342Swollman * most once an hour. 91220342Swollman */ 91320342Swollman if (ms->until > now.tv_sec) 91420342Swollman ms = 0; 91520342Swollman break; 91620342Swollman } 91720342Swollman if (ms->until < ms1->until) 91820342Swollman ms = ms1; 91920342Swollman } 92020342Swollman if (ms != 0) { 92120342Swollman ms->addr = addr; 92220342Swollman ms->until = now.tv_sec + 60*60; /* 60 minutes */ 92319896Swollman 92419896Swollman trace_flush(); 92519896Swollman for (p1 = p; *p1 == ' '; p1++) 92619896Swollman continue; 927163999Strhodes va_start(args, p); 92819896Swollman vsyslog(LOG_ERR, p1, args); 929163999Strhodes va_end(args); 93019896Swollman } 93119896Swollman 93220342Swollman /* always display the message if tracing */ 93319896Swollman if (ftrace != 0) { 934163999Strhodes va_start(args, p); 93519896Swollman (void)vfprintf(ftrace, p, args); 936163999Strhodes va_end(args); 93719896Swollman (void)fputc('\n', ftrace); 93819896Swollman } 93919896Swollman} 94019896Swollman 94119896Swollman 94219896Swollmanvoid 94346303Smarkmlogbad(int dump, const char *p, ...) 94418316Swollman{ 94518316Swollman va_list args; 94618316Swollman 94718316Swollman trace_flush(); 94818316Swollman 94918316Swollman va_start(args, p); 95018316Swollman vsyslog(LOG_ERR, p, args); 951163999Strhodes va_end(args); 95218316Swollman (void)fputs("routed: ", stderr); 953163999Strhodes va_start(args, p); 95418316Swollman (void)vfprintf(stderr, p, args); 955163999Strhodes va_end(args); 95618316Swollman (void)fputs("; giving up\n",stderr); 95718316Swollman (void)fflush(stderr); 95818316Swollman 95918316Swollman if (dump) 96018316Swollman abort(); 96118316Swollman exit(1); 96218316Swollman} 963