Home | History | Annotate | Download | only in snoop
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <stdio.h>
     30 #include <string.h>
     31 #include <sys/types.h>
     32 #include <sys/socket.h>
     33 #include <net/if.h>
     34 #include <sys/stropts.h>
     35 #include <sys/sysmacros.h>
     36 #include <netinet/in_systm.h>
     37 #include <netinet/in.h>
     38 #include <netinet/ip.h>
     39 #include <netinet/igmp.h>
     40 #include <inet/ip.h>
     41 #include <arpa/inet.h>
     42 #include <netdb.h>
     43 #include "snoop.h"
     44 
     45 static void interpret_igmpv3qry(struct igmp *, int);
     46 static void interpret_igmpv3rpt(struct igmp *, int);
     47 
     48 
     49 /*ARGSUSED*/
     50 void
     51 interpret_igmp(int flags, char *data, int iplen, int ilen)
     52 {
     53 	const char *pt;
     54 	char *line;
     55 	struct igmp *igmp = (struct igmp *)data;
     56 	char addrstr[INET_ADDRSTRLEN];
     57 
     58 	if (ilen < IGMP_MINLEN) {
     59 		/* incomplete header */
     60 		line = get_sum_line();
     61 		(void) snprintf(line, MAXLINE, "Malformed IGMP packet");
     62 		return;
     63 	}
     64 
     65 	switch (igmp->igmp_type) {
     66 	case IGMP_MEMBERSHIP_QUERY:
     67 		if (ilen == IGMP_MINLEN) {
     68 			if (igmp->igmp_code == 0)
     69 				pt = "v1 membership query";
     70 			else
     71 				pt = "v2 membership query";
     72 		} else if (ilen >= IGMP_V3_QUERY_MINLEN) {
     73 			pt = "v3 membership query";
     74 		} else {
     75 			pt = "Unknown membership query";
     76 		}
     77 		break;
     78 	case IGMP_V1_MEMBERSHIP_REPORT:
     79 		pt = "v1 membership report";
     80 		break;
     81 	case IGMP_V2_MEMBERSHIP_REPORT:
     82 		pt = "v2 membership report";
     83 		break;
     84 	case IGMP_V3_MEMBERSHIP_REPORT:
     85 		pt = "v3 membership report";
     86 		break;
     87 	case IGMP_V2_LEAVE_GROUP:
     88 		pt = "v2 leave group";
     89 		break;
     90 
     91 	default:
     92 		pt = "Unknown";
     93 		break;
     94 	}
     95 
     96 	if (flags & F_SUM) {
     97 		line = get_sum_line();
     98 		(void) snprintf(line, MAXLINE, "IGMP %s", pt);
     99 	}
    100 
    101 	if (flags & F_DTAIL) {
    102 		show_header("IGMP:  ", "IGMP Header", ilen);
    103 		show_space();
    104 		(void) snprintf(get_line(0, 0), get_line_remain(),
    105 		    "Type = %d (%s)", igmp->igmp_type, pt);
    106 		(void) snprintf(get_line(0, 0), get_line_remain(),
    107 		    "Max Response Time = %d", igmp->igmp_code);
    108 		(void) snprintf(get_line(0, 0), get_line_remain(),
    109 		    "Checksum = %x", ntohs(igmp->igmp_cksum));
    110 
    111 		if (igmp->igmp_type == IGMP_MEMBERSHIP_QUERY &&
    112 		    ilen >= IGMP_V3_QUERY_MINLEN) {
    113 			interpret_igmpv3qry(igmp, ilen);
    114 		} else if (igmp->igmp_type == IGMP_V3_MEMBERSHIP_REPORT) {
    115 			interpret_igmpv3rpt(igmp, ilen);
    116 		} else {
    117 			(void) snprintf(get_line(0, 0), get_line_remain(),
    118 			    "Group = %s",
    119 			    inet_ntop(AF_INET, &igmp->igmp_group.s_addr,
    120 			    addrstr, INET_ADDRSTRLEN));
    121 		}
    122 
    123 		show_space();
    124 	}
    125 }
    126 
    127 static void
    128 interpret_igmpv3qry(struct igmp *igmp, int ilen)
    129 {
    130 	struct igmp3q *qry;
    131 	struct in_addr *src;
    132 	int rem = ilen;
    133 	int srccnt;
    134 	char addrstr[INET_ADDRSTRLEN];
    135 
    136 	if (ilen < sizeof (*qry)) {
    137 		(void) snprintf(get_line(0, 0), get_line_remain(),
    138 		    "Malformed IGMP Query");
    139 		return;
    140 	}
    141 
    142 	qry = (struct igmp3q *)igmp;
    143 	rem -= sizeof (*qry);
    144 	srccnt = ntohs(qry->igmp3q_numsrc);
    145 	(void) snprintf(get_line(0, 0), get_line_remain(),
    146 	    "Group = %s", inet_ntop(AF_INET, &qry->igmp3q_group, addrstr,
    147 	    INET_ADDRSTRLEN));
    148 	(void) snprintf(get_line(0, 0), get_line_remain(),
    149 	    "%d Source Address%s:", srccnt, (srccnt == 1) ? "" : "es");
    150 
    151 	src = (struct in_addr *)&qry[1];
    152 	while (srccnt > 0 && rem >= sizeof (*src)) {
    153 		rem -= sizeof (*src);
    154 
    155 		(void) snprintf(get_line(0, 0), get_line_remain(), "    %s",
    156 		    inet_ntop(AF_INET, &src->s_addr, addrstr, INET_ADDRSTRLEN));
    157 
    158 		srccnt--;
    159 		src++;
    160 	}
    161 }
    162 
    163 #define	MAX_IGMPV3_REPORT_TYPE	6
    164 
    165 const char *igmpv3rpt_types[] = {
    166 	"<unknown>",
    167 	"MODE_IS_INCLUDE",
    168 	"MODE_IS_EXCLUDE",
    169 	"CHANGE_TO_INCLUDE",
    170 	"CHANGE_TO_EXCLUDE",
    171 	"ALLOW_NEW_SOURCES",
    172 	"BLOCK_OLD_SOURCES",
    173 };
    174 
    175 static void
    176 interpret_igmpv3rpt(struct igmp *igmp, int ilen)
    177 {
    178 	struct igmp3r *rpt;
    179 	struct grphdr *grh;
    180 	struct in_addr *src;
    181 	int rem = ilen, auxlen;
    182 	uint16_t grhcnt, srccnt;
    183 	char addrstr[INET_ADDRSTRLEN];
    184 
    185 	if (ilen < sizeof (*rpt)) {
    186 		(void) snprintf(get_line(0, 0), get_line_remain(),
    187 		    "Malformed IGMPv3 Report");
    188 		return;
    189 	}
    190 
    191 	rpt = (struct igmp3r *)igmp;
    192 	grh = (struct grphdr *)&rpt[1];
    193 	grhcnt = ntohs(rpt->igmp3r_numrec);
    194 	(void) snprintf(get_line(0, 0), get_line_remain(),
    195 	    "%d Group Record%s:", grhcnt, (grhcnt == 1) ? "" : "s");
    196 	rem -= sizeof (*rpt);
    197 	while (grhcnt > 0 && rem >= sizeof (*grh)) {
    198 		rem -= sizeof (*grh);
    199 
    200 		(void) snprintf(get_line(0, 0), get_line_remain(),
    201 		    "Group = %s  type = %s", inet_ntop(AF_INET,
    202 		    &grh->grphdr_group.s_addr, addrstr, INET_ADDRSTRLEN),
    203 		    (grh->grphdr_type > MAX_IGMPV3_REPORT_TYPE) ?
    204 		    "<unknown>" : igmpv3rpt_types[grh->grphdr_type]);
    205 		srccnt = ntohs(grh->grphdr_numsrc);
    206 		(void) snprintf(get_line(0, 0), get_line_remain(),
    207 		    "%d Source Address%s:", srccnt, (srccnt == 1) ? "" : "es");
    208 
    209 		src = (struct in_addr *)&grh[1];
    210 		while (srccnt > 0 && rem >= sizeof (*src)) {
    211 			rem -= sizeof (*src);
    212 
    213 			(void) snprintf(get_line(0, 0), get_line_remain(),
    214 			    "    %s", inet_ntop(AF_INET, &src->s_addr, addrstr,
    215 			    INET_ADDRSTRLEN));
    216 
    217 			srccnt--;
    218 			src++;
    219 		}
    220 
    221 		grhcnt--;
    222 		auxlen = grh->grphdr_auxlen * 4;
    223 		rem -= auxlen;
    224 		grh = (struct grphdr *)((uint8_t *)src + auxlen);
    225 	}
    226 }
    227