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 #include "defs.h" 36 37 struct sockaddr_in6 allrouters; 38 char *control; 39 boolean_t dopoison = _B_TRUE; /* Do poison reverse */ 40 int iocsoc; 41 struct timeval lastfullupdate; /* last time full table multicast */ 42 struct timeval lastmcast; /* last time all/changes multicast */ 43 int max_poll_ifs = START_POLL_SIZE; 44 struct rip6 *msg; 45 boolean_t needupdate; /* true if need update at nextmcast */ 46 struct timeval nextmcast; /* time to wait before changes mcast */ 47 struct timeval now; /* current idea of time */ 48 char *packet; 49 struct pollfd *poll_ifs = NULL; 50 int poll_ifs_num = 0; 51 int rip6_port; 52 boolean_t supplier = _B_TRUE; /* process should supply updates */ 53 54 struct in6_addr allrouters_in6 = { 55 /* BEGIN CSTYLED */ 56 { 0xff, 0x2, 0x0, 0x0, 57 0x0, 0x0, 0x0, 0x0, 58 0x0, 0x0, 0x0, 0x0, 59 0x0, 0x0, 0x0, 0x9 } 60 /* END CSTYLED */ 61 }; 62 63 static void timevalsub(struct timeval *t1, struct timeval *t2); 64 65 static void 66 usage(char *fname) 67 { 68 (void) fprintf(stderr, 69 "usage: " 70 "%s [ -P ] [ -p port ] [ -q ] [ -s ] [ -t ] [ -v ] [<logfile>]\n", 71 fname); 72 exit(EXIT_FAILURE); 73 } 74 75 int 76 main(int argc, char *argv[]) 77 { 78 int i, n; 79 struct interface *ifp; 80 int c; 81 struct timeval waittime; 82 int timeout; 83 boolean_t daemon = _B_TRUE; /* Fork off a detached daemon */ 84 FILE *pidfp; 85 mode_t pidmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* 0644 */ 86 87 rip6_port = htons(IPPORT_ROUTESERVER6); 88 allrouters.sin6_family = AF_INET6; 89 allrouters.sin6_port = rip6_port; 90 allrouters.sin6_addr = allrouters_in6; 91 92 while ((c = getopt(argc, argv, "nsqvTtdgPp:")) != EOF) { 93 switch (c) { 94 case 'n': 95 install = _B_FALSE; 96 break; 97 case 's': 98 supplier = _B_TRUE; 99 break; 100 case 'q': 101 supplier = _B_FALSE; 102 break; 103 case 'v': 104 tracing |= ACTION_BIT; 105 break; 106 case 'T': 107 daemon = _B_FALSE; 108 break; 109 case 't': 110 tracepackets = _B_TRUE; 111 daemon = _B_FALSE; 112 tracing |= (INPUT_BIT | OUTPUT_BIT); 113 break; 114 case 'd': 115 break; 116 case 'P': 117 dopoison = _B_FALSE; 118 break; 119 case 'p': 120 rip6_port = htons(atoi(optarg)); 121 allrouters.sin6_port = rip6_port; 122 break; 123 default: 124 usage(argv[0]); 125 /* NOTREACHED */ 126 } 127 } 128 129 /* 130 * Any extra argument is considered 131 * a tracing log file. 132 */ 133 if (optind < argc) { 134 traceon(argv[optind]); 135 } else if (tracing && !daemon) { 136 traceonfp(stdout); 137 } else if (tracing) { 138 (void) fprintf(stderr, "Need logfile with -v\n"); 139 usage(argv[0]); 140 /* NOTREACHED */ 141 } 142 143 if (daemon) { 144 int t; 145 146 if (fork()) 147 exit(EXIT_SUCCESS); 148 for (t = 0; t < 20; t++) { 149 if (!tracing || (t != fileno(ftrace))) 150 (void) close(t); 151 } 152 (void) open("/", 0); 153 (void) dup2(0, 1); 154 (void) dup2(0, 2); 155 (void) setsid(); 156 } 157 158 /* Store our process id, blow away any existing file if it exists. */ 159 if ((pidfp = fopen(PATH_PID, "w")) == NULL) { 160 (void) fprintf(stderr, "%s: unable to open " PATH_PID ": %s\n", 161 argv[0], strerror(errno)); 162 } else { 163 (void) fprintf(pidfp, "%ld\n", getpid()); 164 (void) fclose(pidfp); 165 (void) chmod(PATH_PID, pidmode); 166 } 167 168 169 iocsoc = socket(AF_INET6, SOCK_DGRAM, 0); 170 if (iocsoc < 0) { 171 syslog(LOG_ERR, "main: socket: %m"); 172 exit(EXIT_FAILURE); 173 } 174 175 setup_rtsock(); 176 177 /* 178 * Allocate the buffer to hold the RIPng packet. In reality, it will be 179 * smaller than IPV6_MAX_PACKET octets due to (at least) the IPv6 and 180 * UDP headers but IPV6_MAX_PACKET is a convenient size. 181 */ 182 packet = (char *)malloc(IPV6_MAX_PACKET); 183 if (packet == NULL) { 184 syslog(LOG_ERR, "main: malloc: %m"); 185 exit(EXIT_FAILURE); 186 } 187 msg = (struct rip6 *)packet; 188 189 /* 190 * Allocate the buffer to hold the ancillary data. This data is used to 191 * insure that the incoming hop count of a RIPCMD6_RESPONSE message is 192 * IPV6_MAX_HOPS which indicates that it came from a direct neighbor 193 * (namely, no intervening router decremented it). 194 */ 195 control = (char *)malloc(IPV6_MAX_PACKET); 196 if (control == NULL) { 197 syslog(LOG_ERR, "main: malloc: %m"); 198 exit(EXIT_FAILURE); 199 } 200 201 openlog("in.ripngd", LOG_PID | LOG_CONS, LOG_DAEMON); 202 203 (void) gettimeofday(&now, (struct timezone *)NULL); 204 205 initifs(); 206 solicitall(&allrouters); 207 208 if (supplier) 209 supplyall(&allrouters, 0, (struct interface *)NULL, _B_TRUE); 210 211 (void) sigset(SIGALRM, (void (*)(int))timer); 212 (void) sigset(SIGHUP, (void (*)(int))initifs); 213 (void) sigset(SIGTERM, (void (*)(int))term); 214 (void) sigset(SIGUSR1, (void (*)(int))if_dump); 215 (void) sigset(SIGUSR2, (void (*)(int))rtdump); 216 217 /* 218 * Seed the pseudo-random number generator for GET_RANDOM(). 219 */ 220 srandom((uint_t)gethostid()); 221 222 timer(); 223 224 for (;;) { 225 if (needupdate) { 226 waittime = nextmcast; 227 timevalsub(&waittime, &now); 228 if (waittime.tv_sec < 0) { 229 timeout = 0; 230 } else { 231 timeout = TIME_TO_MSECS(waittime); 232 } 233 if (tracing & ACTION_BIT) { 234 (void) fprintf(ftrace, 235 "poll until dynamic update in %d msec\n", 236 timeout); 237 (void) fflush(ftrace); 238 } 239 } else { 240 timeout = INFTIM; 241 } 242 243 if ((n = poll(poll_ifs, poll_ifs_num, timeout)) < 0) { 244 if (errno == EINTR) 245 continue; 246 syslog(LOG_ERR, "main: poll: %m"); 247 exit(EXIT_FAILURE); 248 } 249 (void) sighold(SIGALRM); 250 (void) sighold(SIGHUP); 251 /* 252 * Poll timed out. 253 */ 254 if (n == 0) { 255 if (needupdate) { 256 TRACE_ACTION("send delayed dynamic update", 257 (struct rt_entry *)NULL); 258 (void) gettimeofday(&now, 259 (struct timezone *)NULL); 260 supplyall(&allrouters, RTS_CHANGED, 261 (struct interface *)NULL, _B_TRUE); 262 lastmcast = now; 263 needupdate = _B_FALSE; 264 nextmcast.tv_sec = 0; 265 } 266 (void) sigrelse(SIGHUP); 267 (void) sigrelse(SIGALRM); 268 continue; 269 } 270 (void) gettimeofday(&now, (struct timezone *)NULL); 271 for (i = 0; i < poll_ifs_num; i++) { 272 /* 273 * This case should never happen. 274 */ 275 if (poll_ifs[i].revents & POLLERR) { 276 syslog(LOG_ERR, 277 "main: poll returned a POLLERR event"); 278 continue; 279 } 280 if (poll_ifs[i].revents & POLLIN) { 281 for (ifp = ifnet; ifp != NULL; 282 ifp = ifp->int_next) { 283 if (poll_ifs[i].fd == ifp->int_sock) 284 in_data(ifp); 285 } 286 } 287 } 288 (void) sigrelse(SIGHUP); 289 (void) sigrelse(SIGALRM); 290 } 291 292 return (0); 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