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