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