]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/print-icmp.c
This commit was generated by cvs2svn to compensate for changes in r132722,
[FreeBSD/FreeBSD.git] / contrib / tcpdump / print-icmp.c
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  * $FreeBSD$
22  */
23
24 #ifndef lint
25 static const char rcsid[] _U_ =
26     "@(#) $Header: /tcpdump/master/tcpdump/print-icmp.c,v 1.73.2.3 2004/03/24 00:56:34 guy Exp $ (LBL)";
27 #endif
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <tcpdump-stdinc.h>
34
35 #include <stdio.h>
36 #include <string.h>
37
38 #include "interface.h"
39 #include "addrtoname.h"
40 #include "extract.h"                    /* must come after interface.h */
41
42 #include "ip.h"
43 #include "udp.h"
44 #include "ipproto.h"
45
46 /*
47  * Interface Control Message Protocol Definitions.
48  * Per RFC 792, September 1981.
49  */
50
51 /*
52  * Structure of an icmp header.
53  */
54 struct icmp {
55         u_int8_t  icmp_type;            /* type of message, see below */
56         u_int8_t  icmp_code;            /* type sub code */
57         u_int16_t icmp_cksum;           /* ones complement cksum of struct */
58         union {
59                 u_int8_t ih_pptr;                       /* ICMP_PARAMPROB */
60                 struct in_addr ih_gwaddr;       /* ICMP_REDIRECT */
61                 struct ih_idseq {
62                         u_int16_t icd_id;
63                         u_int16_t icd_seq;
64                 } ih_idseq;
65                 u_int32_t ih_void;
66
67                 /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
68                 struct ih_pmtu {
69                         u_int16_t ipm_void;
70                         u_int16_t ipm_nextmtu;
71                 } ih_pmtu;
72         } icmp_hun;
73 #define icmp_pptr       icmp_hun.ih_pptr
74 #define icmp_gwaddr     icmp_hun.ih_gwaddr
75 #define icmp_id         icmp_hun.ih_idseq.icd_id
76 #define icmp_seq        icmp_hun.ih_idseq.icd_seq
77 #define icmp_void       icmp_hun.ih_void
78 #define icmp_pmvoid     icmp_hun.ih_pmtu.ipm_void
79 #define icmp_nextmtu    icmp_hun.ih_pmtu.ipm_nextmtu
80         union {
81                 struct id_ts {
82                         u_int32_t its_otime;
83                         u_int32_t its_rtime;
84                         u_int32_t its_ttime;
85                 } id_ts;
86                 struct id_ip  {
87                         struct ip idi_ip;
88                         /* options and then 64 bits of data */
89                 } id_ip;
90                 u_int32_t id_mask;
91                 u_int8_t id_data[1];
92         } icmp_dun;
93 #define icmp_otime      icmp_dun.id_ts.its_otime
94 #define icmp_rtime      icmp_dun.id_ts.its_rtime
95 #define icmp_ttime      icmp_dun.id_ts.its_ttime
96 #define icmp_ip         icmp_dun.id_ip.idi_ip
97 #define icmp_mask       icmp_dun.id_mask
98 #define icmp_data       icmp_dun.id_data
99 };
100
101 /*
102  * Lower bounds on packet lengths for various types.
103  * For the error advice packets must first insure that the
104  * packet is large enought to contain the returned ip header.
105  * Only then can we do the check to see if 64 bits of packet
106  * data have been returned, since we need to check the returned
107  * ip header length.
108  */
109 #define ICMP_MINLEN     8                               /* abs minimum */
110 #define ICMP_TSLEN      (8 + 3 * sizeof (u_int32_t))    /* timestamp */
111 #define ICMP_MASKLEN    12                              /* address mask */
112 #define ICMP_ADVLENMIN  (8 + sizeof (struct ip) + 8)    /* min */
113 #define ICMP_ADVLEN(p)  (8 + (IP_HL(&(p)->icmp_ip) << 2) + 8)
114         /* N.B.: must separately check that ip_hl >= 5 */
115
116 /*
117  * Definition of type and code field values.
118  */
119 #define ICMP_ECHOREPLY          0               /* echo reply */
120 #define ICMP_UNREACH            3               /* dest unreachable, codes: */
121 #define         ICMP_UNREACH_NET        0               /* bad net */
122 #define         ICMP_UNREACH_HOST       1               /* bad host */
123 #define         ICMP_UNREACH_PROTOCOL   2               /* bad protocol */
124 #define         ICMP_UNREACH_PORT       3               /* bad port */
125 #define         ICMP_UNREACH_NEEDFRAG   4               /* IP_DF caused drop */
126 #define         ICMP_UNREACH_SRCFAIL    5               /* src route failed */
127 #define         ICMP_UNREACH_NET_UNKNOWN 6              /* unknown net */
128 #define         ICMP_UNREACH_HOST_UNKNOWN 7             /* unknown host */
129 #define         ICMP_UNREACH_ISOLATED   8               /* src host isolated */
130 #define         ICMP_UNREACH_NET_PROHIB 9               /* prohibited access */
131 #define         ICMP_UNREACH_HOST_PROHIB 10             /* ditto */
132 #define         ICMP_UNREACH_TOSNET     11              /* bad tos for net */
133 #define         ICMP_UNREACH_TOSHOST    12              /* bad tos for host */
134 #define ICMP_SOURCEQUENCH       4               /* packet lost, slow down */
135 #define ICMP_REDIRECT           5               /* shorter route, codes: */
136 #define         ICMP_REDIRECT_NET       0               /* for network */
137 #define         ICMP_REDIRECT_HOST      1               /* for host */
138 #define         ICMP_REDIRECT_TOSNET    2               /* for tos and net */
139 #define         ICMP_REDIRECT_TOSHOST   3               /* for tos and host */
140 #define ICMP_ECHO               8               /* echo service */
141 #define ICMP_ROUTERADVERT       9               /* router advertisement */
142 #define ICMP_ROUTERSOLICIT      10              /* router solicitation */
143 #define ICMP_TIMXCEED           11              /* time exceeded, code: */
144 #define         ICMP_TIMXCEED_INTRANS   0               /* ttl==0 in transit */
145 #define         ICMP_TIMXCEED_REASS     1               /* ttl==0 in reass */
146 #define ICMP_PARAMPROB          12              /* ip header bad */
147 #define         ICMP_PARAMPROB_OPTABSENT 1              /* req. opt. absent */
148 #define ICMP_TSTAMP             13              /* timestamp request */
149 #define ICMP_TSTAMPREPLY        14              /* timestamp reply */
150 #define ICMP_IREQ               15              /* information request */
151 #define ICMP_IREQREPLY          16              /* information reply */
152 #define ICMP_MASKREQ            17              /* address mask request */
153 #define ICMP_MASKREPLY          18              /* address mask reply */
154
155 #define ICMP_MAXTYPE            18
156
157 #define ICMP_INFOTYPE(type) \
158         ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
159         (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \
160         (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
161         (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
162         (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
163 /* rfc1700 */
164 #ifndef ICMP_UNREACH_NET_UNKNOWN
165 #define ICMP_UNREACH_NET_UNKNOWN        6       /* destination net unknown */
166 #endif
167 #ifndef ICMP_UNREACH_HOST_UNKNOWN
168 #define ICMP_UNREACH_HOST_UNKNOWN       7       /* destination host unknown */
169 #endif
170 #ifndef ICMP_UNREACH_ISOLATED
171 #define ICMP_UNREACH_ISOLATED           8       /* source host isolated */
172 #endif
173 #ifndef ICMP_UNREACH_NET_PROHIB
174 #define ICMP_UNREACH_NET_PROHIB         9       /* admin prohibited net */
175 #endif
176 #ifndef ICMP_UNREACH_HOST_PROHIB
177 #define ICMP_UNREACH_HOST_PROHIB        10      /* admin prohibited host */
178 #endif
179 #ifndef ICMP_UNREACH_TOSNET
180 #define ICMP_UNREACH_TOSNET             11      /* tos prohibited net */
181 #endif
182 #ifndef ICMP_UNREACH_TOSHOST
183 #define ICMP_UNREACH_TOSHOST            12      /* tos prohibited host */
184 #endif
185
186 /* rfc1716 */
187 #ifndef ICMP_UNREACH_FILTER_PROHIB
188 #define ICMP_UNREACH_FILTER_PROHIB      13      /* admin prohibited filter */
189 #endif
190 #ifndef ICMP_UNREACH_HOST_PRECEDENCE
191 #define ICMP_UNREACH_HOST_PRECEDENCE    14      /* host precedence violation */
192 #endif
193 #ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
194 #define ICMP_UNREACH_PRECEDENCE_CUTOFF  15      /* precedence cutoff */
195 #endif
196
197 /* Most of the icmp types */
198 static struct tok icmp2str[] = {
199         { ICMP_ECHOREPLY,               "echo reply" },
200         { ICMP_SOURCEQUENCH,            "source quench" },
201         { ICMP_ECHO,                    "echo request" },
202         { ICMP_ROUTERSOLICIT,           "router solicitation" },
203         { ICMP_TSTAMP,                  "time stamp request" },
204         { ICMP_TSTAMPREPLY,             "time stamp reply" },
205         { ICMP_IREQ,                    "information request" },
206         { ICMP_IREQREPLY,               "information reply" },
207         { ICMP_MASKREQ,                 "address mask request" },
208         { 0,                            NULL }
209 };
210
211 /* Formats for most of the ICMP_UNREACH codes */
212 static struct tok unreach2str[] = {
213         { ICMP_UNREACH_NET,             "net %s unreachable" },
214         { ICMP_UNREACH_HOST,            "host %s unreachable" },
215         { ICMP_UNREACH_SRCFAIL,
216             "%s unreachable - source route failed" },
217         { ICMP_UNREACH_NET_UNKNOWN,     "net %s unreachable - unknown" },
218         { ICMP_UNREACH_HOST_UNKNOWN,    "host %s unreachable - unknown" },
219         { ICMP_UNREACH_ISOLATED,
220             "%s unreachable - source host isolated" },
221         { ICMP_UNREACH_NET_PROHIB,
222             "net %s unreachable - admin prohibited" },
223         { ICMP_UNREACH_HOST_PROHIB,
224             "host %s unreachable - admin prohibited" },
225         { ICMP_UNREACH_TOSNET,
226             "net %s unreachable - tos prohibited" },
227         { ICMP_UNREACH_TOSHOST,
228             "host %s unreachable - tos prohibited" },
229         { ICMP_UNREACH_FILTER_PROHIB,
230             "host %s unreachable - admin prohibited filter" },
231         { ICMP_UNREACH_HOST_PRECEDENCE,
232             "host %s unreachable - host precedence violation" },
233         { ICMP_UNREACH_PRECEDENCE_CUTOFF,
234             "host %s unreachable - precedence cutoff" },
235         { 0,                            NULL }
236 };
237
238 /* Formats for the ICMP_REDIRECT codes */
239 static struct tok type2str[] = {
240         { ICMP_REDIRECT_NET,            "redirect %s to net %s" },
241         { ICMP_REDIRECT_HOST,           "redirect %s to host %s" },
242         { ICMP_REDIRECT_TOSNET,         "redirect-tos %s to net %s" },
243         { ICMP_REDIRECT_TOSHOST,        "redirect-tos %s to host %s" },
244         { 0,                            NULL }
245 };
246
247 /* rfc1191 */
248 struct mtu_discovery {
249         u_int16_t unused;
250         u_int16_t nexthopmtu;
251 };
252
253 /* rfc1256 */
254 struct ih_rdiscovery {
255         u_int8_t ird_addrnum;
256         u_int8_t ird_addrsiz;
257         u_int16_t ird_lifetime;
258 };
259
260 struct id_rdiscovery {
261         u_int32_t ird_addr;
262         u_int32_t ird_pref;
263 };
264
265 void
266 icmp_print(const u_char *bp, u_int plen, const u_char *bp2, int fragmented)
267 {
268         char *cp;
269         const struct icmp *dp;
270         const struct ip *ip;
271         const char *str, *fmt;
272         const struct ip *oip;
273         const struct udphdr *ouh;
274         u_int hlen, dport, mtu;
275         char buf[MAXHOSTNAMELEN + 100];
276
277         dp = (struct icmp *)bp;
278         ip = (struct ip *)bp2;
279         str = buf;
280
281         TCHECK(dp->icmp_code);
282         switch (dp->icmp_type) {
283
284         case ICMP_ECHO:
285         case ICMP_ECHOREPLY:
286                 TCHECK(dp->icmp_seq);
287                 (void)snprintf(buf, sizeof(buf), "echo %s seq %u",
288                         dp->icmp_type == ICMP_ECHO ?
289                         "request" : "reply",
290                         EXTRACT_16BITS(&dp->icmp_seq));
291                 break;
292
293         case ICMP_UNREACH:
294                 TCHECK(dp->icmp_ip.ip_dst);
295                 switch (dp->icmp_code) {
296
297                 case ICMP_UNREACH_PROTOCOL:
298                         TCHECK(dp->icmp_ip.ip_p);
299                         (void)snprintf(buf, sizeof(buf),
300                             "%s protocol %d unreachable",
301                             ipaddr_string(&dp->icmp_ip.ip_dst),
302                             dp->icmp_ip.ip_p);
303                         break;
304
305                 case ICMP_UNREACH_PORT:
306                         TCHECK(dp->icmp_ip.ip_p);
307                         oip = &dp->icmp_ip;
308                         hlen = IP_HL(oip) * 4;
309                         ouh = (struct udphdr *)(((u_char *)oip) + hlen);
310                         TCHECK(ouh->uh_dport);
311                         dport = EXTRACT_16BITS(&ouh->uh_dport);
312                         switch (oip->ip_p) {
313
314                         case IPPROTO_TCP:
315                                 (void)snprintf(buf, sizeof(buf),
316                                         "%s tcp port %s unreachable",
317                                         ipaddr_string(&oip->ip_dst),
318                                         tcpport_string(dport));
319                                 break;
320
321                         case IPPROTO_UDP:
322                                 (void)snprintf(buf, sizeof(buf),
323                                         "%s udp port %s unreachable",
324                                         ipaddr_string(&oip->ip_dst),
325                                         udpport_string(dport));
326                                 break;
327
328                         default:
329                                 (void)snprintf(buf, sizeof(buf),
330                                         "%s protocol %d port %d unreachable",
331                                         ipaddr_string(&oip->ip_dst),
332                                         oip->ip_p, dport);
333                                 break;
334                         }
335                         break;
336
337                 case ICMP_UNREACH_NEEDFRAG:
338                     {
339                         register const struct mtu_discovery *mp;
340                         mp = (struct mtu_discovery *)&dp->icmp_void;
341                         mtu = EXTRACT_16BITS(&mp->nexthopmtu);
342                         if (mtu) {
343                                 (void)snprintf(buf, sizeof(buf),
344                                     "%s unreachable - need to frag (mtu %d)",
345                                     ipaddr_string(&dp->icmp_ip.ip_dst), mtu);
346                         } else {
347                                 (void)snprintf(buf, sizeof(buf),
348                                     "%s unreachable - need to frag",
349                                     ipaddr_string(&dp->icmp_ip.ip_dst));
350                         }
351                     }
352                         break;
353
354                 default:
355                         fmt = tok2str(unreach2str, "#%d %%s unreachable",
356                             dp->icmp_code);
357                         (void)snprintf(buf, sizeof(buf), fmt,
358                             ipaddr_string(&dp->icmp_ip.ip_dst));
359                         break;
360                 }
361                 break;
362
363         case ICMP_REDIRECT:
364                 TCHECK(dp->icmp_ip.ip_dst);
365                 fmt = tok2str(type2str, "redirect-#%d %%s to net %%s",
366                     dp->icmp_code);
367                 (void)snprintf(buf, sizeof(buf), fmt,
368                     ipaddr_string(&dp->icmp_ip.ip_dst),
369                     ipaddr_string(&dp->icmp_gwaddr));
370                 break;
371
372         case ICMP_ROUTERADVERT:
373             {
374                 register const struct ih_rdiscovery *ihp;
375                 register const struct id_rdiscovery *idp;
376                 u_int lifetime, num, size;
377
378                 (void)snprintf(buf, sizeof(buf), "router advertisement");
379                 cp = buf + strlen(buf);
380
381                 ihp = (struct ih_rdiscovery *)&dp->icmp_void;
382                 TCHECK(*ihp);
383                 (void)strncpy(cp, " lifetime ", sizeof(buf) - (cp - buf));
384                 cp = buf + strlen(buf);
385                 lifetime = EXTRACT_16BITS(&ihp->ird_lifetime);
386                 if (lifetime < 60) {
387                         (void)snprintf(cp, sizeof(buf) - (cp - buf), "%u",
388                             lifetime);
389                 } else if (lifetime < 60 * 60) {
390                         (void)snprintf(cp, sizeof(buf) - (cp - buf), "%u:%02u",
391                             lifetime / 60, lifetime % 60);
392                 } else {
393                         (void)snprintf(cp, sizeof(buf) - (cp - buf),
394                             "%u:%02u:%02u",
395                             lifetime / 3600,
396                             (lifetime % 3600) / 60,
397                             lifetime % 60);
398                 }
399                 cp = buf + strlen(buf);
400
401                 num = ihp->ird_addrnum;
402                 (void)snprintf(cp, sizeof(buf) - (cp - buf), " %d:", num);
403                 cp = buf + strlen(buf);
404
405                 size = ihp->ird_addrsiz;
406                 if (size != 2) {
407                         (void)snprintf(cp, sizeof(buf) - (cp - buf),
408                             " [size %d]", size);
409                         break;
410                 }
411                 idp = (struct id_rdiscovery *)&dp->icmp_data;
412                 while (num-- > 0) {
413                         TCHECK(*idp);
414                         (void)snprintf(cp, sizeof(buf) - (cp - buf), " {%s %u}",
415                             ipaddr_string(&idp->ird_addr),
416                             EXTRACT_32BITS(&idp->ird_pref));
417                         cp = buf + strlen(buf);
418                         ++idp;
419                 }
420             }
421                 break;
422
423         case ICMP_TIMXCEED:
424                 TCHECK(dp->icmp_ip.ip_dst);
425                 switch (dp->icmp_code) {
426
427                 case ICMP_TIMXCEED_INTRANS:
428                         str = "time exceeded in-transit";
429                         break;
430
431                 case ICMP_TIMXCEED_REASS:
432                         str = "ip reassembly time exceeded";
433                         break;
434
435                 default:
436                         (void)snprintf(buf, sizeof(buf), "time exceeded-#%d",
437                             dp->icmp_code);
438                         break;
439                 }
440                 break;
441
442         case ICMP_PARAMPROB:
443                 if (dp->icmp_code)
444                         (void)snprintf(buf, sizeof(buf),
445                             "parameter problem - code %d", dp->icmp_code);
446                 else {
447                         TCHECK(dp->icmp_pptr);
448                         (void)snprintf(buf, sizeof(buf),
449                             "parameter problem - octet %d", dp->icmp_pptr);
450                 }
451                 break;
452
453         case ICMP_MASKREPLY:
454                 TCHECK(dp->icmp_mask);
455                 (void)snprintf(buf, sizeof(buf), "address mask is 0x%08x",
456                     EXTRACT_32BITS(&dp->icmp_mask));
457                 break;
458
459         case ICMP_TSTAMP:
460                 TCHECK(dp->icmp_seq);
461                 (void)snprintf(buf, sizeof(buf),
462                     "time stamp query id %u seq %u",
463                     EXTRACT_16BITS(&dp->icmp_id),
464                     EXTRACT_16BITS(&dp->icmp_seq));
465                 break;
466
467         case ICMP_TSTAMPREPLY:
468                 TCHECK(dp->icmp_ttime);
469                 (void)snprintf(buf, sizeof(buf),
470                     "time stamp reply id %u seq %u : org 0x%x recv 0x%x xmit 0x%x",
471                     EXTRACT_16BITS(&dp->icmp_id),
472                     EXTRACT_16BITS(&dp->icmp_seq),
473                     EXTRACT_32BITS(&dp->icmp_otime),
474                     EXTRACT_32BITS(&dp->icmp_rtime),
475                     EXTRACT_32BITS(&dp->icmp_ttime));
476                 break;
477
478         default:
479                 str = tok2str(icmp2str, "type-#%d", dp->icmp_type);
480                 break;
481         }
482         (void)printf("icmp %d: %s", plen, str);
483         if (vflag && !fragmented) { /* don't attempt checksumming if this is a frag */
484                 u_int16_t sum, icmp_sum;
485                 if (TTEST2(*bp, plen)) {
486                         sum = in_cksum((u_short*)dp, plen, 0);
487                         if (sum != 0) {
488                                 icmp_sum = EXTRACT_16BITS(&dp->icmp_cksum);
489                                 (void)printf(" (wrong icmp cksum %x (->%x)!)",
490                                              icmp_sum,
491                                              in_cksum_shouldbe(icmp_sum, sum));
492                         }
493                 }
494         }
495         if (vflag > 1 && !ICMP_INFOTYPE(dp->icmp_type)) {
496                 bp += 8;
497                 (void)printf(" for ");
498                 ip = (struct ip *)bp;
499                 snaplen = snapend - bp;
500                 ip_print(bp, EXTRACT_16BITS(&ip->ip_len));
501         }
502         return;
503 trunc:
504         fputs("[|icmp]", stdout);
505 }