• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996
3   *  The Regents of the University of California.  All rights reserved.
4   *
5   * Redistribution and use in source and binary forms, with or without
6   * modification, are permitted provided that: (1) source code distributions
7   * retain the above copyright notice and this paragraph in its entirety, (2)
8   * distributions including binary code include the above copyright notice and
9   * this paragraph in its entirety in the documentation or other materials
10   * provided with the distribution, and (3) all advertising materials mentioning
11   * features or use of this software display the following acknowledgement:
12   * ``This product includes software developed by the University of California,
13   * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14   * the University nor the names of its contributors may be used to endorse
15   * or promote products derived from this software without specific prior
16   * written permission.
17   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18   * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20   */
21  
22  #define NETDISSECT_REWORKED
23  #ifdef HAVE_CONFIG_H
24  #include "config.h"
25  #endif
26  
27  #include <tcpdump-stdinc.h>
28  
29  #include "interface.h"
30  #include "addrtoname.h"
31  #include "extract.h"            /* must come after interface.h */
32  
33  #ifndef IN_CLASSD
34  #define IN_CLASSD(i) (((int32_t)(i) & 0xf0000000) == 0xe0000000)
35  #endif
36  
37  static const char tstr[] = "[|igmp]";
38  
39  /* (following from ipmulti/mrouted/prune.h) */
40  
41  /*
42   * The packet format for a traceroute request.
43   */
44  struct tr_query {
45      uint32_t  tr_src;          /* traceroute source */
46      uint32_t  tr_dst;          /* traceroute destination */
47      uint32_t  tr_raddr;        /* traceroute response address */
48      uint32_t  tr_rttlqid;      /* response ttl and qid */
49  };
50  
51  #define TR_GETTTL(x)        (int)(((x) >> 24) & 0xff)
52  #define TR_GETQID(x)        ((x) & 0x00ffffff)
53  
54  /*
55   * Traceroute response format.  A traceroute response has a tr_query at the
56   * beginning, followed by one tr_resp for each hop taken.
57   */
58  struct tr_resp {
59      uint32_t tr_qarr;          /* query arrival time */
60      uint32_t tr_inaddr;        /* incoming interface address */
61      uint32_t tr_outaddr;       /* outgoing interface address */
62      uint32_t tr_rmtaddr;       /* parent address in source tree */
63      uint32_t tr_vifin;         /* input packet count on interface */
64      uint32_t tr_vifout;        /* output packet count on interface */
65      uint32_t tr_pktcnt;        /* total incoming packets for src-grp */
66      uint8_t  tr_rproto;      /* routing proto deployed on router */
67      uint8_t  tr_fttl;        /* ttl required to forward on outvif */
68      uint8_t  tr_smask;       /* subnet mask for src addr */
69      uint8_t  tr_rflags;      /* forwarding error codes */
70  };
71  
72  /* defs within mtrace */
73  #define TR_QUERY 1
74  #define TR_RESP 2
75  
76  /* fields for tr_rflags (forwarding error codes) */
77  #define TR_NO_ERR   0
78  #define TR_WRONG_IF 1
79  #define TR_PRUNED   2
80  #define TR_OPRUNED  3
81  #define TR_SCOPED   4
82  #define TR_NO_RTE   5
83  #define TR_NO_FWD   7
84  #define TR_NO_SPACE 0x81
85  #define TR_OLD_ROUTER   0x82
86  
87  /* fields for tr_rproto (routing protocol) */
88  #define TR_PROTO_DVMRP  1
89  #define TR_PROTO_MOSPF  2
90  #define TR_PROTO_PIM    3
91  #define TR_PROTO_CBT    4
92  
93  /* igmpv3 report types */
94  static const struct tok igmpv3report2str[] = {
95  	{ 1,	"is_in" },
96  	{ 2,	"is_ex" },
97  	{ 3,	"to_in" },
98  	{ 4,	"to_ex" },
99  	{ 5,	"allow" },
100  	{ 6,	"block" },
101  	{ 0,	NULL }
102  };
103  
104  static void
print_mtrace(netdissect_options * ndo,register const u_char * bp,register u_int len)105  print_mtrace(netdissect_options *ndo,
106               register const u_char *bp, register u_int len)
107  {
108      register const struct tr_query *tr = (const struct tr_query *)(bp + 8);
109  
110      ND_TCHECK(*tr);
111      if (len < 8 + sizeof (struct tr_query)) {
112  	ND_PRINT((ndo, " [invalid len %d]", len));
113  	return;
114      }
115      ND_PRINT((ndo, "mtrace %u: %s to %s reply-to %s",
116          TR_GETQID(EXTRACT_32BITS(&tr->tr_rttlqid)),
117          ipaddr_string(ndo, &tr->tr_src), ipaddr_string(ndo, &tr->tr_dst),
118          ipaddr_string(ndo, &tr->tr_raddr)));
119      if (IN_CLASSD(EXTRACT_32BITS(&tr->tr_raddr)))
120          ND_PRINT((ndo, " with-ttl %d", TR_GETTTL(EXTRACT_32BITS(&tr->tr_rttlqid))));
121      return;
122  trunc:
123      ND_PRINT((ndo, "%s", tstr));
124  }
125  
126  static void
print_mresp(netdissect_options * ndo,register const u_char * bp,register u_int len)127  print_mresp(netdissect_options *ndo,
128              register const u_char *bp, register u_int len)
129  {
130      register const struct tr_query *tr = (const struct tr_query *)(bp + 8);
131  
132      ND_TCHECK(*tr);
133      if (len < 8 + sizeof (struct tr_query)) {
134  	ND_PRINT((ndo, " [invalid len %d]", len));
135  	return;
136      }
137      ND_PRINT((ndo, "mresp %lu: %s to %s reply-to %s",
138          (u_long)TR_GETQID(EXTRACT_32BITS(&tr->tr_rttlqid)),
139          ipaddr_string(ndo, &tr->tr_src), ipaddr_string(ndo, &tr->tr_dst),
140          ipaddr_string(ndo, &tr->tr_raddr)));
141      if (IN_CLASSD(EXTRACT_32BITS(&tr->tr_raddr)))
142          ND_PRINT((ndo, " with-ttl %d", TR_GETTTL(EXTRACT_32BITS(&tr->tr_rttlqid))));
143      return;
144  trunc:
145      ND_PRINT((ndo, "%s", tstr));
146  }
147  
148  static void
print_igmpv3_report(netdissect_options * ndo,register const u_char * bp,register u_int len)149  print_igmpv3_report(netdissect_options *ndo,
150                      register const u_char *bp, register u_int len)
151  {
152      u_int group, nsrcs, ngroups;
153      register u_int i, j;
154  
155      /* Minimum len is 16, and should be a multiple of 4 */
156      if (len < 16 || len & 0x03) {
157  	ND_PRINT((ndo, " [invalid len %d]", len));
158  	return;
159      }
160      ND_TCHECK2(bp[6], 2);
161      ngroups = EXTRACT_16BITS(&bp[6]);
162      ND_PRINT((ndo, ", %d group record(s)", ngroups));
163      if (ndo->ndo_vflag > 0) {
164  	/* Print the group records */
165  	group = 8;
166          for (i=0; i<ngroups; i++) {
167  	    if (len < group+8) {
168  		ND_PRINT((ndo, " [invalid number of groups]"));
169  		return;
170  	    }
171  	    ND_TCHECK2(bp[group+4], 4);
172              ND_PRINT((ndo, " [gaddr %s", ipaddr_string(ndo, &bp[group+4])));
173  	    ND_PRINT((ndo, " %s", tok2str(igmpv3report2str, " [v3-report-#%d]",
174  								bp[group])));
175              nsrcs = EXTRACT_16BITS(&bp[group+2]);
176  	    /* Check the number of sources and print them */
177  	    if (len < group+8+(nsrcs<<2)) {
178  		ND_PRINT((ndo, " [invalid number of sources %d]", nsrcs));
179  		return;
180  	    }
181              if (ndo->ndo_vflag == 1)
182                  ND_PRINT((ndo, ", %d source(s)", nsrcs));
183              else {
184  		/* Print the sources */
185                  ND_PRINT((ndo, " {"));
186                  for (j=0; j<nsrcs; j++) {
187  		    ND_TCHECK2(bp[group+8+(j<<2)], 4);
188  		    ND_PRINT((ndo, " %s", ipaddr_string(ndo, &bp[group+8+(j<<2)])));
189  		}
190                  ND_PRINT((ndo, " }"));
191              }
192  	    /* Next group record */
193              group += 8 + (nsrcs << 2);
194  	    ND_PRINT((ndo, "]"));
195          }
196      }
197      return;
198  trunc:
199      ND_PRINT((ndo, "%s", tstr));
200  }
201  
202  static void
print_igmpv3_query(netdissect_options * ndo,register const u_char * bp,register u_int len)203  print_igmpv3_query(netdissect_options *ndo,
204                     register const u_char *bp, register u_int len)
205  {
206      u_int mrc;
207      int mrt;
208      u_int nsrcs;
209      register u_int i;
210  
211      ND_PRINT((ndo, " v3"));
212      /* Minimum len is 12, and should be a multiple of 4 */
213      if (len < 12 || len & 0x03) {
214  	ND_PRINT((ndo, " [invalid len %d]", len));
215  	return;
216      }
217      ND_TCHECK(bp[1]);
218      mrc = bp[1];
219      if (mrc < 128) {
220  	mrt = mrc;
221      } else {
222          mrt = ((mrc & 0x0f) | 0x10) << (((mrc & 0x70) >> 4) + 3);
223      }
224      if (mrc != 100) {
225  	ND_PRINT((ndo, " [max resp time "));
226          if (mrt < 600) {
227              ND_PRINT((ndo, "%.1fs", mrt * 0.1));
228          } else {
229              relts_print(ndo, mrt / 10);
230          }
231  	ND_PRINT((ndo, "]"));
232      }
233      ND_TCHECK2(bp[4], 4);
234      if (EXTRACT_32BITS(&bp[4]) == 0)
235  	return;
236      ND_PRINT((ndo, " [gaddr %s", ipaddr_string(ndo, &bp[4])));
237      ND_TCHECK2(bp[10], 2);
238      nsrcs = EXTRACT_16BITS(&bp[10]);
239      if (nsrcs > 0) {
240  	if (len < 12 + (nsrcs << 2))
241  	    ND_PRINT((ndo, " [invalid number of sources]"));
242  	else if (ndo->ndo_vflag > 1) {
243  	    ND_PRINT((ndo, " {"));
244  	    for (i=0; i<nsrcs; i++) {
245  		ND_TCHECK2(bp[12+(i<<2)], 4);
246  		ND_PRINT((ndo, " %s", ipaddr_string(ndo, &bp[12+(i<<2)])));
247  	    }
248  	    ND_PRINT((ndo, " }"));
249  	} else
250  	    ND_PRINT((ndo, ", %d source(s)", nsrcs));
251      }
252      ND_PRINT((ndo, "]"));
253      return;
254  trunc:
255      ND_PRINT((ndo, "%s", tstr));
256  }
257  
258  void
igmp_print(netdissect_options * ndo,register const u_char * bp,register u_int len)259  igmp_print(netdissect_options *ndo,
260             register const u_char *bp, register u_int len)
261  {
262      struct cksum_vec vec[1];
263  
264      if (ndo->ndo_qflag) {
265          ND_PRINT((ndo, "igmp"));
266          return;
267      }
268  
269      ND_TCHECK(bp[0]);
270      switch (bp[0]) {
271      case 0x11:
272          ND_PRINT((ndo, "igmp query"));
273  	if (len >= 12)
274  	    print_igmpv3_query(ndo, bp, len);
275  	else {
276              ND_TCHECK(bp[1]);
277  	    if (bp[1]) {
278  		ND_PRINT((ndo, " v2"));
279  		if (bp[1] != 100)
280  		    ND_PRINT((ndo, " [max resp time %d]", bp[1]));
281  	    } else
282  		ND_PRINT((ndo, " v1"));
283              ND_TCHECK2(bp[4], 4);
284  	    if (EXTRACT_32BITS(&bp[4]))
285                  ND_PRINT((ndo, " [gaddr %s]", ipaddr_string(ndo, &bp[4])));
286              if (len != 8)
287                  ND_PRINT((ndo, " [len %d]", len));
288  	}
289          break;
290      case 0x12:
291          ND_TCHECK2(bp[4], 4);
292          ND_PRINT((ndo, "igmp v1 report %s", ipaddr_string(ndo, &bp[4])));
293          if (len != 8)
294              ND_PRINT((ndo, " [len %d]", len));
295          break;
296      case 0x16:
297          ND_TCHECK2(bp[4], 4);
298          ND_PRINT((ndo, "igmp v2 report %s", ipaddr_string(ndo, &bp[4])));
299          break;
300      case 0x22:
301          ND_PRINT((ndo, "igmp v3 report"));
302  	print_igmpv3_report(ndo, bp, len);
303          break;
304      case 0x17:
305          ND_TCHECK2(bp[4], 4);
306          ND_PRINT((ndo, "igmp leave %s", ipaddr_string(ndo, &bp[4])));
307          break;
308      case 0x13:
309          ND_PRINT((ndo, "igmp dvmrp"));
310          if (len < 8)
311              ND_PRINT((ndo, " [len %d]", len));
312          else
313              dvmrp_print(ndo, bp, len);
314          break;
315      case 0x14:
316          ND_PRINT((ndo, "igmp pimv1"));
317          pimv1_print(ndo, bp, len);
318          break;
319      case 0x1e:
320          print_mresp(ndo, bp, len);
321          break;
322      case 0x1f:
323          print_mtrace(ndo, bp, len);
324          break;
325      default:
326          ND_PRINT((ndo, "igmp-%d", bp[0]));
327          break;
328      }
329  
330      if (ndo->ndo_vflag && ND_TTEST2(bp[0], len)) {
331          /* Check the IGMP checksum */
332          vec[0].ptr = bp;
333          vec[0].len = len;
334          if (in_cksum(vec, 1))
335              ND_PRINT((ndo, " bad igmp cksum %x!", EXTRACT_16BITS(&bp[2])));
336      }
337      return;
338  trunc:
339      ND_PRINT((ndo, "%s", tstr));
340  }
341