xref: /netbsd-src/sbin/routed/main.c (revision ce0bb6e8d2e560ecacbe865a848624f94498063b)
1 /*	$NetBSD: main.c,v 1.11 1995/03/23 00:02:49 mycroft Exp $	*/
2 
3 /*
4  * Copyright (c) 1983, 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #ifndef lint
37 static char copyright[] =
38 "@(#) Copyright (c) 1983, 1988, 1993\n\
39 	The Regents of the University of California.  All rights reserved.\n";
40 #endif /* not lint */
41 
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/5/93";
45 #else
46 static char rcsid[] = "$NetBSD: main.c,v 1.11 1995/03/23 00:02:49 mycroft Exp $";
47 #endif
48 #endif /* not lint */
49 
50 /*
51  * Routing Table Management Daemon
52  */
53 #include "defs.h"
54 #include <sys/ioctl.h>
55 #include <sys/file.h>
56 
57 #include <net/if.h>
58 
59 #include <sys/errno.h>
60 #include <sys/signal.h>
61 #include <sys/syslog.h>
62 #include "pathnames.h"
63 
64 int	supplier = -1;		/* process should supply updates */
65 int	gateway = 0;		/* 1 if we are a gateway to parts beyond */
66 int	debug = 0;
67 int	bufspace = 127*1024;	/* max. input buffer size to request */
68 struct	rip *msg = (struct rip *)packet;
69 
70 int getsocket __P((int, int, struct sockaddr_in *));
71 void process __P((int));
72 
73 int
74 main(argc, argv)
75 	int argc;
76 	char *argv[];
77 {
78 	int n, nfd, tflags = 0;
79 	struct timeval *tvp, waittime;
80 	struct itimerval itval;
81 	register struct rip *query = msg;
82 	fd_set ibits;
83 	sigset_t sigset, osigset;
84 
85 	argv0 = argv;
86 #if BSD >= 43
87 	openlog("routed", LOG_PID | LOG_ODELAY, LOG_DAEMON);
88 	setlogmask(LOG_UPTO(LOG_WARNING));
89 #else
90 	openlog("routed", LOG_PID);
91 #define LOG_UPTO(x) (x)
92 #define setlogmask(x) (x)
93 #endif
94 	sp = getservbyname("router", "udp");
95 	if (sp == NULL) {
96 		fprintf(stderr, "routed: router/udp: unknown service\n");
97 		exit(1);
98 	}
99 	addr.sin_family = AF_INET;
100 	addr.sin_port = sp->s_port;
101 	r = socket(AF_ROUTE, SOCK_RAW, 0);
102 	/* later, get smart about lookingforinterfaces */
103 	if (r)
104 		shutdown(r, 0); /* for now, don't want reponses */
105 	else {
106 		fprintf(stderr, "routed: no routing socket\n");
107 		exit(1);
108 	}
109 	s = getsocket(AF_INET, SOCK_DGRAM, &addr);
110 	if (s < 0)
111 		exit(1);
112 	argv++, argc--;
113 	while (argc > 0 && **argv == '-') {
114 		if (strcmp(*argv, "-s") == 0) {
115 			supplier = 1;
116 			argv++, argc--;
117 			continue;
118 		}
119 		if (strcmp(*argv, "-q") == 0) {
120 			supplier = 0;
121 			argv++, argc--;
122 			continue;
123 		}
124 		if (strcmp(*argv, "-t") == 0) {
125 			tflags++;
126 			setlogmask(LOG_UPTO(LOG_DEBUG));
127 			argv++, argc--;
128 			continue;
129 		}
130 		if (strcmp(*argv, "-d") == 0) {
131 			debug++;
132 			setlogmask(LOG_UPTO(LOG_DEBUG));
133 			argv++, argc--;
134 			continue;
135 		}
136 		if (strcmp(*argv, "-g") == 0) {
137 			gateway = 1;
138 			argv++, argc--;
139 			continue;
140 		}
141 		fprintf(stderr,
142 			"usage: routed [ -s ] [ -q ] [ -t ] [ -g ]\n");
143 		exit(1);
144 	}
145 
146 	if (debug == 0 && tflags == 0)
147 		daemon(0, 0);
148 	/*
149 	 * Any extra argument is considered
150 	 * a tracing log file.
151 	 */
152 	if (argc > 0)
153 		traceon(*argv);
154 	while (tflags-- > 0)
155 		bumploglevel();
156 
157 	(void) gettimeofday(&now, (struct timezone *)NULL);
158 	/*
159 	 * Collect an initial view of the world by
160 	 * checking the interface configuration and the gateway kludge
161 	 * file.  Then, send a request packet on all
162 	 * directly connected networks to find out what
163 	 * everyone else thinks.
164 	 */
165 	rtinit();
166 	ifinit();
167 	gwkludge();
168 	if (gateway > 0)
169 		rtdefault();
170 	if (supplier < 0)
171 		supplier = 0;
172 	query->rip_cmd = RIPCMD_REQUEST;
173 	query->rip_vers = RIPVERSION;
174 	if (sizeof(query->rip_nets[0].rip_dst.sa_family) > 1)	/* XXX */
175 		query->rip_nets[0].rip_dst.sa_family = htons((u_short)AF_UNSPEC);
176 	else
177 		query->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
178 	query->rip_nets[0].rip_metric = htonl((u_long)HOPCNT_INFINITY);
179 	toall(sndmsg, 0, NULL);
180 	signal(SIGALRM, timer);
181 	signal(SIGHUP, hup);
182 	signal(SIGTERM, hup);
183 	signal(SIGINT, rtdeleteall);
184 	signal(SIGUSR1, sigtrace);
185 	signal(SIGUSR2, sigtrace);
186 	itval.it_interval.tv_sec = TIMER_RATE;
187 	itval.it_value.tv_sec = TIMER_RATE;
188 	itval.it_interval.tv_usec = 0;
189 	itval.it_value.tv_usec = 0;
190 	srandom(getpid());
191 	if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0)
192 		syslog(LOG_ERR, "setitimer: %m\n");
193 
194 	FD_ZERO(&ibits);
195 	nfd = s + 1;			/* 1 + max(fd's) */
196 	for (;;) {
197 		FD_SET(s, &ibits);
198 		/*
199 		 * If we need a dynamic update that was held off,
200 		 * needupdate will be set, and nextbcast is the time
201 		 * by which we want select to return.  Compute time
202 		 * until dynamic update should be sent, and select only
203 		 * until then.  If we have already passed nextbcast,
204 		 * just poll.
205 		 */
206 		if (needupdate) {
207 			timersub(&nextbcast, &now, &waittime);
208 			if (waittime.tv_sec < 0) {
209 				waittime.tv_sec = 0;
210 				waittime.tv_usec = 0;
211 			}
212 			if (traceactions)
213 				fprintf(ftrace,
214 				 "select until dynamic update %d/%d sec/usec\n",
215 				    waittime.tv_sec, waittime.tv_usec);
216 			tvp = &waittime;
217 		} else
218 			tvp = (struct timeval *)NULL;
219 		n = select(nfd, &ibits, 0, 0, tvp);
220 		if (n <= 0) {
221 			/*
222 			 * Need delayed dynamic update if select returned
223 			 * nothing and we timed out.  Otherwise, ignore
224 			 * errors (e.g. EINTR).
225 			 */
226 			if (n < 0) {
227 				if (errno == EINTR)
228 					continue;
229 				syslog(LOG_ERR, "select: %m");
230 			}
231 			sigemptyset(&sigset);
232 			sigaddset(&sigset, SIGALRM);
233 			sigprocmask(SIG_BLOCK, &sigset, &osigset);
234 			if (n == 0 && needupdate) {
235 				if (traceactions)
236 					fprintf(ftrace,
237 					    "send delayed dynamic update\n");
238 				(void) gettimeofday(&now,
239 					    (struct timezone *)NULL);
240 				toall(supply, RTS_CHANGED,
241 				    (struct interface *)NULL);
242 				lastbcast = now;
243 				needupdate = 0;
244 				nextbcast.tv_sec = 0;
245 			}
246 			sigprocmask(SIG_SETMASK, &osigset, NULL);
247 			continue;
248 		}
249 		(void) gettimeofday(&now, (struct timezone *)NULL);
250 		sigemptyset(&sigset);
251 		sigaddset(&sigset, SIGALRM);
252 		sigprocmask(SIG_BLOCK, &sigset, &osigset);
253 #ifdef doesntwork
254 /*
255 printf("s %d, ibits %x index %d, mod %d, sh %x, or %x &ibits %x\n",
256 	s,
257 	ibits.fds_bits[0],
258 	(s)/(sizeof(fd_mask) * 8),
259 	((s) % (sizeof(fd_mask) * 8)),
260 	(1 << ((s) % (sizeof(fd_mask) * 8))),
261 	ibits.fds_bits[(s)/(sizeof(fd_mask) * 8)] & (1 << ((s) % (sizeof(fd_mask) * 8))),
262 	&ibits
263 	);
264 */
265 		if (FD_ISSET(s, &ibits))
266 #else
267 		if (ibits.fds_bits[s/32] & (1 << s))
268 #endif
269 			process(s);
270 		/* handle ICMP redirects */
271 		sigprocmask(SIG_SETMASK, &osigset, NULL);
272 	}
273 }
274 
275 void
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 int
301 getsocket(domain, type, sin)
302 	int domain, type;
303 	struct sockaddr_in *sin;
304 {
305 	int sock, on = 1;
306 
307 	if ((sock = socket(domain, type, 0)) < 0) {
308 		perror("socket");
309 		syslog(LOG_ERR, "socket: %m");
310 		return (-1);
311 	}
312 #ifdef SO_BROADCAST
313 	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
314 		syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
315 		close(sock);
316 		return (-1);
317 	}
318 #endif
319 #ifdef SO_RCVBUF
320 	for (on = bufspace; ; on -= 1024) {
321 		if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
322 		    &on, sizeof (on)) == 0)
323 			break;
324 		if (on <= 8*1024) {
325 			syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
326 			break;
327 		}
328 	}
329 	if (traceactions)
330 		fprintf(ftrace, "recv buf %d\n", on);
331 #endif
332 	if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0) {
333 		perror("bind");
334 		syslog(LOG_ERR, "bind: %m");
335 		close(sock);
336 		return (-1);
337 	}
338 	if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
339 		syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
340 	return (sock);
341 }
342