1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * Portions of this source code were derived from Berkeley 4.3 BSD
32  * under license from the Regents of the University of California.
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 #include "defs.h"
38 
39 struct		sockaddr_in6 allrouters;
40 char		*control;
41 boolean_t	dopoison = _B_TRUE;	/* Do poison reverse */
42 int		iocsoc;
43 struct		timeval lastfullupdate;	/* last time full table multicast */
44 struct		timeval lastmcast;	/* last time all/changes multicast */
45 int		max_poll_ifs = START_POLL_SIZE;
46 struct		rip6 *msg;
47 boolean_t	needupdate;		/* true if need update at nextmcast */
48 struct		timeval nextmcast;	/* time to wait before changes mcast */
49 struct		timeval now;		/* current idea of time */
50 char		*packet;
51 struct		pollfd *poll_ifs = NULL;
52 int		poll_ifs_num = 0;
53 int		rip6_port;
54 boolean_t	supplier = _B_TRUE;	/* process should supply updates */
55 
56 struct		in6_addr allrouters_in6 = {
57 /* BEGIN CSTYLED */
58     { 0xff, 0x2, 0x0, 0x0,
59       0x0,  0x0, 0x0, 0x0,
60       0x0,  0x0, 0x0, 0x0,
61       0x0,  0x0, 0x0, 0x9 }
62 /* END CSTYLED */
63 };
64 
65 static void	timevalsub(struct timeval *t1, struct timeval *t2);
66 
67 static void
68 usage(char *fname)
69 {
70 	(void) fprintf(stderr,
71 	    "usage: "
72 	    "%s [ -P ] [ -p port ] [ -q ] [ -s ] [ -t ] [ -v ] [<logfile>]\n",
73 	    fname);
74 	exit(EXIT_FAILURE);
75 }
76 
77 void
78 main(int argc, char *argv[])
79 {
80 	int i, n;
81 	struct interface *ifp;
82 	int c;
83 	struct timeval waittime;
84 	int timeout;
85 	boolean_t daemon = _B_TRUE;	/* Fork off a detached daemon */
86 	FILE *pidfp;
87 	mode_t pidmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* 0644 */
88 
89 	rip6_port = htons(IPPORT_ROUTESERVER6);
90 	allrouters.sin6_family = AF_INET6;
91 	allrouters.sin6_port = rip6_port;
92 	allrouters.sin6_addr = allrouters_in6;
93 
94 	while ((c = getopt(argc, argv, "nsqvTtdgPp:")) != EOF) {
95 		switch (c) {
96 		case 'n':
97 			install = _B_FALSE;
98 			break;
99 		case 's':
100 			supplier = _B_TRUE;
101 			break;
102 		case 'q':
103 			supplier = _B_FALSE;
104 			break;
105 		case 'v':
106 			tracing |= ACTION_BIT;
107 			break;
108 		case 'T':
109 			daemon = _B_FALSE;
110 			break;
111 		case 't':
112 			tracepackets = _B_TRUE;
113 			daemon = _B_FALSE;
114 			tracing |= (INPUT_BIT | OUTPUT_BIT);
115 			break;
116 		case 'd':
117 			break;
118 		case 'P':
119 			dopoison = _B_FALSE;
120 			break;
121 		case 'p':
122 			rip6_port = htons(atoi(optarg));
123 			allrouters.sin6_port = rip6_port;
124 			break;
125 		default:
126 			usage(argv[0]);
127 			/* NOTREACHED */
128 		}
129 	}
130 
131 	/*
132 	 * Any extra argument is considered
133 	 * a tracing log file.
134 	 */
135 	if (optind < argc) {
136 		traceon(argv[optind]);
137 	} else if (tracing && !daemon) {
138 		traceonfp(stdout);
139 	} else if (tracing) {
140 		(void) fprintf(stderr, "Need logfile with -v\n");
141 		usage(argv[0]);
142 		/* NOTREACHED */
143 	}
144 
145 	if (daemon) {
146 		int t;
147 
148 		if (fork())
149 			exit(EXIT_SUCCESS);
150 		for (t = 0; t < 20; t++) {
151 			if (!tracing || (t != fileno(ftrace)))
152 				(void) close(t);
153 		}
154 		(void) open("/", 0);
155 		(void) dup2(0, 1);
156 		(void) dup2(0, 2);
157 		(void) setsid();
158 	}
159 
160 	/* Store our process id, blow away any existing file if it exists. */
161 	if ((pidfp = fopen(PATH_PID, "w")) == NULL) {
162 		(void) fprintf(stderr, "%s: unable to open " PATH_PID ": %s\n",
163 		    argv[0], strerror(errno));
164 	} else {
165 		(void) fprintf(pidfp, "%ld\n", getpid());
166 		(void) fclose(pidfp);
167 		(void) chmod(PATH_PID, pidmode);
168 	}
169 
170 
171 	iocsoc = socket(AF_INET6, SOCK_DGRAM, 0);
172 	if (iocsoc < 0) {
173 		syslog(LOG_ERR, "main: socket: %m");
174 		exit(EXIT_FAILURE);
175 	}
176 
177 	setup_rtsock();
178 
179 	/*
180 	 * Allocate the buffer to hold the RIPng packet.  In reality, it will be
181 	 * smaller than IPV6_MAX_PACKET octets due to (at least) the IPv6 and
182 	 * UDP headers but IPV6_MAX_PACKET is a convenient size.
183 	 */
184 	packet = (char *)malloc(IPV6_MAX_PACKET);
185 	if (packet == NULL) {
186 		syslog(LOG_ERR, "main: malloc: %m");
187 		exit(EXIT_FAILURE);
188 	}
189 	msg = (struct rip6 *)packet;
190 
191 	/*
192 	 * Allocate the buffer to hold the ancillary data.  This data is used to
193 	 * insure that the incoming hop count of a RIPCMD6_RESPONSE message is
194 	 * IPV6_MAX_HOPS which indicates that it came from a direct neighbor
195 	 * (namely, no intervening router decremented it).
196 	 */
197 	control = (char *)malloc(IPV6_MAX_PACKET);
198 	if (control == NULL) {
199 		syslog(LOG_ERR, "main: malloc: %m");
200 		exit(EXIT_FAILURE);
201 	}
202 
203 	openlog("in.ripngd", LOG_PID | LOG_CONS, LOG_DAEMON);
204 
205 	(void) gettimeofday(&now, (struct timezone *)NULL);
206 
207 	initifs();
208 	solicitall(&allrouters);
209 
210 	if (supplier)
211 		supplyall(&allrouters, 0, (struct interface *)NULL, _B_TRUE);
212 
213 	(void) sigset(SIGALRM, (void (*)(int))timer);
214 	(void) sigset(SIGHUP, (void (*)(int))initifs);
215 	(void) sigset(SIGTERM, (void (*)(int))term);
216 	(void) sigset(SIGUSR1, (void (*)(int))if_dump);
217 	(void) sigset(SIGUSR2, (void (*)(int))rtdump);
218 
219 	/*
220 	 * Seed the pseudo-random number generator for GET_RANDOM().
221 	 */
222 	srandom((uint_t)gethostid());
223 
224 	timer();
225 
226 	for (;;) {
227 		if (needupdate) {
228 			waittime = nextmcast;
229 			timevalsub(&waittime, &now);
230 			if (waittime.tv_sec < 0) {
231 				timeout = 0;
232 			} else {
233 				timeout = TIME_TO_MSECS(waittime);
234 			}
235 			if (tracing & ACTION_BIT) {
236 				(void) fprintf(ftrace,
237 				    "poll until dynamic update in %d msec\n",
238 				    timeout);
239 				(void) fflush(ftrace);
240 			}
241 		} else {
242 			timeout = INFTIM;
243 		}
244 
245 		if ((n = poll(poll_ifs, poll_ifs_num, timeout)) < 0) {
246 			if (errno == EINTR)
247 				continue;
248 			syslog(LOG_ERR, "main: poll: %m");
249 			exit(EXIT_FAILURE);
250 		}
251 		(void) sighold(SIGALRM);
252 		(void) sighold(SIGHUP);
253 		/*
254 		 * Poll timed out.
255 		 */
256 		if (n == 0) {
257 			if (needupdate) {
258 				TRACE_ACTION("send delayed dynamic update",
259 				    (struct rt_entry *)NULL);
260 				(void) gettimeofday(&now,
261 				    (struct timezone *)NULL);
262 				supplyall(&allrouters, RTS_CHANGED,
263 				    (struct interface *)NULL, _B_TRUE);
264 				lastmcast = now;
265 				needupdate = _B_FALSE;
266 				nextmcast.tv_sec = 0;
267 			}
268 			(void) sigrelse(SIGHUP);
269 			(void) sigrelse(SIGALRM);
270 			continue;
271 		}
272 		(void) gettimeofday(&now, (struct timezone *)NULL);
273 		for (i = 0; i < poll_ifs_num; i++) {
274 			/*
275 			 * This case should never happen.
276 			 */
277 			if (poll_ifs[i].revents & POLLERR) {
278 				syslog(LOG_ERR,
279 				    "main: poll returned a POLLERR event");
280 				continue;
281 			}
282 			if (poll_ifs[i].revents & POLLIN) {
283 				for (ifp = ifnet; ifp != NULL;
284 				    ifp = ifp->int_next) {
285 					if (poll_ifs[i].fd == ifp->int_sock)
286 						in_data(ifp);
287 				}
288 			}
289 		}
290 		(void) sigrelse(SIGHUP);
291 		(void) sigrelse(SIGALRM);
292 	}
293 }
294 
295 void
296 timevaladd(struct timeval *t1, struct timeval *t2)
297 {
298 	t1->tv_sec += t2->tv_sec;
299 	if ((t1->tv_usec += t2->tv_usec) > 1000000) {
300 		t1->tv_sec++;
301 		t1->tv_usec -= 1000000;
302 	}
303 }
304 
305 void
306 timevalsub(struct timeval *t1, struct timeval *t2)
307 {
308 	t1->tv_sec -= t2->tv_sec;
309 	if ((t1->tv_usec -= t2->tv_usec) < 0) {
310 		t1->tv_sec--;
311 		t1->tv_usec += 1000000;
312 	}
313 }
314