main.c revision 19896
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 1418316Swollman * must display the following acknowledgement: 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. 3218316Swollman */ 3318316Swollman 3418316Swollmanchar copyright[] = 3518316Swollman"@(#) Copyright (c) 1983, 1988, 1993\n\ 3618316Swollman The Regents of the University of California. All rights reserved.\n"; 3718316Swollman#if !defined(lint) && !defined(sgi) && !defined(__NetBSD__) 3818316Swollmanstatic char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/5/93"; 3918316Swollman#elif defined(__NetBSD__) 4018316Swollmanstatic char rcsid[] = "$NetBSD$"; 4118316Swollman#endif 4219896Swollman#ident "$Revision: 1.18 $" 4318316Swollman 4418316Swollman#include "defs.h" 4518316Swollman#include "pathnames.h" 4618316Swollman#ifdef sgi 4718316Swollman#include "math.h" 4818316Swollman#endif 4918316Swollman#include <signal.h> 5018316Swollman#include <fcntl.h> 5118316Swollman#include <sys/file.h> 5218316Swollman 5318316Swollmanpid_t mypid; 5418316Swollman 5518316Swollmannaddr myaddr; /* system address */ 5618316Swollmanchar myname[MAXHOSTNAMELEN+1]; 5718316Swollman 5818316Swollmanint supplier; /* supply or broadcast updates */ 5918316Swollmanint supplier_set; 6018316Swollmanint ipforwarding = 1; /* kernel forwarding on */ 6118316Swollman 6218316Swollmanint default_gateway; /* 1=advertise default */ 6318316Swollmanint background = 1; 6418316Swollmanint ridhosts; /* 1=reduce host routes */ 6518316Swollmanint mhome; /* 1=want multi-homed host route */ 6618316Swollmanint advertise_mhome; /* 1=must continue adverising it */ 6718316Swollmanint auth_ok = 1; /* 1=ignore auth if we do not care */ 6818316Swollman 6918316Swollmanstruct timeval epoch; /* when started */ 7018316Swollmanstruct timeval clk, prev_clk; 7118316Swollmanstruct timeval now; /* current idea of time */ 7218316Swollmantime_t now_stale; 7318316Swollmantime_t now_expire; 7418316Swollmantime_t now_garbage; 7518316Swollman 7618316Swollmanstruct timeval next_bcast; /* next general broadcast */ 7718316Swollmanstruct timeval no_flash = {EPOCH+SUPPLY_INTERVAL}; /* inhibit flash update */ 7818316Swollman 7918316Swollmanfd_set fdbits; 8018316Swollmanint sock_max; 8118316Swollmanint rip_sock = -1; /* RIP socket */ 8218316Swollmanstruct interface *rip_sock_mcast; /* current multicast interface */ 8318316Swollmanint rt_sock; /* routing socket */ 8418316Swollmanint rt_sock_seqno; 8518316Swollman 8618316Swollman 8718316Swollmanstatic int get_rip_sock(naddr, int); 8818316Swollmanstatic void timevalsub(struct timeval *, struct timeval *, struct timeval *); 8918316Swollman 9018316Swollmanint 9118316Swollmanmain(int argc, 9218316Swollman char *argv[]) 9318316Swollman{ 9418316Swollman int n, mib[4], off; 9518316Swollman size_t len; 9618316Swollman char *p, *q; 9718316Swollman struct timeval wtime, t2; 9818316Swollman time_t dt; 9918316Swollman fd_set ibits; 10019896Swollman naddr p_net, p_mask; 10118316Swollman struct interface *ifp; 10218316Swollman struct parm parm; 10318316Swollman char *tracename = 0; 10418316Swollman 10518316Swollman 10619896Swollman /* Some shells are badly broken and send SIGHUP to backgrounded 10719896Swollman * processes. 10819896Swollman */ 10919896Swollman signal(SIGHUP, SIG_IGN); 11019896Swollman 11118316Swollman openlog("routed", LOG_PID | LOG_ODELAY, LOG_DAEMON); 11218316Swollman ftrace = stdout; 11318316Swollman 11418316Swollman gettimeofday(&clk, 0); 11518316Swollman prev_clk = clk; 11618316Swollman epoch = clk; 11718316Swollman epoch.tv_sec -= EPOCH; 11818316Swollman now.tv_sec = EPOCH; 11918316Swollman now_stale = EPOCH - STALE_TIME; 12018316Swollman now_expire = EPOCH - EXPIRE_TIME; 12118316Swollman now_garbage = EPOCH - GARBAGE_TIME; 12218316Swollman wtime.tv_sec = 0; 12318316Swollman 12418316Swollman (void)gethostname(myname, sizeof(myname)-1); 12518316Swollman (void)gethost(myname, &myaddr); 12618316Swollman 12719896Swollman while ((n = getopt(argc, argv, "sqdghmpAtT:F:P:")) != EOF) { 12818316Swollman switch (n) { 12918316Swollman case 's': 13018316Swollman supplier = 1; 13118316Swollman supplier_set = 1; 13218316Swollman break; 13318316Swollman 13418316Swollman case 'q': 13518316Swollman supplier = 0; 13618316Swollman supplier_set = 1; 13718316Swollman break; 13818316Swollman 13918316Swollman case 'd': 14018316Swollman background = 0; 14118316Swollman break; 14218316Swollman 14318316Swollman case 'g': 14418316Swollman bzero(&parm, sizeof(parm)); 14518316Swollman parm.parm_d_metric = 1; 14618316Swollman p = check_parms(&parm); 14718316Swollman if (p != 0) 14818316Swollman msglog("bad -g: %s", p); 14918316Swollman else 15018316Swollman default_gateway = 1; 15118316Swollman break; 15218316Swollman 15318316Swollman case 'h': /* suppress extra host routes */ 15418316Swollman ridhosts = 1; 15518316Swollman break; 15618316Swollman 15718316Swollman case 'm': /* advertise host route */ 15818316Swollman mhome = 1; /* on multi-homed hosts */ 15918316Swollman break; 16018316Swollman 16118316Swollman case 'A': 16218316Swollman /* Ignore authentication if we do not care. 16318316Swollman * Crazy as it is, that is what RFC 1723 requires. 16418316Swollman */ 16518316Swollman auth_ok = 0; 16618316Swollman break; 16718316Swollman 16818316Swollman case 't': 16918316Swollman new_tracelevel++; 17018316Swollman break; 17118316Swollman 17218316Swollman case 'T': 17318316Swollman tracename = optarg; 17418316Swollman break; 17518316Swollman 17618316Swollman case 'F': /* minimal routes for SLIP */ 17719896Swollman n = FAKE_METRIC; 17818316Swollman p = strchr(optarg,','); 17918316Swollman if (p && *p != '\0') { 18018316Swollman n = (int)strtoul(p+1, &q, 0); 18118316Swollman if (*q == '\0' 18218316Swollman && n <= HOPCNT_INFINITY-1 18318316Swollman && n >= 1) 18418316Swollman *p = '\0'; 18518316Swollman } 18619896Swollman if (!getnet(optarg, &p_net, &p_mask)) { 18718316Swollman msglog("bad network; \"-F %s\"", 18818316Swollman optarg); 18918316Swollman break; 19018316Swollman } 19118316Swollman bzero(&parm, sizeof(parm)); 19219896Swollman parm.parm_net = p_net; 19318316Swollman parm.parm_mask = p_mask; 19418316Swollman parm.parm_d_metric = n; 19518316Swollman p = check_parms(&parm); 19618316Swollman if (p != 0) 19718316Swollman msglog("bad -F: %s", p); 19818316Swollman break; 19918316Swollman 20018316Swollman case 'P': 20118316Swollman /* handle arbirary, (usually) per-interface 20218316Swollman * parameters. 20318316Swollman */ 20418316Swollman p = parse_parms(optarg); 20518316Swollman if (p != 0) 20618316Swollman msglog("bad \"%s\" in \"%s\"", 20718316Swollman p, optarg); 20818316Swollman break; 20918316Swollman 21018316Swollman default: 21118316Swollman goto usage; 21218316Swollman } 21318316Swollman } 21418316Swollman argc -= optind; 21518316Swollman argv += optind; 21618316Swollman 21718316Swollman if (tracename == 0 && argc >= 1) { 21818316Swollman tracename = *argv++; 21918316Swollman argc--; 22018316Swollman } 22118316Swollman if (argc != 0) { 22218316Swollmanusage: 22318316Swollman logbad(0, "usage: routed [-sqdghmpAt] [-T /tracefile]" 22418316Swollman " [-F net[,metric]] [-P parms]"); 22518316Swollman } 22618316Swollman if (geteuid() != 0) 22718316Swollman logbad(0, "requires UID 0"); 22818316Swollman 22918316Swollman mib[0] = CTL_NET; 23018316Swollman mib[1] = PF_INET; 23118316Swollman mib[2] = IPPROTO_IP; 23218316Swollman mib[3] = IPCTL_FORWARDING; 23318316Swollman len = sizeof(ipforwarding); 23418316Swollman if (sysctl(mib, 4, &ipforwarding, &len, 0, 0) < 0) 23518316Swollman LOGERR("sysctl(IPCTL_FORWARDING)"); 23618316Swollman 23718316Swollman if (!ipforwarding) { 23818316Swollman if (supplier) 23918316Swollman msglog("-s incompatible with ipforwarding=0"); 24018316Swollman if (default_gateway) { 24118316Swollman msglog("-g incompatible with ipforwarding=0"); 24218316Swollman default_gateway = 0; 24318316Swollman } 24418316Swollman supplier = 0; 24518316Swollman supplier_set = 1; 24618316Swollman } 24718316Swollman if (default_gateway) { 24818316Swollman if (supplier_set && !supplier) { 24918316Swollman msglog("-g and -q incompatible"); 25018316Swollman } else { 25118316Swollman supplier = 1; 25218316Swollman supplier_set = 1; 25318316Swollman } 25418316Swollman } 25518316Swollman 25618316Swollman 25718316Swollman signal(SIGALRM, sigalrm); 25818316Swollman if (!background) 25918316Swollman signal(SIGHUP, sigterm); /* SIGHUP fatal during debugging */ 26018316Swollman signal(SIGTERM, sigterm); 26118316Swollman signal(SIGINT, sigterm); 26218316Swollman signal(SIGUSR1, sigtrace_on); 26318316Swollman signal(SIGUSR2, sigtrace_off); 26418316Swollman 26518316Swollman /* get into the background */ 26618316Swollman if (background) { 26718316Swollman#ifdef sgi 26818316Swollman if (0 > _daemonize(_DF_NOCHDIR, 26918316Swollman new_tracelevel == 0 ? -1 : STDOUT_FILENO, 27018316Swollman new_tracelevel == 0 ? -1 : STDERR_FILENO, 27118316Swollman -1)) 27218316Swollman BADERR(0, "_daemonize()"); 27318316Swollman#else 27418316Swollman if (daemon(1, 1) < 0) 27518316Swollman BADERR(0,"daemon()"); 27618316Swollman#endif 27718316Swollman } 27818316Swollman 27918316Swollman mypid = getpid(); 28018316Swollman srandom((int)(clk.tv_sec ^ clk.tv_usec ^ mypid)); 28118316Swollman 28218316Swollman /* prepare socket connected to the kernel. 28318316Swollman */ 28418316Swollman rt_sock = socket(AF_ROUTE, SOCK_RAW, 0); 28518316Swollman if (rt_sock < 0) 28618316Swollman BADERR(1,"rt_sock = socket()"); 28718316Swollman if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1) 28818316Swollman logbad(1, "fcntl(rt_sock) O_NONBLOCK: %s", strerror(errno)); 28918316Swollman off = 0; 29018316Swollman if (setsockopt(rt_sock, SOL_SOCKET,SO_USELOOPBACK, 29118316Swollman &off,sizeof(off)) < 0) 29218316Swollman LOGERR("setsockopt(SO_USELOOPBACK,0)"); 29318316Swollman 29418316Swollman fix_select(); 29518316Swollman 29618316Swollman 29718316Swollman if (background && new_tracelevel == 0) 29818316Swollman ftrace = 0; 29918316Swollman if (tracename != 0) { 30018316Swollman trace_on(tracename, 1); 30118316Swollman if (new_tracelevel == 0) /* use stdout if file is bad */ 30218316Swollman new_tracelevel = 1; 30318316Swollman } 30419896Swollman set_tracelevel(1); 30518316Swollman 30619896Swollman bufinit(); 30719896Swollman 30818316Swollman /* initialize radix tree */ 30918316Swollman rtinit(); 31018316Swollman 31118316Swollman /* Pick a random part of the second for our output to minimize 31218316Swollman * collisions. 31318316Swollman * 31418316Swollman * Start broadcasting after hearing from other routers, and 31518316Swollman * at a random time so a bunch of systems do not get synchronized 31618316Swollman * after a power failure. 31718316Swollman */ 31818316Swollman intvl_random(&next_bcast, EPOCH+MIN_WAITTIME, EPOCH+SUPPLY_INTERVAL); 31918316Swollman age_timer.tv_usec = next_bcast.tv_usec; 32018316Swollman age_timer.tv_sec = EPOCH+MIN_WAITTIME; 32118316Swollman rdisc_timer = next_bcast; 32218316Swollman ifinit_timer.tv_usec = next_bcast.tv_usec; 32318316Swollman 32418316Swollman /* Collect an initial view of the world by checking the interface 32518316Swollman * configuration and the kludge file. 32618316Swollman */ 32718316Swollman gwkludge(); 32818316Swollman ifinit(); 32918316Swollman flush_kern(); 33018316Swollman 33118316Swollman /* Ask for routes */ 33218316Swollman rip_query(); 33319896Swollman rdisc_sol(); 33418316Swollman 33518316Swollman /* Loop forever, listening and broadcasting. 33618316Swollman */ 33718316Swollman for (;;) { 33818316Swollman prev_clk = clk; 33918316Swollman gettimeofday(&clk, 0); 34018316Swollman timevalsub(&t2, &clk, &prev_clk); 34118316Swollman if (t2.tv_sec < 0 34218316Swollman || t2.tv_sec > wtime.tv_sec + 5) { 34318316Swollman /* Deal with time changes before other housekeeping to 34418316Swollman * keep everything straight. 34518316Swollman */ 34618316Swollman dt = t2.tv_sec; 34718316Swollman if (dt > 0) 34818316Swollman dt -= wtime.tv_sec; 34919896Swollman trace_act("time changed by %d sec", dt); 35018316Swollman epoch.tv_sec += dt; 35118316Swollman } 35218316Swollman timevalsub(&now, &clk, &epoch); 35318316Swollman now_stale = now.tv_sec - STALE_TIME; 35418316Swollman now_expire = now.tv_sec - EXPIRE_TIME; 35518316Swollman now_garbage = now.tv_sec - GARBAGE_TIME; 35618316Swollman 35718316Swollman /* deal with interrupts that should affect tracing */ 35819896Swollman set_tracelevel(0); 35918316Swollman 36018316Swollman if (stopint != 0) { 36119896Swollman rip_bcast(0); 36219896Swollman rdisc_adv(); 36318316Swollman trace_off("exiting with signal %d\n", stopint); 36418316Swollman exit(stopint | 128); 36518316Swollman } 36618316Swollman 36718316Swollman /* look for new or dead interfaces */ 36818316Swollman timevalsub(&wtime, &ifinit_timer, &now); 36918316Swollman if (wtime.tv_sec <= 0) { 37018316Swollman wtime.tv_sec = 0; 37118316Swollman ifinit(); 37218316Swollman rip_query(); 37318316Swollman continue; 37418316Swollman } 37518316Swollman 37618316Swollman /* If it is time, then broadcast our routes. 37718316Swollman */ 37818316Swollman if (supplier || advertise_mhome) { 37918316Swollman timevalsub(&t2, &next_bcast, &now); 38018316Swollman if (t2.tv_sec <= 0) { 38118316Swollman /* Synchronize the aging and broadcast 38218316Swollman * timers to minimize awakenings 38318316Swollman */ 38418316Swollman age(0); 38518316Swollman 38618316Swollman rip_bcast(0); 38718316Swollman 38818316Swollman /* It is desirable to send routing updates 38918316Swollman * regularly. So schedule the next update 39018316Swollman * 30 seconds after the previous one was 39118316Swollman * secheduled, instead of 30 seconds after 39218316Swollman * the previous update was finished. 39318316Swollman * Even if we just started after discovering 39418316Swollman * a 2nd interface or were otherwise delayed, 39518316Swollman * pick a 30-second aniversary of the 39618316Swollman * original broadcast time. 39718316Swollman */ 39818316Swollman n = 1 + (0-t2.tv_sec)/SUPPLY_INTERVAL; 39918316Swollman next_bcast.tv_sec += n*SUPPLY_INTERVAL; 40018316Swollman 40118316Swollman continue; 40218316Swollman } 40318316Swollman 40418316Swollman if (timercmp(&t2, &wtime, <)) 40518316Swollman wtime = t2; 40618316Swollman } 40718316Swollman 40818316Swollman /* If we need a flash update, either do it now or 40918316Swollman * set the delay to end when it is time. 41018316Swollman * 41118316Swollman * If we are within MIN_WAITTIME seconds of a full update, 41218316Swollman * do not bother. 41318316Swollman */ 41418316Swollman if (need_flash 41518316Swollman && supplier 41618316Swollman && no_flash.tv_sec+MIN_WAITTIME < next_bcast.tv_sec) { 41718316Swollman /* accurate to the millisecond */ 41818316Swollman if (!timercmp(&no_flash, &now, >)) 41918316Swollman rip_bcast(1); 42018316Swollman timevalsub(&t2, &no_flash, &now); 42118316Swollman if (timercmp(&t2, &wtime, <)) 42218316Swollman wtime = t2; 42318316Swollman } 42418316Swollman 42518316Swollman /* trigger the main aging timer. 42618316Swollman */ 42718316Swollman timevalsub(&t2, &age_timer, &now); 42818316Swollman if (t2.tv_sec <= 0) { 42918316Swollman age(0); 43018316Swollman continue; 43118316Swollman } 43218316Swollman if (timercmp(&t2, &wtime, <)) 43318316Swollman wtime = t2; 43418316Swollman 43518316Swollman /* update the kernel routing table 43618316Swollman */ 43718316Swollman timevalsub(&t2, &need_kern, &now); 43818316Swollman if (t2.tv_sec <= 0) { 43918316Swollman age(0); 44018316Swollman continue; 44118316Swollman } 44218316Swollman if (timercmp(&t2, &wtime, <)) 44318316Swollman wtime = t2; 44418316Swollman 44518316Swollman /* take care of router discovery, 44618316Swollman * but do it to the millisecond 44718316Swollman */ 44818316Swollman if (!timercmp(&rdisc_timer, &now, >)) { 44918316Swollman rdisc_age(0); 45018316Swollman continue; 45118316Swollman } 45218316Swollman timevalsub(&t2, &rdisc_timer, &now); 45318316Swollman if (timercmp(&t2, &wtime, <)) 45418316Swollman wtime = t2; 45518316Swollman 45618316Swollman 45718316Swollman /* wait for input or a timer to expire. 45818316Swollman */ 45918316Swollman trace_flush(); 46018316Swollman ibits = fdbits; 46118316Swollman n = select(sock_max, &ibits, 0, 0, &wtime); 46218316Swollman if (n <= 0) { 46318316Swollman if (n < 0 && errno != EINTR && errno != EAGAIN) 46418316Swollman BADERR(1,"select"); 46518316Swollman continue; 46618316Swollman } 46718316Swollman 46818316Swollman if (FD_ISSET(rt_sock, &ibits)) { 46918316Swollman read_rt(); 47018316Swollman n--; 47118316Swollman } 47218316Swollman if (rdisc_sock >= 0 && FD_ISSET(rdisc_sock, &ibits)) { 47318316Swollman read_d(); 47418316Swollman n--; 47518316Swollman } 47618316Swollman if (rip_sock >= 0 && FD_ISSET(rip_sock, &ibits)) { 47718316Swollman read_rip(rip_sock, 0); 47818316Swollman n--; 47918316Swollman } 48018316Swollman 48118316Swollman for (ifp = ifnet; n > 0 && 0 != ifp; ifp = ifp->int_next) { 48218316Swollman if (ifp->int_rip_sock >= 0 48318316Swollman && FD_ISSET(ifp->int_rip_sock, &ibits)) { 48418316Swollman read_rip(ifp->int_rip_sock, ifp); 48518316Swollman n--; 48618316Swollman } 48718316Swollman } 48818316Swollman } 48918316Swollman} 49018316Swollman 49118316Swollman 49218316Swollman/* ARGSUSED */ 49318316Swollmanvoid 49418316Swollmansigalrm(int sig) 49518316Swollman{ 49618316Swollman /* Historically, SIGALRM would cause the daemon to check for 49718316Swollman * new and broken interfaces. 49818316Swollman */ 49918316Swollman ifinit_timer.tv_sec = now.tv_sec; 50019896Swollman trace_act("SIGALRM"); 50118316Swollman} 50218316Swollman 50318316Swollman 50418316Swollman/* watch for fatal signals */ 50518316Swollmanvoid 50618316Swollmansigterm(int sig) 50718316Swollman{ 50818316Swollman stopint = sig; 50918316Swollman (void)signal(sig, SIG_DFL); /* catch it only once */ 51018316Swollman} 51118316Swollman 51218316Swollman 51318316Swollmanvoid 51418316Swollmanfix_select(void) 51518316Swollman{ 51618316Swollman struct interface *ifp; 51718316Swollman 51818316Swollman 51918316Swollman FD_ZERO(&fdbits); 52018316Swollman sock_max = 0; 52118316Swollman 52218316Swollman FD_SET(rt_sock, &fdbits); 52318316Swollman if (sock_max <= rt_sock) 52418316Swollman sock_max = rt_sock+1; 52518316Swollman if (rip_sock >= 0) { 52618316Swollman FD_SET(rip_sock, &fdbits); 52718316Swollman if (sock_max <= rip_sock) 52818316Swollman sock_max = rip_sock+1; 52918316Swollman } 53018316Swollman for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { 53118316Swollman if (ifp->int_rip_sock >= 0) { 53218316Swollman FD_SET(ifp->int_rip_sock, &fdbits); 53318316Swollman if (sock_max <= ifp->int_rip_sock) 53418316Swollman sock_max = ifp->int_rip_sock+1; 53518316Swollman } 53618316Swollman } 53718316Swollman if (rdisc_sock >= 0) { 53818316Swollman FD_SET(rdisc_sock, &fdbits); 53918316Swollman if (sock_max <= rdisc_sock) 54018316Swollman sock_max = rdisc_sock+1; 54118316Swollman } 54218316Swollman} 54318316Swollman 54418316Swollman 54518316Swollmanvoid 54618316Swollmanfix_sock(int sock, 54718316Swollman char *name) 54818316Swollman{ 54918316Swollman int on; 55018316Swollman#define MIN_SOCKBUF (4*1024) 55118316Swollman static int rbuf; 55218316Swollman 55318316Swollman if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) 55418316Swollman logbad(1, "fcntl(%s) O_NONBLOCK: %s", 55518316Swollman name, strerror(errno)); 55618316Swollman on = 1; 55719896Swollman if (setsockopt(sock, SOL_SOCKET,SO_BROADCAST, &on,sizeof(on)) < 0) 55818316Swollman msglog("setsockopt(%s,SO_BROADCAST): %s", 55918316Swollman name, strerror(errno)); 56019896Swollman#ifdef USE_PASSIFNAME 56119896Swollman on = 1; 56219896Swollman if (setsockopt(sock, SOL_SOCKET, SO_PASSIFNAME, &on,sizeof(on)) < 0) 56319896Swollman msglog("setsockopt(%s,SO_PASSIFNAME): %s", 56419896Swollman name, strerror(errno)); 56519896Swollman#endif 56619896Swollman 56718316Swollman if (rbuf >= MIN_SOCKBUF) { 56818316Swollman if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 56918316Swollman &rbuf, sizeof(rbuf)) < 0) 57018316Swollman msglog("setsockopt(%s,SO_RCVBUF=%d): %s", 57118316Swollman name, rbuf, strerror(errno)); 57218316Swollman } else { 57318316Swollman for (rbuf = 60*1024; ; rbuf -= 4096) { 57418316Swollman if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 57518316Swollman &rbuf, sizeof(rbuf)) == 0) { 57619896Swollman trace_act("RCVBUF=%d", rbuf); 57718316Swollman break; 57818316Swollman } 57918316Swollman if (rbuf < MIN_SOCKBUF) { 58018316Swollman msglog("setsockopt(%s,SO_RCVBUF = %d): %s", 58118316Swollman name, rbuf, strerror(errno)); 58218316Swollman break; 58318316Swollman } 58418316Swollman } 58518316Swollman } 58618316Swollman} 58718316Swollman 58818316Swollman 58918316Swollman/* get a rip socket 59018316Swollman */ 59118316Swollmanstatic int /* <0 or file descriptor */ 59218316Swollmanget_rip_sock(naddr addr, 59318316Swollman int serious) /* 1=failure to bind is serious */ 59418316Swollman{ 59518316Swollman struct sockaddr_in sin; 59618316Swollman unsigned char ttl; 59718316Swollman int s; 59818316Swollman 59918316Swollman 60018316Swollman if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 60118316Swollman BADERR(1,"rip_sock = socket()"); 60218316Swollman 60318316Swollman bzero(&sin,sizeof(sin)); 60418316Swollman#ifdef _HAVE_SIN_LEN 60518316Swollman sin.sin_len = sizeof(sin); 60618316Swollman#endif 60718316Swollman sin.sin_family = AF_INET; 60818316Swollman sin.sin_port = htons(RIP_PORT); 60918316Swollman sin.sin_addr.s_addr = addr; 61018316Swollman if (bind(s, (struct sockaddr *)&sin,sizeof(sin)) < 0) { 61118316Swollman if (serious) 61218316Swollman BADERR(errno != EADDRINUSE, "bind(rip_sock)"); 61318316Swollman return -1; 61418316Swollman } 61518316Swollman fix_sock(s,"rip_sock"); 61618316Swollman 61718316Swollman ttl = 1; 61818316Swollman if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, 61918316Swollman &ttl, sizeof(ttl)) < 0) 62018316Swollman DBGERR(1,"rip_sock setsockopt(IP_MULTICAST_TTL)"); 62118316Swollman 62218316Swollman return s; 62318316Swollman} 62418316Swollman 62518316Swollman 62618316Swollman/* turn off main RIP socket */ 62718316Swollmanvoid 62818316Swollmanrip_off(void) 62918316Swollman{ 63018316Swollman struct interface *ifp; 63118316Swollman register naddr addr; 63218316Swollman 63318316Swollman 63418316Swollman if (rip_sock >= 0 && !mhome) { 63519896Swollman trace_act("turn off RIP"); 63618316Swollman 63718316Swollman (void)close(rip_sock); 63818316Swollman rip_sock = -1; 63918316Swollman 64018316Swollman /* get non-broadcast sockets to listen to queries. 64118316Swollman */ 64218316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 64319896Swollman if (ifp->int_state & IS_REMOTE) 64419896Swollman continue; 64519896Swollman if (ifp->int_rip_sock < 0) { 64618316Swollman addr = ((ifp->int_if_flags & IFF_POINTOPOINT) 64718316Swollman ? ifp->int_dstaddr 64818316Swollman : ifp->int_addr); 64918316Swollman ifp->int_rip_sock = get_rip_sock(addr, 0); 65018316Swollman } 65118316Swollman } 65218316Swollman 65318316Swollman fix_select(); 65418316Swollman 65518316Swollman age(0); 65618316Swollman } 65718316Swollman} 65818316Swollman 65918316Swollman 66018316Swollman/* turn on RIP multicast input via an interface 66118316Swollman */ 66218316Swollmanstatic void 66318316Swollmanrip_mcast_on(struct interface *ifp) 66418316Swollman{ 66518316Swollman struct ip_mreq m; 66618316Swollman 66718316Swollman if (!IS_RIP_IN_OFF(ifp->int_state) 66818316Swollman && (ifp->int_if_flags & IFF_MULTICAST) 66918316Swollman#ifdef MCAST_PPP_BUG 67018316Swollman && !(ifp->int_if_flags & IFF_POINTOPOINT) 67118316Swollman#endif 67218316Swollman && !(ifp->int_state & IS_ALIAS)) { 67318316Swollman m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); 67418316Swollman m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) 67518316Swollman ? ifp->int_dstaddr 67618316Swollman : ifp->int_addr); 67718316Swollman if (setsockopt(rip_sock,IPPROTO_IP, IP_ADD_MEMBERSHIP, 67818316Swollman &m, sizeof(m)) < 0) 67918316Swollman LOGERR("setsockopt(IP_ADD_MEMBERSHIP RIP)"); 68018316Swollman } 68118316Swollman} 68218316Swollman 68318316Swollman 68418316Swollman/* Prepare socket used for RIP. 68518316Swollman */ 68618316Swollmanvoid 68718316Swollmanrip_on(struct interface *ifp) 68818316Swollman{ 68918316Swollman /* If the main RIP socket is already alive, only start receiving 69018316Swollman * multicasts for this interface. 69118316Swollman */ 69218316Swollman if (rip_sock >= 0) { 69318316Swollman if (ifp != 0) 69418316Swollman rip_mcast_on(ifp); 69518316Swollman return; 69618316Swollman } 69718316Swollman 69819896Swollman /* If the main RIP socket is off and it makes sense to turn it on, 69919896Swollman * then turn it on for all of the interfaces. 70018316Swollman */ 70118316Swollman if (rip_interfaces > 0 && !rdisc_ok) { 70219896Swollman trace_act("turn on RIP"); 70318316Swollman 70418316Swollman /* Close all of the query sockets so that we can open 70518316Swollman * the main socket. SO_REUSEPORT is not a solution, 70618316Swollman * since that would let two daemons bind to the broadcast 70718316Swollman * socket. 70818316Swollman */ 70918316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 71018316Swollman if (ifp->int_rip_sock >= 0) { 71118316Swollman (void)close(ifp->int_rip_sock); 71218316Swollman ifp->int_rip_sock = -1; 71318316Swollman } 71418316Swollman } 71518316Swollman 71618316Swollman rip_sock = get_rip_sock(INADDR_ANY, 1); 71718316Swollman rip_sock_mcast = 0; 71818316Swollman 71918316Swollman /* Do not advertise anything until we have heard something 72018316Swollman */ 72118316Swollman if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME) 72218316Swollman next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME; 72318316Swollman 72418316Swollman for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 72519896Swollman ifp->int_query_time = NEVER; 72618316Swollman rip_mcast_on(ifp); 72718316Swollman } 72818316Swollman ifinit_timer.tv_sec = now.tv_sec; 72918316Swollman 73018316Swollman } else if (ifp != 0 73119896Swollman && !(ifp->int_state & IS_REMOTE) 73219896Swollman && ifp->int_rip_sock < 0) { 73318316Swollman /* RIP is off, so ensure there are sockets on which 73418316Swollman * to listen for queries. 73518316Swollman */ 73618316Swollman ifp->int_rip_sock = get_rip_sock(ifp->int_addr, 0); 73719896Swollman } 73818316Swollman 73919896Swollman fix_select(); 74018316Swollman} 74118316Swollman 74218316Swollman 74318316Swollman/* die if malloc(3) fails 74418316Swollman */ 74518316Swollmanvoid * 74618316Swollmanrtmalloc(size_t size, 74718316Swollman char *msg) 74818316Swollman{ 74918316Swollman void *p = malloc(size); 75018316Swollman if (p == 0) 75118316Swollman logbad(1,"malloc() failed in %s", msg); 75218316Swollman return p; 75318316Swollman} 75418316Swollman 75518316Swollman 75618316Swollman/* get a random instant in an interval 75718316Swollman */ 75818316Swollmanvoid 75918316Swollmanintvl_random(struct timeval *tp, /* put value here */ 76018316Swollman u_long lo, /* value is after this second */ 76118316Swollman u_long hi) /* and before this */ 76218316Swollman{ 76318316Swollman tp->tv_sec = (time_t)(hi == lo 76418316Swollman ? lo 76518316Swollman : (lo + random() % ((hi - lo)))); 76618316Swollman tp->tv_usec = random() % 1000000; 76718316Swollman} 76818316Swollman 76918316Swollman 77018316Swollmanvoid 77118316Swollmantimevaladd(struct timeval *t1, 77218316Swollman struct timeval *t2) 77318316Swollman{ 77418316Swollman 77518316Swollman t1->tv_sec += t2->tv_sec; 77618316Swollman if ((t1->tv_usec += t2->tv_usec) > 1000000) { 77718316Swollman t1->tv_sec++; 77818316Swollman t1->tv_usec -= 1000000; 77918316Swollman } 78018316Swollman} 78118316Swollman 78218316Swollman 78318316Swollman/* t1 = t2 - t3 78418316Swollman */ 78518316Swollmanstatic void 78618316Swollmantimevalsub(struct timeval *t1, 78718316Swollman struct timeval *t2, 78818316Swollman struct timeval *t3) 78918316Swollman{ 79018316Swollman t1->tv_sec = t2->tv_sec - t3->tv_sec; 79118316Swollman if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) { 79218316Swollman t1->tv_sec--; 79318316Swollman t1->tv_usec += 1000000; 79418316Swollman } 79518316Swollman} 79618316Swollman 79718316Swollman 79819896Swollman/* put a message into the system log 79919896Swollman */ 80018316Swollmanvoid 80118316Swollmanmsglog(char *p, ...) 80218316Swollman{ 80318316Swollman va_list args; 80418316Swollman 80518316Swollman trace_flush(); 80618316Swollman 80718316Swollman va_start(args, p); 80818316Swollman vsyslog(LOG_ERR, p, args); 80918316Swollman 81018316Swollman if (ftrace != 0) { 81118316Swollman if (ftrace == stdout) 81218316Swollman (void)fputs("routed: ", ftrace); 81318316Swollman (void)vfprintf(ftrace, p, args); 81418316Swollman (void)fputc('\n', ftrace); 81518316Swollman } 81618316Swollman} 81718316Swollman 81818316Swollman 81919896Swollman/* Put a message about a bad router into the system log if 82019896Swollman * we have not complained about it recently. 82119896Swollman */ 82218316Swollmanvoid 82319896Swollmanmsglim(struct msg_limit *lim, naddr addr, char *p, ...) 82419896Swollman{ 82519896Swollman va_list args; 82619896Swollman char *p1; 82719896Swollman 82819896Swollman va_start(args, p); 82919896Swollman 83019896Swollman if ( lim->addr != addr || lim->until <= now.tv_sec) { 83119896Swollman lim->addr = addr; 83219896Swollman lim->until = now.tv_sec + 60*60; 83319896Swollman 83419896Swollman trace_flush(); 83519896Swollman for (p1 = p; *p1 == ' '; p1++) 83619896Swollman continue; 83719896Swollman vsyslog(LOG_ERR, p1, args); 83819896Swollman } 83919896Swollman 84019896Swollman if (ftrace != 0) { 84119896Swollman (void)vfprintf(ftrace, p, args); 84219896Swollman (void)fputc('\n', ftrace); 84319896Swollman } 84419896Swollman} 84519896Swollman 84619896Swollman 84719896Swollmanvoid 84818316Swollmanlogbad(int dump, char *p, ...) 84918316Swollman{ 85018316Swollman va_list args; 85118316Swollman 85218316Swollman trace_flush(); 85318316Swollman 85418316Swollman va_start(args, p); 85518316Swollman vsyslog(LOG_ERR, p, args); 85618316Swollman 85718316Swollman (void)fputs("routed: ", stderr); 85818316Swollman (void)vfprintf(stderr, p, args); 85918316Swollman (void)fputs("; giving up\n",stderr); 86018316Swollman (void)fflush(stderr); 86118316Swollman 86218316Swollman if (dump) 86318316Swollman abort(); 86418316Swollman exit(1); 86518316Swollman} 866