121996Sdist /* 234566Skarels * Copyright (c) 1983, 1988 Regents of the University of California. 333489Sbostic * All rights reserved. 433489Sbostic * 5*42712Sbostic * %sccs.include.redist.c% 621996Sdist */ 721996Sdist 89017Ssam #ifndef lint 921996Sdist char copyright[] = 1034566Skarels "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\ 1121996Sdist All rights reserved.\n"; 1233489Sbostic #endif /* not lint */ 139017Ssam 1421996Sdist #ifndef lint 15*42712Sbostic static char sccsid[] = "@(#)main.c 5.20 (Berkeley) 06/01/90"; 1633489Sbostic #endif /* not lint */ 1721996Sdist 189017Ssam /* 199017Ssam * Routing Table Management Daemon 209017Ssam */ 2110245Ssam #include "defs.h" 229017Ssam #include <sys/ioctl.h> 2336831Skarels #include <sys/file.h> 2413602Ssam 259017Ssam #include <net/if.h> 2613602Ssam 2734566Skarels #include <sys/errno.h> 2834566Skarels #include <sys/signal.h> 2934566Skarels #include <sys/syslog.h> 3037970Sbostic #include "pathnames.h" 319017Ssam 329017Ssam int supplier = -1; /* process should supply updates */ 3321847Skarels int gateway = 0; /* 1 if we are a gateway to parts beyond */ 3431220Skarels int debug = 0; 3536831Skarels int bufspace = 127*1024; /* max. input buffer size to request */ 369017Ssam 379017Ssam struct rip *msg = (struct rip *)packet; 3834566Skarels int hup(), rtdeleteall(), sigtrace(); 399017Ssam 409017Ssam main(argc, argv) 419017Ssam int argc; 429017Ssam char *argv[]; 439017Ssam { 4436831Skarels int n, cc, nfd, omask, tflags = 0; 459017Ssam struct sockaddr from; 4636831Skarels struct timeval *tvp, waittime; 4736831Skarels struct itimerval itval; 4840902Skarels register struct rip *query = msg; 4936831Skarels fd_set ibits; 5010245Ssam u_char retry; 519017Ssam 529017Ssam argv0 = argv; 5334845Skarels #if BSD >= 43 5424848Seric openlog("routed", LOG_PID | LOG_ODELAY, LOG_DAEMON); 5530930Skarels setlogmask(LOG_UPTO(LOG_WARNING)); 5634845Skarels #else 5734845Skarels openlog("routed", LOG_PID); 5834845Skarels #define LOG_UPTO(x) (x) 5934845Skarels #define setlogmask(x) (x) 6034845Skarels #endif 619017Ssam sp = getservbyname("router", "udp"); 6210245Ssam if (sp == NULL) { 6310245Ssam fprintf(stderr, "routed: router/udp: unknown service\n"); 649017Ssam exit(1); 659017Ssam } 6610245Ssam addr.sin_family = AF_INET; 6710245Ssam addr.sin_port = sp->s_port; 6810245Ssam s = getsocket(AF_INET, SOCK_DGRAM, &addr); 6910245Ssam if (s < 0) 7010245Ssam exit(1); 719017Ssam argv++, argc--; 729017Ssam while (argc > 0 && **argv == '-') { 7310636Ssam if (strcmp(*argv, "-s") == 0) { 749017Ssam supplier = 1; 759017Ssam argv++, argc--; 769017Ssam continue; 779017Ssam } 7810636Ssam if (strcmp(*argv, "-q") == 0) { 799017Ssam supplier = 0; 809017Ssam argv++, argc--; 819017Ssam continue; 829017Ssam } 8310636Ssam if (strcmp(*argv, "-t") == 0) { 8436831Skarels tflags++; 8530930Skarels setlogmask(LOG_UPTO(LOG_DEBUG)); 8610636Ssam argv++, argc--; 8710636Ssam continue; 8810636Ssam } 8926341Skarels if (strcmp(*argv, "-d") == 0) { 9031220Skarels debug++; 9130930Skarels setlogmask(LOG_UPTO(LOG_DEBUG)); 9226341Skarels argv++, argc--; 9326341Skarels continue; 9426341Skarels } 9516326Skarels if (strcmp(*argv, "-g") == 0) { 9616326Skarels gateway = 1; 9716326Skarels argv++, argc--; 9816326Skarels continue; 9916326Skarels } 10016326Skarels fprintf(stderr, 10121847Skarels "usage: routed [ -s ] [ -q ] [ -t ] [ -g ]\n"); 1029017Ssam exit(1); 1039017Ssam } 10436831Skarels 10536831Skarels if (debug == 0) { 10610636Ssam int t; 10710636Ssam 10810636Ssam if (fork()) 10910636Ssam exit(0); 11010637Ssam for (t = 0; t < 20; t++) 11110637Ssam if (t != s) 11224761Ssklower (void) close(t); 11310636Ssam (void) open("/", 0); 11410636Ssam (void) dup2(0, 1); 11510636Ssam (void) dup2(0, 2); 11637970Sbostic t = open(_PATH_TTY, 2); 11710636Ssam if (t >= 0) { 11810636Ssam ioctl(t, TIOCNOTTY, (char *)0); 11910636Ssam (void) close(t); 12010636Ssam } 12110636Ssam } 1229017Ssam /* 12310245Ssam * Any extra argument is considered 12410245Ssam * a tracing log file. 12510245Ssam */ 12610245Ssam if (argc > 0) 12710245Ssam traceon(*argv); 12836831Skarels while (tflags-- > 0) 12936831Skarels bumploglevel(); 13036831Skarels 13136831Skarels (void) gettimeofday(&now, (struct timezone *)NULL); 13210245Ssam /* 1339017Ssam * Collect an initial view of the world by 13421847Skarels * checking the interface configuration and the gateway kludge 1359017Ssam * file. Then, send a request packet on all 1369017Ssam * directly connected networks to find out what 1379017Ssam * everyone else thinks. 1389017Ssam */ 1399017Ssam rtinit(); 14030927Skarels ifinit(); 1419017Ssam gwkludge(); 14221847Skarels if (gateway > 0) 14321847Skarels rtdefault(); 1449017Ssam if (supplier < 0) 1459017Ssam supplier = 0; 14640902Skarels query->rip_cmd = RIPCMD_REQUEST; 14740902Skarels query->rip_vers = RIPVERSION; 14840902Skarels if (sizeof(query->rip_nets[0].rip_dst.sa_family) > 1) /* XXX */ 14940902Skarels query->rip_nets[0].rip_dst.sa_family = htons((u_short)AF_UNSPEC); 15036831Skarels else 15140902Skarels query->rip_nets[0].rip_dst.sa_family = AF_UNSPEC; 15240902Skarels query->rip_nets[0].rip_metric = htonl((u_long)HOPCNT_INFINITY); 1539017Ssam toall(sendmsg); 15413036Ssam signal(SIGALRM, timer); 15516314Skarels signal(SIGHUP, hup); 15617570Skarels signal(SIGTERM, hup); 15731220Skarels signal(SIGINT, rtdeleteall); 15834566Skarels signal(SIGUSR1, sigtrace); 15934566Skarels signal(SIGUSR2, sigtrace); 16036831Skarels itval.it_interval.tv_sec = TIMER_RATE; 16136831Skarels itval.it_value.tv_sec = TIMER_RATE; 16236831Skarels itval.it_interval.tv_usec = 0; 16336831Skarels itval.it_value.tv_usec = 0; 16436831Skarels srandom(getpid()); 16536831Skarels if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0) 16636831Skarels syslog(LOG_ERR, "setitimer: %m\n"); 1679017Ssam 16836831Skarels FD_ZERO(&ibits); 16936831Skarels nfd = s + 1; /* 1 + max(fd's) */ 1709017Ssam for (;;) { 17136831Skarels FD_SET(s, &ibits); 17236831Skarels /* 17336831Skarels * If we need a dynamic update that was held off, 17436831Skarels * needupdate will be set, and nextbcast is the time 17536831Skarels * by which we want select to return. Compute time 17636831Skarels * until dynamic update should be sent, and select only 17736831Skarels * until then. If we have already passed nextbcast, 17836831Skarels * just poll. 17936831Skarels */ 18036831Skarels if (needupdate) { 18136831Skarels waittime = nextbcast; 18236831Skarels timevalsub(&waittime, &now); 18336831Skarels if (waittime.tv_sec < 0) { 18436831Skarels waittime.tv_sec = 0; 18536831Skarels waittime.tv_usec = 0; 18636831Skarels } 18736831Skarels if (traceactions) 18836831Skarels fprintf(ftrace, 18936831Skarels "select until dynamic update %d/%d sec/usec\n", 19036831Skarels waittime.tv_sec, waittime.tv_usec); 19136831Skarels tvp = &waittime; 19236831Skarels } else 19336831Skarels tvp = (struct timeval *)NULL; 19436831Skarels n = select(nfd, &ibits, 0, 0, tvp); 19536831Skarels if (n <= 0) { 19636831Skarels /* 19736831Skarels * Need delayed dynamic update if select returned 19836831Skarels * nothing and we timed out. Otherwise, ignore 19936831Skarels * errors (e.g. EINTR). 20036831Skarels */ 20136831Skarels if (n < 0) { 20236831Skarels if (errno == EINTR) 20336831Skarels continue; 20436831Skarels syslog(LOG_ERR, "select: %m"); 20536831Skarels } 20636831Skarels omask = sigblock(sigmask(SIGALRM)); 20736831Skarels if (n == 0 && needupdate) { 20836831Skarels if (traceactions) 20936831Skarels fprintf(ftrace, 21036831Skarels "send delayed dynamic update\n"); 21136831Skarels (void) gettimeofday(&now, 21236831Skarels (struct timezone *)NULL); 21336831Skarels toall(supply, RTS_CHANGED, 21436831Skarels (struct interface *)NULL); 21536831Skarels lastbcast = now; 21636831Skarels needupdate = 0; 21736831Skarels nextbcast.tv_sec = 0; 21836831Skarels } 21936831Skarels sigsetmask(omask); 2209017Ssam continue; 22136831Skarels } 22236831Skarels (void) gettimeofday(&now, (struct timezone *)NULL); 22336846Skarels omask = sigblock(sigmask(SIGALRM)); 22436831Skarels #ifdef doesntwork 22536831Skarels /* 22636831Skarels printf("s %d, ibits %x index %d, mod %d, sh %x, or %x &ibits %x\n", 22736831Skarels s, 22836831Skarels ibits.fds_bits[0], 22936831Skarels (s)/(sizeof(fd_mask) * 8), 23036831Skarels ((s) % (sizeof(fd_mask) * 8)), 23136831Skarels (1 << ((s) % (sizeof(fd_mask) * 8))), 23236831Skarels ibits.fds_bits[(s)/(sizeof(fd_mask) * 8)] & (1 << ((s) % (sizeof(fd_mask) * 8))), 23336831Skarels &ibits 23436831Skarels ); 23536831Skarels */ 23636831Skarels if (FD_ISSET(s, &ibits)) 23736831Skarels #else 23836831Skarels if (ibits.fds_bits[s/32] & (1 << s)) 23936831Skarels #endif 2409017Ssam process(s); 24110245Ssam /* handle ICMP redirects */ 24236846Skarels sigsetmask(omask); 2439017Ssam } 2449017Ssam } 2459017Ssam 24636831Skarels timevaladd(t1, t2) 24736831Skarels struct timeval *t1, *t2; 24836831Skarels { 24936831Skarels 25036831Skarels t1->tv_sec += t2->tv_sec; 25136831Skarels if ((t1->tv_usec += t2->tv_usec) > 1000000) { 25236831Skarels t1->tv_sec++; 25336831Skarels t1->tv_usec -= 1000000; 25436831Skarels } 25536831Skarels } 25636831Skarels 25736831Skarels timevalsub(t1, t2) 25836831Skarels struct timeval *t1, *t2; 25936831Skarels { 26036831Skarels 26136831Skarels t1->tv_sec -= t2->tv_sec; 26236831Skarels if ((t1->tv_usec -= t2->tv_usec) < 0) { 26336831Skarels t1->tv_sec--; 26436831Skarels t1->tv_usec += 1000000; 26536831Skarels } 26636831Skarels } 26736831Skarels 2689017Ssam process(fd) 2699017Ssam int fd; 2709017Ssam { 2719017Ssam struct sockaddr from; 27236846Skarels int fromlen, cc; 27336846Skarels union { 27436846Skarels char buf[MAXPACKETSIZE+1]; 27536846Skarels struct rip rip; 27636846Skarels } inbuf; 2779017Ssam 27836831Skarels for (;;) { 27936831Skarels fromlen = sizeof (from); 28036846Skarels cc = recvfrom(fd, &inbuf, sizeof (inbuf), 0, &from, &fromlen); 28136831Skarels if (cc <= 0) { 28236831Skarels if (cc < 0 && errno != EWOULDBLOCK) 28336831Skarels perror("recvfrom"); 28436831Skarels break; 28536831Skarels } 28636831Skarels if (fromlen != sizeof (struct sockaddr_in)) 28736831Skarels break; 28836846Skarels rip_input(&from, &inbuf.rip, cc); 2899017Ssam } 2909017Ssam } 29110245Ssam 29210245Ssam getsocket(domain, type, sin) 29310245Ssam int domain, type; 29410245Ssam struct sockaddr_in *sin; 29510245Ssam { 29636831Skarels int sock, on = 1; 29710245Ssam 29836831Skarels if ((sock = socket(domain, type, 0)) < 0) { 29910245Ssam perror("socket"); 30017570Skarels syslog(LOG_ERR, "socket: %m"); 30110245Ssam return (-1); 30217570Skarels } 30334845Skarels #ifdef SO_BROADCAST 30436831Skarels if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { 30517570Skarels syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); 30636831Skarels close(sock); 30725516Skarels return (-1); 30817570Skarels } 30934845Skarels #endif 31034845Skarels #ifdef SO_RCVBUF 31136831Skarels for (on = bufspace; ; on -= 1024) { 31236831Skarels if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 31336831Skarels &on, sizeof (on)) == 0) 31436831Skarels break; 31536831Skarels if (on <= 8*1024) { 31636831Skarels syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m"); 31736831Skarels break; 31836831Skarels } 31936831Skarels } 32036831Skarels if (traceactions) 32136831Skarels fprintf(ftrace, "recv buf %d\n", on); 32234845Skarels #endif 32336831Skarels if (bind(sock, sin, sizeof (*sin), 0) < 0) { 32410245Ssam perror("bind"); 32517570Skarels syslog(LOG_ERR, "bind: %m"); 32636831Skarels close(sock); 32710245Ssam return (-1); 32817570Skarels } 32936831Skarels if (fcntl(sock, F_SETFL, FNDELAY) == -1) 33036831Skarels syslog(LOG_ERR, "fcntl FNDELAY: %m\n"); 33136831Skarels return (sock); 33210245Ssam } 333