1 |
/* |
2 |
* Copyright (c) 1983, 1988, 1993 |
3 |
* The Regents of the University of California. 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 |
* 4. Neither the name of the University nor the names of its contributors |
14 |
* may be used to endorse or promote products derived from this software |
15 |
* without specific prior written permission. |
16 |
* |
17 |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
18 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
19 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
20 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
21 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
22 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
23 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
24 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
25 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
26 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
27 |
* SUCH DAMAGE. |
28 |
* |
29 |
* $MidnightBSD$ |
30 |
*/ |
31 |
|
32 |
#include "defs.h" |
33 |
#include "pathnames.h" |
34 |
#ifdef sgi |
35 |
#include "math.h" |
36 |
#endif |
37 |
#include <signal.h> |
38 |
#include <fcntl.h> |
39 |
#include <sys/file.h> |
40 |
|
41 |
__COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993 " |
42 |
"The Regents of the University of California." |
43 |
" All rights reserved."); |
44 |
#ifdef __NetBSD__ |
45 |
__RCSID("$NetBSD$"); |
46 |
#include <util.h> |
47 |
#elif defined(__FreeBSD__) |
48 |
__RCSID("$MidnightBSD$"); |
49 |
#else |
50 |
__RCSID("$Revision: 2.31 $"); |
51 |
#ident "$Revision: 2.31 $" |
52 |
#endif |
53 |
|
54 |
pid_t mypid; |
55 |
|
56 |
naddr myaddr; /* system address */ |
57 |
static char myname[MAXHOSTNAMELEN+1]; |
58 |
|
59 |
static int verbose; |
60 |
|
61 |
int supplier; /* supply or broadcast updates */ |
62 |
int supplier_set; |
63 |
static int ipforwarding = 1; /* kernel forwarding on */ |
64 |
|
65 |
static int default_gateway; /* 1=advertise default */ |
66 |
static int background = 1; |
67 |
int ridhosts; /* 1=reduce host routes */ |
68 |
int mhome; /* 1=want multi-homed host route */ |
69 |
int advertise_mhome; /* 1=must continue advertising it */ |
70 |
int auth_ok = 1; /* 1=ignore auth if we do not care */ |
71 |
|
72 |
struct timeval epoch; /* when started */ |
73 |
struct timeval clk; |
74 |
static struct timeval prev_clk; |
75 |
static int usec_fudge; |
76 |
struct timeval now; /* current idea of time */ |
77 |
time_t now_stale; |
78 |
time_t now_expire; |
79 |
time_t now_garbage; |
80 |
|
81 |
static struct timeval next_bcast; /* next general broadcast */ |
82 |
struct timeval no_flash = { /* inhibit flash update */ |
83 |
EPOCH+SUPPLY_INTERVAL, 0 |
84 |
}; |
85 |
|
86 |
static struct timeval flush_kern_timer; |
87 |
|
88 |
static fd_set fdbits; |
89 |
static int sock_max; |
90 |
int rip_sock = -1; /* RIP socket */ |
91 |
const struct interface *rip_sock_mcast; /* current multicast interface */ |
92 |
int rt_sock; /* routing socket */ |
93 |
int rt_sock_seqno; |
94 |
|
95 |
|
96 |
static int get_rip_sock(naddr, int); |
97 |
static void timevalsub(struct timeval *, struct timeval *, struct timeval *); |
98 |
static void sigalrm(int s UNUSED); |
99 |
static void sigterm(int sig); |
100 |
|
101 |
int |
102 |
main(int argc, |
103 |
char *argv[]) |
104 |
{ |
105 |
int n, mib[4], off; |
106 |
size_t len; |
107 |
char *p, *q; |
108 |
const char *cp; |
109 |
struct timeval wtime, t2; |
110 |
time_t dt; |
111 |
fd_set ibits; |
112 |
naddr p_net, p_mask; |
113 |
struct interface *ifp; |
114 |
struct parm parm; |
115 |
char *tracename = 0; |
116 |
|
117 |
|
118 |
/* Some shells are badly broken and send SIGHUP to backgrounded |
119 |
* processes. |
120 |
*/ |
121 |
signal(SIGHUP, SIG_IGN); |
122 |
|
123 |
openlog("routed", LOG_PID, LOG_DAEMON); |
124 |
ftrace = stdout; |
125 |
|
126 |
gettimeofday(&clk, 0); |
127 |
prev_clk = clk; |
128 |
epoch = clk; |
129 |
epoch.tv_sec -= EPOCH; |
130 |
now.tv_sec = EPOCH; |
131 |
now_stale = EPOCH - STALE_TIME; |
132 |
now_expire = EPOCH - EXPIRE_TIME; |
133 |
now_garbage = EPOCH - GARBAGE_TIME; |
134 |
wtime.tv_sec = 0; |
135 |
|
136 |
(void)gethostname(myname, sizeof(myname)-1); |
137 |
(void)gethost(myname, &myaddr); |
138 |
|
139 |
while ((n = getopt(argc, argv, "sqdghmAtvT:F:P:")) != -1) { |
140 |
switch (n) { |
141 |
case 's': |
142 |
supplier = 1; |
143 |
supplier_set = 1; |
144 |
break; |
145 |
|
146 |
case 'q': |
147 |
supplier = 0; |
148 |
supplier_set = 1; |
149 |
break; |
150 |
|
151 |
case 'd': |
152 |
background = 0; |
153 |
break; |
154 |
|
155 |
case 'g': |
156 |
memset(&parm, 0, sizeof(parm)); |
157 |
parm.parm_d_metric = 1; |
158 |
cp = check_parms(&parm); |
159 |
if (cp != 0) |
160 |
msglog("bad -g: %s", cp); |
161 |
else |
162 |
default_gateway = 1; |
163 |
break; |
164 |
|
165 |
case 'h': /* suppress extra host routes */ |
166 |
ridhosts = 1; |
167 |
break; |
168 |
|
169 |
case 'm': /* advertise host route */ |
170 |
mhome = 1; /* on multi-homed hosts */ |
171 |
break; |
172 |
|
173 |
case 'A': |
174 |
/* Ignore authentication if we do not care. |
175 |
* Crazy as it is, that is what RFC 1723 requires. |
176 |
*/ |
177 |
auth_ok = 0; |
178 |
break; |
179 |
|
180 |
case 't': |
181 |
new_tracelevel++; |
182 |
break; |
183 |
|
184 |
case 'T': |
185 |
tracename = optarg; |
186 |
break; |
187 |
|
188 |
case 'F': /* minimal routes for SLIP */ |
189 |
n = FAKE_METRIC; |
190 |
p = strchr(optarg,','); |
191 |
if (p && *p != '\0') { |
192 |
n = (int)strtoul(p+1, &q, 0); |
193 |
if (*q == '\0' |
194 |
&& n <= HOPCNT_INFINITY-1 |
195 |
&& n >= 1) |
196 |
*p = '\0'; |
197 |
} |
198 |
if (!getnet(optarg, &p_net, &p_mask)) { |
199 |
msglog("bad network; \"-F %s\"", |
200 |
optarg); |
201 |
break; |
202 |
} |
203 |
memset(&parm, 0, sizeof(parm)); |
204 |
parm.parm_net = p_net; |
205 |
parm.parm_mask = p_mask; |
206 |
parm.parm_d_metric = n; |
207 |
cp = check_parms(&parm); |
208 |
if (cp != 0) |
209 |
msglog("bad -F: %s", cp); |
210 |
break; |
211 |
|
212 |
case 'P': |
213 |
/* handle arbitrary parameters. |
214 |
*/ |
215 |
q = strdup(optarg); |
216 |
cp = parse_parms(q, 0); |
217 |
if (cp != 0) |
218 |
msglog("%s in \"-P %s\"", cp, optarg); |
219 |
free(q); |
220 |
break; |
221 |
|
222 |
case 'v': |
223 |
/* display version */ |
224 |
verbose++; |
225 |
msglog("version 2.31"); |
226 |
break; |
227 |
|
228 |
default: |
229 |
goto usage; |
230 |
} |
231 |
} |
232 |
argc -= optind; |
233 |
argv += optind; |
234 |
|
235 |
if (tracename == 0 && argc >= 1) { |
236 |
tracename = *argv++; |
237 |
argc--; |
238 |
} |
239 |
if (tracename != 0 && tracename[0] == '\0') |
240 |
goto usage; |
241 |
if (argc != 0) { |
242 |
usage: |
243 |
logbad(0, "usage: routed [-sqdghmAtv] [-T tracefile]" |
244 |
" [-F net[,metric]] [-P parms]"); |
245 |
} |
246 |
if (geteuid() != 0) { |
247 |
if (verbose) |
248 |
exit(0); |
249 |
logbad(0, "requires UID 0"); |
250 |
} |
251 |
|
252 |
mib[0] = CTL_NET; |
253 |
mib[1] = PF_INET; |
254 |
mib[2] = IPPROTO_IP; |
255 |
mib[3] = IPCTL_FORWARDING; |
256 |
len = sizeof(ipforwarding); |
257 |
if (sysctl(mib, 4, &ipforwarding, &len, 0, 0) < 0) |
258 |
LOGERR("sysctl(IPCTL_FORWARDING)"); |
259 |
|
260 |
if (!ipforwarding) { |
261 |
if (supplier) |
262 |
msglog("-s incompatible with ipforwarding=0"); |
263 |
if (default_gateway) { |
264 |
msglog("-g incompatible with ipforwarding=0"); |
265 |
default_gateway = 0; |
266 |
} |
267 |
supplier = 0; |
268 |
supplier_set = 1; |
269 |
} |
270 |
if (default_gateway) { |
271 |
if (supplier_set && !supplier) { |
272 |
msglog("-g and -q incompatible"); |
273 |
} else { |
274 |
supplier = 1; |
275 |
supplier_set = 1; |
276 |
} |
277 |
} |
278 |
|
279 |
|
280 |
signal(SIGALRM, sigalrm); |
281 |
if (!background) |
282 |
signal(SIGHUP, sigterm); /* SIGHUP fatal during debugging */ |
283 |
signal(SIGTERM, sigterm); |
284 |
signal(SIGINT, sigterm); |
285 |
signal(SIGUSR1, sigtrace_on); |
286 |
signal(SIGUSR2, sigtrace_off); |
287 |
|
288 |
/* get into the background */ |
289 |
#ifdef sgi |
290 |
if (0 > _daemonize(background ? 0 : (_DF_NOCHDIR|_DF_NOFORK), |
291 |
STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)) |
292 |
BADERR(0, "_daemonize()"); |
293 |
#else |
294 |
if (background && daemon(0, 1) < 0) |
295 |
BADERR(0,"daemon()"); |
296 |
#endif |
297 |
|
298 |
#if defined(__NetBSD__) |
299 |
pidfile(0); |
300 |
#endif |
301 |
mypid = getpid(); |
302 |
#ifdef __FreeBSD__ |
303 |
srandomdev(); |
304 |
#else |
305 |
srandom((int)(clk.tv_sec ^ clk.tv_usec ^ mypid)); |
306 |
#endif |
307 |
|
308 |
/* prepare socket connected to the kernel. |
309 |
*/ |
310 |
rt_sock = socket(AF_ROUTE, SOCK_RAW, 0); |
311 |
if (rt_sock < 0) |
312 |
BADERR(1,"rt_sock = socket()"); |
313 |
if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1) |
314 |
logbad(1, "fcntl(rt_sock) O_NONBLOCK: %s", strerror(errno)); |
315 |
off = 0; |
316 |
if (setsockopt(rt_sock, SOL_SOCKET,SO_USELOOPBACK, |
317 |
&off,sizeof(off)) < 0) |
318 |
LOGERR("setsockopt(SO_USELOOPBACK,0)"); |
319 |
|
320 |
fix_select(); |
321 |
|
322 |
|
323 |
if (tracename != 0) { |
324 |
strncpy(inittracename, tracename, sizeof(inittracename)-1); |
325 |
set_tracefile(inittracename, "%s", -1); |
326 |
} else { |
327 |
tracelevel_msg("%s", -1); /* turn on tracing to stdio */ |
328 |
} |
329 |
|
330 |
bufinit(); |
331 |
|
332 |
/* initialize radix tree */ |
333 |
rtinit(); |
334 |
|
335 |
/* Pick a random part of the second for our output to minimize |
336 |
* collisions. |
337 |
* |
338 |
* Start broadcasting after hearing from other routers, and |
339 |
* at a random time so a bunch of systems do not get synchronized |
340 |
* after a power failure. |
341 |
*/ |
342 |
intvl_random(&next_bcast, EPOCH+MIN_WAITTIME, EPOCH+SUPPLY_INTERVAL); |
343 |
age_timer.tv_usec = next_bcast.tv_usec; |
344 |
age_timer.tv_sec = EPOCH+MIN_WAITTIME; |
345 |
rdisc_timer = next_bcast; |
346 |
ifinit_timer.tv_usec = next_bcast.tv_usec; |
347 |
|
348 |
/* Collect an initial view of the world by checking the interface |
349 |
* configuration and the kludge file. |
350 |
*/ |
351 |
gwkludge(); |
352 |
ifinit(); |
353 |
|
354 |
/* Ask for routes */ |
355 |
rip_query(); |
356 |
rdisc_sol(); |
357 |
|
358 |
/* Now turn off stdio if not tracing */ |
359 |
if (new_tracelevel == 0) |
360 |
trace_close(background); |
361 |
|
362 |
/* Loop forever, listening and broadcasting. |
363 |
*/ |
364 |
for (;;) { |
365 |
prev_clk = clk; |
366 |
gettimeofday(&clk, 0); |
367 |
if (prev_clk.tv_sec == clk.tv_sec |
368 |
&& prev_clk.tv_usec == clk.tv_usec+usec_fudge) { |
369 |
/* Much of `routed` depends on time always advancing. |
370 |
* On systems that do not guarantee that gettimeofday() |
371 |
* produces unique timestamps even if called within |
372 |
* a single tick, use trickery like that in classic |
373 |
* BSD kernels. |
374 |
*/ |
375 |
clk.tv_usec += ++usec_fudge; |
376 |
|
377 |
} else { |
378 |
usec_fudge = 0; |
379 |
|
380 |
timevalsub(&t2, &clk, &prev_clk); |
381 |
if (t2.tv_sec < 0 |
382 |
|| t2.tv_sec > wtime.tv_sec + 5) { |
383 |
/* Deal with time changes before other |
384 |
* housekeeping to keep everything straight. |
385 |
*/ |
386 |
dt = t2.tv_sec; |
387 |
if (dt > 0) |
388 |
dt -= wtime.tv_sec; |
389 |
trace_act("time changed by %d sec", (int)dt); |
390 |
epoch.tv_sec += dt; |
391 |
} |
392 |
} |
393 |
timevalsub(&now, &clk, &epoch); |
394 |
now_stale = now.tv_sec - STALE_TIME; |
395 |
now_expire = now.tv_sec - EXPIRE_TIME; |
396 |
now_garbage = now.tv_sec - GARBAGE_TIME; |
397 |
|
398 |
/* deal with signals that should affect tracing */ |
399 |
set_tracelevel(); |
400 |
|
401 |
if (stopint != 0) { |
402 |
rip_bcast(0); |
403 |
rdisc_adv(); |
404 |
trace_off("exiting with signal %d", stopint); |
405 |
exit(stopint | 128); |
406 |
} |
407 |
|
408 |
/* look for new or dead interfaces */ |
409 |
timevalsub(&wtime, &ifinit_timer, &now); |
410 |
if (wtime.tv_sec <= 0) { |
411 |
wtime.tv_sec = 0; |
412 |
ifinit(); |
413 |
rip_query(); |
414 |
continue; |
415 |
} |
416 |
|
417 |
/* Check the kernel table occassionally for mysteriously |
418 |
* evaporated routes |
419 |
*/ |
420 |
timevalsub(&t2, &flush_kern_timer, &now); |
421 |
if (t2.tv_sec <= 0) { |
422 |
flush_kern(); |
423 |
flush_kern_timer.tv_sec = (now.tv_sec |
424 |
+ CHECK_QUIET_INTERVAL); |
425 |
continue; |
426 |
} |
427 |
if (timercmp(&t2, &wtime, <)) |
428 |
wtime = t2; |
429 |
|
430 |
/* If it is time, then broadcast our routes. |
431 |
*/ |
432 |
if (supplier || advertise_mhome) { |
433 |
timevalsub(&t2, &next_bcast, &now); |
434 |
if (t2.tv_sec <= 0) { |
435 |
/* Synchronize the aging and broadcast |
436 |
* timers to minimize awakenings |
437 |
*/ |
438 |
age(0); |
439 |
|
440 |
rip_bcast(0); |
441 |
|
442 |
/* It is desirable to send routing updates |
443 |
* regularly. So schedule the next update |
444 |
* 30 seconds after the previous one was |
445 |
* scheduled, instead of 30 seconds after |
446 |
* the previous update was finished. |
447 |
* Even if we just started after discovering |
448 |
* a 2nd interface or were otherwise delayed, |
449 |
* pick a 30-second aniversary of the |
450 |
* original broadcast time. |
451 |
*/ |
452 |
n = 1 + (0-t2.tv_sec)/SUPPLY_INTERVAL; |
453 |
next_bcast.tv_sec += n*SUPPLY_INTERVAL; |
454 |
|
455 |
continue; |
456 |
} |
457 |
|
458 |
if (timercmp(&t2, &wtime, <)) |
459 |
wtime = t2; |
460 |
} |
461 |
|
462 |
/* If we need a flash update, either do it now or |
463 |
* set the delay to end when it is time. |
464 |
* |
465 |
* If we are within MIN_WAITTIME seconds of a full update, |
466 |
* do not bother. |
467 |
*/ |
468 |
if (need_flash |
469 |
&& supplier |
470 |
&& no_flash.tv_sec+MIN_WAITTIME < next_bcast.tv_sec) { |
471 |
/* accurate to the millisecond */ |
472 |
if (!timercmp(&no_flash, &now, >)) |
473 |
rip_bcast(1); |
474 |
timevalsub(&t2, &no_flash, &now); |
475 |
if (timercmp(&t2, &wtime, <)) |
476 |
wtime = t2; |
477 |
} |
478 |
|
479 |
/* trigger the main aging timer. |
480 |
*/ |
481 |
timevalsub(&t2, &age_timer, &now); |
482 |
if (t2.tv_sec <= 0) { |
483 |
age(0); |
484 |
continue; |
485 |
} |
486 |
if (timercmp(&t2, &wtime, <)) |
487 |
wtime = t2; |
488 |
|
489 |
/* update the kernel routing table |
490 |
*/ |
491 |
timevalsub(&t2, &need_kern, &now); |
492 |
if (t2.tv_sec <= 0) { |
493 |
age(0); |
494 |
continue; |
495 |
} |
496 |
if (timercmp(&t2, &wtime, <)) |
497 |
wtime = t2; |
498 |
|
499 |
/* take care of router discovery, |
500 |
* but do it in the correct the millisecond |
501 |
*/ |
502 |
if (!timercmp(&rdisc_timer, &now, >)) { |
503 |
rdisc_age(0); |
504 |
continue; |
505 |
} |
506 |
timevalsub(&t2, &rdisc_timer, &now); |
507 |
if (timercmp(&t2, &wtime, <)) |
508 |
wtime = t2; |
509 |
|
510 |
|
511 |
/* wait for input or a timer to expire. |
512 |
*/ |
513 |
trace_flush(); |
514 |
ibits = fdbits; |
515 |
n = select(sock_max, &ibits, 0, 0, &wtime); |
516 |
if (n <= 0) { |
517 |
if (n < 0 && errno != EINTR && errno != EAGAIN) |
518 |
BADERR(1,"select"); |
519 |
continue; |
520 |
} |
521 |
|
522 |
if (FD_ISSET(rt_sock, &ibits)) { |
523 |
read_rt(); |
524 |
n--; |
525 |
} |
526 |
if (rdisc_sock >= 0 && FD_ISSET(rdisc_sock, &ibits)) { |
527 |
read_d(); |
528 |
n--; |
529 |
} |
530 |
if (rip_sock >= 0 && FD_ISSET(rip_sock, &ibits)) { |
531 |
read_rip(rip_sock, 0); |
532 |
n--; |
533 |
} |
534 |
|
535 |
LIST_FOREACH(ifp, &ifnet, int_list) { |
536 |
if (n <= 0) |
537 |
break; |
538 |
if (ifp->int_rip_sock >= 0 |
539 |
&& FD_ISSET(ifp->int_rip_sock, &ibits)) { |
540 |
read_rip(ifp->int_rip_sock, ifp); |
541 |
n--; |
542 |
} |
543 |
} |
544 |
} |
545 |
} |
546 |
|
547 |
|
548 |
/* ARGSUSED */ |
549 |
static void |
550 |
sigalrm(int s UNUSED) |
551 |
{ |
552 |
/* Historically, SIGALRM would cause the daemon to check for |
553 |
* new and broken interfaces. |
554 |
*/ |
555 |
ifinit_timer.tv_sec = now.tv_sec; |
556 |
trace_act("SIGALRM"); |
557 |
} |
558 |
|
559 |
|
560 |
/* watch for fatal signals */ |
561 |
static void |
562 |
sigterm(int sig) |
563 |
{ |
564 |
stopint = sig; |
565 |
(void)signal(sig, SIG_DFL); /* catch it only once */ |
566 |
} |
567 |
|
568 |
|
569 |
void |
570 |
fix_select(void) |
571 |
{ |
572 |
struct interface *ifp; |
573 |
|
574 |
|
575 |
FD_ZERO(&fdbits); |
576 |
sock_max = 0; |
577 |
|
578 |
FD_SET(rt_sock, &fdbits); |
579 |
if (sock_max <= rt_sock) |
580 |
sock_max = rt_sock+1; |
581 |
if (rip_sock >= 0) { |
582 |
FD_SET(rip_sock, &fdbits); |
583 |
if (sock_max <= rip_sock) |
584 |
sock_max = rip_sock+1; |
585 |
} |
586 |
LIST_FOREACH(ifp, &ifnet, int_list) { |
587 |
if (ifp->int_rip_sock >= 0) { |
588 |
FD_SET(ifp->int_rip_sock, &fdbits); |
589 |
if (sock_max <= ifp->int_rip_sock) |
590 |
sock_max = ifp->int_rip_sock+1; |
591 |
} |
592 |
} |
593 |
if (rdisc_sock >= 0) { |
594 |
FD_SET(rdisc_sock, &fdbits); |
595 |
if (sock_max <= rdisc_sock) |
596 |
sock_max = rdisc_sock+1; |
597 |
} |
598 |
} |
599 |
|
600 |
|
601 |
void |
602 |
fix_sock(int sock, |
603 |
const char *name) |
604 |
{ |
605 |
int on; |
606 |
#define MIN_SOCKBUF (4*1024) |
607 |
static int rbuf; |
608 |
|
609 |
if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) |
610 |
logbad(1, "fcntl(%s) O_NONBLOCK: %s", |
611 |
name, strerror(errno)); |
612 |
on = 1; |
613 |
if (setsockopt(sock, SOL_SOCKET,SO_BROADCAST, &on,sizeof(on)) < 0) |
614 |
msglog("setsockopt(%s,SO_BROADCAST): %s", |
615 |
name, strerror(errno)); |
616 |
#ifdef USE_PASSIFNAME |
617 |
on = 1; |
618 |
if (setsockopt(sock, SOL_SOCKET, SO_PASSIFNAME, &on,sizeof(on)) < 0) |
619 |
msglog("setsockopt(%s,SO_PASSIFNAME): %s", |
620 |
name, strerror(errno)); |
621 |
#endif |
622 |
|
623 |
if (rbuf >= MIN_SOCKBUF) { |
624 |
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, |
625 |
&rbuf, sizeof(rbuf)) < 0) |
626 |
msglog("setsockopt(%s,SO_RCVBUF=%d): %s", |
627 |
name, rbuf, strerror(errno)); |
628 |
} else { |
629 |
for (rbuf = 60*1024; ; rbuf -= 4096) { |
630 |
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, |
631 |
&rbuf, sizeof(rbuf)) == 0) { |
632 |
trace_act("RCVBUF=%d", rbuf); |
633 |
break; |
634 |
} |
635 |
if (rbuf < MIN_SOCKBUF) { |
636 |
msglog("setsockopt(%s,SO_RCVBUF = %d): %s", |
637 |
name, rbuf, strerror(errno)); |
638 |
break; |
639 |
} |
640 |
} |
641 |
} |
642 |
} |
643 |
|
644 |
|
645 |
/* get a rip socket |
646 |
*/ |
647 |
static int /* <0 or file descriptor */ |
648 |
get_rip_sock(naddr addr, |
649 |
int serious) /* 1=failure to bind is serious */ |
650 |
{ |
651 |
struct sockaddr_in rsin; |
652 |
unsigned char ttl; |
653 |
int s; |
654 |
|
655 |
|
656 |
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) |
657 |
BADERR(1,"rip_sock = socket()"); |
658 |
|
659 |
memset(&rsin, 0, sizeof(rsin)); |
660 |
#ifdef _HAVE_SIN_LEN |
661 |
rsin.sin_len = sizeof(rsin); |
662 |
#endif |
663 |
rsin.sin_family = AF_INET; |
664 |
rsin.sin_port = htons(RIP_PORT); |
665 |
rsin.sin_addr.s_addr = addr; |
666 |
if (bind(s, (struct sockaddr *)&rsin, sizeof(rsin)) < 0) { |
667 |
if (serious) |
668 |
BADERR(errno != EADDRINUSE, "bind(rip_sock)"); |
669 |
return -1; |
670 |
} |
671 |
fix_sock(s,"rip_sock"); |
672 |
|
673 |
ttl = 1; |
674 |
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, |
675 |
&ttl, sizeof(ttl)) < 0) |
676 |
DBGERR(1,"rip_sock setsockopt(IP_MULTICAST_TTL)"); |
677 |
|
678 |
return s; |
679 |
} |
680 |
|
681 |
|
682 |
/* turn off main RIP socket */ |
683 |
void |
684 |
rip_off(void) |
685 |
{ |
686 |
struct interface *ifp; |
687 |
naddr addr; |
688 |
|
689 |
|
690 |
if (rip_sock >= 0 && !mhome) { |
691 |
trace_act("turn off RIP"); |
692 |
|
693 |
(void)close(rip_sock); |
694 |
rip_sock = -1; |
695 |
|
696 |
/* get non-broadcast sockets to listen to queries. |
697 |
*/ |
698 |
LIST_FOREACH(ifp, &ifnet, int_list) { |
699 |
if (ifp->int_state & IS_REMOTE) |
700 |
continue; |
701 |
if (ifp->int_rip_sock < 0) { |
702 |
addr = ((ifp->int_if_flags & IFF_POINTOPOINT) |
703 |
? ifp->int_dstaddr |
704 |
: ifp->int_addr); |
705 |
ifp->int_rip_sock = get_rip_sock(addr, 0); |
706 |
} |
707 |
} |
708 |
|
709 |
fix_select(); |
710 |
|
711 |
age(0); |
712 |
} |
713 |
} |
714 |
|
715 |
|
716 |
/* turn on RIP multicast input via an interface |
717 |
*/ |
718 |
static void |
719 |
rip_mcast_on(struct interface *ifp) |
720 |
{ |
721 |
struct group_req gr; |
722 |
struct sockaddr_in *sin; |
723 |
|
724 |
if (!IS_RIP_IN_OFF(ifp->int_state) |
725 |
&& (ifp->int_if_flags & IFF_MULTICAST) |
726 |
&& !(ifp->int_state & IS_ALIAS)) { |
727 |
memset(&gr, 0, sizeof(gr)); |
728 |
gr.gr_interface = ifp->int_index; |
729 |
sin = (struct sockaddr_in *)&gr.gr_group; |
730 |
sin->sin_family = AF_INET; |
731 |
#ifdef _HAVE_SIN_LEN |
732 |
sin->sin_len = sizeof(struct sockaddr_in); |
733 |
#endif |
734 |
sin->sin_addr.s_addr = htonl(INADDR_RIP_GROUP); |
735 |
if (setsockopt(rip_sock, IPPROTO_IP, MCAST_JOIN_GROUP, |
736 |
&gr, sizeof(gr)) < 0) |
737 |
LOGERR("setsockopt(MCAST_JOIN_GROUP RIP)"); |
738 |
} |
739 |
} |
740 |
|
741 |
|
742 |
/* Prepare socket used for RIP. |
743 |
*/ |
744 |
void |
745 |
rip_on(struct interface *ifp) |
746 |
{ |
747 |
/* If the main RIP socket is already alive, only start receiving |
748 |
* multicasts for this interface. |
749 |
*/ |
750 |
if (rip_sock >= 0) { |
751 |
if (ifp != 0) |
752 |
rip_mcast_on(ifp); |
753 |
return; |
754 |
} |
755 |
|
756 |
/* If the main RIP socket is off and it makes sense to turn it on, |
757 |
* then turn it on for all of the interfaces. |
758 |
* It makes sense if either router discovery is off, or if |
759 |
* router discover is on and at most one interface is doing RIP. |
760 |
*/ |
761 |
if (rip_interfaces > 0 && (!rdisc_ok || rip_interfaces > 1)) { |
762 |
trace_act("turn on RIP"); |
763 |
|
764 |
/* Close all of the query sockets so that we can open |
765 |
* the main socket. SO_REUSEPORT is not a solution, |
766 |
* since that would let two daemons bind to the broadcast |
767 |
* socket. |
768 |
*/ |
769 |
LIST_FOREACH(ifp, &ifnet, int_list) { |
770 |
if (ifp->int_rip_sock >= 0) { |
771 |
(void)close(ifp->int_rip_sock); |
772 |
ifp->int_rip_sock = -1; |
773 |
} |
774 |
} |
775 |
|
776 |
rip_sock = get_rip_sock(INADDR_ANY, 1); |
777 |
rip_sock_mcast = 0; |
778 |
|
779 |
/* Do not advertise anything until we have heard something |
780 |
*/ |
781 |
if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME) |
782 |
next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME; |
783 |
|
784 |
LIST_FOREACH(ifp, &ifnet, int_list) { |
785 |
ifp->int_query_time = NEVER; |
786 |
rip_mcast_on(ifp); |
787 |
} |
788 |
ifinit_timer.tv_sec = now.tv_sec; |
789 |
|
790 |
} else if (ifp != 0 |
791 |
&& !(ifp->int_state & IS_REMOTE) |
792 |
&& ifp->int_rip_sock < 0) { |
793 |
/* RIP is off, so ensure there are sockets on which |
794 |
* to listen for queries. |
795 |
*/ |
796 |
ifp->int_rip_sock = get_rip_sock(ifp->int_addr, 0); |
797 |
} |
798 |
|
799 |
fix_select(); |
800 |
} |
801 |
|
802 |
|
803 |
/* die if malloc(3) fails |
804 |
*/ |
805 |
void * |
806 |
rtmalloc(size_t size, |
807 |
const char *msg) |
808 |
{ |
809 |
void *p = malloc(size); |
810 |
if (p == 0) |
811 |
logbad(1,"malloc(%lu) failed in %s", (u_long)size, msg); |
812 |
return p; |
813 |
} |
814 |
|
815 |
|
816 |
/* get a random instant in an interval |
817 |
*/ |
818 |
void |
819 |
intvl_random(struct timeval *tp, /* put value here */ |
820 |
u_long lo, /* value is after this second */ |
821 |
u_long hi) /* and before this */ |
822 |
{ |
823 |
tp->tv_sec = (time_t)(hi == lo |
824 |
? lo |
825 |
: (lo + random() % ((hi - lo)))); |
826 |
tp->tv_usec = random() % 1000000; |
827 |
} |
828 |
|
829 |
|
830 |
void |
831 |
timevaladd(struct timeval *t1, |
832 |
struct timeval *t2) |
833 |
{ |
834 |
|
835 |
t1->tv_sec += t2->tv_sec; |
836 |
if ((t1->tv_usec += t2->tv_usec) >= 1000000) { |
837 |
t1->tv_sec++; |
838 |
t1->tv_usec -= 1000000; |
839 |
} |
840 |
} |
841 |
|
842 |
|
843 |
/* t1 = t2 - t3 |
844 |
*/ |
845 |
static void |
846 |
timevalsub(struct timeval *t1, |
847 |
struct timeval *t2, |
848 |
struct timeval *t3) |
849 |
{ |
850 |
t1->tv_sec = t2->tv_sec - t3->tv_sec; |
851 |
if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) { |
852 |
t1->tv_sec--; |
853 |
t1->tv_usec += 1000000; |
854 |
} |
855 |
} |
856 |
|
857 |
|
858 |
/* put a message into the system log |
859 |
*/ |
860 |
void |
861 |
msglog(const char *p, ...) |
862 |
{ |
863 |
va_list args; |
864 |
|
865 |
trace_flush(); |
866 |
|
867 |
va_start(args, p); |
868 |
vsyslog(LOG_ERR, p, args); |
869 |
va_end(args); |
870 |
if (ftrace != 0) { |
871 |
if (ftrace == stdout) |
872 |
(void)fputs("routed: ", ftrace); |
873 |
va_start(args, p); |
874 |
(void)vfprintf(ftrace, p, args); |
875 |
va_end(args); |
876 |
(void)fputc('\n', ftrace); |
877 |
} |
878 |
} |
879 |
|
880 |
|
881 |
/* Put a message about a bad system into the system log if |
882 |
* we have not complained about it recently. |
883 |
* |
884 |
* It is desirable to complain about all bad systems, but not too often. |
885 |
* In the worst case, it is not practical to keep track of all bad systems. |
886 |
* For example, there can be many systems with the wrong password. |
887 |
*/ |
888 |
void |
889 |
msglim(struct msg_limit *lim, naddr addr, const char *p, ...) |
890 |
{ |
891 |
va_list args; |
892 |
int i; |
893 |
struct msg_sub *ms1, *ms; |
894 |
const char *p1; |
895 |
|
896 |
/* look for the oldest slot in the table |
897 |
* or the slot for the bad router. |
898 |
*/ |
899 |
ms = ms1 = lim->subs; |
900 |
for (i = MSG_SUBJECT_N; ; i--, ms1++) { |
901 |
if (i == 0) { |
902 |
/* Reuse a slot at most once every 10 minutes. |
903 |
*/ |
904 |
if (lim->reuse > now.tv_sec) { |
905 |
ms = 0; |
906 |
} else { |
907 |
ms = ms1; |
908 |
lim->reuse = now.tv_sec + 10*60; |
909 |
} |
910 |
break; |
911 |
} |
912 |
if (ms->addr == addr) { |
913 |
/* Repeat a complaint about a given system at |
914 |
* most once an hour. |
915 |
*/ |
916 |
if (ms->until > now.tv_sec) |
917 |
ms = 0; |
918 |
break; |
919 |
} |
920 |
if (ms->until < ms1->until) |
921 |
ms = ms1; |
922 |
} |
923 |
if (ms != 0) { |
924 |
ms->addr = addr; |
925 |
ms->until = now.tv_sec + 60*60; /* 60 minutes */ |
926 |
|
927 |
trace_flush(); |
928 |
for (p1 = p; *p1 == ' '; p1++) |
929 |
continue; |
930 |
va_start(args, p); |
931 |
vsyslog(LOG_ERR, p1, args); |
932 |
va_end(args); |
933 |
} |
934 |
|
935 |
/* always display the message if tracing */ |
936 |
if (ftrace != 0) { |
937 |
va_start(args, p); |
938 |
(void)vfprintf(ftrace, p, args); |
939 |
va_end(args); |
940 |
(void)fputc('\n', ftrace); |
941 |
} |
942 |
} |
943 |
|
944 |
|
945 |
void |
946 |
logbad(int dump, const char *p, ...) |
947 |
{ |
948 |
va_list args; |
949 |
|
950 |
trace_flush(); |
951 |
|
952 |
va_start(args, p); |
953 |
vsyslog(LOG_ERR, p, args); |
954 |
va_end(args); |
955 |
(void)fputs("routed: ", stderr); |
956 |
va_start(args, p); |
957 |
(void)vfprintf(stderr, p, args); |
958 |
va_end(args); |
959 |
(void)fputs("; giving up\n",stderr); |
960 |
(void)fflush(stderr); |
961 |
|
962 |
if (dump) |
963 |
abort(); |
964 |
exit(1); |
965 |
} |