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 2005 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
usage(char * fname)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 int
main(int argc,char * argv[])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 return (0);
295 }
296
297 void
timevaladd(struct timeval * t1,struct timeval * t2)298 timevaladd(struct timeval *t1, struct timeval *t2)
299 {
300 t1->tv_sec += t2->tv_sec;
301 if ((t1->tv_usec += t2->tv_usec) > 1000000) {
302 t1->tv_sec++;
303 t1->tv_usec -= 1000000;
304 }
305 }
306
307 void
timevalsub(struct timeval * t1,struct timeval * t2)308 timevalsub(struct timeval *t1, struct timeval *t2)
309 {
310 t1->tv_sec -= t2->tv_sec;
311 if ((t1->tv_usec -= t2->tv_usec) < 0) {
312 t1->tv_sec--;
313 t1->tv_usec += 1000000;
314 }
315 }
316