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