1a17240f2Sderaadt /* $NetBSD: main.c,v 1.6 1995/12/10 10:07:05 mycroft Exp $ */ 2df930be7Sderaadt 3df930be7Sderaadt /* 4df930be7Sderaadt * The mrouted program is covered by the license in the accompanying file 5df930be7Sderaadt * named "LICENSE". Use of the mrouted program represents acceptance of 6df930be7Sderaadt * the terms and conditions listed in that file. 7df930be7Sderaadt * 8df930be7Sderaadt * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of 9df930be7Sderaadt * Leland Stanford Junior University. 10df930be7Sderaadt */ 11df930be7Sderaadt 12df930be7Sderaadt /* 13df930be7Sderaadt * Written by Steve Deering, Stanford University, February 1989. 14df930be7Sderaadt * 15df930be7Sderaadt * (An earlier version of DVMRP was implemented by David Waitzman of 16df930be7Sderaadt * BBN STC by extending Berkeley's routed program. Some of Waitzman's 17df930be7Sderaadt * extensions have been incorporated into mrouted, but none of the 18df930be7Sderaadt * original routed code has been adopted.) 19df930be7Sderaadt */ 20df930be7Sderaadt 21df930be7Sderaadt 22df930be7Sderaadt #include "defs.h" 23a17240f2Sderaadt #include <stdarg.h> 24a17240f2Sderaadt #include <fcntl.h> 2525944688Sderaadt #include <poll.h> 26b7827e9bSmiod #include <util.h> 2787988018Sjsg #include <err.h> 28df930be7Sderaadt 29df930be7Sderaadt extern char *configfilename; 30a17240f2Sderaadt char versionstring[100]; 31df930be7Sderaadt 32df930be7Sderaadt static char dumpfilename[] = _PATH_MROUTED_DUMP; 33df930be7Sderaadt static char cachefilename[] = _PATH_MROUTED_CACHE; 34df930be7Sderaadt static char genidfilename[] = _PATH_MROUTED_GENID; 35df930be7Sderaadt 36df930be7Sderaadt int cache_lifetime = DEFAULT_CACHE_LIFETIME; 37df930be7Sderaadt int max_prune_lifetime = DEFAULT_CACHE_LIFETIME * 2; 38df930be7Sderaadt 39df930be7Sderaadt int debug = 0; 40df930be7Sderaadt u_char pruning = 1; /* Enable pruning by default */ 41df930be7Sderaadt 42df930be7Sderaadt #define NHANDLERS 2 43df930be7Sderaadt 44df930be7Sderaadt static struct ihandler { 45df930be7Sderaadt int fd; /* File descriptor */ 4625944688Sderaadt ihfunc_t func; /* Function to call */ 47df930be7Sderaadt } ihandlers[NHANDLERS]; 48df930be7Sderaadt static int nhandlers = 0; 49df930be7Sderaadt 50df930be7Sderaadt /* 51df930be7Sderaadt * Forward declarations. 52df930be7Sderaadt */ 53c72b5b24Smillert static void fasttimer(int); 54c72b5b24Smillert static void done(int); 55c72b5b24Smillert static void dump(int); 56c72b5b24Smillert static void fdump(int); 57c72b5b24Smillert static void cdump(int); 58c72b5b24Smillert static void restart(int); 59c72b5b24Smillert static void timer(void); 60c72b5b24Smillert static void cleanup(void); 61c72b5b24Smillert static void resetlogging(void *); 62a17240f2Sderaadt 63df930be7Sderaadt int 645017e83eSderaadt register_input_handler(int fd, ihfunc_t func) 65df930be7Sderaadt { 66df930be7Sderaadt if (nhandlers >= NHANDLERS) 67df930be7Sderaadt return -1; 68df930be7Sderaadt 69df930be7Sderaadt ihandlers[nhandlers].fd = fd; 70df930be7Sderaadt ihandlers[nhandlers++].func = func; 71df930be7Sderaadt 72df930be7Sderaadt return 0; 73df930be7Sderaadt } 74df930be7Sderaadt 75a17240f2Sderaadt int 765017e83eSderaadt main(int argc, char *argv[]) 77df930be7Sderaadt { 78fcc7c6a8Stedu int recvlen; 79df930be7Sderaadt int dummy; 80df930be7Sderaadt FILE *fp; 8121253fdaSderaadt struct timeval now; 82a17240f2Sderaadt u_int32_t prev_genid; 8325944688Sderaadt struct pollfd *pfd; 8425944688Sderaadt int vers, n, i, ch; 859a7fa6a3Smillert sigset_t mask, omask; 866ce2b0b8Srobert const char *errstr; 87df930be7Sderaadt 88df930be7Sderaadt if (geteuid() != 0) { 89df930be7Sderaadt fprintf(stderr, "must be root\n"); 90df930be7Sderaadt exit(1); 91df930be7Sderaadt } 92*b9a887b6Smillert setvbuf(stderr, NULL, _IOLBF, 0); 93df930be7Sderaadt 946ce2b0b8Srobert while ((ch = getopt(argc, argv, "c:d::p")) != -1) { 956ce2b0b8Srobert switch (ch) { 966ce2b0b8Srobert case 'c': 976ce2b0b8Srobert configfilename = optarg; 986ce2b0b8Srobert break; 996ce2b0b8Srobert case 'd': 1006ce2b0b8Srobert if (!optarg) 101df930be7Sderaadt debug = DEFAULT_DEBUG; 1026ce2b0b8Srobert else { 1036ce2b0b8Srobert debug = strtonum(optarg, 0, 3, &errstr); 1046ce2b0b8Srobert if (errstr) { 1056ce2b0b8Srobert warnx("debug level %s", errstr); 1066ce2b0b8Srobert debug = DEFAULT_DEBUG; 107df930be7Sderaadt } 1086ce2b0b8Srobert } 1096ce2b0b8Srobert break; 1106ce2b0b8Srobert case 'p': 1116ce2b0b8Srobert pruning = 0; 1126ce2b0b8Srobert break; 1136ce2b0b8Srobert default: 1146ce2b0b8Srobert goto usage; 1156ce2b0b8Srobert } 1166ce2b0b8Srobert } 1176ce2b0b8Srobert argc -= optind; 1186ce2b0b8Srobert argv += optind; 119df930be7Sderaadt 120df930be7Sderaadt if (argc > 0) { 121df930be7Sderaadt usage: fprintf(stderr, 12286066bc7Sjmc "usage: mrouted [-p] [-c config_file] [-d [debug_level]]\n"); 123df930be7Sderaadt exit(1); 124df930be7Sderaadt } 125df930be7Sderaadt 126df930be7Sderaadt if (debug == 0) { 127df930be7Sderaadt /* 128df930be7Sderaadt * Detach from the terminal 129df930be7Sderaadt */ 130df930be7Sderaadt int t; 131df930be7Sderaadt 132df930be7Sderaadt if (fork()) exit(0); 133df930be7Sderaadt (void)close(0); 134df930be7Sderaadt (void)close(1); 135df930be7Sderaadt (void)close(2); 136df930be7Sderaadt (void)open("/", 0); 137df930be7Sderaadt (void)dup2(0, 1); 138df930be7Sderaadt (void)dup2(0, 2); 139a17240f2Sderaadt #ifdef SYSV 140a17240f2Sderaadt (void)setpgrp(); 141a17240f2Sderaadt #else 142df930be7Sderaadt #ifdef TIOCNOTTY 143df930be7Sderaadt t = open("/dev/tty", 2); 144df930be7Sderaadt if (t >= 0) { 145df930be7Sderaadt (void)ioctl(t, TIOCNOTTY, (char *)0); 146df930be7Sderaadt (void)close(t); 147df930be7Sderaadt } 148df930be7Sderaadt #else 149df930be7Sderaadt if (setsid() < 0) 150df930be7Sderaadt perror("setsid"); 151df930be7Sderaadt #endif 152a17240f2Sderaadt #endif 153df930be7Sderaadt } 154df930be7Sderaadt else 155df930be7Sderaadt fprintf(stderr, "debug level %u\n", debug); 156df930be7Sderaadt 157df930be7Sderaadt #ifdef LOG_DAEMON 158df930be7Sderaadt (void)openlog("mrouted", LOG_PID, LOG_DAEMON); 159df930be7Sderaadt (void)setlogmask(LOG_UPTO(LOG_NOTICE)); 160df930be7Sderaadt #else 161df930be7Sderaadt (void)openlog("mrouted", LOG_PID); 162df930be7Sderaadt #endif 163c2458fd3Sderaadt snprintf(versionstring, sizeof versionstring, "mrouted version %d.%d", 164df930be7Sderaadt PROTOCOL_VERSION, MROUTED_VERSION); 165df930be7Sderaadt 16640443a2fSmillert logit(LOG_NOTICE, 0, "%s", versionstring); 167a17240f2Sderaadt 168df930be7Sderaadt /* 169df930be7Sderaadt * Get generation id 170df930be7Sderaadt */ 17121253fdaSderaadt gettimeofday(&now, NULL); 17221253fdaSderaadt dvmrp_genid = (u_int32_t)now.tv_sec; /* for a while after 2038 */ 173df930be7Sderaadt 174df930be7Sderaadt fp = fopen(genidfilename, "r"); 175df930be7Sderaadt if (fp != NULL) { 176df930be7Sderaadt fscanf(fp, "%d", &prev_genid); 177df930be7Sderaadt if (prev_genid == dvmrp_genid) 178df930be7Sderaadt dvmrp_genid++; 179df930be7Sderaadt (void) fclose(fp); 180df930be7Sderaadt } 181df930be7Sderaadt 182df930be7Sderaadt fp = fopen(genidfilename, "w"); 183df930be7Sderaadt if (fp != NULL) { 184df930be7Sderaadt fprintf(fp, "%d", dvmrp_genid); 185df930be7Sderaadt (void) fclose(fp); 186df930be7Sderaadt } 187df930be7Sderaadt 188df930be7Sderaadt callout_init(); 189df930be7Sderaadt init_igmp(); 190a17240f2Sderaadt init_routes(); 191a17240f2Sderaadt init_ktable(); 192df930be7Sderaadt k_init_dvmrp(); /* enable DVMRP routing in kernel */ 193df930be7Sderaadt 194df930be7Sderaadt #ifndef OLD_KERNEL 195df930be7Sderaadt vers = k_get_version(); 196a17240f2Sderaadt /*XXX 197a17240f2Sderaadt * This function must change whenever the kernel version changes 198a17240f2Sderaadt */ 199a17240f2Sderaadt if ((((vers >> 8) & 0xff) != 3) || 200a17240f2Sderaadt ((vers & 0xff) != 5)) 20140443a2fSmillert logit(LOG_ERR, 0, "kernel (v%d.%d)/mrouted (v%d.%d) version mismatch", 202df930be7Sderaadt (vers >> 8) & 0xff, vers & 0xff, 203df930be7Sderaadt PROTOCOL_VERSION, MROUTED_VERSION); 204df930be7Sderaadt #endif 205df930be7Sderaadt 206df930be7Sderaadt init_vifs(); 207a17240f2Sderaadt 208df930be7Sderaadt #ifdef RSRR 209df930be7Sderaadt rsrr_init(); 210df930be7Sderaadt #endif /* RSRR */ 211df930be7Sderaadt 212a17240f2Sderaadt /* 213a17240f2Sderaadt * Allow cleanup if unexpected exit. Apparently some architectures 214df930be7Sderaadt * have a kernel bug where closing the socket doesn't do an 215df930be7Sderaadt * ip_mrouter_done(), so we attempt to do it on exit. 216df930be7Sderaadt */ 217df930be7Sderaadt atexit(cleanup); 218df930be7Sderaadt 219df930be7Sderaadt if (debug) 220df930be7Sderaadt fprintf(stderr, "pruning %s\n", pruning ? "on" : "off"); 221df930be7Sderaadt 222b7827e9bSmiod pidfile(NULL); 223df930be7Sderaadt 224df930be7Sderaadt (void)signal(SIGALRM, fasttimer); 225df930be7Sderaadt 226df930be7Sderaadt (void)signal(SIGHUP, restart); 227df930be7Sderaadt (void)signal(SIGTERM, done); 228df930be7Sderaadt (void)signal(SIGINT, done); 229df930be7Sderaadt (void)signal(SIGUSR1, fdump); 230df930be7Sderaadt (void)signal(SIGUSR2, cdump); 231df930be7Sderaadt if (debug != 0) 232df930be7Sderaadt (void)signal(SIGQUIT, dump); 233df930be7Sderaadt 23425944688Sderaadt pfd = calloc(sizeof(struct pollfd), 1 + nhandlers); 23525944688Sderaadt pfd[0].fd = igmp_socket; 23625944688Sderaadt pfd[0].events = POLLIN; 237df930be7Sderaadt for (i = 0; i < nhandlers; i++) { 23825944688Sderaadt pfd[i + 1].fd = ihandlers[i].fd; 23925944688Sderaadt pfd[i + 1].events = POLLIN; 240df930be7Sderaadt } 241df930be7Sderaadt 242a17240f2Sderaadt /* 243a17240f2Sderaadt * Install the vifs in the kernel as late as possible in the 244a17240f2Sderaadt * initialization sequence. 245a17240f2Sderaadt */ 246a17240f2Sderaadt init_installvifs(); 247a17240f2Sderaadt 248a17240f2Sderaadt if (debug >= 2) dump(0); 249a17240f2Sderaadt 250a17240f2Sderaadt /* Start up the log rate-limiter */ 251a17240f2Sderaadt resetlogging(NULL); 252a17240f2Sderaadt 253df930be7Sderaadt (void)alarm(1); /* schedule first timer interrupt */ 254df930be7Sderaadt 255df930be7Sderaadt /* 256df930be7Sderaadt * Main receive loop. 257df930be7Sderaadt */ 258df930be7Sderaadt dummy = 0; 259df930be7Sderaadt for(;;) { 26025944688Sderaadt if ((n = poll(pfd, nhandlers + 1, -1)) < 0) { 261df930be7Sderaadt if (errno != EINTR) /* SIGALRM is expected */ 26225944688Sderaadt logit(LOG_WARNING, errno, "poll failed"); 263df930be7Sderaadt continue; 264df930be7Sderaadt } 265df930be7Sderaadt 26625944688Sderaadt if (pfd[0].revents & POLLIN) { 267df930be7Sderaadt recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE, 268df930be7Sderaadt 0, NULL, &dummy); 269df930be7Sderaadt if (recvlen < 0) { 27040443a2fSmillert if (errno != EINTR) logit(LOG_ERR, errno, "recvfrom"); 271df930be7Sderaadt continue; 272df930be7Sderaadt } 2739a7fa6a3Smillert (void)sigemptyset(&mask); 2749a7fa6a3Smillert (void)sigaddset(&mask, SIGALRM); 2759a7fa6a3Smillert if (sigprocmask(SIG_BLOCK, &mask, &omask) < 0) 27640443a2fSmillert logit(LOG_ERR, errno, "sigprocmask"); 277df930be7Sderaadt accept_igmp(recvlen); 2789a7fa6a3Smillert (void)sigprocmask(SIG_SETMASK, &omask, NULL); 279df930be7Sderaadt } 280df930be7Sderaadt 281df930be7Sderaadt for (i = 0; i < nhandlers; i++) { 28225944688Sderaadt if (pfd[i + 1].revents & POLLIN) { 28325944688Sderaadt (*ihandlers[i].func)(ihandlers[i].fd); 284df930be7Sderaadt } 285df930be7Sderaadt } 286df930be7Sderaadt } 287df930be7Sderaadt } 288df930be7Sderaadt 289df930be7Sderaadt 290df930be7Sderaadt /* 291df930be7Sderaadt * routine invoked every second. Its main goal is to cycle through 292df930be7Sderaadt * the routing table and send partial updates to all neighbors at a 293df930be7Sderaadt * rate that will cause the entire table to be sent in ROUTE_REPORT_INTERVAL 294df930be7Sderaadt * seconds. Also, every TIMER_INTERVAL seconds it calls timer() to 295df930be7Sderaadt * do all the other time-based processing. 296df930be7Sderaadt */ 2977c595a54Sderaadt /* XXX signal race */ 298df930be7Sderaadt static void 2995017e83eSderaadt fasttimer(int i) 300df930be7Sderaadt { 301df930be7Sderaadt static unsigned int tlast; 302df930be7Sderaadt static unsigned int nsent; 303fcc7c6a8Stedu unsigned int t = tlast + 1; 304fcc7c6a8Stedu int n; 305df930be7Sderaadt 306df930be7Sderaadt /* 307df930be7Sderaadt * if we're in the last second, send everything that's left. 308df930be7Sderaadt * otherwise send at least the fraction we should have sent by now. 309df930be7Sderaadt */ 310df930be7Sderaadt if (t >= ROUTE_REPORT_INTERVAL) { 311fcc7c6a8Stedu int nleft = nroutes - nsent; 312df930be7Sderaadt while (nleft > 0) { 313df930be7Sderaadt if ((n = report_next_chunk()) <= 0) 314df930be7Sderaadt break; 315df930be7Sderaadt nleft -= n; 316df930be7Sderaadt } 317df930be7Sderaadt tlast = 0; 318df930be7Sderaadt nsent = 0; 319df930be7Sderaadt } else { 320fcc7c6a8Stedu unsigned int ncum = nroutes * t / ROUTE_REPORT_INTERVAL; 321df930be7Sderaadt while (nsent < ncum) { 322df930be7Sderaadt if ((n = report_next_chunk()) <= 0) 323df930be7Sderaadt break; 324df930be7Sderaadt nsent += n; 325df930be7Sderaadt } 326df930be7Sderaadt tlast = t; 327df930be7Sderaadt } 328df930be7Sderaadt if ((t % TIMER_INTERVAL) == 0) 329df930be7Sderaadt timer(); 330df930be7Sderaadt 331df930be7Sderaadt age_callout_queue();/* Advance the timer for the callout queue 332df930be7Sderaadt for groups */ 333df930be7Sderaadt alarm(1); 334df930be7Sderaadt } 335df930be7Sderaadt 336df930be7Sderaadt /* 337df930be7Sderaadt * The 'virtual_time' variable is initialized to a value that will cause the 338df930be7Sderaadt * first invocation of timer() to send a probe or route report to all vifs 339df930be7Sderaadt * and send group membership queries to all subnets for which this router is 340df930be7Sderaadt * querier. This first invocation occurs approximately TIMER_INTERVAL seconds 341df930be7Sderaadt * after the router starts up. Note that probes for neighbors and queries 342df930be7Sderaadt * for group memberships are also sent at start-up time, as part of initial- 343df930be7Sderaadt * ization. This repetition after a short interval is desirable for quickly 344df930be7Sderaadt * building up topology and membership information in the presence of possible 345df930be7Sderaadt * packet loss. 346df930be7Sderaadt * 347df930be7Sderaadt * 'virtual_time' advances at a rate that is only a crude approximation of 348df930be7Sderaadt * real time, because it does not take into account any time spent processing, 349df930be7Sderaadt * and because the timer intervals are sometimes shrunk by a random amount to 350df930be7Sderaadt * avoid unwanted synchronization with other routers. 351df930be7Sderaadt */ 352df930be7Sderaadt 353df930be7Sderaadt static u_long virtual_time = 0; 354df930be7Sderaadt 355df930be7Sderaadt 356df930be7Sderaadt /* 357df930be7Sderaadt * Timer routine. Performs periodic neighbor probing, route reporting, and 358df930be7Sderaadt * group querying duties, and drives various timers in routing entries and 359df930be7Sderaadt * virtual interface data structures. 360df930be7Sderaadt */ 361df930be7Sderaadt static void 3625017e83eSderaadt timer(void) 363df930be7Sderaadt { 364df930be7Sderaadt age_routes(); /* Advance the timers in the route entries */ 365df930be7Sderaadt age_vifs(); /* Advance the timers for neighbors */ 366df930be7Sderaadt age_table_entry(); /* Advance the timers for the cache entries */ 367df930be7Sderaadt 368df930be7Sderaadt if (virtual_time % GROUP_QUERY_INTERVAL == 0) { 369df930be7Sderaadt /* 370df930be7Sderaadt * Time to query the local group memberships on all subnets 371df930be7Sderaadt * for which this router is the elected querier. 372df930be7Sderaadt */ 373df930be7Sderaadt query_groups(); 374df930be7Sderaadt } 375df930be7Sderaadt 376df930be7Sderaadt if (virtual_time % NEIGHBOR_PROBE_INTERVAL == 0) { 377df930be7Sderaadt /* 378df930be7Sderaadt * Time to send a probe on all vifs from which no neighbors have 379df930be7Sderaadt * been heard. Also, check if any inoperative interfaces have now 380df930be7Sderaadt * come up. (If they have, they will also be probed as part of 381df930be7Sderaadt * their initialization.) 382df930be7Sderaadt */ 383df930be7Sderaadt probe_for_neighbors(); 384df930be7Sderaadt 385df930be7Sderaadt if (vifs_down) 386df930be7Sderaadt check_vif_state(); 387df930be7Sderaadt } 388df930be7Sderaadt 389df930be7Sderaadt delay_change_reports = FALSE; 390df930be7Sderaadt if (routes_changed) { 391df930be7Sderaadt /* 392df930be7Sderaadt * Some routes have changed since the last timer interrupt, but 393df930be7Sderaadt * have not been reported yet. Report the changed routes to all 394df930be7Sderaadt * neighbors. 395df930be7Sderaadt */ 396df930be7Sderaadt report_to_all_neighbors(CHANGED_ROUTES); 397df930be7Sderaadt } 398df930be7Sderaadt 399df930be7Sderaadt /* 400df930be7Sderaadt * Advance virtual time 401df930be7Sderaadt */ 402df930be7Sderaadt virtual_time += TIMER_INTERVAL; 403df930be7Sderaadt } 404df930be7Sderaadt 405df930be7Sderaadt 406df930be7Sderaadt /* 407df930be7Sderaadt * On termination, let everyone know we're going away. 408df930be7Sderaadt */ 4097c595a54Sderaadt /* XXX signal race */ 410df930be7Sderaadt static void 4115017e83eSderaadt done(int i) 412df930be7Sderaadt { 41340443a2fSmillert logit(LOG_NOTICE, 0, "%s exiting", versionstring); 414df930be7Sderaadt cleanup(); 415df930be7Sderaadt _exit(1); 416df930be7Sderaadt } 417df930be7Sderaadt 4187c595a54Sderaadt /* XXX signal race, atexit race */ 419df930be7Sderaadt static void 4205017e83eSderaadt cleanup(void) 421df930be7Sderaadt { 4224788b1e0Sdaniel static int in_cleanup = 0; 423df930be7Sderaadt 424df930be7Sderaadt if (!in_cleanup) { 425df930be7Sderaadt in_cleanup++; 426df930be7Sderaadt #ifdef RSRR 427df930be7Sderaadt rsrr_clean(); 428df930be7Sderaadt #endif /* RSRR */ 429df930be7Sderaadt expire_all_routes(); 430df930be7Sderaadt report_to_all_neighbors(ALL_ROUTES); 431df930be7Sderaadt k_stop_dvmrp(); 432df930be7Sderaadt } 433df930be7Sderaadt } 434df930be7Sderaadt 435df930be7Sderaadt 436df930be7Sderaadt /* 437df930be7Sderaadt * Dump internal data structures to stderr. 438df930be7Sderaadt */ 4397c595a54Sderaadt /* XXX signal race */ 440df930be7Sderaadt static void 4415017e83eSderaadt dump(int i) 442df930be7Sderaadt { 443df930be7Sderaadt dump_vifs(stderr); 444df930be7Sderaadt dump_routes(stderr); 445df930be7Sderaadt } 446df930be7Sderaadt 447df930be7Sderaadt 448df930be7Sderaadt /* 449df930be7Sderaadt * Dump internal data structures to a file. 450df930be7Sderaadt */ 451df930be7Sderaadt static void 4525017e83eSderaadt fdump(int i) 453df930be7Sderaadt { 454df930be7Sderaadt FILE *fp; 455df930be7Sderaadt 456df930be7Sderaadt fp = fopen(dumpfilename, "w"); 457df930be7Sderaadt if (fp != NULL) { 458df930be7Sderaadt dump_vifs(fp); 459df930be7Sderaadt dump_routes(fp); 460df930be7Sderaadt (void) fclose(fp); 461df930be7Sderaadt } 462df930be7Sderaadt } 463df930be7Sderaadt 464df930be7Sderaadt 465df930be7Sderaadt /* 466df930be7Sderaadt * Dump local cache contents to a file. 467df930be7Sderaadt */ 4687c595a54Sderaadt /* XXX signal race */ 469df930be7Sderaadt static void 4705017e83eSderaadt cdump(int i) 471df930be7Sderaadt { 472df930be7Sderaadt FILE *fp; 473df930be7Sderaadt 474df930be7Sderaadt fp = fopen(cachefilename, "w"); 475df930be7Sderaadt if (fp != NULL) { 476df930be7Sderaadt dump_cache(fp); 477df930be7Sderaadt (void) fclose(fp); 478df930be7Sderaadt } 479df930be7Sderaadt } 480df930be7Sderaadt 481df930be7Sderaadt 482df930be7Sderaadt /* 483df930be7Sderaadt * Restart mrouted 484df930be7Sderaadt */ 4857c595a54Sderaadt /* XXX signal race */ 486df930be7Sderaadt static void 4875017e83eSderaadt restart(int i) 488df930be7Sderaadt { 4899a7fa6a3Smillert sigset_t mask, omask; 490df930be7Sderaadt 49140443a2fSmillert logit(LOG_NOTICE, 0, "%s restart", versionstring); 492df930be7Sderaadt 493df930be7Sderaadt /* 494df930be7Sderaadt * reset all the entries 495df930be7Sderaadt */ 4969a7fa6a3Smillert (void)sigemptyset(&mask); 4979a7fa6a3Smillert (void)sigaddset(&mask, SIGALRM); 4989a7fa6a3Smillert if (sigprocmask(SIG_BLOCK, &mask, &omask) < 0) 49940443a2fSmillert logit(LOG_ERR, errno, "sigprocmask"); 500df930be7Sderaadt free_all_prunes(); 501df930be7Sderaadt free_all_routes(); 502df930be7Sderaadt stop_all_vifs(); 503df930be7Sderaadt k_stop_dvmrp(); 504df930be7Sderaadt close(igmp_socket); 505df930be7Sderaadt close(udp_socket); 506df930be7Sderaadt 507df930be7Sderaadt /* 508df930be7Sderaadt * start processing again 509df930be7Sderaadt */ 510df930be7Sderaadt dvmrp_genid++; 511df930be7Sderaadt pruning = 1; 512df930be7Sderaadt 513df930be7Sderaadt init_igmp(); 514df930be7Sderaadt init_routes(); 515df930be7Sderaadt init_ktable(); 516df930be7Sderaadt init_vifs(); 517a17240f2Sderaadt k_init_dvmrp(); /* enable DVMRP routing in kernel */ 518a17240f2Sderaadt init_installvifs(); 519df930be7Sderaadt 5209a7fa6a3Smillert (void)sigprocmask(SIG_SETMASK, &omask, NULL); 521df930be7Sderaadt } 522df930be7Sderaadt 523a17240f2Sderaadt #define LOG_MAX_MSGS 20 /* if > 20/minute then shut up for a while */ 524a17240f2Sderaadt #define LOG_SHUT_UP 600 /* shut up for 10 minutes */ 525a17240f2Sderaadt static int log_nmsgs = 0; 526a17240f2Sderaadt 527a17240f2Sderaadt static void 5285017e83eSderaadt resetlogging(void *arg) 529a17240f2Sderaadt { 530a17240f2Sderaadt int nxttime = 60; 531a17240f2Sderaadt void *narg = NULL; 532a17240f2Sderaadt 533a17240f2Sderaadt if (arg == NULL && log_nmsgs > LOG_MAX_MSGS) { 534a17240f2Sderaadt nxttime = LOG_SHUT_UP; 535a17240f2Sderaadt narg = (void *)&log_nmsgs; /* just need some valid void * */ 536a17240f2Sderaadt syslog(LOG_WARNING, "logging too fast, shutting up for %d minutes", 537a17240f2Sderaadt LOG_SHUT_UP / 60); 538a17240f2Sderaadt } else { 539a17240f2Sderaadt log_nmsgs = 0; 540a17240f2Sderaadt } 541a17240f2Sderaadt 542a17240f2Sderaadt timer_setTimer(nxttime, resetlogging, narg); 543a17240f2Sderaadt } 544df930be7Sderaadt 545df930be7Sderaadt /* 546df930be7Sderaadt * Log errors and other messages to the system log daemon and to stderr, 547df930be7Sderaadt * according to the severity of the message and the current debug level. 548df930be7Sderaadt * For errors of severity LOG_ERR or worse, terminate the program. 549df930be7Sderaadt */ 550a17240f2Sderaadt void 55140443a2fSmillert logit(int severity, int syserr, char *format, ...) 552a17240f2Sderaadt { 553a17240f2Sderaadt va_list ap; 554a17240f2Sderaadt static char fmt[211] = "warning - "; 555a17240f2Sderaadt char *msg; 556a17240f2Sderaadt char tbuf[20]; 557a17240f2Sderaadt struct timeval now; 558a17240f2Sderaadt struct tm *thyme; 559168d1740Sderaadt time_t t; 560a17240f2Sderaadt 561a17240f2Sderaadt va_start(ap, format); 562c2458fd3Sderaadt vsnprintf(&fmt[10], sizeof fmt - 10, format, ap); 563df930be7Sderaadt va_end(ap); 564df930be7Sderaadt msg = (severity == LOG_WARNING) ? fmt : &fmt[10]; 565df930be7Sderaadt 566df930be7Sderaadt switch (debug) { 567df930be7Sderaadt case 0: break; 568df930be7Sderaadt case 1: if (severity > LOG_NOTICE) break; 569df930be7Sderaadt case 2: if (severity > LOG_INFO ) break; 570df930be7Sderaadt default: 571df930be7Sderaadt gettimeofday(&now,NULL); 572168d1740Sderaadt t = now.tv_sec; 573168d1740Sderaadt thyme = localtime(&t); 574df930be7Sderaadt strftime(tbuf, sizeof(tbuf), "%X.%%03d ", thyme); 575df930be7Sderaadt fprintf(stderr, tbuf, now.tv_usec / 1000); 576df930be7Sderaadt fprintf(stderr, "%s", msg); 577df930be7Sderaadt if (syserr == 0) 578df930be7Sderaadt fprintf(stderr, "\n"); 579a17240f2Sderaadt else if (syserr < sys_nerr) 580a17240f2Sderaadt fprintf(stderr, ": %s\n", sys_errlist[syserr]); 581df930be7Sderaadt else 582a17240f2Sderaadt fprintf(stderr, ": errno %d\n", syserr); 583df930be7Sderaadt } 584df930be7Sderaadt 585df930be7Sderaadt if (severity <= LOG_NOTICE) { 586a17240f2Sderaadt if (log_nmsgs++ < LOG_MAX_MSGS) { 587df930be7Sderaadt if (syserr != 0) { 588df930be7Sderaadt errno = syserr; 589df930be7Sderaadt syslog(severity, "%s: %m", msg); 590df930be7Sderaadt } else 591df930be7Sderaadt syslog(severity, "%s", msg); 592a17240f2Sderaadt } 593df930be7Sderaadt 59443ae5fd5Sderaadt if (severity <= LOG_ERR) exit(1); 595df930be7Sderaadt } 596df930be7Sderaadt } 597a17240f2Sderaadt 598a17240f2Sderaadt #ifdef DEBUG_MFC 599a17240f2Sderaadt void 60040443a2fSmillert md_logit(int what, u_int32_t origin, u_int32_t mcastgrp) 601a17240f2Sderaadt { 602a17240f2Sderaadt static FILE *f = NULL; 603a17240f2Sderaadt struct timeval tv; 604a17240f2Sderaadt u_int32_t buf[4]; 605a17240f2Sderaadt 606a17240f2Sderaadt if (!f) { 607a17240f2Sderaadt if ((f = fopen("/tmp/mrouted.clog", "w")) == NULL) { 60840443a2fSmillert logit(LOG_ERR, errno, "open /tmp/mrouted.clog"); 609a17240f2Sderaadt } 610a17240f2Sderaadt } 611a17240f2Sderaadt 612a17240f2Sderaadt gettimeofday(&tv, NULL); 613a17240f2Sderaadt buf[0] = tv.tv_sec; 614a17240f2Sderaadt buf[1] = what; 615a17240f2Sderaadt buf[2] = origin; 616a17240f2Sderaadt buf[3] = mcastgrp; 617a17240f2Sderaadt 618a17240f2Sderaadt fwrite(buf, sizeof(u_int32_t), 4, f); 619a17240f2Sderaadt } 620a17240f2Sderaadt #endif 621