GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/mrouted/main.c Lines: 0 218 0.0 %
Date: 2017-11-13 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 TIOCNOTTY
139
	t = open("/dev/tty", O_RDWR);
140
	if (t >= 0) {
141
	    (void)ioctl(t, TIOCNOTTY, (char *)0);
142
	    (void)close(t);
143
	}
144
#else
145
	if (setsid() < 0)
146
	    perror("setsid");
147
#endif
148
    }
149
    else
150
	fprintf(stderr, "debug level %u\n", debug);
151
152
#ifdef LOG_DAEMON
153
    (void)openlog("mrouted", LOG_PID, LOG_DAEMON);
154
    (void)setlogmask(LOG_UPTO(LOG_NOTICE));
155
#else
156
    (void)openlog("mrouted", LOG_PID);
157
#endif
158
    snprintf(versionstring, sizeof versionstring, "mrouted version %d.%d",
159
			PROTOCOL_VERSION, MROUTED_VERSION);
160
161
    logit(LOG_NOTICE, 0, "%s", versionstring);
162
163
    /*
164
     * Get generation id
165
     */
166
    gettimeofday(&now, NULL);
167
    dvmrp_genid = (u_int32_t)now.tv_sec;	/* for a while after 2038 */
168
169
    fp = fopen(genidfilename, "r");
170
    if (fp != NULL) {
171
	fscanf(fp, "%d", &prev_genid);
172
	if (prev_genid == dvmrp_genid)
173
	    dvmrp_genid++;
174
	(void) fclose(fp);
175
    }
176
177
    fp = fopen(genidfilename, "w");
178
    if (fp != NULL) {
179
	fprintf(fp, "%d", dvmrp_genid);
180
	(void) fclose(fp);
181
    }
182
183
    callout_init();
184
    init_igmp();
185
    init_routes();
186
    init_ktable();
187
    k_init_dvmrp();		/* enable DVMRP routing in kernel */
188
189
#ifndef OLD_KERNEL
190
    vers = k_get_version();
191
    /*XXX
192
     * This function must change whenever the kernel version changes
193
     */
194
    if ((((vers >> 8) & 0xff) != 3) ||
195
	 ((vers & 0xff) != 5))
196
	logit(LOG_ERR, 0, "kernel (v%d.%d)/mrouted (v%d.%d) version mismatch",
197
		(vers >> 8) & 0xff, vers & 0xff,
198
		PROTOCOL_VERSION, MROUTED_VERSION);
199
#endif
200
201
    init_vifs();
202
203
#ifdef RSRR
204
    rsrr_init();
205
#endif /* RSRR */
206
207
    /*
208
     * Allow cleanup if unexpected exit.  Apparently some architectures
209
     * have a kernel bug where closing the socket doesn't do an
210
     * ip_mrouter_done(), so we attempt to do it on exit.
211
     */
212
    atexit(cleanup);
213
214
    if (debug)
215
	fprintf(stderr, "pruning %s\n", pruning ? "on" : "off");
216
217
    (void)signal(SIGALRM, fasttimer);
218
219
    (void)signal(SIGHUP,  restart);
220
    (void)signal(SIGTERM, done);
221
    (void)signal(SIGINT,  done);
222
    (void)signal(SIGUSR1, fdump);
223
    (void)signal(SIGUSR2, cdump);
224
    if (debug != 0)
225
	(void)signal(SIGQUIT, dump);
226
227
    pfd = calloc(sizeof(struct pollfd), 1 + nhandlers);
228
    pfd[0].fd = igmp_socket;
229
    pfd[0].events = POLLIN;
230
    for (i = 0; i < nhandlers; i++) {
231
	pfd[i + 1].fd = ihandlers[i].fd;
232
	pfd[i + 1].events = POLLIN;
233
    }
234
235
    /*
236
     * Install the vifs in the kernel as late as possible in the
237
     * initialization sequence.
238
     */
239
    init_installvifs();
240
241
    if (debug >= 2) dump(0);
242
243
    /* Start up the log rate-limiter */
244
    resetlogging(NULL);
245
246
    (void)alarm(1);	 /* schedule first timer interrupt */
247
248
    /*
249
     * Main receive loop.
250
     */
251
    dummy = 0;
252
    for(;;) {
253
	if ((n = poll(pfd, nhandlers + 1, -1)) < 0) {
254
            if (errno != EINTR) /* SIGALRM is expected */
255
                logit(LOG_WARNING, errno, "poll failed");
256
            continue;
257
        }
258
259
	if (pfd[0].revents & POLLIN) {
260
	    recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
261
			       0, NULL, &dummy);
262
	    if (recvlen < 0) {
263
		if (errno != EINTR) logit(LOG_ERR, errno, "recvfrom");
264
		continue;
265
	    }
266
	    (void)sigemptyset(&mask);
267
	    (void)sigaddset(&mask, SIGALRM);
268
	    if (sigprocmask(SIG_BLOCK, &mask, &omask) < 0)
269
		    logit(LOG_ERR, errno, "sigprocmask");
270
	    accept_igmp(recvlen);
271
	    (void)sigprocmask(SIG_SETMASK, &omask, NULL);
272
        }
273
274
	for (i = 0; i < nhandlers; i++) {
275
	    if (pfd[i + 1].revents & POLLIN) {
276
		(*ihandlers[i].func)(ihandlers[i].fd);
277
	    }
278
	}
279
    }
280
}
281
282
283
/*
284
 * routine invoked every second.  Its main goal is to cycle through
285
 * the routing table and send partial updates to all neighbors at a
286
 * rate that will cause the entire table to be sent in ROUTE_REPORT_INTERVAL
287
 * seconds.  Also, every TIMER_INTERVAL seconds it calls timer() to
288
 * do all the other time-based processing.
289
 */
290
/* XXX signal race */
291
static void
292
fasttimer(int i)
293
{
294
    static unsigned int tlast;
295
    static unsigned int nsent;
296
    unsigned int t = tlast + 1;
297
    int n;
298
299
    /*
300
     * if we're in the last second, send everything that's left.
301
     * otherwise send at least the fraction we should have sent by now.
302
     */
303
    if (t >= ROUTE_REPORT_INTERVAL) {
304
	int nleft = nroutes - nsent;
305
	while (nleft > 0) {
306
	    if ((n = report_next_chunk()) <= 0)
307
		break;
308
	    nleft -= n;
309
	}
310
	tlast = 0;
311
	nsent = 0;
312
    } else {
313
	unsigned int ncum = nroutes * t / ROUTE_REPORT_INTERVAL;
314
	while (nsent < ncum) {
315
	    if ((n = report_next_chunk()) <= 0)
316
		break;
317
	    nsent += n;
318
	}
319
	tlast = t;
320
    }
321
    if ((t % TIMER_INTERVAL) == 0)
322
	timer();
323
324
    age_callout_queue();/* Advance the timer for the callout queue
325
				for groups */
326
    alarm(1);
327
}
328
329
/*
330
 * The 'virtual_time' variable is initialized to a value that will cause the
331
 * first invocation of timer() to send a probe or route report to all vifs
332
 * and send group membership queries to all subnets for which this router is
333
 * querier.  This first invocation occurs approximately TIMER_INTERVAL seconds
334
 * after the router starts up.   Note that probes for neighbors and queries
335
 * for group memberships are also sent at start-up time, as part of initial-
336
 * ization.  This repetition after a short interval is desirable for quickly
337
 * building up topology and membership information in the presence of possible
338
 * packet loss.
339
 *
340
 * 'virtual_time' advances at a rate that is only a crude approximation of
341
 * real time, because it does not take into account any time spent processing,
342
 * and because the timer intervals are sometimes shrunk by a random amount to
343
 * avoid unwanted synchronization with other routers.
344
 */
345
346
static u_long virtual_time = 0;
347
348
349
/*
350
 * Timer routine.  Performs periodic neighbor probing, route reporting, and
351
 * group querying duties, and drives various timers in routing entries and
352
 * virtual interface data structures.
353
 */
354
static void
355
timer(void)
356
{
357
    age_routes();	/* Advance the timers in the route entries     */
358
    age_vifs();		/* Advance the timers for neighbors */
359
    age_table_entry();	/* Advance the timers for the cache entries */
360
361
    if (virtual_time % GROUP_QUERY_INTERVAL == 0) {
362
	/*
363
	 * Time to query the local group memberships on all subnets
364
	 * for which this router is the elected querier.
365
	 */
366
	query_groups();
367
    }
368
369
    if (virtual_time % NEIGHBOR_PROBE_INTERVAL == 0) {
370
	/*
371
	 * Time to send a probe on all vifs from which no neighbors have
372
	 * been heard.  Also, check if any inoperative interfaces have now
373
	 * come up.  (If they have, they will also be probed as part of
374
	 * their initialization.)
375
	 */
376
	probe_for_neighbors();
377
378
	if (vifs_down)
379
	    check_vif_state();
380
    }
381
382
    delay_change_reports = FALSE;
383
    if (routes_changed) {
384
	/*
385
	 * Some routes have changed since the last timer interrupt, but
386
	 * have not been reported yet.  Report the changed routes to all
387
	 * neighbors.
388
	 */
389
	report_to_all_neighbors(CHANGED_ROUTES);
390
    }
391
392
    /*
393
     * Advance virtual time
394
     */
395
    virtual_time += TIMER_INTERVAL;
396
}
397
398
399
/*
400
 * On termination, let everyone know we're going away.
401
 */
402
/* XXX signal race */
403
static void
404
done(int i)
405
{
406
    logit(LOG_NOTICE, 0, "%s exiting", versionstring);
407
    cleanup();
408
    _exit(1);
409
}
410
411
/* XXX signal race, atexit race */
412
static void
413
cleanup(void)
414
{
415
    static int in_cleanup = 0;
416
417
    if (!in_cleanup) {
418
	in_cleanup++;
419
#ifdef RSRR
420
	rsrr_clean();
421
#endif /* RSRR */
422
	expire_all_routes();
423
	report_to_all_neighbors(ALL_ROUTES);
424
	k_stop_dvmrp();
425
    }
426
}
427
428
429
/*
430
 * Dump internal data structures to stderr.
431
 */
432
/* XXX signal race */
433
static void
434
dump(int i)
435
{
436
    dump_vifs(stderr);
437
    dump_routes(stderr);
438
}
439
440
441
/*
442
 * Dump internal data structures to a file.
443
 */
444
static void
445
fdump(int i)
446
{
447
    FILE *fp;
448
449
    fp = fopen(dumpfilename, "w");
450
    if (fp != NULL) {
451
	dump_vifs(fp);
452
	dump_routes(fp);
453
	(void) fclose(fp);
454
    }
455
}
456
457
458
/*
459
 * Dump local cache contents to a file.
460
 */
461
/* XXX signal race */
462
static void
463
cdump(int i)
464
{
465
    FILE *fp;
466
467
    fp = fopen(cachefilename, "w");
468
    if (fp != NULL) {
469
	dump_cache(fp);
470
	(void) fclose(fp);
471
    }
472
}
473
474
475
/*
476
 * Restart mrouted
477
 */
478
/* XXX signal race */
479
static void
480
restart(int i)
481
{
482
    sigset_t mask, omask;
483
484
    logit(LOG_NOTICE, 0, "%s restart", versionstring);
485
486
    /*
487
     * reset all the entries
488
     */
489
    (void)sigemptyset(&mask);
490
    (void)sigaddset(&mask, SIGALRM);
491
    if (sigprocmask(SIG_BLOCK, &mask, &omask) < 0)
492
	logit(LOG_ERR, errno, "sigprocmask");
493
    free_all_prunes();
494
    free_all_routes();
495
    stop_all_vifs();
496
    k_stop_dvmrp();
497
    close(igmp_socket);
498
    close(udp_socket);
499
500
    /*
501
     * start processing again
502
     */
503
    dvmrp_genid++;
504
    pruning = 1;
505
506
    init_igmp();
507
    init_routes();
508
    init_ktable();
509
    init_vifs();
510
    k_init_dvmrp();		/* enable DVMRP routing in kernel */
511
    init_installvifs();
512
513
    (void)sigprocmask(SIG_SETMASK, &omask, NULL);
514
}
515
516
#define LOG_MAX_MSGS	20	/* if > 20/minute then shut up for a while */
517
#define LOG_SHUT_UP	600	/* shut up for 10 minutes */
518
static int log_nmsgs = 0;
519
520
static void
521
resetlogging(void *arg)
522
{
523
    int nxttime = 60;
524
    void *narg = NULL;
525
526
    if (arg == NULL && log_nmsgs > LOG_MAX_MSGS) {
527
	nxttime = LOG_SHUT_UP;
528
	narg = (void *)&log_nmsgs;	/* just need some valid void * */
529
	syslog(LOG_WARNING, "logging too fast, shutting up for %d minutes",
530
			LOG_SHUT_UP / 60);
531
    } else {
532
	log_nmsgs = 0;
533
    }
534
535
    timer_setTimer(nxttime, resetlogging, narg);
536
}
537
538
/*
539
 * Log errors and other messages to the system log daemon and to stderr,
540
 * according to the severity of the message and the current debug level.
541
 * For errors of severity LOG_ERR or worse, terminate the program.
542
 */
543
void
544
logit(int severity, int syserr, char *format, ...)
545
{
546
    va_list ap;
547
    static char fmt[211] = "warning - ";
548
    char *msg;
549
    char tbuf[20];
550
    struct timeval now;
551
    struct tm *thyme;
552
    time_t t;
553
554
    va_start(ap, format);
555
    vsnprintf(&fmt[10], sizeof fmt - 10, format, ap);
556
    va_end(ap);
557
    msg = (severity == LOG_WARNING) ? fmt : &fmt[10];
558
559
    switch (debug) {
560
	case 0: break;
561
	case 1: if (severity > LOG_NOTICE) break;
562
	case 2: if (severity > LOG_INFO  ) break;
563
	default:
564
	    gettimeofday(&now,NULL);
565
	    t = now.tv_sec;
566
	    thyme = localtime(&t);
567
	    strftime(tbuf, sizeof(tbuf), "%X.%%03d ", thyme);
568
	    fprintf(stderr, tbuf, now.tv_usec / 1000);
569
	    fprintf(stderr, "%s", msg);
570
	    if (syserr == 0)
571
		fprintf(stderr, "\n");
572
	    else if (syserr < sys_nerr)
573
		fprintf(stderr, ": %s\n", sys_errlist[syserr]);
574
	    else
575
		fprintf(stderr, ": errno %d\n", syserr);
576
    }
577
578
    if (severity <= LOG_NOTICE) {
579
	if (log_nmsgs++ < LOG_MAX_MSGS) {
580
	    if (syserr != 0) {
581
		errno = syserr;
582
		syslog(severity, "%s: %m", msg);
583
	    } else
584
		syslog(severity, "%s", msg);
585
	}
586
587
	if (severity <= LOG_ERR) exit(1);
588
    }
589
}
590
591
#ifdef DEBUG_MFC
592
void
593
md_logit(int what, u_int32_t origin, u_int32_t mcastgrp)
594
{
595
    static FILE *f = NULL;
596
    struct timeval tv;
597
    u_int32_t buf[4];
598
599
    if (!f) {
600
	if ((f = fopen("/tmp/mrouted.clog", "w")) == NULL) {
601
	    logit(LOG_ERR, errno, "open /tmp/mrouted.clog");
602
	}
603
    }
604
605
    gettimeofday(&tv, NULL);
606
    buf[0] = tv.tv_sec;
607
    buf[1] = what;
608
    buf[2] = origin;
609
    buf[3] = mcastgrp;
610
611
    fwrite(buf, sizeof(u_int32_t), 4, f);
612
}
613
#endif