nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 | |||
22 | #define NETDISSECT_REWORKED |
||
23 | #ifdef HAVE_CONFIG_H |
||
24 | #include "config.h" |
||
25 | #endif |
||
26 | |||
27 | #include <tcpdump-stdinc.h> |
||
28 | |||
29 | #include <stdio.h> |
||
30 | #include <string.h> |
||
31 | |||
32 | #include "interface.h" |
||
33 | #include "addrtoname.h" |
||
34 | #include "extract.h" /* must come after interface.h */ |
||
35 | |||
36 | #include "ip.h" |
||
37 | #include "udp.h" |
||
38 | #include "ipproto.h" |
||
39 | #include "mpls.h" |
||
40 | |||
41 | /* |
||
42 | * Interface Control Message Protocol Definitions. |
||
43 | * Per RFC 792, September 1981. |
||
44 | */ |
||
45 | |||
46 | /* |
||
47 | * Structure of an icmp header. |
||
48 | */ |
||
49 | struct icmp { |
||
50 | uint8_t icmp_type; /* type of message, see below */ |
||
51 | uint8_t icmp_code; /* type sub code */ |
||
52 | uint16_t icmp_cksum; /* ones complement cksum of struct */ |
||
53 | union { |
||
54 | uint8_t ih_pptr; /* ICMP_PARAMPROB */ |
||
55 | struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ |
||
56 | struct ih_idseq { |
||
57 | uint16_t icd_id; |
||
58 | uint16_t icd_seq; |
||
59 | } ih_idseq; |
||
60 | uint32_t ih_void; |
||
61 | } icmp_hun; |
||
62 | #define icmp_pptr icmp_hun.ih_pptr |
||
63 | #define icmp_gwaddr icmp_hun.ih_gwaddr |
||
64 | #define icmp_id icmp_hun.ih_idseq.icd_id |
||
65 | #define icmp_seq icmp_hun.ih_idseq.icd_seq |
||
66 | #define icmp_void icmp_hun.ih_void |
||
67 | union { |
||
68 | struct id_ts { |
||
69 | uint32_t its_otime; |
||
70 | uint32_t its_rtime; |
||
71 | uint32_t its_ttime; |
||
72 | } id_ts; |
||
73 | struct id_ip { |
||
74 | struct ip idi_ip; |
||
75 | /* options and then 64 bits of data */ |
||
76 | } id_ip; |
||
77 | uint32_t id_mask; |
||
78 | uint8_t id_data[1]; |
||
79 | } icmp_dun; |
||
80 | #define icmp_otime icmp_dun.id_ts.its_otime |
||
81 | #define icmp_rtime icmp_dun.id_ts.its_rtime |
||
82 | #define icmp_ttime icmp_dun.id_ts.its_ttime |
||
83 | #define icmp_ip icmp_dun.id_ip.idi_ip |
||
84 | #define icmp_mask icmp_dun.id_mask |
||
85 | #define icmp_data icmp_dun.id_data |
||
86 | }; |
||
87 | |||
88 | #define ICMP_MPLS_EXT_EXTRACT_VERSION(x) (((x)&0xf0)>>4) |
||
89 | #define ICMP_MPLS_EXT_VERSION 2 |
||
90 | |||
91 | /* |
||
92 | * Lower bounds on packet lengths for various types. |
||
93 | * For the error advice packets must first insure that the |
||
94 | * packet is large enought to contain the returned ip header. |
||
95 | * Only then can we do the check to see if 64 bits of packet |
||
96 | * data have been returned, since we need to check the returned |
||
97 | * ip header length. |
||
98 | */ |
||
99 | #define ICMP_MINLEN 8 /* abs minimum */ |
||
100 | #define ICMP_EXTD_MINLEN (156 - sizeof (struct ip)) /* draft-bonica-internet-icmp-08 */ |
||
101 | #define ICMP_TSLEN (8 + 3 * sizeof (uint32_t)) /* timestamp */ |
||
102 | #define ICMP_MASKLEN 12 /* address mask */ |
||
103 | #define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ |
||
104 | #define ICMP_ADVLEN(p) (8 + (IP_HL(&(p)->icmp_ip) << 2) + 8) |
||
105 | /* N.B.: must separately check that ip_hl >= 5 */ |
||
106 | |||
107 | /* |
||
108 | * Definition of type and code field values. |
||
109 | */ |
||
110 | #define ICMP_ECHOREPLY 0 /* echo reply */ |
||
111 | #define ICMP_UNREACH 3 /* dest unreachable, codes: */ |
||
112 | #define ICMP_UNREACH_NET 0 /* bad net */ |
||
113 | #define ICMP_UNREACH_HOST 1 /* bad host */ |
||
114 | #define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ |
||
115 | #define ICMP_UNREACH_PORT 3 /* bad port */ |
||
116 | #define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ |
||
117 | #define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ |
||
118 | #define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ |
||
119 | #define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ |
||
120 | #define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ |
||
121 | #define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ |
||
122 | #define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ |
||
123 | #define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ |
||
124 | #define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ |
||
125 | #define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ |
||
126 | #define ICMP_REDIRECT 5 /* shorter route, codes: */ |
||
127 | #define ICMP_REDIRECT_NET 0 /* for network */ |
||
128 | #define ICMP_REDIRECT_HOST 1 /* for host */ |
||
129 | #define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ |
||
130 | #define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ |
||
131 | #define ICMP_ECHO 8 /* echo service */ |
||
132 | #define ICMP_ROUTERADVERT 9 /* router advertisement */ |
||
133 | #define ICMP_ROUTERSOLICIT 10 /* router solicitation */ |
||
134 | #define ICMP_TIMXCEED 11 /* time exceeded, code: */ |
||
135 | #define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ |
||
136 | #define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ |
||
137 | #define ICMP_PARAMPROB 12 /* ip header bad */ |
||
138 | #define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ |
||
139 | #define ICMP_TSTAMP 13 /* timestamp request */ |
||
140 | #define ICMP_TSTAMPREPLY 14 /* timestamp reply */ |
||
141 | #define ICMP_IREQ 15 /* information request */ |
||
142 | #define ICMP_IREQREPLY 16 /* information reply */ |
||
143 | #define ICMP_MASKREQ 17 /* address mask request */ |
||
144 | #define ICMP_MASKREPLY 18 /* address mask reply */ |
||
145 | |||
146 | #define ICMP_MAXTYPE 18 |
||
147 | |||
148 | #define ICMP_ERRTYPE(type) \ |
||
149 | ((type) == ICMP_UNREACH || (type) == ICMP_SOURCEQUENCH || \ |
||
150 | (type) == ICMP_REDIRECT || (type) == ICMP_TIMXCEED || \ |
||
151 | (type) == ICMP_PARAMPROB) |
||
152 | #define ICMP_MPLS_EXT_TYPE(type) \ |
||
153 | ((type) == ICMP_UNREACH || \ |
||
154 | (type) == ICMP_TIMXCEED || \ |
||
155 | (type) == ICMP_PARAMPROB) |
||
156 | /* rfc1700 */ |
||
157 | #ifndef ICMP_UNREACH_NET_UNKNOWN |
||
158 | #define ICMP_UNREACH_NET_UNKNOWN 6 /* destination net unknown */ |
||
159 | #endif |
||
160 | #ifndef ICMP_UNREACH_HOST_UNKNOWN |
||
161 | #define ICMP_UNREACH_HOST_UNKNOWN 7 /* destination host unknown */ |
||
162 | #endif |
||
163 | #ifndef ICMP_UNREACH_ISOLATED |
||
164 | #define ICMP_UNREACH_ISOLATED 8 /* source host isolated */ |
||
165 | #endif |
||
166 | #ifndef ICMP_UNREACH_NET_PROHIB |
||
167 | #define ICMP_UNREACH_NET_PROHIB 9 /* admin prohibited net */ |
||
168 | #endif |
||
169 | #ifndef ICMP_UNREACH_HOST_PROHIB |
||
170 | #define ICMP_UNREACH_HOST_PROHIB 10 /* admin prohibited host */ |
||
171 | #endif |
||
172 | #ifndef ICMP_UNREACH_TOSNET |
||
173 | #define ICMP_UNREACH_TOSNET 11 /* tos prohibited net */ |
||
174 | #endif |
||
175 | #ifndef ICMP_UNREACH_TOSHOST |
||
176 | #define ICMP_UNREACH_TOSHOST 12 /* tos prohibited host */ |
||
177 | #endif |
||
178 | |||
179 | /* rfc1716 */ |
||
180 | #ifndef ICMP_UNREACH_FILTER_PROHIB |
||
181 | #define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */ |
||
182 | #endif |
||
183 | #ifndef ICMP_UNREACH_HOST_PRECEDENCE |
||
184 | #define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host precedence violation */ |
||
185 | #endif |
||
186 | #ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF |
||
187 | #define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* precedence cutoff */ |
||
188 | #endif |
||
189 | |||
190 | /* Most of the icmp types */ |
||
191 | static const struct tok icmp2str[] = { |
||
192 | { ICMP_ECHOREPLY, "echo reply" }, |
||
193 | { ICMP_SOURCEQUENCH, "source quench" }, |
||
194 | { ICMP_ECHO, "echo request" }, |
||
195 | { ICMP_ROUTERSOLICIT, "router solicitation" }, |
||
196 | { ICMP_TSTAMP, "time stamp request" }, |
||
197 | { ICMP_TSTAMPREPLY, "time stamp reply" }, |
||
198 | { ICMP_IREQ, "information request" }, |
||
199 | { ICMP_IREQREPLY, "information reply" }, |
||
200 | { ICMP_MASKREQ, "address mask request" }, |
||
201 | { 0, NULL } |
||
202 | }; |
||
203 | |||
204 | /* Formats for most of the ICMP_UNREACH codes */ |
||
205 | static const struct tok unreach2str[] = { |
||
206 | { ICMP_UNREACH_NET, "net %s unreachable" }, |
||
207 | { ICMP_UNREACH_HOST, "host %s unreachable" }, |
||
208 | { ICMP_UNREACH_SRCFAIL, |
||
209 | "%s unreachable - source route failed" }, |
||
210 | { ICMP_UNREACH_NET_UNKNOWN, "net %s unreachable - unknown" }, |
||
211 | { ICMP_UNREACH_HOST_UNKNOWN, "host %s unreachable - unknown" }, |
||
212 | { ICMP_UNREACH_ISOLATED, |
||
213 | "%s unreachable - source host isolated" }, |
||
214 | { ICMP_UNREACH_NET_PROHIB, |
||
215 | "net %s unreachable - admin prohibited" }, |
||
216 | { ICMP_UNREACH_HOST_PROHIB, |
||
217 | "host %s unreachable - admin prohibited" }, |
||
218 | { ICMP_UNREACH_TOSNET, |
||
219 | "net %s unreachable - tos prohibited" }, |
||
220 | { ICMP_UNREACH_TOSHOST, |
||
221 | "host %s unreachable - tos prohibited" }, |
||
222 | { ICMP_UNREACH_FILTER_PROHIB, |
||
223 | "host %s unreachable - admin prohibited filter" }, |
||
224 | { ICMP_UNREACH_HOST_PRECEDENCE, |
||
225 | "host %s unreachable - host precedence violation" }, |
||
226 | { ICMP_UNREACH_PRECEDENCE_CUTOFF, |
||
227 | "host %s unreachable - precedence cutoff" }, |
||
228 | { 0, NULL } |
||
229 | }; |
||
230 | |||
231 | /* Formats for the ICMP_REDIRECT codes */ |
||
232 | static const struct tok type2str[] = { |
||
233 | { ICMP_REDIRECT_NET, "redirect %s to net %s" }, |
||
234 | { ICMP_REDIRECT_HOST, "redirect %s to host %s" }, |
||
235 | { ICMP_REDIRECT_TOSNET, "redirect-tos %s to net %s" }, |
||
236 | { ICMP_REDIRECT_TOSHOST, "redirect-tos %s to host %s" }, |
||
237 | { 0, NULL } |
||
238 | }; |
||
239 | |||
240 | /* rfc1191 */ |
||
241 | struct mtu_discovery { |
||
242 | uint16_t unused; |
||
243 | uint16_t nexthopmtu; |
||
244 | }; |
||
245 | |||
246 | /* rfc1256 */ |
||
247 | struct ih_rdiscovery { |
||
248 | uint8_t ird_addrnum; |
||
249 | uint8_t ird_addrsiz; |
||
250 | uint16_t ird_lifetime; |
||
251 | }; |
||
252 | |||
253 | struct id_rdiscovery { |
||
254 | uint32_t ird_addr; |
||
255 | uint32_t ird_pref; |
||
256 | }; |
||
257 | |||
258 | /* |
||
259 | * draft-bonica-internet-icmp-08 |
||
260 | * |
||
261 | * The Destination Unreachable, Time Exceeded |
||
262 | * and Parameter Problem messages are slighly changed as per |
||
263 | * the above draft. A new Length field gets added to give |
||
264 | * the caller an idea about the length of the piggypacked |
||
265 | * IP packet before the MPLS extension header starts. |
||
266 | * |
||
267 | * The Length field represents length of the padded "original datagram" |
||
268 | * field measured in 32-bit words. |
||
269 | * |
||
270 | * 0 1 2 3 |
||
271 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
||
272 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
||
273 | * | Type | Code | Checksum | |
||
274 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
||
275 | * | unused | Length | unused | |
||
276 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
||
277 | * | Internet Header + leading octets of original datagram | |
||
278 | * | | |
||
279 | * | // | |
||
280 | * | | |
||
281 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
||
282 | */ |
||
283 | |||
284 | struct icmp_ext_t { |
||
285 | uint8_t icmp_type; |
||
286 | uint8_t icmp_code; |
||
287 | uint8_t icmp_checksum[2]; |
||
288 | uint8_t icmp_reserved; |
||
289 | uint8_t icmp_length; |
||
290 | uint8_t icmp_reserved2[2]; |
||
291 | uint8_t icmp_ext_legacy_header[128]; /* extension header starts 128 bytes after ICMP header */ |
||
292 | uint8_t icmp_ext_version_res[2]; |
||
293 | uint8_t icmp_ext_checksum[2]; |
||
294 | uint8_t icmp_ext_data[1]; |
||
295 | }; |
||
296 | |||
297 | struct icmp_mpls_ext_object_header_t { |
||
298 | uint8_t length[2]; |
||
299 | uint8_t class_num; |
||
300 | uint8_t ctype; |
||
301 | }; |
||
302 | |||
303 | static const struct tok icmp_mpls_ext_obj_values[] = { |
||
304 | { 1, "MPLS Stack Entry" }, |
||
305 | { 2, "Extended Payload" }, |
||
306 | { 0, NULL} |
||
307 | }; |
||
308 | |||
309 | /* prototypes */ |
||
310 | const char *icmp_tstamp_print(u_int); |
||
311 | |||
312 | /* print the milliseconds since midnight UTC */ |
||
313 | const char * |
||
314 | icmp_tstamp_print(u_int tstamp) |
||
315 | { |
||
316 | u_int msec,sec,min,hrs; |
||
317 | |||
318 | static char buf[64]; |
||
319 | |||
320 | msec = tstamp % 1000; |
||
321 | sec = tstamp / 1000; |
||
322 | min = sec / 60; sec -= min * 60; |
||
323 | hrs = min / 60; min -= hrs * 60; |
||
324 | snprintf(buf, sizeof(buf), "%02u:%02u:%02u.%03u",hrs,min,sec,msec); |
||
325 | return buf; |
||
326 | } |
||
327 | |||
328 | void |
||
329 | icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, const u_char *bp2, |
||
330 | int fragmented) |
||
331 | { |
||
332 | char *cp; |
||
333 | const struct icmp *dp; |
||
334 | const struct icmp_ext_t *ext_dp; |
||
335 | const struct ip *ip; |
||
336 | const char *str, *fmt; |
||
337 | const struct ip *oip; |
||
338 | const struct udphdr *ouh; |
||
339 | const uint8_t *obj_tptr; |
||
340 | uint32_t raw_label; |
||
341 | const u_char *snapend_save; |
||
342 | const struct icmp_mpls_ext_object_header_t *icmp_mpls_ext_object_header; |
||
343 | u_int hlen, dport, mtu, obj_tlen, obj_class_num, obj_ctype; |
||
344 | char buf[MAXHOSTNAMELEN + 100]; |
||
345 | struct cksum_vec vec[1]; |
||
346 | |||
347 | dp = (struct icmp *)bp; |
||
348 | ext_dp = (struct icmp_ext_t *)bp; |
||
349 | ip = (struct ip *)bp2; |
||
350 | str = buf; |
||
351 | |||
352 | ND_TCHECK(dp->icmp_code); |
||
353 | switch (dp->icmp_type) { |
||
354 | |||
355 | case ICMP_ECHO: |
||
356 | case ICMP_ECHOREPLY: |
||
357 | ND_TCHECK(dp->icmp_seq); |
||
358 | (void)snprintf(buf, sizeof(buf), "echo %s, id %u, seq %u", |
||
359 | dp->icmp_type == ICMP_ECHO ? |
||
360 | "request" : "reply", |
||
361 | EXTRACT_16BITS(&dp->icmp_id), |
||
362 | EXTRACT_16BITS(&dp->icmp_seq)); |
||
363 | break; |
||
364 | |||
365 | case ICMP_UNREACH: |
||
366 | ND_TCHECK(dp->icmp_ip.ip_dst); |
||
367 | switch (dp->icmp_code) { |
||
368 | |||
369 | case ICMP_UNREACH_PROTOCOL: |
||
370 | ND_TCHECK(dp->icmp_ip.ip_p); |
||
371 | (void)snprintf(buf, sizeof(buf), |
||
372 | "%s protocol %d unreachable", |
||
373 | ipaddr_string(ndo, &dp->icmp_ip.ip_dst), |
||
374 | dp->icmp_ip.ip_p); |
||
375 | break; |
||
376 | |||
377 | case ICMP_UNREACH_PORT: |
||
378 | ND_TCHECK(dp->icmp_ip.ip_p); |
||
379 | oip = &dp->icmp_ip; |
||
380 | hlen = IP_HL(oip) * 4; |
||
381 | ouh = (struct udphdr *)(((u_char *)oip) + hlen); |
||
382 | ND_TCHECK(ouh->uh_dport); |
||
383 | dport = EXTRACT_16BITS(&ouh->uh_dport); |
||
384 | switch (oip->ip_p) { |
||
385 | |||
386 | case IPPROTO_TCP: |
||
387 | (void)snprintf(buf, sizeof(buf), |
||
388 | "%s tcp port %s unreachable", |
||
389 | ipaddr_string(ndo, &oip->ip_dst), |
||
390 | tcpport_string(dport)); |
||
391 | break; |
||
392 | |||
393 | case IPPROTO_UDP: |
||
394 | (void)snprintf(buf, sizeof(buf), |
||
395 | "%s udp port %s unreachable", |
||
396 | ipaddr_string(ndo, &oip->ip_dst), |
||
397 | udpport_string(dport)); |
||
398 | break; |
||
399 | |||
400 | default: |
||
401 | (void)snprintf(buf, sizeof(buf), |
||
402 | "%s protocol %d port %d unreachable", |
||
403 | ipaddr_string(ndo, &oip->ip_dst), |
||
404 | oip->ip_p, dport); |
||
405 | break; |
||
406 | } |
||
407 | break; |
||
408 | |||
409 | case ICMP_UNREACH_NEEDFRAG: |
||
410 | { |
||
411 | register const struct mtu_discovery *mp; |
||
412 | mp = (struct mtu_discovery *)(u_char *)&dp->icmp_void; |
||
413 | mtu = EXTRACT_16BITS(&mp->nexthopmtu); |
||
414 | if (mtu) { |
||
415 | (void)snprintf(buf, sizeof(buf), |
||
416 | "%s unreachable - need to frag (mtu %d)", |
||
417 | ipaddr_string(ndo, &dp->icmp_ip.ip_dst), mtu); |
||
418 | } else { |
||
419 | (void)snprintf(buf, sizeof(buf), |
||
420 | "%s unreachable - need to frag", |
||
421 | ipaddr_string(ndo, &dp->icmp_ip.ip_dst)); |
||
422 | } |
||
423 | } |
||
424 | break; |
||
425 | |||
426 | default: |
||
427 | fmt = tok2str(unreach2str, "#%d %%s unreachable", |
||
428 | dp->icmp_code); |
||
429 | (void)snprintf(buf, sizeof(buf), fmt, |
||
430 | ipaddr_string(ndo, &dp->icmp_ip.ip_dst)); |
||
431 | break; |
||
432 | } |
||
433 | break; |
||
434 | |||
435 | case ICMP_REDIRECT: |
||
436 | ND_TCHECK(dp->icmp_ip.ip_dst); |
||
437 | fmt = tok2str(type2str, "redirect-#%d %%s to net %%s", |
||
438 | dp->icmp_code); |
||
439 | (void)snprintf(buf, sizeof(buf), fmt, |
||
440 | ipaddr_string(ndo, &dp->icmp_ip.ip_dst), |
||
441 | ipaddr_string(ndo, &dp->icmp_gwaddr)); |
||
442 | break; |
||
443 | |||
444 | case ICMP_ROUTERADVERT: |
||
445 | { |
||
446 | register const struct ih_rdiscovery *ihp; |
||
447 | register const struct id_rdiscovery *idp; |
||
448 | u_int lifetime, num, size; |
||
449 | |||
450 | (void)snprintf(buf, sizeof(buf), "router advertisement"); |
||
451 | cp = buf + strlen(buf); |
||
452 | |||
453 | ihp = (struct ih_rdiscovery *)&dp->icmp_void; |
||
454 | ND_TCHECK(*ihp); |
||
455 | (void)strncpy(cp, " lifetime ", sizeof(buf) - (cp - buf)); |
||
456 | cp = buf + strlen(buf); |
||
457 | lifetime = EXTRACT_16BITS(&ihp->ird_lifetime); |
||
458 | if (lifetime < 60) { |
||
459 | (void)snprintf(cp, sizeof(buf) - (cp - buf), "%u", |
||
460 | lifetime); |
||
461 | } else if (lifetime < 60 * 60) { |
||
462 | (void)snprintf(cp, sizeof(buf) - (cp - buf), "%u:%02u", |
||
463 | lifetime / 60, lifetime % 60); |
||
464 | } else { |
||
465 | (void)snprintf(cp, sizeof(buf) - (cp - buf), |
||
466 | "%u:%02u:%02u", |
||
467 | lifetime / 3600, |
||
468 | (lifetime % 3600) / 60, |
||
469 | lifetime % 60); |
||
470 | } |
||
471 | cp = buf + strlen(buf); |
||
472 | |||
473 | num = ihp->ird_addrnum; |
||
474 | (void)snprintf(cp, sizeof(buf) - (cp - buf), " %d:", num); |
||
475 | cp = buf + strlen(buf); |
||
476 | |||
477 | size = ihp->ird_addrsiz; |
||
478 | if (size != 2) { |
||
479 | (void)snprintf(cp, sizeof(buf) - (cp - buf), |
||
480 | " [size %d]", size); |
||
481 | break; |
||
482 | } |
||
483 | idp = (struct id_rdiscovery *)&dp->icmp_data; |
||
484 | while (num-- > 0) { |
||
485 | ND_TCHECK(*idp); |
||
486 | (void)snprintf(cp, sizeof(buf) - (cp - buf), " {%s %u}", |
||
487 | ipaddr_string(ndo, &idp->ird_addr), |
||
488 | EXTRACT_32BITS(&idp->ird_pref)); |
||
489 | cp = buf + strlen(buf); |
||
490 | ++idp; |
||
491 | } |
||
492 | } |
||
493 | break; |
||
494 | |||
495 | case ICMP_TIMXCEED: |
||
496 | ND_TCHECK(dp->icmp_ip.ip_dst); |
||
497 | switch (dp->icmp_code) { |
||
498 | |||
499 | case ICMP_TIMXCEED_INTRANS: |
||
500 | str = "time exceeded in-transit"; |
||
501 | break; |
||
502 | |||
503 | case ICMP_TIMXCEED_REASS: |
||
504 | str = "ip reassembly time exceeded"; |
||
505 | break; |
||
506 | |||
507 | default: |
||
508 | (void)snprintf(buf, sizeof(buf), "time exceeded-#%d", |
||
509 | dp->icmp_code); |
||
510 | break; |
||
511 | } |
||
512 | break; |
||
513 | |||
514 | case ICMP_PARAMPROB: |
||
515 | if (dp->icmp_code) |
||
516 | (void)snprintf(buf, sizeof(buf), |
||
517 | "parameter problem - code %d", dp->icmp_code); |
||
518 | else { |
||
519 | ND_TCHECK(dp->icmp_pptr); |
||
520 | (void)snprintf(buf, sizeof(buf), |
||
521 | "parameter problem - octet %d", dp->icmp_pptr); |
||
522 | } |
||
523 | break; |
||
524 | |||
525 | case ICMP_MASKREPLY: |
||
526 | ND_TCHECK(dp->icmp_mask); |
||
527 | (void)snprintf(buf, sizeof(buf), "address mask is 0x%08x", |
||
528 | EXTRACT_32BITS(&dp->icmp_mask)); |
||
529 | break; |
||
530 | |||
531 | case ICMP_TSTAMP: |
||
532 | ND_TCHECK(dp->icmp_seq); |
||
533 | (void)snprintf(buf, sizeof(buf), |
||
534 | "time stamp query id %u seq %u", |
||
535 | EXTRACT_16BITS(&dp->icmp_id), |
||
536 | EXTRACT_16BITS(&dp->icmp_seq)); |
||
537 | break; |
||
538 | |||
539 | case ICMP_TSTAMPREPLY: |
||
540 | ND_TCHECK(dp->icmp_ttime); |
||
541 | (void)snprintf(buf, sizeof(buf), |
||
542 | "time stamp reply id %u seq %u: org %s", |
||
543 | EXTRACT_16BITS(&dp->icmp_id), |
||
544 | EXTRACT_16BITS(&dp->icmp_seq), |
||
545 | icmp_tstamp_print(EXTRACT_32BITS(&dp->icmp_otime))); |
||
546 | |||
547 | (void)snprintf(buf+strlen(buf),sizeof(buf)-strlen(buf),", recv %s", |
||
548 | icmp_tstamp_print(EXTRACT_32BITS(&dp->icmp_rtime))); |
||
549 | (void)snprintf(buf+strlen(buf),sizeof(buf)-strlen(buf),", xmit %s", |
||
550 | icmp_tstamp_print(EXTRACT_32BITS(&dp->icmp_ttime))); |
||
551 | break; |
||
552 | |||
553 | default: |
||
554 | str = tok2str(icmp2str, "type-#%d", dp->icmp_type); |
||
555 | break; |
||
556 | } |
||
557 | ND_PRINT((ndo, "ICMP %s, length %u", str, plen)); |
||
558 | if (ndo->ndo_vflag && !fragmented) { /* don't attempt checksumming if this is a frag */ |
||
559 | uint16_t sum, icmp_sum; |
||
560 | struct cksum_vec vec[1]; |
||
561 | if (ND_TTEST2(*bp, plen)) { |
||
562 | vec[0].ptr = (const uint8_t *)(void *)dp; |
||
563 | vec[0].len = plen; |
||
564 | sum = in_cksum(vec, 1); |
||
565 | if (sum != 0) { |
||
566 | icmp_sum = EXTRACT_16BITS(&dp->icmp_cksum); |
||
567 | ND_PRINT((ndo, " (wrong icmp cksum %x (->%x)!)", |
||
568 | icmp_sum, |
||
569 | in_cksum_shouldbe(icmp_sum, sum))); |
||
570 | } |
||
571 | } |
||
572 | } |
||
573 | |||
574 | /* |
||
575 | * print the remnants of the IP packet. |
||
576 | * save the snaplength as this may get overidden in the IP printer. |
||
577 | */ |
||
578 | if (ndo->ndo_vflag >= 1 && ICMP_ERRTYPE(dp->icmp_type)) { |
||
579 | bp += 8; |
||
580 | ND_PRINT((ndo, "\n\t")); |
||
581 | ip = (struct ip *)bp; |
||
582 | ndo->ndo_snaplen = ndo->ndo_snapend - bp; |
||
583 | snapend_save = ndo->ndo_snapend; |
||
584 | ip_print(ndo, bp, EXTRACT_16BITS(&ip->ip_len)); |
||
585 | ndo->ndo_snapend = snapend_save; |
||
586 | } |
||
587 | |||
588 | /* |
||
589 | * Attempt to decode the MPLS extensions only for some ICMP types. |
||
590 | */ |
||
591 | if (ndo->ndo_vflag >= 1 && plen > ICMP_EXTD_MINLEN && ICMP_MPLS_EXT_TYPE(dp->icmp_type)) { |
||
592 | |||
593 | ND_TCHECK(*ext_dp); |
||
594 | |||
595 | /* |
||
596 | * Check first if the mpls extension header shows a non-zero length. |
||
597 | * If the length field is not set then silently verify the checksum |
||
598 | * to check if an extension header is present. This is expedient, |
||
599 | * however not all implementations set the length field proper. |
||
600 | */ |
||
601 | if (!ext_dp->icmp_length) { |
||
602 | vec[0].ptr = (const uint8_t *)(void *)&ext_dp->icmp_ext_version_res; |
||
603 | vec[0].len = plen - ICMP_EXTD_MINLEN; |
||
604 | if (in_cksum(vec, 1)) { |
||
605 | return; |
||
606 | } |
||
607 | } |
||
608 | |||
609 | ND_PRINT((ndo, "\n\tMPLS extension v%u", |
||
610 | ICMP_MPLS_EXT_EXTRACT_VERSION(*(ext_dp->icmp_ext_version_res)))); |
||
611 | |||
612 | /* |
||
613 | * Sanity checking of the header. |
||
614 | */ |
||
615 | if (ICMP_MPLS_EXT_EXTRACT_VERSION(*(ext_dp->icmp_ext_version_res)) != |
||
616 | ICMP_MPLS_EXT_VERSION) { |
||
617 | ND_PRINT((ndo, " packet not supported")); |
||
618 | return; |
||
619 | } |
||
620 | |||
621 | hlen = plen - ICMP_EXTD_MINLEN; |
||
622 | vec[0].ptr = (const uint8_t *)(void *)&ext_dp->icmp_ext_version_res; |
||
623 | vec[0].len = hlen; |
||
624 | ND_PRINT((ndo, ", checksum 0x%04x (%scorrect), length %u", |
||
625 | EXTRACT_16BITS(ext_dp->icmp_ext_checksum), |
||
626 | in_cksum(vec, 1) ? "in" : "", |
||
627 | hlen)); |
||
628 | |||
629 | hlen -= 4; /* subtract common header size */ |
||
630 | obj_tptr = (uint8_t *)ext_dp->icmp_ext_data; |
||
631 | |||
632 | while (hlen > sizeof(struct icmp_mpls_ext_object_header_t)) { |
||
633 | |||
634 | icmp_mpls_ext_object_header = (struct icmp_mpls_ext_object_header_t *)obj_tptr; |
||
635 | ND_TCHECK(*icmp_mpls_ext_object_header); |
||
636 | obj_tlen = EXTRACT_16BITS(icmp_mpls_ext_object_header->length); |
||
637 | obj_class_num = icmp_mpls_ext_object_header->class_num; |
||
638 | obj_ctype = icmp_mpls_ext_object_header->ctype; |
||
639 | obj_tptr += sizeof(struct icmp_mpls_ext_object_header_t); |
||
640 | |||
641 | ND_PRINT((ndo, "\n\t %s Object (%u), Class-Type: %u, length %u", |
||
642 | tok2str(icmp_mpls_ext_obj_values,"unknown",obj_class_num), |
||
643 | obj_class_num, |
||
644 | obj_ctype, |
||
645 | obj_tlen)); |
||
646 | |||
647 | hlen-=sizeof(struct icmp_mpls_ext_object_header_t); /* length field includes tlv header */ |
||
648 | |||
649 | /* infinite loop protection */ |
||
650 | if ((obj_class_num == 0) || |
||
651 | (obj_tlen < sizeof(struct icmp_mpls_ext_object_header_t))) { |
||
652 | return; |
||
653 | } |
||
654 | obj_tlen-=sizeof(struct icmp_mpls_ext_object_header_t); |
||
655 | |||
656 | switch (obj_class_num) { |
||
657 | case 1: |
||
658 | switch(obj_ctype) { |
||
659 | case 1: |
||
660 | ND_TCHECK2(*obj_tptr, 4); |
||
661 | raw_label = EXTRACT_32BITS(obj_tptr); |
||
662 | ND_PRINT((ndo, "\n\t label %u, exp %u", MPLS_LABEL(raw_label), MPLS_EXP(raw_label))); |
||
663 | if (MPLS_STACK(raw_label)) |
||
664 | ND_PRINT((ndo, ", [S]")); |
||
665 | ND_PRINT((ndo, ", ttl %u", MPLS_TTL(raw_label))); |
||
666 | break; |
||
667 | default: |
||
668 | print_unknown_data(ndo, obj_tptr, "\n\t ", obj_tlen); |
||
669 | } |
||
670 | break; |
||
671 | |||
672 | /* |
||
673 | * FIXME those are the defined objects that lack a decoder |
||
674 | * you are welcome to contribute code ;-) |
||
675 | */ |
||
676 | case 2: |
||
677 | default: |
||
678 | print_unknown_data(ndo, obj_tptr, "\n\t ", obj_tlen); |
||
679 | break; |
||
680 | } |
||
681 | if (hlen < obj_tlen) |
||
682 | break; |
||
683 | hlen -= obj_tlen; |
||
684 | obj_tptr += obj_tlen; |
||
685 | } |
||
686 | } |
||
687 | |||
688 | return; |
||
689 | trunc: |
||
690 | ND_PRINT((ndo, "[|icmp]")); |
||
691 | } |
||
692 | /* |
||
693 | * Local Variables: |
||
694 | * c-style: whitesmith |
||
695 | * c-basic-offset: 8 |
||
696 | * End: |
||
697 | */ |