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