GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/mrouted/main.c Lines: 0 216 0.0 %
Date: 2017-11-07 Branches: 0 106 0.0 %

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