main.c revision 1.9 1 /* $NetBSD: main.c,v 1.9 1995/03/21 14:05:36 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.9 1995/03/21 14:05:36 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, omask, tflags = 0;
79 struct timeval *tvp, waittime;
80 struct itimerval itval;
81 register struct rip *query = msg;
82 fd_set ibits;
83
84 argv0 = argv;
85 #if BSD >= 43
86 openlog("routed", LOG_PID | LOG_ODELAY, LOG_DAEMON);
87 setlogmask(LOG_UPTO(LOG_WARNING));
88 #else
89 openlog("routed", LOG_PID);
90 #define LOG_UPTO(x) (x)
91 #define setlogmask(x) (x)
92 #endif
93 sp = getservbyname("router", "udp");
94 if (sp == NULL) {
95 fprintf(stderr, "routed: router/udp: unknown service\n");
96 exit(1);
97 }
98 addr.sin_family = AF_INET;
99 addr.sin_port = sp->s_port;
100 r = socket(AF_ROUTE, SOCK_RAW, 0);
101 /* later, get smart about lookingforinterfaces */
102 if (r)
103 shutdown(r, 0); /* for now, don't want reponses */
104 else {
105 fprintf(stderr, "routed: no routing socket\n");
106 exit(1);
107 }
108 s = getsocket(AF_INET, SOCK_DGRAM, &addr);
109 if (s < 0)
110 exit(1);
111 argv++, argc--;
112 while (argc > 0 && **argv == '-') {
113 if (strcmp(*argv, "-s") == 0) {
114 supplier = 1;
115 argv++, argc--;
116 continue;
117 }
118 if (strcmp(*argv, "-q") == 0) {
119 supplier = 0;
120 argv++, argc--;
121 continue;
122 }
123 if (strcmp(*argv, "-t") == 0) {
124 tflags++;
125 setlogmask(LOG_UPTO(LOG_DEBUG));
126 argv++, argc--;
127 continue;
128 }
129 if (strcmp(*argv, "-d") == 0) {
130 debug++;
131 setlogmask(LOG_UPTO(LOG_DEBUG));
132 argv++, argc--;
133 continue;
134 }
135 if (strcmp(*argv, "-g") == 0) {
136 gateway = 1;
137 argv++, argc--;
138 continue;
139 }
140 fprintf(stderr,
141 "usage: routed [ -s ] [ -q ] [ -t ] [ -g ]\n");
142 exit(1);
143 }
144
145 if (debug == 0 && tflags == 0)
146 daemon(0, 0);
147 /*
148 * Any extra argument is considered
149 * a tracing log file.
150 */
151 if (argc > 0)
152 traceon(*argv);
153 while (tflags-- > 0)
154 bumploglevel();
155
156 (void) gettimeofday(&now, (struct timezone *)NULL);
157 /*
158 * Collect an initial view of the world by
159 * checking the interface configuration and the gateway kludge
160 * file. Then, send a request packet on all
161 * directly connected networks to find out what
162 * everyone else thinks.
163 */
164 rtinit();
165 ifinit();
166 gwkludge();
167 if (gateway > 0)
168 rtdefault();
169 if (supplier < 0)
170 supplier = 0;
171 query->rip_cmd = RIPCMD_REQUEST;
172 query->rip_vers = RIPVERSION;
173 if (sizeof(query->rip_nets[0].rip_dst.sa_family) > 1) /* XXX */
174 query->rip_nets[0].rip_dst.sa_family = htons((u_short)AF_UNSPEC);
175 else
176 query->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
177 query->rip_nets[0].rip_metric = htonl((u_long)HOPCNT_INFINITY);
178 toall(sndmsg, 0, NULL);
179 signal(SIGALRM, timer);
180 signal(SIGHUP, hup);
181 signal(SIGTERM, hup);
182 signal(SIGINT, rtdeleteall);
183 signal(SIGUSR1, sigtrace);
184 signal(SIGUSR2, sigtrace);
185 itval.it_interval.tv_sec = TIMER_RATE;
186 itval.it_value.tv_sec = TIMER_RATE;
187 itval.it_interval.tv_usec = 0;
188 itval.it_value.tv_usec = 0;
189 srandom(getpid());
190 if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0)
191 syslog(LOG_ERR, "setitimer: %m\n");
192
193 FD_ZERO(&ibits);
194 nfd = s + 1; /* 1 + max(fd's) */
195 for (;;) {
196 FD_SET(s, &ibits);
197 /*
198 * If we need a dynamic update that was held off,
199 * needupdate will be set, and nextbcast is the time
200 * by which we want select to return. Compute time
201 * until dynamic update should be sent, and select only
202 * until then. If we have already passed nextbcast,
203 * just poll.
204 */
205 if (needupdate) {
206 timersub(&nextbcast, &now, &waittime);
207 if (waittime.tv_sec < 0) {
208 waittime.tv_sec = 0;
209 waittime.tv_usec = 0;
210 }
211 if (traceactions)
212 fprintf(ftrace,
213 "select until dynamic update %d/%d sec/usec\n",
214 waittime.tv_sec, waittime.tv_usec);
215 tvp = &waittime;
216 } else
217 tvp = (struct timeval *)NULL;
218 n = select(nfd, &ibits, 0, 0, tvp);
219 if (n <= 0) {
220 /*
221 * Need delayed dynamic update if select returned
222 * nothing and we timed out. Otherwise, ignore
223 * errors (e.g. EINTR).
224 */
225 if (n < 0) {
226 if (errno == EINTR)
227 continue;
228 syslog(LOG_ERR, "select: %m");
229 }
230 omask = sigblock(sigmask(SIGALRM));
231 if (n == 0 && needupdate) {
232 if (traceactions)
233 fprintf(ftrace,
234 "send delayed dynamic update\n");
235 (void) gettimeofday(&now,
236 (struct timezone *)NULL);
237 toall(supply, RTS_CHANGED,
238 (struct interface *)NULL);
239 lastbcast = now;
240 needupdate = 0;
241 nextbcast.tv_sec = 0;
242 }
243 sigsetmask(omask);
244 continue;
245 }
246 (void) gettimeofday(&now, (struct timezone *)NULL);
247 omask = sigblock(sigmask(SIGALRM));
248 #ifdef doesntwork
249 /*
250 printf("s %d, ibits %x index %d, mod %d, sh %x, or %x &ibits %x\n",
251 s,
252 ibits.fds_bits[0],
253 (s)/(sizeof(fd_mask) * 8),
254 ((s) % (sizeof(fd_mask) * 8)),
255 (1 << ((s) % (sizeof(fd_mask) * 8))),
256 ibits.fds_bits[(s)/(sizeof(fd_mask) * 8)] & (1 << ((s) % (sizeof(fd_mask) * 8))),
257 &ibits
258 );
259 */
260 if (FD_ISSET(s, &ibits))
261 #else
262 if (ibits.fds_bits[s/32] & (1 << s))
263 #endif
264 process(s);
265 /* handle ICMP redirects */
266 sigsetmask(omask);
267 }
268 }
269
270 void
271 process(fd)
272 int fd;
273 {
274 struct sockaddr from;
275 int fromlen, cc;
276 union {
277 char buf[MAXPACKETSIZE+1];
278 struct rip rip;
279 } inbuf;
280
281 for (;;) {
282 fromlen = sizeof (from);
283 cc = recvfrom(fd, &inbuf, sizeof (inbuf), 0, &from, &fromlen);
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;
291 rip_input(&from, &inbuf.rip, cc);
292 }
293 }
294
295 int
296 getsocket(domain, type, sin)
297 int domain, type;
298 struct sockaddr_in *sin;
299 {
300 int sock, on = 1;
301
302 if ((sock = socket(domain, type, 0)) < 0) {
303 perror("socket");
304 syslog(LOG_ERR, "socket: %m");
305 return (-1);
306 }
307 #ifdef SO_BROADCAST
308 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
309 syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
310 close(sock);
311 return (-1);
312 }
313 #endif
314 #ifdef SO_RCVBUF
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);
326 #endif
327 if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0) {
328 perror("bind");
329 syslog(LOG_ERR, "bind: %m");
330 close(sock);
331 return (-1);
332 }
333 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
334 syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
335 return (sock);
336 }
337