1 /* 2 * Copyright (c) 1983, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)main.c 5.20 (Berkeley) 06/01/90"; 16 #endif /* not lint */ 17 18 /* 19 * Routing Table Management Daemon 20 */ 21 #include "defs.h" 22 #include <sys/ioctl.h> 23 #include <sys/file.h> 24 25 #include <net/if.h> 26 27 #include <sys/errno.h> 28 #include <sys/signal.h> 29 #include <sys/syslog.h> 30 #include "pathnames.h" 31 32 int supplier = -1; /* process should supply updates */ 33 int gateway = 0; /* 1 if we are a gateway to parts beyond */ 34 int debug = 0; 35 int bufspace = 127*1024; /* max. input buffer size to request */ 36 37 struct rip *msg = (struct rip *)packet; 38 int hup(), rtdeleteall(), sigtrace(); 39 40 main(argc, argv) 41 int argc; 42 char *argv[]; 43 { 44 int n, cc, nfd, omask, tflags = 0; 45 struct sockaddr from; 46 struct timeval *tvp, waittime; 47 struct itimerval itval; 48 register struct rip *query = msg; 49 fd_set ibits; 50 u_char retry; 51 52 argv0 = argv; 53 #if BSD >= 43 54 openlog("routed", LOG_PID | LOG_ODELAY, LOG_DAEMON); 55 setlogmask(LOG_UPTO(LOG_WARNING)); 56 #else 57 openlog("routed", LOG_PID); 58 #define LOG_UPTO(x) (x) 59 #define setlogmask(x) (x) 60 #endif 61 sp = getservbyname("router", "udp"); 62 if (sp == NULL) { 63 fprintf(stderr, "routed: router/udp: unknown service\n"); 64 exit(1); 65 } 66 addr.sin_family = AF_INET; 67 addr.sin_port = sp->s_port; 68 s = getsocket(AF_INET, SOCK_DGRAM, &addr); 69 if (s < 0) 70 exit(1); 71 argv++, argc--; 72 while (argc > 0 && **argv == '-') { 73 if (strcmp(*argv, "-s") == 0) { 74 supplier = 1; 75 argv++, argc--; 76 continue; 77 } 78 if (strcmp(*argv, "-q") == 0) { 79 supplier = 0; 80 argv++, argc--; 81 continue; 82 } 83 if (strcmp(*argv, "-t") == 0) { 84 tflags++; 85 setlogmask(LOG_UPTO(LOG_DEBUG)); 86 argv++, argc--; 87 continue; 88 } 89 if (strcmp(*argv, "-d") == 0) { 90 debug++; 91 setlogmask(LOG_UPTO(LOG_DEBUG)); 92 argv++, argc--; 93 continue; 94 } 95 if (strcmp(*argv, "-g") == 0) { 96 gateway = 1; 97 argv++, argc--; 98 continue; 99 } 100 fprintf(stderr, 101 "usage: routed [ -s ] [ -q ] [ -t ] [ -g ]\n"); 102 exit(1); 103 } 104 105 if (debug == 0) { 106 int t; 107 108 if (fork()) 109 exit(0); 110 for (t = 0; t < 20; t++) 111 if (t != s) 112 (void) close(t); 113 (void) open("/", 0); 114 (void) dup2(0, 1); 115 (void) dup2(0, 2); 116 t = open(_PATH_TTY, 2); 117 if (t >= 0) { 118 ioctl(t, TIOCNOTTY, (char *)0); 119 (void) close(t); 120 } 121 } 122 /* 123 * Any extra argument is considered 124 * a tracing log file. 125 */ 126 if (argc > 0) 127 traceon(*argv); 128 while (tflags-- > 0) 129 bumploglevel(); 130 131 (void) gettimeofday(&now, (struct timezone *)NULL); 132 /* 133 * Collect an initial view of the world by 134 * checking the interface configuration and the gateway kludge 135 * file. Then, send a request packet on all 136 * directly connected networks to find out what 137 * everyone else thinks. 138 */ 139 rtinit(); 140 ifinit(); 141 gwkludge(); 142 if (gateway > 0) 143 rtdefault(); 144 if (supplier < 0) 145 supplier = 0; 146 query->rip_cmd = RIPCMD_REQUEST; 147 query->rip_vers = RIPVERSION; 148 if (sizeof(query->rip_nets[0].rip_dst.sa_family) > 1) /* XXX */ 149 query->rip_nets[0].rip_dst.sa_family = htons((u_short)AF_UNSPEC); 150 else 151 query->rip_nets[0].rip_dst.sa_family = AF_UNSPEC; 152 query->rip_nets[0].rip_metric = htonl((u_long)HOPCNT_INFINITY); 153 toall(sendmsg); 154 signal(SIGALRM, timer); 155 signal(SIGHUP, hup); 156 signal(SIGTERM, hup); 157 signal(SIGINT, rtdeleteall); 158 signal(SIGUSR1, sigtrace); 159 signal(SIGUSR2, sigtrace); 160 itval.it_interval.tv_sec = TIMER_RATE; 161 itval.it_value.tv_sec = TIMER_RATE; 162 itval.it_interval.tv_usec = 0; 163 itval.it_value.tv_usec = 0; 164 srandom(getpid()); 165 if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0) 166 syslog(LOG_ERR, "setitimer: %m\n"); 167 168 FD_ZERO(&ibits); 169 nfd = s + 1; /* 1 + max(fd's) */ 170 for (;;) { 171 FD_SET(s, &ibits); 172 /* 173 * If we need a dynamic update that was held off, 174 * needupdate will be set, and nextbcast is the time 175 * by which we want select to return. Compute time 176 * until dynamic update should be sent, and select only 177 * until then. If we have already passed nextbcast, 178 * just poll. 179 */ 180 if (needupdate) { 181 waittime = nextbcast; 182 timevalsub(&waittime, &now); 183 if (waittime.tv_sec < 0) { 184 waittime.tv_sec = 0; 185 waittime.tv_usec = 0; 186 } 187 if (traceactions) 188 fprintf(ftrace, 189 "select until dynamic update %d/%d sec/usec\n", 190 waittime.tv_sec, waittime.tv_usec); 191 tvp = &waittime; 192 } else 193 tvp = (struct timeval *)NULL; 194 n = select(nfd, &ibits, 0, 0, tvp); 195 if (n <= 0) { 196 /* 197 * Need delayed dynamic update if select returned 198 * nothing and we timed out. Otherwise, ignore 199 * errors (e.g. EINTR). 200 */ 201 if (n < 0) { 202 if (errno == EINTR) 203 continue; 204 syslog(LOG_ERR, "select: %m"); 205 } 206 omask = sigblock(sigmask(SIGALRM)); 207 if (n == 0 && needupdate) { 208 if (traceactions) 209 fprintf(ftrace, 210 "send delayed dynamic update\n"); 211 (void) gettimeofday(&now, 212 (struct timezone *)NULL); 213 toall(supply, RTS_CHANGED, 214 (struct interface *)NULL); 215 lastbcast = now; 216 needupdate = 0; 217 nextbcast.tv_sec = 0; 218 } 219 sigsetmask(omask); 220 continue; 221 } 222 (void) gettimeofday(&now, (struct timezone *)NULL); 223 omask = sigblock(sigmask(SIGALRM)); 224 #ifdef doesntwork 225 /* 226 printf("s %d, ibits %x index %d, mod %d, sh %x, or %x &ibits %x\n", 227 s, 228 ibits.fds_bits[0], 229 (s)/(sizeof(fd_mask) * 8), 230 ((s) % (sizeof(fd_mask) * 8)), 231 (1 << ((s) % (sizeof(fd_mask) * 8))), 232 ibits.fds_bits[(s)/(sizeof(fd_mask) * 8)] & (1 << ((s) % (sizeof(fd_mask) * 8))), 233 &ibits 234 ); 235 */ 236 if (FD_ISSET(s, &ibits)) 237 #else 238 if (ibits.fds_bits[s/32] & (1 << s)) 239 #endif 240 process(s); 241 /* handle ICMP redirects */ 242 sigsetmask(omask); 243 } 244 } 245 246 timevaladd(t1, t2) 247 struct timeval *t1, *t2; 248 { 249 250 t1->tv_sec += t2->tv_sec; 251 if ((t1->tv_usec += t2->tv_usec) > 1000000) { 252 t1->tv_sec++; 253 t1->tv_usec -= 1000000; 254 } 255 } 256 257 timevalsub(t1, t2) 258 struct timeval *t1, *t2; 259 { 260 261 t1->tv_sec -= t2->tv_sec; 262 if ((t1->tv_usec -= t2->tv_usec) < 0) { 263 t1->tv_sec--; 264 t1->tv_usec += 1000000; 265 } 266 } 267 268 process(fd) 269 int fd; 270 { 271 struct sockaddr from; 272 int fromlen, cc; 273 union { 274 char buf[MAXPACKETSIZE+1]; 275 struct rip rip; 276 } inbuf; 277 278 for (;;) { 279 fromlen = sizeof (from); 280 cc = recvfrom(fd, &inbuf, sizeof (inbuf), 0, &from, &fromlen); 281 if (cc <= 0) { 282 if (cc < 0 && errno != EWOULDBLOCK) 283 perror("recvfrom"); 284 break; 285 } 286 if (fromlen != sizeof (struct sockaddr_in)) 287 break; 288 rip_input(&from, &inbuf.rip, cc); 289 } 290 } 291 292 getsocket(domain, type, sin) 293 int domain, type; 294 struct sockaddr_in *sin; 295 { 296 int sock, on = 1; 297 298 if ((sock = socket(domain, type, 0)) < 0) { 299 perror("socket"); 300 syslog(LOG_ERR, "socket: %m"); 301 return (-1); 302 } 303 #ifdef SO_BROADCAST 304 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { 305 syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); 306 close(sock); 307 return (-1); 308 } 309 #endif 310 #ifdef SO_RCVBUF 311 for (on = bufspace; ; on -= 1024) { 312 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 313 &on, sizeof (on)) == 0) 314 break; 315 if (on <= 8*1024) { 316 syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m"); 317 break; 318 } 319 } 320 if (traceactions) 321 fprintf(ftrace, "recv buf %d\n", on); 322 #endif 323 if (bind(sock, sin, sizeof (*sin), 0) < 0) { 324 perror("bind"); 325 syslog(LOG_ERR, "bind: %m"); 326 close(sock); 327 return (-1); 328 } 329 if (fcntl(sock, F_SETFL, FNDELAY) == -1) 330 syslog(LOG_ERR, "fcntl FNDELAY: %m\n"); 331 return (sock); 332 } 333