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