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