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