GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/mrinfo/mrinfo.c Lines: 0 236 0.0 %
Date: 2017-11-07 Branches: 0 147 0.0 %

Line Branch Exec Source
1
/*	$NetBSD: mrinfo.c,v 1.4 1995/12/10 11:00:51 mycroft Exp $	*/
2
3
/*
4
 * This tool requests configuration info from a multicast router
5
 * and prints the reply (if any).  Invoke it as:
6
 *
7
 *	mrinfo router-name-or-address
8
 *
9
 * Written Wed Mar 24 1993 by Van Jacobson (adapted from the
10
 * multicast mapper written by Pavel Curtis).
11
 *
12
 * The lawyers insist we include the following UC copyright notice.
13
 * The mapper from which this is derived contained a Xerox copyright
14
 * notice which follows the UC one.  Try not to get depressed noting
15
 * that the legal gibberish is larger than the program.
16
 *
17
 * Copyright (c) 1993 Regents of the University of California.
18
 * All rights reserved.
19
 *
20
 * Redistribution and use in source and binary forms, with or without
21
 * modification, are permitted provided that the following conditions
22
 * are met:
23
 * 1. Redistributions of source code must retain the above copyright
24
 *    notice, this list of conditions and the following disclaimer.
25
 * 2. Redistributions in binary form must reproduce the above copyright
26
 *    notice, this list of conditions and the following disclaimer in the
27
 *    documentation and/or other materials provided with the distribution.
28
 * 3. All advertising materials mentioning features or use of this software
29
 *    must display the following acknowledgement:
30
 *	This product includes software developed by the Computer Systems
31
 *	Engineering Group at Lawrence Berkeley Laboratory.
32
 * 4. Neither the name of the University nor of the Laboratory may be used
33
 *    to endorse or promote products derived from this software without
34
 *    specific prior written permission.
35
 *
36
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
37
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
40
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46
 * SUCH DAMAGE.
47
 * ---------------------------------
48
 * Copyright (c) 1992, 2001 Xerox Corporation.  All rights reserved.
49
 *
50
 * Redistribution and use in source and binary forms, with or without modification,
51
 * are permitted provided that the following conditions are met:
52
 *
53
 * Redistributions of source code must retain the above copyright notice,
54
 * this list of conditions and the following disclaimer.
55
 *
56
 * Redistributions in binary form must reproduce the above copyright notice,
57
 * this list of conditions and the following disclaimer in the documentation
58
 * and/or other materials provided with the distribution.
59
60
 * Neither name of the Xerox, PARC, nor the names of its contributors may be used
61
 * to endorse or promote products derived from this software
62
 * without specific prior written permission.
63
 *
64
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
65
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
66
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
67
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE XEROX CORPORATION OR CONTRIBUTORS
68
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
69
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
70
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
71
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
72
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
73
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
74
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
75
 */
76
77
#include <string.h>
78
#include <netdb.h>
79
#include <sys/time.h>
80
#include "defs.h"
81
#include <arpa/inet.h>
82
#include <stdarg.h>
83
#include <poll.h>
84
#include <limits.h>
85
#include <err.h>
86
87
#define DEFAULT_TIMEOUT	4	/* How long to wait before retrying requests */
88
#define DEFAULT_RETRIES 3	/* How many times to ask each router */
89
90
u_int32_t	our_addr, target_addr = 0;	/* in NET order */
91
int     debug = 0;
92
int	nflag = 0;
93
int     retries = DEFAULT_RETRIES;
94
int     timeout = DEFAULT_TIMEOUT;
95
int	target_level = 0;
96
vifi_t  numvifs;		/* to keep loader happy */
97
				/* (see COPY_TABLES macro called in kern.c) */
98
99
char		*inet_name(u_int32_t addr);
100
void		ask(u_int32_t dst);
101
void		ask2(u_int32_t dst);
102
u_int32_t	host_addr(char *name);
103
void		usage(void);
104
105
char *
106
inet_name(u_int32_t addr)
107
{
108
	struct hostent *e;
109
	struct in_addr in;
110
111
	if (addr == 0)
112
		return "local";
113
114
	if (nflag ||
115
	    (e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET)) == NULL) {
116
		in.s_addr = addr;
117
		return (inet_ntoa(in));
118
	}
119
	return (e->h_name);
120
}
121
122
/*
123
 * Log errors and other messages to stderr, according to the severity of the
124
 * message and the current debug level.  For errors of severity LOG_ERR or
125
 * worse, terminate the program.
126
 */
127
void
128
logit(int severity, int syserr, char *format, ...)
129
{
130
	va_list ap;
131
132
	switch (debug) {
133
	case 0:
134
		if (severity > LOG_WARNING)
135
			return;
136
	case 1:
137
		if (severity > LOG_NOTICE)
138
			return;
139
	case 2:
140
		if (severity > LOG_INFO)
141
			return;
142
	default:
143
		if (severity == LOG_WARNING)
144
			fprintf(stderr, "warning - ");
145
		va_start(ap, format);
146
		vfprintf(stderr, format, ap);
147
		va_end(ap);
148
		if (syserr == 0)
149
			fputc('\n', stderr);
150
		else if (syserr < sys_nerr)
151
			fprintf(stderr, ": %s\n", sys_errlist[syserr]);
152
		else
153
			fprintf(stderr, ": errno %d\n", syserr);
154
	}
155
156
	if (severity <= LOG_ERR)
157
		exit(1);
158
}
159
160
/*
161
 * Send a neighbors-list request.
162
 */
163
void
164
ask(u_int32_t dst)
165
{
166
	send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
167
	    htonl(MROUTED_LEVEL), 0);
168
}
169
170
void
171
ask2(u_int32_t dst)
172
{
173
	send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
174
	    htonl(MROUTED_LEVEL), 0);
175
}
176
177
/*
178
 * Process an incoming neighbor-list message.
179
 */
180
void
181
accept_neighbors(u_int32_t src, u_int32_t dst, u_char *p, int datalen,
182
    u_int32_t level)
183
{
184
	u_char *ep = p + datalen;
185
186
#define GET_ADDR(a) (a = ((u_int32_t)*p++ << 24), a += ((u_int32_t)*p++ << 16),\
187
		     a += ((u_int32_t)*p++ << 8), a += *p++)
188
189
	printf("%s (%s):\n", inet_fmt(src, s1), inet_name(src));
190
	while (p < ep) {
191
		u_char metric, thresh;
192
		u_int32_t laddr;
193
		int ncount;
194
195
		GET_ADDR(laddr);
196
		laddr = htonl(laddr);
197
		metric = *p++;
198
		thresh = *p++;
199
		ncount = *p++;
200
		while (--ncount >= 0) {
201
			u_int32_t neighbor;
202
203
			GET_ADDR(neighbor);
204
			neighbor = htonl(neighbor);
205
			printf("  %s -> ", inet_fmt(laddr, s1));
206
			printf("%s (%s) [%d/%d]\n", inet_fmt(neighbor, s1),
207
			    inet_name(neighbor), metric, thresh);
208
		}
209
	}
210
}
211
212
void
213
accept_neighbors2(u_int32_t src, u_int32_t dst, u_char *p, int datalen,
214
    u_int32_t level)
215
{
216
	u_char *ep = p + datalen;
217
	u_int broken_cisco = ((level & 0xffff) == 0x020a); /* 10.2 */
218
	/* well, only possibly_broken_cisco, but that's too long to type. */
219
220
	printf("%s (%s) [version %d.%d", inet_fmt(src, s1), inet_name(src),
221
	    level & 0xff, (level >> 8) & 0xff);
222
	if ((level >> 16) & NF_LEAF)
223
		printf (",leaf");
224
	if ((level >> 16) & NF_PRUNE)
225
		printf (",prune");
226
	if ((level >> 16) & NF_GENID)
227
		printf (",genid");
228
	if ((level >> 16) & NF_MTRACE)
229
		printf (",mtrace");
230
	printf ("]:\n");
231
232
	while (p < ep) {
233
		u_char metric, thresh, flags;
234
		u_int32_t laddr = *(u_int32_t*)p;
235
		int ncount;
236
237
		p += 4;
238
		metric = *p++;
239
		thresh = *p++;
240
		flags = *p++;
241
		ncount = *p++;
242
		if (broken_cisco && ncount == 0)	/* dumb Ciscos */
243
			ncount = 1;
244
		if (broken_cisco && ncount > 15)	/* dumb Ciscos */
245
			ncount = ncount & 0xf;
246
		while (--ncount >= 0 && p < ep) {
247
			u_int32_t neighbor = *(u_int32_t*)p;
248
			p += 4;
249
			printf("  %s -> ", inet_fmt(laddr, s1));
250
			printf("%s (%s) [%d/%d", inet_fmt(neighbor, s1),
251
			    inet_name(neighbor), metric, thresh);
252
			if (flags & DVMRP_NF_TUNNEL)
253
				printf("/tunnel");
254
			if (flags & DVMRP_NF_SRCRT)
255
				printf("/srcrt");
256
			if (flags & DVMRP_NF_PIM)
257
				printf("/pim");
258
			if (flags & DVMRP_NF_QUERIER)
259
				printf("/querier");
260
			if (flags & DVMRP_NF_DISABLED)
261
				printf("/disabled");
262
			if (flags & DVMRP_NF_DOWN)
263
				printf("/down");
264
			if (flags & DVMRP_NF_LEAF)
265
				printf("/leaf");
266
			printf("]\n");
267
		}
268
	}
269
}
270
271
void
272
usage()
273
{
274
	fprintf(stderr,
275
	    "Usage: mrinfo [-d [debug_level]] [-n] [-t timeout] [-r retries] [router]\n");
276
	exit(1);
277
}
278
279
int
280
main(int argc, char *argv[])
281
{
282
	int tries, trynew, curaddr, udp, ch;
283
	struct hostent *hp, bogus;
284
	struct sockaddr_in addr;
285
	socklen_t addrlen;
286
	struct timeval et;
287
	char *host;
288
	uid_t uid;
289
	const char *errstr;
290
291
	if (geteuid() != 0) {
292
		fprintf(stderr, "mrinfo: must be root\n");
293
		exit(1);
294
	}
295
296
	init_igmp();
297
298
	uid = getuid();
299
	if (setresuid(uid, uid, uid) == -1)
300
		err(1, "setresuid");
301
302
	setvbuf(stderr, NULL, _IOLBF, 0);
303
304
	while ((ch = getopt(argc, argv, "d::nr:t:")) != -1) {
305
		switch (ch) {
306
		case 'd':
307
			if (!optarg)
308
				debug = DEFAULT_DEBUG;
309
			else {
310
				debug = strtonum(optarg, 0, 3, &errstr);
311
				if (errstr) {
312
					warnx("debug level %s", errstr);
313
					debug = DEFAULT_DEBUG;
314
				}
315
			}
316
			break;
317
		case 'n':
318
			++nflag;
319
			break;
320
		case 'r':
321
			retries = strtonum(optarg, 0, INT_MAX, &errstr);
322
			if (errstr) {
323
				warnx("retries %s", errstr);
324
				usage();
325
			}
326
			break;
327
		case 't':
328
			timeout = strtonum(optarg, 0, INT_MAX, &errstr);
329
			if (errstr) {
330
				warnx("timeout %s", errstr);
331
				usage();
332
			}
333
			break;
334
		default:
335
			usage();
336
		}
337
	}
338
	argc -= optind;
339
	argv += optind;
340
341
	if (argc > 1)
342
		usage();
343
	if (argc == 1)
344
		host = argv[0];
345
	else
346
		host = "127.0.0.1";
347
348
	if ((target_addr = inet_addr(host)) != -1) {
349
		hp = &bogus;
350
		hp->h_length = sizeof(target_addr);
351
		if (!(hp->h_addr_list = calloc(2, sizeof(char *))))
352
			err(1, "can't allocate memory");
353
		if (!(hp->h_addr_list[0] = malloc(hp->h_length)))
354
			err(1, "can't allocate memory");
355
		memcpy(hp->h_addr_list[0], &target_addr, hp->h_length);
356
		hp->h_addr_list[1] = 0;
357
	} else
358
		hp = gethostbyname(host);
359
360
	if (hp == NULL || hp->h_length != sizeof(target_addr)) {
361
		fprintf(stderr, "mrinfo: %s: no such host\n", argv[0]);
362
		exit(1);
363
	}
364
	if (debug)
365
		fprintf(stderr, "Debug level %u\n", debug);
366
367
	/* Check all addresses; mrouters often have unreachable interfaces */
368
	for (curaddr = 0; hp->h_addr_list[curaddr] != NULL; curaddr++) {
369
		memcpy(&target_addr, hp->h_addr_list[curaddr], hp->h_length);
370
		/* Find a good local address for us. */
371
		addrlen = sizeof(addr);
372
		memset(&addr, 0, sizeof addr);
373
		addr.sin_family = AF_INET;
374
		addr.sin_len = sizeof addr;
375
		addr.sin_addr.s_addr = target_addr;
376
		addr.sin_port = htons(2000);	/* any port over 1024 will
377
						 * do... */
378
		if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
379
		    connect(udp, (struct sockaddr *) & addr, sizeof(addr)) < 0 ||
380
		    getsockname(udp, (struct sockaddr *) & addr, &addrlen) < 0) {
381
			perror("Determining local address");
382
			exit(1);
383
		}
384
		close(udp);
385
		our_addr = addr.sin_addr.s_addr;
386
387
		tries = 0;
388
		trynew = 1;
389
		/*
390
		 * New strategy: send 'ask2' for two timeouts, then fall back
391
		 * to 'ask', since it's not very likely that we are going to
392
		 * find someone who only responds to 'ask' these days
393
		 */
394
		ask2(target_addr);
395
396
		gettimeofday(&et, 0);
397
		et.tv_sec += timeout;
398
399
		/* Main receive loop */
400
		for (;;) {
401
			int count, recvlen, ipdatalen, iphdrlen, igmpdatalen;
402
			u_int32_t src, dst, group;
403
			struct timeval tv, now;
404
			socklen_t dummy = 0;
405
			struct igmp *igmp;
406
			struct ip *ip;
407
			struct pollfd pfd[1];
408
409
			pfd[0].fd = igmp_socket;
410
			pfd[0].events = POLLIN;
411
412
			gettimeofday(&now, 0);
413
			tv.tv_sec = et.tv_sec - now.tv_sec;
414
			tv.tv_usec = et.tv_usec - now.tv_usec;
415
416
			if (tv.tv_usec < 0) {
417
				tv.tv_usec += 1000000L;
418
				--tv.tv_sec;
419
			}
420
			if (tv.tv_sec < 0)
421
				timerclear(&tv);
422
423
			count = poll(pfd, 1, tv.tv_sec * 1000);
424
425
			if (count < 0) {
426
				if (errno != EINTR)
427
					perror("select");
428
				continue;
429
			} else if (count == 0) {
430
				logit(LOG_DEBUG, 0,
431
				    "Timed out receiving neighbor lists");
432
				if (++tries > retries)
433
					break;
434
				/* If we've tried ASK_NEIGHBORS2 twice with
435
				 * no response, fall back to ASK_NEIGHBORS
436
				 */
437
				if (tries == 2 && target_level == 0)
438
					trynew = 0;
439
				if (target_level == 0 && trynew == 0)
440
					ask(target_addr);
441
				else
442
					ask2(target_addr);
443
				gettimeofday(&et, 0);
444
				et.tv_sec += timeout;
445
				continue;
446
			}
447
			recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
448
			    0, NULL, &dummy);
449
			if (recvlen <= 0) {
450
				if (recvlen && errno != EINTR)
451
					perror("recvfrom");
452
				continue;
453
			}
454
455
			if (recvlen < sizeof(struct ip)) {
456
				logit(LOG_WARNING, 0,
457
				    "packet too short (%u bytes) for IP header",
458
				    recvlen);
459
				continue;
460
			}
461
			ip = (struct ip *) recv_buf;
462
			if (ip->ip_p == 0)
463
				continue;	/* Request to install cache entry */
464
			src = ip->ip_src.s_addr;
465
			dst = ip->ip_dst.s_addr;
466
			iphdrlen = ip->ip_hl << 2;
467
			ipdatalen = ntohs(ip->ip_len) - iphdrlen;
468
			if (iphdrlen + ipdatalen != recvlen) {
469
				logit(LOG_WARNING, 0,
470
				    "packet shorter (%u bytes) than "
471
				    "hdr+data length (%u+%u)",
472
				    recvlen, iphdrlen, ipdatalen);
473
				continue;
474
			}
475
			igmp = (struct igmp *) (recv_buf + iphdrlen);
476
			group = igmp->igmp_group.s_addr;
477
			igmpdatalen = ipdatalen - IGMP_MINLEN;
478
			if (igmpdatalen < 0) {
479
				logit(LOG_WARNING, 0,
480
				    "IP data field too short (%u bytes) "
481
				    "for IGMP, from %s",
482
				    ipdatalen, inet_fmt(src, s1));
483
				continue;
484
			}
485
			if (igmp->igmp_type != IGMP_DVMRP)
486
				continue;
487
488
			switch (igmp->igmp_code) {
489
			case DVMRP_NEIGHBORS:
490
			case DVMRP_NEIGHBORS2:
491
				if (src != target_addr) {
492
					fprintf(stderr, "mrinfo: got reply from %s",
493
					    inet_fmt(src, s1));
494
					fprintf(stderr, " instead of %s\n",
495
					    inet_fmt(target_addr, s1));
496
					/*continue;*/
497
				}
498
				break;
499
			default:
500
				continue;	/* ignore all other DVMRP messages */
501
			}
502
503
			switch (igmp->igmp_code) {
504
			case DVMRP_NEIGHBORS:
505
				if (group) {
506
					/* knows about DVMRP_NEIGHBORS2 msg */
507
					if (target_level == 0) {
508
						target_level = ntohl(group);
509
						ask2(target_addr);
510
					}
511
				} else {
512
					accept_neighbors(src, dst, (u_char *)(igmp + 1),
513
					    igmpdatalen, ntohl(group));
514
					exit(0);
515
				}
516
				break;
517
			case DVMRP_NEIGHBORS2:
518
				accept_neighbors2(src, dst, (u_char *)(igmp + 1),
519
				    igmpdatalen, ntohl(group));
520
				exit(0);
521
			}
522
		}
523
	}
524
	exit(1);
525
}
526
527
/* dummies */
528
void
529
accept_probe(u_int32_t src, u_int32_t dst, char *p, int datalen,
530
    u_int32_t level)
531
{
532
}
533
534
void
535
accept_group_report(u_int32_t src, u_int32_t dst, u_int32_t group, int r_type)
536
{
537
}
538
539
void
540
accept_neighbor_request2(u_int32_t src, u_int32_t dst)
541
{
542
}
543
544
void
545
accept_report(u_int32_t src, u_int32_t dst, char *p, int datalen,
546
    u_int32_t level)
547
{
548
}
549
550
void
551
accept_neighbor_request(u_int32_t src, u_int32_t dst)
552
{
553
}
554
555
void
556
accept_prune(u_int32_t src, u_int32_t dst, char *p, int datalen)
557
{
558
}
559
560
void
561
accept_graft(u_int32_t src, u_int32_t dst, char *p, int datalen)
562
{
563
}
564
565
void
566
accept_g_ack(u_int32_t src, u_int32_t dst, char *p, int datalen)
567
{
568
}
569
570
void
571
add_table_entry(u_int32_t origin, u_int32_t mcastgrp)
572
{
573
}
574
575
void
576
check_vif_state(void)
577
{
578
}
579
580
void
581
accept_leave_message(u_int32_t src, u_int32_t dst, u_int32_t group)
582
{
583
}
584
585
void
586
accept_mtrace(u_int32_t src, u_int32_t dst, u_int32_t group, char *data,
587
    u_int no, int datalen)
588
{
589
}
590
591
void
592
accept_membership_query(u_int32_t src, u_int32_t dst, u_int32_t group, int tmo)
593
{
594
}
595
596
void
597
accept_info_request(u_int32_t src, u_int32_t dst, u_char *p, int datalen)
598
{
599
}
600
601
void
602
accept_info_reply(u_int32_t src, u_int32_t dst, u_char *p, int datalen)
603
{
604
}