1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 *
5 * Copyright (c) 1983, 1988, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgment:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * $FreeBSD: src/sbin/routed/main.c,v 1.14 2000/08/11 08:24:38 sheldonh Exp $
37 * char copyright[] = "@(#) Copyright (c) 1983, 1988, 1993\n"
38 * " The Regents of the University of California. All rights reserved.\n";
39 */
40
41 #include "defs.h"
42 #include "pathnames.h"
43 #include <signal.h>
44 #include <fcntl.h>
45 #include <sys/file.h>
46 #include <sys/stat.h>
47
48 #define IN_ROUTED_VERSION "2.22"
49
50 int stopint;
51 boolean_t supplier; /* supply or broadcast updates */
52 boolean_t supplier_set;
53 /* -S option. _B_TRUE=treat all RIP speakers as default routers. */
54 boolean_t save_space = _B_FALSE;
55
56 static boolean_t default_gateway; /* _B_TRUE=advertise default */
57 static boolean_t background = _B_TRUE;
58 boolean_t ridhosts; /* _B_TRUE=reduce host routes */
59 boolean_t mhome; /* _B_TRUE=want multi-homed host route */
60 boolean_t advertise_mhome; /* _B_TRUE=must continue advertising it */
61 boolean_t auth_ok = _B_TRUE; /* _B_TRUE=ignore auth if we don't care */
62 boolean_t no_install; /* _B_TRUE=don't install in kernel */
63
64 struct timeval epoch; /* when started */
65 struct timeval clk;
66 static struct timeval prev_clk;
67 static int usec_fudge;
68 struct timeval now; /* current idea of time */
69 /* If a route's rts_time is <= to now_stale, the route is stale. */
70 time_t now_stale;
71 /* If a route's rts_time is <= to now_expire, the route is expired */
72 time_t now_expire;
73 /* If a route's rts_time is <= to now_garbage, the route needs to be deleted */
74 time_t now_garbage;
75
76 static struct timeval next_bcast; /* next general broadcast */
77 struct timeval no_flash = { /* inhibit flash update */
78 EPOCH+SUPPLY_INTERVAL, 0
79 };
80
81 /* When now reaches this time, it's time to call sync_kern() */
82 static struct timeval sync_kern_timer;
83
84 static fd_set fdbits;
85 static int sock_max;
86 int rip_sock = -1; /* RIP socket */
87 boolean_t rip_enabled;
88 static boolean_t openlog_done;
89
90 /*
91 * The interface to which rip_sock is currently pointing for
92 * output.
93 */
94 struct interface *rip_sock_interface;
95
96 int rt_sock; /* routing socket */
97
98
99 static int open_rip_sock();
100 static void timevalsub(struct timeval *, struct timeval *, struct timeval *);
101 static void sigalrm(int);
102 static void sigterm(int);
103
104 int
105 main(int argc, char *argv[])
106 {
107 int n, off;
108 char *p, *q;
109 const char *cp;
110 struct timeval select_timeout, result;
111 fd_set ibits;
112 in_addr_t p_net, p_mask;
113 struct parm parm;
114 char *tracename = NULL;
115 boolean_t vflag = _B_FALSE;
116 boolean_t version = _B_FALSE;
117 int sigerr = 0;
118 FILE *pidfp;
119 mode_t pidmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* 0644 */
120
121 (void) setlocale(LC_ALL, "");
122
123 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
124 #define TEXT_DOMAIN "SYS_TEXT"
125 #endif /* ! TEXT_DOMAIN */
126
127 (void) textdomain(TEXT_DOMAIN);
128
129 /*
130 * Some shells are badly broken and send SIGHUP to backgrounded
131 * processes.
132 */
133 if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
134 sigerr = errno;
135
136 ftrace = stdout;
137
138 if (gettimeofday(&clk, 0) == -1) {
139 logbad(_B_FALSE, "gettimeofday: %s", rip_strerror(errno));
140 }
141 prev_clk = clk;
142 epoch = clk;
143 epoch.tv_sec -= EPOCH;
144 now.tv_sec = EPOCH;
145 now_stale = EPOCH - STALE_TIME;
146 now_expire = EPOCH - EXPIRE_TIME;
147 now_garbage = EPOCH - GARBAGE_TIME;
148 select_timeout.tv_sec = 0;
149
150 while ((n = getopt(argc, argv, "sSqdghmpAztVvnT:F:P:")) != -1) {
151 switch (n) {
152 case 'A':
153 /*
154 * Ignore authentication if we do not care.
155 * Crazy as it is, that is what RFC 2453 requires.
156 */
157 auth_ok = _B_FALSE;
158 break;
159
160 case 't':
161 if (new_tracelevel < 2)
162 new_tracelevel = 2;
163 background = _B_FALSE;
164 break;
165
166 case 'd': /* put in.routed in foreground */
167 background = _B_FALSE;
168 break;
169
170 case 'F': /* minimal routes for SLIP */
171 n = FAKE_METRIC;
172 p = strchr(optarg, ',');
173 if (p != NULL) {
174 n = (int)strtoul(p+1, &q, 0);
175 if (*q == '\0' && p+1 != q &&
176 n <= HOPCNT_INFINITY-1 && n >= 1)
177 *p = '\0';
178 }
179 if (!getnet(optarg, &p_net, &p_mask)) {
180 if (p != NULL)
181 *p = ',';
182 msglog(gettext("bad network; \"-F %s\""),
183 optarg);
184 break;
185 }
186 (void) memset(&parm, 0, sizeof (parm));
187 parm.parm_net = p_net;
188 parm.parm_mask = p_mask;
189 parm.parm_d_metric = n;
190 cp = insert_parm(&parm);
191 if (cp != NULL)
192 msglog(gettext("bad -F: %s"), cp);
193 break;
194
195 case 'g':
196 (void) memset(&parm, 0, sizeof (parm));
197 parm.parm_d_metric = 1;
198 cp = insert_parm(&parm);
199 if (cp != NULL)
200 msglog(gettext("bad -g: %s"), cp);
201 else
202 default_gateway = _B_TRUE;
203 break;
204
205 case 'h': /* suppress extra host routes */
206 ridhosts = _B_TRUE;
207 break;
208
209 case 'm': /* advertise host route */
210 mhome = _B_TRUE; /* on multi-homed hosts */
211 break;
212
213 case 'n': /* No-install mode */
214 no_install = _B_TRUE;
215 break;
216
217 case 'P':
218 /* handle arbitrary parameters. */
219 q = strdup(optarg);
220 if (q == NULL)
221 logbad(_B_FALSE, "strdup: %s",
222 rip_strerror(errno));
223 cp = parse_parms(q, _B_FALSE);
224 if (cp != NULL)
225 msglog(gettext("%1$s in \"-P %2$s\""), cp,
226 optarg);
227 free(q);
228 break;
229
230 case 'q':
231 supplier = _B_FALSE;
232 supplier_set = _B_TRUE;
233 break;
234
235 case 's':
236 supplier = _B_TRUE;
237 supplier_set = _B_TRUE;
238 break;
239
240 case 'S': /* save-space option */
241 save_space = _B_TRUE;
242 break;
243
244 case 'T':
245 tracename = optarg;
246 break;
247
248 case 'V':
249 /* display version */
250 version = _B_TRUE;
251 msglog(gettext("version " IN_ROUTED_VERSION));
252 break;
253
254 case 'v':
255 /* display route changes to supplied logfile */
256 new_tracelevel = 1;
257 vflag = _B_TRUE;
258 break;
259
260 case 'z': /* increase debug-level */
261 new_tracelevel++;
262 break;
263
264 default:
265 goto usage;
266 }
267 }
268 argc -= optind;
269 argv += optind;
270
271 if (tracename == NULL && argc >= 1) {
272 tracename = *argv++;
273 argc--;
274 }
275 if (tracename != NULL && tracename[0] == '\0')
276 goto usage;
277 if (vflag && tracename == NULL)
278 goto usage;
279 if (argc != 0) {
280 usage:
281 (void) fprintf(stderr, gettext(
282 "usage: in.routed [-AdghmnqsStVvz] "
283 "[-T <tracefile>]\n"));
284 (void) fprintf(stderr,
285 gettext("\t[-F <net>[/<mask>][,<metric>]] [-P <parms>]\n"));
286 logbad(_B_FALSE, gettext("excess arguments"));
287 }
288 if (geteuid() != 0) {
289 /*
290 * Regular users are allowed to run in.routed for the
291 * sole purpose of obtaining the version number. In
292 * that case, exit(EXIT_SUCCESS) without complaining.
293 */
294 if (version)
295 exit(EXIT_SUCCESS);
296 logbad(_B_FALSE, gettext("requires UID 0"));
297 }
298
299 if (default_gateway) {
300 if (supplier_set && !supplier) {
301 msglog(gettext("-g and -q are incompatible"));
302 } else {
303 supplier = _B_TRUE;
304 supplier_set = _B_TRUE;
305 }
306 }
307
308 if (signal(SIGALRM, sigalrm) == SIG_ERR)
309 sigerr = errno;
310 /* SIGHUP fatal during debugging */
311 if (!background)
312 if (signal(SIGHUP, sigterm) == SIG_ERR)
313 sigerr = errno;
314 if (signal(SIGTERM, sigterm) == SIG_ERR)
315 sigerr = errno;
316 if (signal(SIGINT, sigterm) == SIG_ERR)
317 sigerr = errno;
318 if (signal(SIGUSR1, sigtrace_more) == SIG_ERR)
319 sigerr = errno;
320 if (signal(SIGUSR2, sigtrace_less) == SIG_ERR)
321 sigerr = errno;
322 if (signal(SIGHUP, sigtrace_dump) == SIG_ERR)
323 sigerr = errno;
324
325 if (sigerr)
326 msglog("signal: %s", rip_strerror(sigerr));
327
328 /* get into the background */
329 if (background && daemon(0, 0) < 0)
330 BADERR(_B_FALSE, "daemon()");
331
332 /* Store our process id, blow away any existing file if it exists. */
333 if ((pidfp = fopen(PATH_PID, "w")) == NULL) {
334 (void) fprintf(stderr,
335 gettext("in.routed: unable to open " PATH_PID ": %s\n"),
336 strerror(errno));
337 } else {
338 (void) fprintf(pidfp, "%ld\n", getpid());
339 (void) fclose(pidfp);
340 (void) chmod(PATH_PID, pidmode);
341 }
342
343 srandom((int)(clk.tv_sec ^ clk.tv_usec ^ getpid()));
344
345 /* allocate the interface tables */
346 iftbl_alloc();
347
348 /* prepare socket connected to the kernel. */
349 rt_sock = socket(PF_ROUTE, SOCK_RAW, AF_INET);
350 if (rt_sock < 0)
351 BADERR(_B_TRUE, "rt_sock = socket()");
352 if (fcntl(rt_sock, F_SETFL, O_NONBLOCK) == -1)
353 logbad(_B_TRUE, "fcntl(rt_sock) O_NONBLOCK: %s",
354 rip_strerror(errno));
355 off = 0;
356 if (setsockopt(rt_sock, SOL_SOCKET, SO_USELOOPBACK,
357 &off, sizeof (off)) < 0)
358 LOGERR("setsockopt(SO_USELOOPBACK,0)");
359
360 fix_select();
361
362
363 if (tracename != NULL) {
364 (void) strlcpy(inittracename, tracename,
365 sizeof (inittracename));
366 set_tracefile(inittracename, "%s", -1);
367 } else {
368 tracelevel_msg("%s", -1); /* turn on tracing to stdio */
369 }
370
371 bufinit();
372
373 /* initialize radix tree */
374 rtinit();
375
376 /*
377 * Pick a random part of the second for our output to minimize
378 * collisions.
379 *
380 * Start broadcasting after hearing from other routers, and
381 * at a random time so a bunch of systems do not get synchronized
382 * after a power failure.
383 *
384 * Since now is the number of seconds since epoch (this is initially
385 * EPOCH seconds), these times are really relative to now.
386 */
387 intvl_random(&next_bcast, EPOCH+MIN_WAITTIME, EPOCH+SUPPLY_INTERVAL);
388 age_timer.tv_usec = next_bcast.tv_usec;
389 age_timer.tv_sec = EPOCH+MIN_WAITTIME;
390 rdisc_timer = next_bcast;
391 ifscan_timer.tv_usec = next_bcast.tv_usec;
392
393 /*
394 * Open the global rip socket. From now on, this socket can be
395 * assumed to be open. It will remain open until in.routed
396 * exits.
397 */
398 rip_sock = open_rip_sock();
399
400 /*
401 * Collect an initial view of the world by checking the interface
402 * configuration and the kludge file.
403 *
404 * gwkludge() could call addroutefordefault(), resulting in a call to
405 * iflookup, and thus ifscan() to find the physical interfaces.
406 * ifscan() will attempt to use the rip_sock in order to join
407 * mcast groups, so gwkludge *must* be called after opening
408 * the rip_sock.
409 */
410 gwkludge();
411
412 ifscan();
413
414 /* Ask for routes */
415 rip_query();
416 rdisc_sol();
417
418 /* Now turn off stdio if not tracing */
419 if (new_tracelevel == 0)
420 trace_close(background);
421
422 /* Loop until a fatal error occurs, listening and broadcasting. */
423 for (;;) {
424 prev_clk = clk;
425 if (gettimeofday(&clk, 0) == -1) {
426 logbad(_B_FALSE, "gettimeofday: %s",
427 rip_strerror(errno));
428 }
429 if (prev_clk.tv_sec == clk.tv_sec &&
430 prev_clk.tv_usec == clk.tv_usec+usec_fudge) {
431 /*
432 * Much of `in.routed` depends on time always advancing.
433 * On systems that do not guarantee that gettimeofday()
434 * produces unique timestamps even if called within
435 * a single tick, use trickery like that in classic
436 * BSD kernels.
437 */
438 clk.tv_usec += ++usec_fudge;
439
440 } else {
441 time_t dt;
442
443 usec_fudge = 0;
444
445 timevalsub(&result, &clk, &prev_clk);
446 if (result.tv_sec < 0 || result.tv_sec >
447 select_timeout.tv_sec + 5) {
448 /*
449 * Deal with time changes before other
450 * housekeeping to keep everything straight.
451 */
452 dt = result.tv_sec;
453 if (dt > 0)
454 dt -= select_timeout.tv_sec;
455 trace_act("time changed by %d sec", (int)dt);
456 epoch.tv_sec += dt;
457 }
458 }
459 timevalsub(&now, &clk, &epoch);
460 now_stale = now.tv_sec - STALE_TIME;
461 now_expire = now.tv_sec - EXPIRE_TIME;
462 now_garbage = now.tv_sec - GARBAGE_TIME;
463
464 /* deal with signals that should affect tracing */
465 set_tracelevel();
466
467 if (stopint != 0) {
468 trace_off("exiting with signal %d", stopint);
469 break;
470 }
471
472 /* look for new or dead interfaces */
473 timevalsub(&select_timeout, &ifscan_timer, &now);
474 if (select_timeout.tv_sec <= 0) {
475 select_timeout.tv_sec = 0;
476 ifscan();
477 rip_query();
478 continue;
479 }
480
481 /*
482 * Check the kernel table occassionally for mysteriously
483 * evaporated routes
484 */
485 timevalsub(&result, &sync_kern_timer, &now);
486 if (result.tv_sec <= 0) {
487 sync_kern();
488 sync_kern_timer.tv_sec = (now.tv_sec
489 + CHECK_QUIET_INTERVAL);
490 continue;
491 }
492 if (timercmp(&result, &select_timeout, < /* */))
493 select_timeout = result;
494
495 /* If it is time, then broadcast our routes. */
496 if (should_supply(NULL) || advertise_mhome) {
497 timevalsub(&result, &next_bcast, &now);
498 if (result.tv_sec <= 0) {
499 /*
500 * Synchronize the aging and broadcast
501 * timers to minimize awakenings
502 */
503 age(0);
504 age_peer_info();
505
506 rip_bcast(0);
507
508 /*
509 * It is desirable to send routing updates
510 * regularly. So schedule the next update
511 * 30 seconds after the previous one was
512 * scheduled, instead of 30 seconds after
513 * the previous update was finished.
514 * Even if we just started after discovering
515 * a 2nd interface or were otherwise delayed,
516 * pick a 30-second aniversary of the
517 * original broadcast time.
518 */
519 n = 1 + (0-result.tv_sec)/SUPPLY_INTERVAL;
520 next_bcast.tv_sec += n*SUPPLY_INTERVAL;
521
522 continue;
523 }
524
525 if (timercmp(&result, &select_timeout, < /* */))
526 select_timeout = result;
527 }
528
529 /*
530 * If we need a flash update, either do it now or
531 * set the delay to end when it is time.
532 *
533 * If we are within MIN_WAITTIME seconds of a full update,
534 * do not bother.
535 */
536 if (need_flash && should_supply(NULL) &&
537 no_flash.tv_sec+MIN_WAITTIME < next_bcast.tv_sec) {
538 /* accurate to the millisecond */
539 if (!timercmp(&no_flash, &now, > /* */))
540 rip_bcast(1);
541 timevalsub(&result, &no_flash, &now);
542 if (timercmp(&result, &select_timeout, < /* */))
543 select_timeout = result;
544 }
545
546 /* trigger the main aging timer. */
547 timevalsub(&result, &age_timer, &now);
548 if (result.tv_sec <= 0) {
549 age(0);
550 continue;
551 }
552 if (timercmp(&result, &select_timeout, < /* */))
553 select_timeout = result;
554
555 /* update the kernel routing table */
556 timevalsub(&result, &need_kern, &now);
557 if (result.tv_sec <= 0) {
558 age(0);
559 continue;
560 }
561 if (timercmp(&result, &select_timeout, < /* */))
562 select_timeout = result;
563
564 /*
565 * take care of router discovery. We compare timeval
566 * structures here to have millisecond granularity.
567 */
568 if (!timercmp(&rdisc_timer, &now, > /* */)) {
569 rdisc_age(0);
570 continue;
571 }
572 timevalsub(&result, &rdisc_timer, &now);
573 if (timercmp(&result, &select_timeout, < /* */))
574 select_timeout = result;
575
576 /*
577 * Well-known bit of select(3c) silliness inherited
578 * from BSD: anything over 100 million seconds is
579 * considered an "error." Reset that to zero.
580 */
581 if (select_timeout.tv_sec > 100000000)
582 select_timeout.tv_sec = 0;
583
584 /* wait for input or a timer to expire. */
585 trace_flush();
586 ibits = fdbits;
587 n = select(sock_max, &ibits, 0, 0, &select_timeout);
588 if (n <= 0) {
589 if (n < 0 && errno != EINTR && errno != EAGAIN)
590 BADERR(_B_TRUE, "select");
591 continue;
592 }
593
594 if (FD_ISSET(rt_sock, &ibits)) {
595 read_rt();
596 n--;
597 }
598 if (rdisc_sock >= 0 && FD_ISSET(rdisc_sock, &ibits)) {
599 read_d();
600 n--;
601 }
602 if (rdisc_mib_sock >= 0 && FD_ISSET(rdisc_mib_sock, &ibits)) {
603 process_d_mib_sock();
604 n--;
605 }
606 if (rip_sock >= 0 && FD_ISSET(rip_sock, &ibits)) {
607 if (read_rip() == -1) {
608 rip_enabled = _B_FALSE;
609 trace_off("main rip socket failed");
610 (void) close(rip_sock);
611 rip_sock = -1;
612 fix_select();
613 break;
614 }
615 n--;
616 }
617 }
618 rip_bcast(0);
619 rdisc_adv(_B_FALSE);
620 (void) unlink(PATH_PID);
621 return (stopint | 128);
622 }
623
624
625 static void
626 sigalrm(int sig)
627 {
628 /*
629 * Historically, SIGALRM would cause the daemon to check for
630 * new and broken interfaces.
631 */
632 ifscan_timer.tv_sec = now.tv_sec;
633 trace_act("SIGALRM");
634 if (signal(sig, sigalrm) == SIG_ERR)
635 msglog("signal: %s", rip_strerror(errno));
636 }
637
638
639 /* watch for fatal signals */
640 static void
641 sigterm(int sig)
642 {
643 stopint = sig;
644 if (signal(sig, SIG_DFL) == SIG_ERR) /* catch it only once */
645 msglog("signal: %s", rip_strerror(errno));
646 }
647
648
649 void
650 fix_select(void)
651 {
652 (void) FD_ZERO(&fdbits);
653 sock_max = 0;
654
655 FD_SET(rt_sock, &fdbits);
656 if (sock_max <= rt_sock)
657 sock_max = rt_sock+1;
658 if (rip_sock >= 0) {
659 FD_SET(rip_sock, &fdbits);
660 if (sock_max <= rip_sock)
661 sock_max = rip_sock+1;
662 }
663 if (rdisc_sock >= 0) {
664 FD_SET(rdisc_sock, &fdbits);
665 if (sock_max <= rdisc_sock)
666 sock_max = rdisc_sock+1;
667 FD_SET(rdisc_mib_sock, &fdbits);
668 if (sock_max <= rdisc_mib_sock)
669 sock_max = rdisc_mib_sock+1;
670 }
671 }
672
673
674 void
675 fix_sock(int sock,
676 const char *name)
677 {
678 int on;
679 #define MIN_SOCKBUF (4*1024)
680 static int rbuf;
681
682 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
683 logbad(_B_TRUE, "fcntl(%s) O_NONBLOCK: %s", name,
684 rip_strerror(errno));
685 on = 1;
686 if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0)
687 msglog("setsockopt(%s,SO_BROADCAST): %s",
688 name, rip_strerror(errno));
689
690 if (rbuf >= MIN_SOCKBUF) {
691 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
692 &rbuf, sizeof (rbuf)) < 0)
693 msglog("setsockopt(%s,SO_RCVBUF=%d): %s",
694 name, rbuf, rip_strerror(errno));
695 } else {
696 for (rbuf = 60*1024; ; rbuf -= 4096) {
697 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
698 &rbuf, sizeof (rbuf)) == 0) {
699 trace_act("RCVBUF=%d", rbuf);
700 break;
701 }
702 if (rbuf < MIN_SOCKBUF) {
703 msglog("setsockopt(%s,SO_RCVBUF = %d): %s",
704 name, rbuf, rip_strerror(errno));
705 break;
706 }
707 }
708 }
709 }
710
711
712 /*
713 * Open and return the global rip socket. It is guaranteed to return
714 * a good file descriptor.
715 */
716 static int
717 open_rip_sock()
718 {
719 struct sockaddr_in sin;
720 unsigned char ttl;
721 int s;
722 int on = 1;
723
724
725 if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
726 BADERR(_B_TRUE, "rip_sock = socket()");
727
728 (void) memset(&sin, 0, sizeof (sin));
729 sin.sin_family = AF_INET;
730 sin.sin_port = htons(RIP_PORT);
731 sin.sin_addr.s_addr = INADDR_ANY;
732 if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
733 BADERR(_B_FALSE, "bind(rip_sock)");
734 }
735 fix_sock(s, "rip_sock");
736
737 ttl = 1;
738 if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
739 &ttl, sizeof (ttl)) < 0)
740 DBGERR(_B_TRUE, "rip_sock setsockopt(IP_MULTICAST_TTL)");
741
742 if (setsockopt(s, IPPROTO_IP, IP_RECVIF, &on, sizeof (on)))
743 BADERR(_B_FALSE, "setsockopt(IP_RECVIF)");
744
745 return (s);
746 }
747
748
749 /*
750 * Disable RIP. Note that we don't close the global rip socket since
751 * it is used even when RIP is disabled to receive and answer certain
752 * queries.
753 */
754 void
755 rip_off(void)
756 {
757 struct ip_mreq m;
758 struct interface *ifp;
759 char addrstr[INET_ADDRSTRLEN];
760
761 if (rip_enabled && !mhome) {
762 trace_act("turn off RIP");
763
764 /*
765 * Unsubscribe from the 224.0.0.9 RIP multicast
766 * group address
767 */
768 for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
769 if ((ifp->int_if_flags & IFF_MULTICAST) &&
770 !IS_IFF_QUIET(ifp->int_if_flags) &&
771 !IS_RIP_IN_OFF(ifp->int_state) &&
772 !(ifp->int_state & IS_DUP)) {
773 m.imr_multiaddr.s_addr =
774 htonl(INADDR_RIP_GROUP);
775 m.imr_interface.s_addr =
776 (ifp->int_if_flags & IFF_POINTOPOINT) ?
777 ifp->int_dstaddr : ifp->int_addr;
778 (void) strlcpy(addrstr,
779 inet_ntoa(m.imr_multiaddr),
780 sizeof (addrstr));
781 if (setsockopt(rip_sock, IPPROTO_IP,
782 IP_DROP_MEMBERSHIP, &m,
783 sizeof (m)) < 0 &&
784 errno != EADDRNOTAVAIL && errno != ENOENT)
785 writelog(LOG_WARNING,
786 "%s: setsockopt(IP_DROP_MEMBERSHIP "
787 "%s, %s): %s", ifp->int_name,
788 addrstr, inet_ntoa(m.imr_interface),
789 rip_strerror(errno));
790 }
791 }
792 rip_enabled = _B_FALSE;
793
794 age(0);
795 }
796 }
797
798
799 /* turn on RIP multicast input via an interface */
800 void
801 rip_mcast_on(struct interface *ifp)
802 {
803 struct ip_mreq m;
804
805 if (!IS_RIP_IN_OFF(ifp->int_state) &&
806 (ifp->int_if_flags & IFF_MULTICAST) &&
807 !IS_IFF_QUIET(ifp->int_if_flags) &&
808 !(ifp->int_state & IS_DUP)) {
809 m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP);
810 m.imr_interface.s_addr = (ifp->int_if_flags & IFF_POINTOPOINT) ?
811 ifp->int_dstaddr : ifp->int_addr;
812 if ((setsockopt(rip_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
813 &m, sizeof (m)) < 0) && !(ifp->int_state & IS_BROKE))
814 writelog(LOG_WARNING,
815 "Could not join 224.0.0.9 on interface %s: %s",
816 ifp->int_name, rip_strerror(errno));
817 }
818 }
819
820 /* turn off RIP multicast input via an interface */
821 void
822 rip_mcast_off(struct interface *ifp)
823 {
824 struct ip_mreq m;
825
826 if ((ifp->int_if_flags & IFF_MULTICAST) &&
827 !IS_IFF_QUIET(ifp->int_if_flags) && rip_enabled) {
828 m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP);
829 m.imr_interface.s_addr = (ifp->int_if_flags & IFF_POINTOPOINT) ?
830 ifp->int_dstaddr : ifp->int_addr;
831 if ((setsockopt(rip_sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
832 &m, sizeof (m)) < 0) && errno != EADDRNOTAVAIL &&
833 errno != ENOENT)
834 writelog(LOG_WARNING,
835 "setsockopt(IP_DROP_MEMBERSHIP RIP) for %s: %s",
836 ifp->int_name, rip_strerror(errno));
837 }
838 }
839
840 /* enable RIP */
841 void
842 rip_on(struct interface *ifp)
843 {
844 /*
845 * If RIP is already enabled, only start receiving
846 * multicasts for this interface.
847 */
848 if (rip_enabled) {
849 if (ifp != NULL)
850 rip_mcast_on(ifp);
851 return;
852 }
853
854 /*
855 * If RIP is disabled and it makes sense to enable it, then enable
856 * it on all of the interfaces. It makes sense if either router
857 * discovery is off, or if router discovery is on and at most one
858 * interface is doing RIP.
859 */
860 if (rip_interfaces > 0 && (!rdisc_ok || rip_interfaces > 1)) {
861 trace_act("turn on RIP");
862
863 rip_enabled = _B_TRUE;
864 rip_sock_interface = NULL;
865
866 /* Do not advertise anything until we have heard something */
867 if (next_bcast.tv_sec < now.tv_sec+MIN_WAITTIME)
868 next_bcast.tv_sec = now.tv_sec+MIN_WAITTIME;
869
870 for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
871 ifp->int_query_time = NEVER;
872 rip_mcast_on(ifp);
873 }
874 ifscan_timer.tv_sec = now.tv_sec;
875 }
876
877 fix_select();
878 }
879
880
881 /* die if malloc(3) fails */
882 void *
883 rtmalloc(size_t size,
884 const char *msg)
885 {
886 void *p = malloc(size);
887 if (p == NULL)
888 logbad(_B_TRUE, "malloc(%lu) failed in %s: %s", (ulong_t)size,
889 msg, rip_strerror(errno));
890 return (p);
891 }
892
893
894 /* get a random instant in an interval */
895 void
896 intvl_random(struct timeval *tp, /* put value here */
897 ulong_t lo, /* value is after this second */
898 ulong_t hi) /* and before this */
899 {
900 tp->tv_sec = (time_t)(hi == lo ? lo : (lo + random() % ((hi - lo))));
901 tp->tv_usec = random() % 1000000;
902 }
903
904
905 void
906 timevaladd(struct timeval *t1,
907 struct timeval *t2)
908 {
909
910 t1->tv_sec += t2->tv_sec;
911 if ((t1->tv_usec += t2->tv_usec) >= 1000000) {
912 t1->tv_sec++;
913 t1->tv_usec -= 1000000;
914 }
915 }
916
917
918 /* t1 = t2 - t3 */
919 static void
920 timevalsub(struct timeval *t1,
921 struct timeval *t2,
922 struct timeval *t3)
923 {
924 t1->tv_sec = t2->tv_sec - t3->tv_sec;
925 if ((t1->tv_usec = t2->tv_usec - t3->tv_usec) < 0) {
926 t1->tv_sec--;
927 t1->tv_usec += 1000000;
928 }
929 }
930
931 static void
932 do_openlog(void)
933 {
934 openlog_done = _B_TRUE;
935 openlog("in.routed", LOG_PID | LOG_ODELAY, LOG_DAEMON);
936 }
937
938 /* put a LOG_ERR message into the system log */
939 void
940 msglog(const char *p, ...)
941 {
942 va_list args;
943
944 trace_flush();
945
946 if (!openlog_done)
947 do_openlog();
948 va_start(args, p);
949 vsyslog(LOG_ERR, p, args);
950
951 if (ftrace != 0) {
952 if (ftrace == stdout)
953 (void) fputs("in.routed: ", ftrace);
954 (void) vfprintf(ftrace, p, args);
955 (void) fputc('\n', ftrace);
956 }
957 }
958
959
960 /*
961 * Put a message about a bad system into the system log if
962 * we have not complained about it recently.
963 *
964 * It is desirable to complain about all bad systems, but not too often.
965 * In the worst case, it is not practical to keep track of all bad systems.
966 * For example, there can be many systems with the wrong password.
967 */
968 void
969 msglim(struct msg_limit *lim, in_addr_t addr, const char *p, ...)
970 {
971 va_list args;
972 int i;
973 struct msg_sub *ms1, *ms;
974 const char *p1;
975
976 va_start(args, p);
977
978 /*
979 * look for the oldest slot in the table
980 * or the slot for the bad router.
981 */
982 ms = ms1 = lim->subs;
983 for (i = MSG_SUBJECT_N; ; i--, ms1++) {
984 if (i == 0) {
985 /* Reuse a slot at most once every 10 minutes. */
986 if (lim->reuse > now.tv_sec) {
987 ms = NULL;
988 } else {
989 lim->reuse = now.tv_sec + 10*60;
990 }
991 break;
992 }
993 if (ms->addr == addr) {
994 /*
995 * Repeat a complaint about a given system at
996 * most once an hour.
997 */
998 if (ms->until > now.tv_sec)
999 ms = NULL;
1000 break;
1001 }
1002 if (ms->until < ms1->until)
1003 ms = ms1;
1004 }
1005 if (ms != NULL) {
1006 ms->addr = addr;
1007 ms->until = now.tv_sec + 60*60; /* 60 minutes */
1008
1009 if (!openlog_done)
1010 do_openlog();
1011 trace_flush();
1012 for (p1 = p; *p1 == ' '; p1++)
1013 continue;
1014 vsyslog(LOG_ERR, p1, args);
1015 }
1016
1017 /* always display the message if tracing */
1018 if (ftrace != 0) {
1019 (void) vfprintf(ftrace, p, args);
1020 (void) fputc('\n', ftrace);
1021 }
1022 }
1023
1024
1025 void
1026 logbad(boolean_t dump, const char *p, ...)
1027 {
1028 va_list args;
1029
1030 trace_flush();
1031
1032 if (!openlog_done)
1033 do_openlog();
1034 va_start(args, p);
1035 vsyslog(LOG_ERR, p, args);
1036
1037 (void) fputs(gettext("in.routed: "), stderr);
1038 (void) vfprintf(stderr, p, args);
1039 (void) fputs(gettext("; giving up\n"), stderr);
1040 (void) fflush(stderr);
1041
1042 if (dump)
1043 abort();
1044 exit(EXIT_FAILURE);
1045 }
1046
1047 /* put a message into the system log */
1048 void
1049 writelog(int level, const char *p, ...)
1050 {
1051 va_list args;
1052
1053 trace_flush();
1054
1055 if (!openlog_done)
1056 do_openlog();
1057 va_start(args, p);
1058 vsyslog(level, p, args);
1059
1060 if (ftrace != 0) {
1061 if (ftrace == stdout)
1062 (void) fputs("in.routed: ", ftrace);
1063 (void) vfprintf(ftrace, p, args);
1064 (void) fputc('\n', ftrace);
1065 }
1066 }