1 /* $OpenBSD: print-icmp.c,v 1.12 2001/09/02 12:06:57 jakob Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that: (1) source code distributions 9 * retain the above copyright notice and this paragraph in its entirety, (2) 10 * distributions including binary code include the above copyright notice and 11 * this paragraph in its entirety in the documentation or other materials 12 * provided with the distribution, and (3) all advertising materials mentioning 13 * features or use of this software display the following acknowledgement: 14 * ``This product includes software developed by the University of California, 15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 16 * the University nor the names of its contributors may be used to endorse 17 * or promote products derived from this software without specific prior 18 * written permission. 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 */ 23 24 #ifndef lint 25 static const char rcsid[] = 26 "@(#) $Header: /home/cvs/src/usr.sbin/tcpdump/print-icmp.c,v 1.12 2001/09/02 12:06:57 jakob Exp $ (LBL)"; 27 #endif 28 29 #include <sys/param.h> 30 #include <sys/time.h> 31 #include <sys/socket.h> 32 33 #ifdef __STDC__ 34 struct mbuf; 35 struct rtentry; 36 #endif 37 #include <net/if.h> 38 39 #include <netinet/in.h> 40 #include <netinet/if_ether.h> 41 #include <netinet/in_systm.h> 42 #include <netinet/ip.h> 43 #include <netinet/ip_icmp.h> 44 #include <netinet/ip_var.h> 45 #include <netinet/udp.h> 46 #include <netinet/udp_var.h> 47 #include <netinet/tcp.h> 48 #include <netinet/tcpip.h> 49 50 #include <stdio.h> 51 #include <string.h> 52 53 #include "interface.h" 54 #include "addrtoname.h" 55 #include "extract.h" /* must come after interface.h */ 56 57 /* rfc1700 */ 58 #ifndef ICMP_UNREACH_NET_UNKNOWN 59 #define ICMP_UNREACH_NET_UNKNOWN 6 /* destination net unknown */ 60 #endif 61 #ifndef ICMP_UNREACH_HOST_UNKNOWN 62 #define ICMP_UNREACH_HOST_UNKNOWN 7 /* destination host unknown */ 63 #endif 64 #ifndef ICMP_UNREACH_ISOLATED 65 #define ICMP_UNREACH_ISOLATED 8 /* source host isolated */ 66 #endif 67 #ifndef ICMP_UNREACH_NET_PROHIB 68 #define ICMP_UNREACH_NET_PROHIB 9 /* admin prohibited net */ 69 #endif 70 #ifndef ICMP_UNREACH_HOST_PROHIB 71 #define ICMP_UNREACH_HOST_PROHIB 10 /* admin prohibited host */ 72 #endif 73 #ifndef ICMP_UNREACH_TOSNET 74 #define ICMP_UNREACH_TOSNET 11 /* tos prohibited net */ 75 #endif 76 #ifndef ICMP_UNREACH_TOSHOST 77 #define ICMP_UNREACH_TOSHOST 12 /* tos prohibited host */ 78 #endif 79 80 /* rfc1716 */ 81 #ifndef ICMP_UNREACH_FILTER_PROHIB 82 #define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */ 83 #endif 84 #ifndef ICMP_UNREACH_HOST_PRECEDENCE 85 #define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host precedence violation */ 86 #endif 87 #ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF 88 #define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* precedence cutoff */ 89 #endif 90 91 /* rfc1256 */ 92 #ifndef ICMP_ROUTERADVERT 93 #define ICMP_ROUTERADVERT 9 /* router advertisement */ 94 #endif 95 #ifndef ICMP_ROUTERSOLICIT 96 #define ICMP_ROUTERSOLICIT 10 /* router solicitation */ 97 #endif 98 99 /* Most of the icmp types */ 100 static struct tok icmp2str[] = { 101 { ICMP_ECHOREPLY, "echo reply" }, 102 { ICMP_SOURCEQUENCH, "source quench" }, 103 { ICMP_ECHO, "echo request" }, 104 { ICMP_ROUTERSOLICIT, "router solicitation" }, 105 { ICMP_TSTAMP, "time stamp request" }, 106 { ICMP_TSTAMPREPLY, "time stamp reply" }, 107 { ICMP_IREQ, "information request" }, 108 { ICMP_IREQREPLY, "information reply" }, 109 { ICMP_MASKREQ, "address mask request" }, 110 { 0, NULL } 111 }; 112 113 /* Formats for most of the ICMP_UNREACH codes */ 114 static struct tok unreach2str[] = { 115 { ICMP_UNREACH_NET, "net %s unreachable" }, 116 { ICMP_UNREACH_HOST, "host %s unreachable" }, 117 { ICMP_UNREACH_SRCFAIL, 118 "%s unreachable - source route failed" }, 119 { ICMP_UNREACH_NET_UNKNOWN, "net %s unreachable - unknown" }, 120 { ICMP_UNREACH_HOST_UNKNOWN, "host %s unreachable - unknown" }, 121 { ICMP_UNREACH_ISOLATED, 122 "%s unreachable - source host isolated" }, 123 { ICMP_UNREACH_NET_PROHIB, 124 "net %s unreachable - admin prohibited" }, 125 { ICMP_UNREACH_HOST_PROHIB, 126 "host %s unreachable - admin prohibited" }, 127 { ICMP_UNREACH_TOSNET, 128 "net %s unreachable - tos prohibited" }, 129 { ICMP_UNREACH_TOSHOST, 130 "host %s unreachable - tos prohibited" }, 131 { ICMP_UNREACH_FILTER_PROHIB, 132 "host %s unreachable - admin prohibited filter" }, 133 { ICMP_UNREACH_HOST_PRECEDENCE, 134 "host %s unreachable - host precedence violation" }, 135 { ICMP_UNREACH_PRECEDENCE_CUTOFF, 136 "host %s unreachable - precedence cutoff" }, 137 { 0, NULL } 138 }; 139 140 /* Formats for the ICMP_REDIRECT codes */ 141 static struct tok type2str[] = { 142 { ICMP_REDIRECT_NET, "redirect %s to net %s" }, 143 { ICMP_REDIRECT_HOST, "redirect %s to host %s" }, 144 { ICMP_REDIRECT_TOSNET, "redirect-tos %s to net %s" }, 145 { ICMP_REDIRECT_TOSHOST, "redirect-tos %s to net %s" }, 146 { 0, NULL } 147 }; 148 149 /* rfc1191 */ 150 struct mtu_discovery { 151 short unused; 152 short nexthopmtu; 153 }; 154 155 /* rfc1256 */ 156 struct ih_rdiscovery { 157 u_char ird_addrnum; 158 u_char ird_addrsiz; 159 u_short ird_lifetime; 160 }; 161 162 struct id_rdiscovery { 163 u_int32_t ird_addr; 164 u_int32_t ird_pref; 165 }; 166 167 void 168 icmp_print(register const u_char *bp, register const u_char *bp2) 169 { 170 register char *cp; 171 register const struct icmp *dp; 172 register const struct ip *ip; 173 register const char *str, *fmt; 174 register const struct ip *oip; 175 register const struct udphdr *ouh; 176 register u_int hlen, dport, mtu; 177 char buf[MAXHOSTNAMELEN+256]; 178 179 dp = (struct icmp *)bp; 180 ip = (struct ip *)bp2; 181 str = buf; 182 183 (void)printf("%s > %s: ", 184 ipaddr_string(&ip->ip_src), 185 ipaddr_string(&ip->ip_dst)); 186 187 TCHECK(dp->icmp_code); 188 switch (dp->icmp_type) { 189 190 case ICMP_ECHOREPLY: 191 case ICMP_ECHO: 192 if (vflag) { 193 TCHECK(dp->icmp_seq); 194 (void)snprintf(buf, sizeof buf, 195 "echo %s (id:%d seq:%d)", 196 (dp->icmp_type == ICMP_ECHO)? 197 "request": "reply", 198 dp->icmp_id, dp->icmp_seq); 199 } else 200 str = tok2str(icmp2str, "type-#%d", dp->icmp_type); 201 break; 202 203 case ICMP_UNREACH: 204 TCHECK(dp->icmp_ip.ip_dst); 205 switch (dp->icmp_code) { 206 207 case ICMP_UNREACH_PROTOCOL: 208 TCHECK(dp->icmp_ip.ip_p); 209 (void)snprintf(buf, sizeof buf, 210 "%s protocol %d unreachable", 211 ipaddr_string(&dp->icmp_ip.ip_dst), 212 dp->icmp_ip.ip_p); 213 break; 214 215 case ICMP_UNREACH_PORT: 216 TCHECK(dp->icmp_ip.ip_p); 217 oip = &dp->icmp_ip; 218 hlen = oip->ip_hl * 4; 219 ouh = (struct udphdr *)(((u_char *)oip) + hlen); 220 dport = ntohs(ouh->uh_dport); 221 switch (oip->ip_p) { 222 223 case IPPROTO_TCP: 224 (void)snprintf(buf, sizeof buf, 225 "%s tcp port %s unreachable", 226 ipaddr_string(&oip->ip_dst), 227 tcpport_string(dport)); 228 break; 229 230 case IPPROTO_UDP: 231 (void)snprintf(buf, sizeof buf, 232 "%s udp port %s unreachable", 233 ipaddr_string(&oip->ip_dst), 234 udpport_string(dport)); 235 break; 236 237 default: 238 (void)snprintf(buf, sizeof buf, 239 "%s protocol %d port %d unreachable", 240 ipaddr_string(&oip->ip_dst), 241 oip->ip_p, dport); 242 break; 243 } 244 break; 245 246 case ICMP_UNREACH_NEEDFRAG: 247 { 248 register const struct mtu_discovery *mp; 249 250 mp = (struct mtu_discovery *)&dp->icmp_void; 251 mtu = EXTRACT_16BITS(&mp->nexthopmtu); 252 if (mtu) 253 (void)snprintf(buf, sizeof buf, 254 "%s unreachable - need to frag (mtu %d)", 255 ipaddr_string(&dp->icmp_ip.ip_dst), mtu); 256 else 257 (void)snprintf(buf, sizeof buf, 258 "%s unreachable - need to frag", 259 ipaddr_string(&dp->icmp_ip.ip_dst)); 260 } 261 break; 262 263 default: 264 fmt = tok2str(unreach2str, "#%d %%s unreachable", 265 dp->icmp_code); 266 (void)snprintf(buf, sizeof buf, fmt, 267 ipaddr_string(&dp->icmp_ip.ip_dst)); 268 break; 269 } 270 break; 271 272 case ICMP_REDIRECT: 273 TCHECK(dp->icmp_ip.ip_dst); 274 fmt = tok2str(type2str, "redirect-#%d %%s to net %%s", 275 dp->icmp_code); 276 (void)snprintf(buf, sizeof buf, fmt, 277 ipaddr_string(&dp->icmp_ip.ip_dst), 278 ipaddr_string(&dp->icmp_gwaddr)); 279 break; 280 281 case ICMP_ROUTERADVERT: 282 { 283 register const struct ih_rdiscovery *ihp; 284 register const struct id_rdiscovery *idp; 285 u_int lifetime, num, size; 286 287 (void)strncpy(buf, "router advertisement", sizeof buf-1); 288 buf[sizeof buf-1] = '\0'; 289 cp = buf + strlen(buf); 290 291 ihp = (struct ih_rdiscovery *)&dp->icmp_void; 292 TCHECK(*ihp); 293 (void)strcpy(cp, " lifetime "); 294 cp = buf + strlen(buf); 295 lifetime = EXTRACT_16BITS(&ihp->ird_lifetime); 296 if (lifetime < 60) 297 (void)snprintf(cp, buf + sizeof buf - cp, "%u", lifetime); 298 else if (lifetime < 60 * 60) 299 (void)snprintf(cp, buf + sizeof buf - cp, "%u:%02u", 300 lifetime / 60, lifetime % 60); 301 else 302 (void)snprintf(cp, buf + sizeof buf - cp, "%u:%02u:%02u", 303 lifetime / 3600, 304 (lifetime % 3600) / 60, 305 lifetime % 60); 306 cp = buf + strlen(buf); 307 308 num = ihp->ird_addrnum; 309 (void)snprintf(cp, buf + sizeof buf - cp, " %d:", num); 310 cp = buf + strlen(buf); 311 312 size = ihp->ird_addrsiz; 313 if (size != 2) { 314 (void)snprintf(cp, buf - sizeof buf - cp, 315 " [size %d]", size); 316 break; 317 } 318 idp = (struct id_rdiscovery *)&dp->icmp_data; 319 while (num-- > 0) { 320 TCHECK(*idp); 321 (void)snprintf(cp, buf + sizeof buf - cp, " {%s %u}", 322 ipaddr_string(&idp->ird_addr), 323 EXTRACT_32BITS(&idp->ird_pref)); 324 cp = buf + strlen(buf); 325 } 326 } 327 break; 328 329 case ICMP_TIMXCEED: 330 TCHECK(dp->icmp_ip.ip_dst); 331 switch (dp->icmp_code) { 332 333 case ICMP_TIMXCEED_INTRANS: 334 str = "time exceeded in-transit"; 335 break; 336 337 case ICMP_TIMXCEED_REASS: 338 str = "ip reassembly time exceeded"; 339 break; 340 341 default: 342 (void)snprintf(buf, sizeof buf, 343 "time exceeded-#%d", dp->icmp_code); 344 break; 345 } 346 break; 347 348 case ICMP_PARAMPROB: 349 switch (dp->icmp_code) { 350 case ICMP_PARAMPROB_OPTABSENT: 351 str = "requested option absent"; 352 break; 353 case ICMP_PARAMPROB_LENGTH: 354 snprintf(buf, sizeof buf, "bad length %d", dp->icmp_pptr); 355 break; 356 default: 357 TCHECK(dp->icmp_pptr); 358 (void)snprintf(buf, sizeof buf, 359 "parameter problem - octet %d", 360 dp->icmp_pptr); 361 break; 362 } 363 break; 364 365 case ICMP_MASKREPLY: 366 TCHECK(dp->icmp_mask); 367 (void)snprintf(buf, sizeof buf, "address mask is 0x%08x", 368 (u_int32_t)ntohl(dp->icmp_mask)); 369 break; 370 371 default: 372 str = tok2str(icmp2str, "type-#%d", dp->icmp_type); 373 break; 374 } 375 (void)printf("icmp: %s", str); 376 return; 377 trunc: 378 fputs("[|icmp]", stdout); 379 } 380