17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*b2460f2fSpj157603 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 327c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California. 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include "defs.h" 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate struct sockaddr_in6 allrouters; 407c478bd9Sstevel@tonic-gate char *control; 417c478bd9Sstevel@tonic-gate boolean_t dopoison = _B_TRUE; /* Do poison reverse */ 427c478bd9Sstevel@tonic-gate int iocsoc; 437c478bd9Sstevel@tonic-gate struct timeval lastfullupdate; /* last time full table multicast */ 447c478bd9Sstevel@tonic-gate struct timeval lastmcast; /* last time all/changes multicast */ 457c478bd9Sstevel@tonic-gate int max_poll_ifs = START_POLL_SIZE; 467c478bd9Sstevel@tonic-gate struct rip6 *msg; 477c478bd9Sstevel@tonic-gate boolean_t needupdate; /* true if need update at nextmcast */ 487c478bd9Sstevel@tonic-gate struct timeval nextmcast; /* time to wait before changes mcast */ 497c478bd9Sstevel@tonic-gate struct timeval now; /* current idea of time */ 507c478bd9Sstevel@tonic-gate char *packet; 517c478bd9Sstevel@tonic-gate struct pollfd *poll_ifs = NULL; 527c478bd9Sstevel@tonic-gate int poll_ifs_num = 0; 537c478bd9Sstevel@tonic-gate int rip6_port; 547c478bd9Sstevel@tonic-gate boolean_t supplier = _B_TRUE; /* process should supply updates */ 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate struct in6_addr allrouters_in6 = { 577c478bd9Sstevel@tonic-gate /* BEGIN CSTYLED */ 587c478bd9Sstevel@tonic-gate { 0xff, 0x2, 0x0, 0x0, 597c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 607c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x0, 617c478bd9Sstevel@tonic-gate 0x0, 0x0, 0x0, 0x9 } 627c478bd9Sstevel@tonic-gate /* END CSTYLED */ 637c478bd9Sstevel@tonic-gate }; 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate static void timevalsub(struct timeval *t1, struct timeval *t2); 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate static void 687c478bd9Sstevel@tonic-gate usage(char *fname) 697c478bd9Sstevel@tonic-gate { 707c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 717c478bd9Sstevel@tonic-gate "usage: " 727c478bd9Sstevel@tonic-gate "%s [ -P ] [ -p port ] [ -q ] [ -s ] [ -t ] [ -v ] [<logfile>]\n", 737c478bd9Sstevel@tonic-gate fname); 747c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 757c478bd9Sstevel@tonic-gate } 767c478bd9Sstevel@tonic-gate 77*b2460f2fSpj157603 int 787c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 797c478bd9Sstevel@tonic-gate { 807c478bd9Sstevel@tonic-gate int i, n; 817c478bd9Sstevel@tonic-gate struct interface *ifp; 827c478bd9Sstevel@tonic-gate int c; 837c478bd9Sstevel@tonic-gate struct timeval waittime; 847c478bd9Sstevel@tonic-gate int timeout; 857c478bd9Sstevel@tonic-gate boolean_t daemon = _B_TRUE; /* Fork off a detached daemon */ 867c478bd9Sstevel@tonic-gate FILE *pidfp; 877c478bd9Sstevel@tonic-gate mode_t pidmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); /* 0644 */ 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate rip6_port = htons(IPPORT_ROUTESERVER6); 907c478bd9Sstevel@tonic-gate allrouters.sin6_family = AF_INET6; 917c478bd9Sstevel@tonic-gate allrouters.sin6_port = rip6_port; 927c478bd9Sstevel@tonic-gate allrouters.sin6_addr = allrouters_in6; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "nsqvTtdgPp:")) != EOF) { 957c478bd9Sstevel@tonic-gate switch (c) { 967c478bd9Sstevel@tonic-gate case 'n': 977c478bd9Sstevel@tonic-gate install = _B_FALSE; 987c478bd9Sstevel@tonic-gate break; 997c478bd9Sstevel@tonic-gate case 's': 1007c478bd9Sstevel@tonic-gate supplier = _B_TRUE; 1017c478bd9Sstevel@tonic-gate break; 1027c478bd9Sstevel@tonic-gate case 'q': 1037c478bd9Sstevel@tonic-gate supplier = _B_FALSE; 1047c478bd9Sstevel@tonic-gate break; 1057c478bd9Sstevel@tonic-gate case 'v': 1067c478bd9Sstevel@tonic-gate tracing |= ACTION_BIT; 1077c478bd9Sstevel@tonic-gate break; 1087c478bd9Sstevel@tonic-gate case 'T': 1097c478bd9Sstevel@tonic-gate daemon = _B_FALSE; 1107c478bd9Sstevel@tonic-gate break; 1117c478bd9Sstevel@tonic-gate case 't': 1127c478bd9Sstevel@tonic-gate tracepackets = _B_TRUE; 1137c478bd9Sstevel@tonic-gate daemon = _B_FALSE; 1147c478bd9Sstevel@tonic-gate tracing |= (INPUT_BIT | OUTPUT_BIT); 1157c478bd9Sstevel@tonic-gate break; 1167c478bd9Sstevel@tonic-gate case 'd': 1177c478bd9Sstevel@tonic-gate break; 1187c478bd9Sstevel@tonic-gate case 'P': 1197c478bd9Sstevel@tonic-gate dopoison = _B_FALSE; 1207c478bd9Sstevel@tonic-gate break; 1217c478bd9Sstevel@tonic-gate case 'p': 1227c478bd9Sstevel@tonic-gate rip6_port = htons(atoi(optarg)); 1237c478bd9Sstevel@tonic-gate allrouters.sin6_port = rip6_port; 1247c478bd9Sstevel@tonic-gate break; 1257c478bd9Sstevel@tonic-gate default: 1267c478bd9Sstevel@tonic-gate usage(argv[0]); 1277c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate } 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate /* 1327c478bd9Sstevel@tonic-gate * Any extra argument is considered 1337c478bd9Sstevel@tonic-gate * a tracing log file. 1347c478bd9Sstevel@tonic-gate */ 1357c478bd9Sstevel@tonic-gate if (optind < argc) { 1367c478bd9Sstevel@tonic-gate traceon(argv[optind]); 1377c478bd9Sstevel@tonic-gate } else if (tracing && !daemon) { 1387c478bd9Sstevel@tonic-gate traceonfp(stdout); 1397c478bd9Sstevel@tonic-gate } else if (tracing) { 1407c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Need logfile with -v\n"); 1417c478bd9Sstevel@tonic-gate usage(argv[0]); 1427c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate if (daemon) { 1467c478bd9Sstevel@tonic-gate int t; 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate if (fork()) 1497c478bd9Sstevel@tonic-gate exit(EXIT_SUCCESS); 1507c478bd9Sstevel@tonic-gate for (t = 0; t < 20; t++) { 1517c478bd9Sstevel@tonic-gate if (!tracing || (t != fileno(ftrace))) 1527c478bd9Sstevel@tonic-gate (void) close(t); 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate (void) open("/", 0); 1557c478bd9Sstevel@tonic-gate (void) dup2(0, 1); 1567c478bd9Sstevel@tonic-gate (void) dup2(0, 2); 1577c478bd9Sstevel@tonic-gate (void) setsid(); 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate /* Store our process id, blow away any existing file if it exists. */ 1617c478bd9Sstevel@tonic-gate if ((pidfp = fopen(PATH_PID, "w")) == NULL) { 1627c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: unable to open " PATH_PID ": %s\n", 1637c478bd9Sstevel@tonic-gate argv[0], strerror(errno)); 1647c478bd9Sstevel@tonic-gate } else { 1657c478bd9Sstevel@tonic-gate (void) fprintf(pidfp, "%ld\n", getpid()); 1667c478bd9Sstevel@tonic-gate (void) fclose(pidfp); 1677c478bd9Sstevel@tonic-gate (void) chmod(PATH_PID, pidmode); 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate iocsoc = socket(AF_INET6, SOCK_DGRAM, 0); 1727c478bd9Sstevel@tonic-gate if (iocsoc < 0) { 1737c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "main: socket: %m"); 1747c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate setup_rtsock(); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* 1807c478bd9Sstevel@tonic-gate * Allocate the buffer to hold the RIPng packet. In reality, it will be 1817c478bd9Sstevel@tonic-gate * smaller than IPV6_MAX_PACKET octets due to (at least) the IPv6 and 1827c478bd9Sstevel@tonic-gate * UDP headers but IPV6_MAX_PACKET is a convenient size. 1837c478bd9Sstevel@tonic-gate */ 1847c478bd9Sstevel@tonic-gate packet = (char *)malloc(IPV6_MAX_PACKET); 1857c478bd9Sstevel@tonic-gate if (packet == NULL) { 1867c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "main: malloc: %m"); 1877c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate msg = (struct rip6 *)packet; 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* 1927c478bd9Sstevel@tonic-gate * Allocate the buffer to hold the ancillary data. This data is used to 1937c478bd9Sstevel@tonic-gate * insure that the incoming hop count of a RIPCMD6_RESPONSE message is 1947c478bd9Sstevel@tonic-gate * IPV6_MAX_HOPS which indicates that it came from a direct neighbor 1957c478bd9Sstevel@tonic-gate * (namely, no intervening router decremented it). 1967c478bd9Sstevel@tonic-gate */ 1977c478bd9Sstevel@tonic-gate control = (char *)malloc(IPV6_MAX_PACKET); 1987c478bd9Sstevel@tonic-gate if (control == NULL) { 1997c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "main: malloc: %m"); 2007c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate openlog("in.ripngd", LOG_PID | LOG_CONS, LOG_DAEMON); 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate (void) gettimeofday(&now, (struct timezone *)NULL); 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate initifs(); 2087c478bd9Sstevel@tonic-gate solicitall(&allrouters); 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate if (supplier) 2117c478bd9Sstevel@tonic-gate supplyall(&allrouters, 0, (struct interface *)NULL, _B_TRUE); 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate (void) sigset(SIGALRM, (void (*)(int))timer); 2147c478bd9Sstevel@tonic-gate (void) sigset(SIGHUP, (void (*)(int))initifs); 2157c478bd9Sstevel@tonic-gate (void) sigset(SIGTERM, (void (*)(int))term); 2167c478bd9Sstevel@tonic-gate (void) sigset(SIGUSR1, (void (*)(int))if_dump); 2177c478bd9Sstevel@tonic-gate (void) sigset(SIGUSR2, (void (*)(int))rtdump); 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * Seed the pseudo-random number generator for GET_RANDOM(). 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate srandom((uint_t)gethostid()); 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate timer(); 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate for (;;) { 2277c478bd9Sstevel@tonic-gate if (needupdate) { 2287c478bd9Sstevel@tonic-gate waittime = nextmcast; 2297c478bd9Sstevel@tonic-gate timevalsub(&waittime, &now); 2307c478bd9Sstevel@tonic-gate if (waittime.tv_sec < 0) { 2317c478bd9Sstevel@tonic-gate timeout = 0; 2327c478bd9Sstevel@tonic-gate } else { 2337c478bd9Sstevel@tonic-gate timeout = TIME_TO_MSECS(waittime); 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate if (tracing & ACTION_BIT) { 2367c478bd9Sstevel@tonic-gate (void) fprintf(ftrace, 2377c478bd9Sstevel@tonic-gate "poll until dynamic update in %d msec\n", 2387c478bd9Sstevel@tonic-gate timeout); 2397c478bd9Sstevel@tonic-gate (void) fflush(ftrace); 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate } else { 2427c478bd9Sstevel@tonic-gate timeout = INFTIM; 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if ((n = poll(poll_ifs, poll_ifs_num, timeout)) < 0) { 2467c478bd9Sstevel@tonic-gate if (errno == EINTR) 2477c478bd9Sstevel@tonic-gate continue; 2487c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "main: poll: %m"); 2497c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate (void) sighold(SIGALRM); 2527c478bd9Sstevel@tonic-gate (void) sighold(SIGHUP); 2537c478bd9Sstevel@tonic-gate /* 2547c478bd9Sstevel@tonic-gate * Poll timed out. 2557c478bd9Sstevel@tonic-gate */ 2567c478bd9Sstevel@tonic-gate if (n == 0) { 2577c478bd9Sstevel@tonic-gate if (needupdate) { 2587c478bd9Sstevel@tonic-gate TRACE_ACTION("send delayed dynamic update", 2597c478bd9Sstevel@tonic-gate (struct rt_entry *)NULL); 2607c478bd9Sstevel@tonic-gate (void) gettimeofday(&now, 2617c478bd9Sstevel@tonic-gate (struct timezone *)NULL); 2627c478bd9Sstevel@tonic-gate supplyall(&allrouters, RTS_CHANGED, 2637c478bd9Sstevel@tonic-gate (struct interface *)NULL, _B_TRUE); 2647c478bd9Sstevel@tonic-gate lastmcast = now; 2657c478bd9Sstevel@tonic-gate needupdate = _B_FALSE; 2667c478bd9Sstevel@tonic-gate nextmcast.tv_sec = 0; 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate (void) sigrelse(SIGHUP); 2697c478bd9Sstevel@tonic-gate (void) sigrelse(SIGALRM); 2707c478bd9Sstevel@tonic-gate continue; 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate (void) gettimeofday(&now, (struct timezone *)NULL); 2737c478bd9Sstevel@tonic-gate for (i = 0; i < poll_ifs_num; i++) { 2747c478bd9Sstevel@tonic-gate /* 2757c478bd9Sstevel@tonic-gate * This case should never happen. 2767c478bd9Sstevel@tonic-gate */ 2777c478bd9Sstevel@tonic-gate if (poll_ifs[i].revents & POLLERR) { 2787c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 2797c478bd9Sstevel@tonic-gate "main: poll returned a POLLERR event"); 2807c478bd9Sstevel@tonic-gate continue; 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate if (poll_ifs[i].revents & POLLIN) { 2837c478bd9Sstevel@tonic-gate for (ifp = ifnet; ifp != NULL; 2847c478bd9Sstevel@tonic-gate ifp = ifp->int_next) { 2857c478bd9Sstevel@tonic-gate if (poll_ifs[i].fd == ifp->int_sock) 2867c478bd9Sstevel@tonic-gate in_data(ifp); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate (void) sigrelse(SIGHUP); 2917c478bd9Sstevel@tonic-gate (void) sigrelse(SIGALRM); 2927c478bd9Sstevel@tonic-gate } 293*b2460f2fSpj157603 294*b2460f2fSpj157603 return (0); 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate void 2987c478bd9Sstevel@tonic-gate timevaladd(struct timeval *t1, struct timeval *t2) 2997c478bd9Sstevel@tonic-gate { 3007c478bd9Sstevel@tonic-gate t1->tv_sec += t2->tv_sec; 3017c478bd9Sstevel@tonic-gate if ((t1->tv_usec += t2->tv_usec) > 1000000) { 3027c478bd9Sstevel@tonic-gate t1->tv_sec++; 3037c478bd9Sstevel@tonic-gate t1->tv_usec -= 1000000; 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate void 3087c478bd9Sstevel@tonic-gate timevalsub(struct timeval *t1, struct timeval *t2) 3097c478bd9Sstevel@tonic-gate { 3107c478bd9Sstevel@tonic-gate t1->tv_sec -= t2->tv_sec; 3117c478bd9Sstevel@tonic-gate if ((t1->tv_usec -= t2->tv_usec) < 0) { 3127c478bd9Sstevel@tonic-gate t1->tv_sec--; 3137c478bd9Sstevel@tonic-gate t1->tv_usec += 1000000; 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate } 316