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