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 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 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 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 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