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