121996Sdist /* 234566Skarels * Copyright (c) 1983, 1988 Regents of the University of California. 333489Sbostic * All rights reserved. 433489Sbostic * 533489Sbostic * Redistribution and use in source and binary forms are permitted 634771Sbostic * provided that the above copyright notice and this paragraph are 734771Sbostic * duplicated in all such forms and that any documentation, 834771Sbostic * advertising materials, and other materials related to such 934771Sbostic * distribution and use acknowledge that the software was developed 1034771Sbostic * by the University of California, Berkeley. The name of the 1134771Sbostic * University may not be used to endorse or promote products derived 1234771Sbostic * from this software without specific prior written permission. 1334771Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434771Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534771Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621996Sdist */ 1721996Sdist 189017Ssam #ifndef lint 1921996Sdist char copyright[] = 2034566Skarels "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\ 2121996Sdist All rights reserved.\n"; 2233489Sbostic #endif /* not lint */ 239017Ssam 2421996Sdist #ifndef lint 25*40902Skarels static char sccsid[] = "@(#)main.c 5.19 (Berkeley) 04/12/90"; 2633489Sbostic #endif /* not lint */ 2721996Sdist 289017Ssam /* 299017Ssam * Routing Table Management Daemon 309017Ssam */ 3110245Ssam #include "defs.h" 329017Ssam #include <sys/ioctl.h> 3336831Skarels #include <sys/file.h> 3413602Ssam 359017Ssam #include <net/if.h> 3613602Ssam 3734566Skarels #include <sys/errno.h> 3834566Skarels #include <sys/signal.h> 3934566Skarels #include <sys/syslog.h> 4037970Sbostic #include "pathnames.h" 419017Ssam 429017Ssam int supplier = -1; /* process should supply updates */ 4321847Skarels int gateway = 0; /* 1 if we are a gateway to parts beyond */ 4431220Skarels int debug = 0; 4536831Skarels int bufspace = 127*1024; /* max. input buffer size to request */ 469017Ssam 479017Ssam struct rip *msg = (struct rip *)packet; 4834566Skarels int hup(), rtdeleteall(), sigtrace(); 499017Ssam 509017Ssam main(argc, argv) 519017Ssam int argc; 529017Ssam char *argv[]; 539017Ssam { 5436831Skarels int n, cc, nfd, omask, tflags = 0; 559017Ssam struct sockaddr from; 5636831Skarels struct timeval *tvp, waittime; 5736831Skarels struct itimerval itval; 58*40902Skarels register struct rip *query = msg; 5936831Skarels fd_set ibits; 6010245Ssam u_char retry; 619017Ssam 629017Ssam argv0 = argv; 6334845Skarels #if BSD >= 43 6424848Seric openlog("routed", LOG_PID | LOG_ODELAY, LOG_DAEMON); 6530930Skarels setlogmask(LOG_UPTO(LOG_WARNING)); 6634845Skarels #else 6734845Skarels openlog("routed", LOG_PID); 6834845Skarels #define LOG_UPTO(x) (x) 6934845Skarels #define setlogmask(x) (x) 7034845Skarels #endif 719017Ssam sp = getservbyname("router", "udp"); 7210245Ssam if (sp == NULL) { 7310245Ssam fprintf(stderr, "routed: router/udp: unknown service\n"); 749017Ssam exit(1); 759017Ssam } 7610245Ssam addr.sin_family = AF_INET; 7710245Ssam addr.sin_port = sp->s_port; 7810245Ssam s = getsocket(AF_INET, SOCK_DGRAM, &addr); 7910245Ssam if (s < 0) 8010245Ssam exit(1); 819017Ssam argv++, argc--; 829017Ssam while (argc > 0 && **argv == '-') { 8310636Ssam if (strcmp(*argv, "-s") == 0) { 849017Ssam supplier = 1; 859017Ssam argv++, argc--; 869017Ssam continue; 879017Ssam } 8810636Ssam if (strcmp(*argv, "-q") == 0) { 899017Ssam supplier = 0; 909017Ssam argv++, argc--; 919017Ssam continue; 929017Ssam } 9310636Ssam if (strcmp(*argv, "-t") == 0) { 9436831Skarels tflags++; 9530930Skarels setlogmask(LOG_UPTO(LOG_DEBUG)); 9610636Ssam argv++, argc--; 9710636Ssam continue; 9810636Ssam } 9926341Skarels if (strcmp(*argv, "-d") == 0) { 10031220Skarels debug++; 10130930Skarels setlogmask(LOG_UPTO(LOG_DEBUG)); 10226341Skarels argv++, argc--; 10326341Skarels continue; 10426341Skarels } 10516326Skarels if (strcmp(*argv, "-g") == 0) { 10616326Skarels gateway = 1; 10716326Skarels argv++, argc--; 10816326Skarels continue; 10916326Skarels } 11016326Skarels fprintf(stderr, 11121847Skarels "usage: routed [ -s ] [ -q ] [ -t ] [ -g ]\n"); 1129017Ssam exit(1); 1139017Ssam } 11436831Skarels 11536831Skarels if (debug == 0) { 11610636Ssam int t; 11710636Ssam 11810636Ssam if (fork()) 11910636Ssam exit(0); 12010637Ssam for (t = 0; t < 20; t++) 12110637Ssam if (t != s) 12224761Ssklower (void) close(t); 12310636Ssam (void) open("/", 0); 12410636Ssam (void) dup2(0, 1); 12510636Ssam (void) dup2(0, 2); 12637970Sbostic t = open(_PATH_TTY, 2); 12710636Ssam if (t >= 0) { 12810636Ssam ioctl(t, TIOCNOTTY, (char *)0); 12910636Ssam (void) close(t); 13010636Ssam } 13110636Ssam } 1329017Ssam /* 13310245Ssam * Any extra argument is considered 13410245Ssam * a tracing log file. 13510245Ssam */ 13610245Ssam if (argc > 0) 13710245Ssam traceon(*argv); 13836831Skarels while (tflags-- > 0) 13936831Skarels bumploglevel(); 14036831Skarels 14136831Skarels (void) gettimeofday(&now, (struct timezone *)NULL); 14210245Ssam /* 1439017Ssam * Collect an initial view of the world by 14421847Skarels * checking the interface configuration and the gateway kludge 1459017Ssam * file. Then, send a request packet on all 1469017Ssam * directly connected networks to find out what 1479017Ssam * everyone else thinks. 1489017Ssam */ 1499017Ssam rtinit(); 15030927Skarels ifinit(); 1519017Ssam gwkludge(); 15221847Skarels if (gateway > 0) 15321847Skarels rtdefault(); 1549017Ssam if (supplier < 0) 1559017Ssam supplier = 0; 156*40902Skarels query->rip_cmd = RIPCMD_REQUEST; 157*40902Skarels query->rip_vers = RIPVERSION; 158*40902Skarels if (sizeof(query->rip_nets[0].rip_dst.sa_family) > 1) /* XXX */ 159*40902Skarels query->rip_nets[0].rip_dst.sa_family = htons((u_short)AF_UNSPEC); 16036831Skarels else 161*40902Skarels query->rip_nets[0].rip_dst.sa_family = AF_UNSPEC; 162*40902Skarels query->rip_nets[0].rip_metric = htonl((u_long)HOPCNT_INFINITY); 1639017Ssam toall(sendmsg); 16413036Ssam signal(SIGALRM, timer); 16516314Skarels signal(SIGHUP, hup); 16617570Skarels signal(SIGTERM, hup); 16731220Skarels signal(SIGINT, rtdeleteall); 16834566Skarels signal(SIGUSR1, sigtrace); 16934566Skarels signal(SIGUSR2, sigtrace); 17036831Skarels itval.it_interval.tv_sec = TIMER_RATE; 17136831Skarels itval.it_value.tv_sec = TIMER_RATE; 17236831Skarels itval.it_interval.tv_usec = 0; 17336831Skarels itval.it_value.tv_usec = 0; 17436831Skarels srandom(getpid()); 17536831Skarels if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0) 17636831Skarels syslog(LOG_ERR, "setitimer: %m\n"); 1779017Ssam 17836831Skarels FD_ZERO(&ibits); 17936831Skarels nfd = s + 1; /* 1 + max(fd's) */ 1809017Ssam for (;;) { 18136831Skarels FD_SET(s, &ibits); 18236831Skarels /* 18336831Skarels * If we need a dynamic update that was held off, 18436831Skarels * needupdate will be set, and nextbcast is the time 18536831Skarels * by which we want select to return. Compute time 18636831Skarels * until dynamic update should be sent, and select only 18736831Skarels * until then. If we have already passed nextbcast, 18836831Skarels * just poll. 18936831Skarels */ 19036831Skarels if (needupdate) { 19136831Skarels waittime = nextbcast; 19236831Skarels timevalsub(&waittime, &now); 19336831Skarels if (waittime.tv_sec < 0) { 19436831Skarels waittime.tv_sec = 0; 19536831Skarels waittime.tv_usec = 0; 19636831Skarels } 19736831Skarels if (traceactions) 19836831Skarels fprintf(ftrace, 19936831Skarels "select until dynamic update %d/%d sec/usec\n", 20036831Skarels waittime.tv_sec, waittime.tv_usec); 20136831Skarels tvp = &waittime; 20236831Skarels } else 20336831Skarels tvp = (struct timeval *)NULL; 20436831Skarels n = select(nfd, &ibits, 0, 0, tvp); 20536831Skarels if (n <= 0) { 20636831Skarels /* 20736831Skarels * Need delayed dynamic update if select returned 20836831Skarels * nothing and we timed out. Otherwise, ignore 20936831Skarels * errors (e.g. EINTR). 21036831Skarels */ 21136831Skarels if (n < 0) { 21236831Skarels if (errno == EINTR) 21336831Skarels continue; 21436831Skarels syslog(LOG_ERR, "select: %m"); 21536831Skarels } 21636831Skarels omask = sigblock(sigmask(SIGALRM)); 21736831Skarels if (n == 0 && needupdate) { 21836831Skarels if (traceactions) 21936831Skarels fprintf(ftrace, 22036831Skarels "send delayed dynamic update\n"); 22136831Skarels (void) gettimeofday(&now, 22236831Skarels (struct timezone *)NULL); 22336831Skarels toall(supply, RTS_CHANGED, 22436831Skarels (struct interface *)NULL); 22536831Skarels lastbcast = now; 22636831Skarels needupdate = 0; 22736831Skarels nextbcast.tv_sec = 0; 22836831Skarels } 22936831Skarels sigsetmask(omask); 2309017Ssam continue; 23136831Skarels } 23236831Skarels (void) gettimeofday(&now, (struct timezone *)NULL); 23336846Skarels omask = sigblock(sigmask(SIGALRM)); 23436831Skarels #ifdef doesntwork 23536831Skarels /* 23636831Skarels printf("s %d, ibits %x index %d, mod %d, sh %x, or %x &ibits %x\n", 23736831Skarels s, 23836831Skarels ibits.fds_bits[0], 23936831Skarels (s)/(sizeof(fd_mask) * 8), 24036831Skarels ((s) % (sizeof(fd_mask) * 8)), 24136831Skarels (1 << ((s) % (sizeof(fd_mask) * 8))), 24236831Skarels ibits.fds_bits[(s)/(sizeof(fd_mask) * 8)] & (1 << ((s) % (sizeof(fd_mask) * 8))), 24336831Skarels &ibits 24436831Skarels ); 24536831Skarels */ 24636831Skarels if (FD_ISSET(s, &ibits)) 24736831Skarels #else 24836831Skarels if (ibits.fds_bits[s/32] & (1 << s)) 24936831Skarels #endif 2509017Ssam process(s); 25110245Ssam /* handle ICMP redirects */ 25236846Skarels sigsetmask(omask); 2539017Ssam } 2549017Ssam } 2559017Ssam 25636831Skarels timevaladd(t1, t2) 25736831Skarels struct timeval *t1, *t2; 25836831Skarels { 25936831Skarels 26036831Skarels t1->tv_sec += t2->tv_sec; 26136831Skarels if ((t1->tv_usec += t2->tv_usec) > 1000000) { 26236831Skarels t1->tv_sec++; 26336831Skarels t1->tv_usec -= 1000000; 26436831Skarels } 26536831Skarels } 26636831Skarels 26736831Skarels timevalsub(t1, t2) 26836831Skarels struct timeval *t1, *t2; 26936831Skarels { 27036831Skarels 27136831Skarels t1->tv_sec -= t2->tv_sec; 27236831Skarels if ((t1->tv_usec -= t2->tv_usec) < 0) { 27336831Skarels t1->tv_sec--; 27436831Skarels t1->tv_usec += 1000000; 27536831Skarels } 27636831Skarels } 27736831Skarels 2789017Ssam process(fd) 2799017Ssam int fd; 2809017Ssam { 2819017Ssam struct sockaddr from; 28236846Skarels int fromlen, cc; 28336846Skarels union { 28436846Skarels char buf[MAXPACKETSIZE+1]; 28536846Skarels struct rip rip; 28636846Skarels } inbuf; 2879017Ssam 28836831Skarels for (;;) { 28936831Skarels fromlen = sizeof (from); 29036846Skarels cc = recvfrom(fd, &inbuf, sizeof (inbuf), 0, &from, &fromlen); 29136831Skarels if (cc <= 0) { 29236831Skarels if (cc < 0 && errno != EWOULDBLOCK) 29336831Skarels perror("recvfrom"); 29436831Skarels break; 29536831Skarels } 29636831Skarels if (fromlen != sizeof (struct sockaddr_in)) 29736831Skarels break; 29836846Skarels rip_input(&from, &inbuf.rip, cc); 2999017Ssam } 3009017Ssam } 30110245Ssam 30210245Ssam getsocket(domain, type, sin) 30310245Ssam int domain, type; 30410245Ssam struct sockaddr_in *sin; 30510245Ssam { 30636831Skarels int sock, on = 1; 30710245Ssam 30836831Skarels if ((sock = socket(domain, type, 0)) < 0) { 30910245Ssam perror("socket"); 31017570Skarels syslog(LOG_ERR, "socket: %m"); 31110245Ssam return (-1); 31217570Skarels } 31334845Skarels #ifdef SO_BROADCAST 31436831Skarels if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { 31517570Skarels syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); 31636831Skarels close(sock); 31725516Skarels return (-1); 31817570Skarels } 31934845Skarels #endif 32034845Skarels #ifdef SO_RCVBUF 32136831Skarels for (on = bufspace; ; on -= 1024) { 32236831Skarels if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 32336831Skarels &on, sizeof (on)) == 0) 32436831Skarels break; 32536831Skarels if (on <= 8*1024) { 32636831Skarels syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m"); 32736831Skarels break; 32836831Skarels } 32936831Skarels } 33036831Skarels if (traceactions) 33136831Skarels fprintf(ftrace, "recv buf %d\n", on); 33234845Skarels #endif 33336831Skarels if (bind(sock, sin, sizeof (*sin), 0) < 0) { 33410245Ssam perror("bind"); 33517570Skarels syslog(LOG_ERR, "bind: %m"); 33636831Skarels close(sock); 33710245Ssam return (-1); 33817570Skarels } 33936831Skarels if (fcntl(sock, F_SETFL, FNDELAY) == -1) 34036831Skarels syslog(LOG_ERR, "fcntl FNDELAY: %m\n"); 34136831Skarels return (sock); 34210245Ssam } 343