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