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.21 (Berkeley) 06/29/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 daemon(0, 0); 107 /* 108 * Any extra argument is considered 109 * a tracing log file. 110 */ 111 if (argc > 0) 112 traceon(*argv); 113 while (tflags-- > 0) 114 bumploglevel(); 115 116 (void) gettimeofday(&now, (struct timezone *)NULL); 117 /* 118 * Collect an initial view of the world by 119 * checking the interface configuration and the gateway kludge 120 * file. Then, send a request packet on all 121 * directly connected networks to find out what 122 * everyone else thinks. 123 */ 124 rtinit(); 125 ifinit(); 126 gwkludge(); 127 if (gateway > 0) 128 rtdefault(); 129 if (supplier < 0) 130 supplier = 0; 131 query->rip_cmd = RIPCMD_REQUEST; 132 query->rip_vers = RIPVERSION; 133 if (sizeof(query->rip_nets[0].rip_dst.sa_family) > 1) /* XXX */ 134 query->rip_nets[0].rip_dst.sa_family = htons((u_short)AF_UNSPEC); 135 else 136 query->rip_nets[0].rip_dst.sa_family = AF_UNSPEC; 137 query->rip_nets[0].rip_metric = htonl((u_long)HOPCNT_INFINITY); 138 toall(sendmsg); 139 signal(SIGALRM, timer); 140 signal(SIGHUP, hup); 141 signal(SIGTERM, hup); 142 signal(SIGINT, rtdeleteall); 143 signal(SIGUSR1, sigtrace); 144 signal(SIGUSR2, sigtrace); 145 itval.it_interval.tv_sec = TIMER_RATE; 146 itval.it_value.tv_sec = TIMER_RATE; 147 itval.it_interval.tv_usec = 0; 148 itval.it_value.tv_usec = 0; 149 srandom(getpid()); 150 if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0) 151 syslog(LOG_ERR, "setitimer: %m\n"); 152 153 FD_ZERO(&ibits); 154 nfd = s + 1; /* 1 + max(fd's) */ 155 for (;;) { 156 FD_SET(s, &ibits); 157 /* 158 * If we need a dynamic update that was held off, 159 * needupdate will be set, and nextbcast is the time 160 * by which we want select to return. Compute time 161 * until dynamic update should be sent, and select only 162 * until then. If we have already passed nextbcast, 163 * just poll. 164 */ 165 if (needupdate) { 166 waittime = nextbcast; 167 timevalsub(&waittime, &now); 168 if (waittime.tv_sec < 0) { 169 waittime.tv_sec = 0; 170 waittime.tv_usec = 0; 171 } 172 if (traceactions) 173 fprintf(ftrace, 174 "select until dynamic update %d/%d sec/usec\n", 175 waittime.tv_sec, waittime.tv_usec); 176 tvp = &waittime; 177 } else 178 tvp = (struct timeval *)NULL; 179 n = select(nfd, &ibits, 0, 0, tvp); 180 if (n <= 0) { 181 /* 182 * Need delayed dynamic update if select returned 183 * nothing and we timed out. Otherwise, ignore 184 * errors (e.g. EINTR). 185 */ 186 if (n < 0) { 187 if (errno == EINTR) 188 continue; 189 syslog(LOG_ERR, "select: %m"); 190 } 191 omask = sigblock(sigmask(SIGALRM)); 192 if (n == 0 && needupdate) { 193 if (traceactions) 194 fprintf(ftrace, 195 "send delayed dynamic update\n"); 196 (void) gettimeofday(&now, 197 (struct timezone *)NULL); 198 toall(supply, RTS_CHANGED, 199 (struct interface *)NULL); 200 lastbcast = now; 201 needupdate = 0; 202 nextbcast.tv_sec = 0; 203 } 204 sigsetmask(omask); 205 continue; 206 } 207 (void) gettimeofday(&now, (struct timezone *)NULL); 208 omask = sigblock(sigmask(SIGALRM)); 209 #ifdef doesntwork 210 /* 211 printf("s %d, ibits %x index %d, mod %d, sh %x, or %x &ibits %x\n", 212 s, 213 ibits.fds_bits[0], 214 (s)/(sizeof(fd_mask) * 8), 215 ((s) % (sizeof(fd_mask) * 8)), 216 (1 << ((s) % (sizeof(fd_mask) * 8))), 217 ibits.fds_bits[(s)/(sizeof(fd_mask) * 8)] & (1 << ((s) % (sizeof(fd_mask) * 8))), 218 &ibits 219 ); 220 */ 221 if (FD_ISSET(s, &ibits)) 222 #else 223 if (ibits.fds_bits[s/32] & (1 << s)) 224 #endif 225 process(s); 226 /* handle ICMP redirects */ 227 sigsetmask(omask); 228 } 229 } 230 231 timevaladd(t1, t2) 232 struct timeval *t1, *t2; 233 { 234 235 t1->tv_sec += t2->tv_sec; 236 if ((t1->tv_usec += t2->tv_usec) > 1000000) { 237 t1->tv_sec++; 238 t1->tv_usec -= 1000000; 239 } 240 } 241 242 timevalsub(t1, t2) 243 struct timeval *t1, *t2; 244 { 245 246 t1->tv_sec -= t2->tv_sec; 247 if ((t1->tv_usec -= t2->tv_usec) < 0) { 248 t1->tv_sec--; 249 t1->tv_usec += 1000000; 250 } 251 } 252 253 process(fd) 254 int fd; 255 { 256 struct sockaddr from; 257 int fromlen, cc; 258 union { 259 char buf[MAXPACKETSIZE+1]; 260 struct rip rip; 261 } inbuf; 262 263 for (;;) { 264 fromlen = sizeof (from); 265 cc = recvfrom(fd, &inbuf, sizeof (inbuf), 0, &from, &fromlen); 266 if (cc <= 0) { 267 if (cc < 0 && errno != EWOULDBLOCK) 268 perror("recvfrom"); 269 break; 270 } 271 if (fromlen != sizeof (struct sockaddr_in)) 272 break; 273 rip_input(&from, &inbuf.rip, cc); 274 } 275 } 276 277 getsocket(domain, type, sin) 278 int domain, type; 279 struct sockaddr_in *sin; 280 { 281 int sock, on = 1; 282 283 if ((sock = socket(domain, type, 0)) < 0) { 284 perror("socket"); 285 syslog(LOG_ERR, "socket: %m"); 286 return (-1); 287 } 288 #ifdef SO_BROADCAST 289 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { 290 syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); 291 close(sock); 292 return (-1); 293 } 294 #endif 295 #ifdef SO_RCVBUF 296 for (on = bufspace; ; on -= 1024) { 297 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, 298 &on, sizeof (on)) == 0) 299 break; 300 if (on <= 8*1024) { 301 syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m"); 302 break; 303 } 304 } 305 if (traceactions) 306 fprintf(ftrace, "recv buf %d\n", on); 307 #endif 308 if (bind(sock, sin, sizeof (*sin), 0) < 0) { 309 perror("bind"); 310 syslog(LOG_ERR, "bind: %m"); 311 close(sock); 312 return (-1); 313 } 314 if (fcntl(sock, F_SETFL, FNDELAY) == -1) 315 syslog(LOG_ERR, "fcntl FNDELAY: %m\n"); 316 return (sock); 317 } 318