68 |
|
|
69 |
void print_icmp_header (struct sockaddr_in *from, |
void print_icmp_header (struct sockaddr_in *from, |
70 |
struct ip *ip, icmphdr_t *icmp, int len); |
struct ip *ip, icmphdr_t *icmp, int len); |
|
static void print_ip_data (struct ip *ip); |
|
71 |
static void print_ip_opt (struct ip *ip, int hlen); |
static void print_ip_opt (struct ip *ip, int hlen); |
72 |
|
|
73 |
static void tvsub (struct timeval *out, struct timeval *in); |
static void tvsub (struct timeval *out, struct timeval *in); |
235 |
} |
} |
236 |
} |
} |
237 |
|
|
238 |
void |
#define NITEMS(a) sizeof(a)/sizeof((a)[0]) |
|
print_icmp_header (struct sockaddr_in *from, |
|
|
struct ip *ip, icmphdr_t *icmp, int len) |
|
|
{ |
|
|
int hlen; |
|
|
struct ip *orig_ip; |
|
|
char *s; |
|
|
|
|
|
/* Length of the IP header */ |
|
|
hlen = ip->ip_hl << 2; |
|
|
/* Original IP header */ |
|
|
orig_ip = &icmp->icmp_ip; |
|
239 |
|
|
240 |
if (!(options & OPT_VERBOSE |
struct icmp_diag { |
241 |
|| orig_ip->ip_dst.s_addr == ping->ping_dest.sin_addr.s_addr)) |
int type; |
242 |
return; |
char *text; |
243 |
|
void (*fun) (struct ip *, icmphdr_t *, void *data); |
244 |
printf ("%d bytes from %s: ", len-hlen, s = ipaddr2str (from->sin_addr)); |
void *data; |
245 |
free (s); |
}; |
246 |
|
|
247 |
switch (icmp->icmp_type) |
struct icmp_code_descr { |
248 |
{ |
int code; |
249 |
case ICMP_ECHOREPLY: |
char *diag; |
250 |
printf ("Echo Reply\n"); |
} icmp_code_descr[] = { |
251 |
break; |
{ ICMP_NET_UNREACH, "Destination Net Unreachable" }, |
252 |
case ICMP_DEST_UNREACH: |
{ ICMP_HOST_UNREACH, "Destination Host Unreachable" }, |
253 |
switch (icmp->icmp_code) |
{ ICMP_PROT_UNREACH, "Destination Protocol Unreachable" }, |
254 |
{ |
{ ICMP_PORT_UNREACH, "Destination Port Unreachable" }, |
255 |
case ICMP_NET_UNREACH: |
{ ICMP_FRAG_NEEDED, "Fragmentation needed and DF set" }, |
256 |
printf ("Destination Net Unreachable\n"); |
{ ICMP_SR_FAILED, "Source Route Failed" }, |
257 |
break; |
{ ICMP_NET_UNKNOWN, "Network Unknown" }, |
258 |
case ICMP_HOST_UNREACH: |
{ ICMP_HOST_UNKNOWN, "Host Unknown" }, |
259 |
printf ("Destination Host Unreachable\n"); |
{ ICMP_HOST_ISOLATED, "Host Isolated" }, |
260 |
break; |
{ ICMP_NET_UNR_TOS, "Destination Network Unreachable At This TOS" }, |
261 |
case ICMP_PROT_UNREACH: |
{ ICMP_HOST_UNR_TOS, "Destination Host Unreachable At This TOS" }, |
|
printf ("Destination Protocol Unreachable\n"); |
|
|
break; |
|
|
case ICMP_PORT_UNREACH: |
|
|
printf ("Destination Port Unreachable\n"); |
|
|
break; |
|
|
case ICMP_FRAG_NEEDED: |
|
|
printf ("frag needed and DF set\n"); |
|
|
break; |
|
|
case ICMP_SR_FAILED: |
|
|
printf ("Source Route Failed\n"); |
|
|
break; |
|
|
case ICMP_NET_UNKNOWN: |
|
|
printf ("Network Unknown\n"); |
|
|
break; |
|
|
case ICMP_HOST_UNKNOWN: |
|
|
printf ("Host Unknown\n"); |
|
|
break; |
|
|
case ICMP_HOST_ISOLATED: |
|
|
printf ("Host Isolated\n"); |
|
|
break; |
|
|
case ICMP_NET_UNR_TOS: |
|
|
printf ("Destination Network Unreachable At This TOS\n"); |
|
|
break; |
|
|
case ICMP_HOST_UNR_TOS: |
|
|
printf ("Destination Host Unreachable At This TOS\n"); |
|
|
break; |
|
262 |
#ifdef ICMP_PKT_FILTERED |
#ifdef ICMP_PKT_FILTERED |
263 |
case ICMP_PKT_FILTERED: |
{ ICMP_PKT_FILTERED, "Packet Filtered" }, |
|
printf ("Packet Filtered\n"); |
|
|
break; |
|
264 |
#endif |
#endif |
265 |
#ifdef ICMP_PREC_VIOLATION |
#ifdef ICMP_PREC_VIOLATION |
266 |
case ICMP_PREC_VIOLATION: |
{ ICMP_PREC_VIOLATION, "Precedence Violation" }, |
|
printf ("Precedence Violation\n"); |
|
|
break; |
|
267 |
#endif |
#endif |
268 |
#ifdef ICMP_PREC_CUTOFF |
#ifdef ICMP_PREC_CUTOFF |
269 |
case ICMP_PREC_CUTOFF: |
{ ICMP_PREC_CUTOFF, "Precedence Cutoff" }, |
|
printf ("Precedence Cutoff\n"); |
|
|
break; |
|
270 |
#endif |
#endif |
271 |
default: |
|
272 |
printf ("Dest Unreachable, Unknown Code: %d\n", |
{ ICMP_REDIR_NET, "Redirect Network" }, |
273 |
icmp->icmp_code); |
{ ICMP_REDIR_HOST, "Redirect Host" }, |
274 |
break; |
{ ICMP_REDIR_NETTOS, "Redirect Type of Service and Network" }, |
275 |
} |
{ ICMP_REDIR_HOSTTOS, "Redirect Type of Service and Host" }, |
276 |
/* Print returned IP header information */ |
|
277 |
print_ip_data (ip); |
{ ICMP_EXC_TTL, "Time to live exceeded" }, |
278 |
break; |
{ ICMP_EXC_FRAGTIME, "Frag reassembly time exceeded" }, |
279 |
case ICMP_SOURCE_QUENCH: |
}; |
280 |
printf ("Source Quench\n"); |
|
281 |
print_ip_data (ip); |
static void |
282 |
break; |
print_icmp_code (int code, char *prefix) |
283 |
case ICMP_REDIRECT: |
{ |
284 |
switch (icmp->icmp_code) |
struct icmp_code_descr *p; |
285 |
{ |
|
286 |
case ICMP_REDIR_NET: |
for (p = icmp_code_descr; p < icmp_code_descr + NITEMS(icmp_code_descr); p++) |
287 |
printf ("Redirect Network"); |
if (p->code == code) |
288 |
break; |
{ |
289 |
case ICMP_REDIR_HOST: |
printf ("%s\n", p->diag); |
290 |
printf ("Redirect Host"); |
return; |
291 |
break; |
} |
292 |
case ICMP_REDIR_NETTOS: |
|
293 |
printf ("Redirect Type of Service and Network"); |
printf ("%s, Unknown Code: %d\n", prefix, code); |
|
break; |
|
|
case ICMP_REDIR_HOSTTOS: |
|
|
printf ("Redirect Type of Service and Host"); |
|
|
break; |
|
|
default: |
|
|
printf ("Redirect, Bad Code: %d", icmp->icmp_code); |
|
|
break; |
|
|
} |
|
|
printf ("(New addr: %s)\n", |
|
|
inet_ntoa (icmp->icmp_gwaddr)); |
|
|
print_ip_data (ip); |
|
|
break; |
|
|
case ICMP_ECHO: |
|
|
printf ("Echo Request\n"); |
|
|
/* XXX ID + Seq + Data */ |
|
|
break; |
|
|
case ICMP_TIME_EXCEEDED: |
|
|
switch (icmp->icmp_code) |
|
|
{ |
|
|
case ICMP_EXC_TTL: |
|
|
printf ("Time to live exceeded\n"); |
|
|
break; |
|
|
case ICMP_EXC_FRAGTIME: |
|
|
printf ("Frag reassembly time exceeded\n"); |
|
|
break; |
|
|
default: |
|
|
printf ("Time exceeded, Bad Code: %d\n", |
|
|
icmp->icmp_code); |
|
|
break; |
|
|
} |
|
|
print_ip_data (ip); |
|
|
break; |
|
|
case ICMP_PARAMETERPROB: |
|
|
printf ("Parameter problem: IP address = %s\n", |
|
|
inet_ntoa (icmp->icmp_gwaddr)); |
|
|
print_ip_data (ip); |
|
|
break; |
|
|
case ICMP_TIMESTAMP: |
|
|
printf ("Timestamp\n"); |
|
|
/* XXX ID + Seq + 3 timestamps */ |
|
|
break; |
|
|
case ICMP_TIMESTAMPREPLY: |
|
|
printf ("Timestamp Reply\n"); |
|
|
/* XXX ID + Seq + 3 timestamps */ |
|
|
break; |
|
|
case ICMP_INFO_REQUEST: |
|
|
printf ("Information Request\n"); |
|
|
/* XXX ID + Seq */ |
|
|
break; |
|
|
case ICMP_INFO_REPLY: |
|
|
printf ("Information Reply\n"); |
|
|
/* XXX ID + Seq */ |
|
|
break; |
|
|
#ifdef ICMP_MASKREQ |
|
|
case ICMP_MASKREQ: |
|
|
printf ("Address Mask Request\n"); |
|
|
break; |
|
|
#endif |
|
|
#ifdef ICMP_MASKREPLY |
|
|
case ICMP_MASKREPLY: |
|
|
printf ("Address Mask Reply\n"); |
|
|
break; |
|
|
#endif |
|
|
default: |
|
|
printf ("Bad ICMP type: %d\n", icmp->icmp_type); |
|
|
} |
|
294 |
} |
} |
295 |
|
|
296 |
static void |
static void |
310 |
printf (" %02x %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum); |
printf (" %02x %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum); |
311 |
printf (" %s ", inet_ntoa (*((struct in_addr *) &ip->ip_src))); |
printf (" %s ", inet_ntoa (*((struct in_addr *) &ip->ip_src))); |
312 |
printf (" %s ", inet_ntoa (*((struct in_addr *) &ip->ip_dst))); |
printf (" %s ", inet_ntoa (*((struct in_addr *) &ip->ip_dst))); |
313 |
/* dump and option bytes */ |
while (hlen-- > 20) |
|
while (hlen-- > 20) { |
|
314 |
printf ("%02x", *cp++); |
printf ("%02x", *cp++); |
315 |
} |
|
316 |
printf ("\n"); |
printf ("\n"); |
317 |
} |
} |
318 |
|
|
319 |
void |
void |
320 |
print_ip_data (struct ip *ip) |
print_ip_data (struct ip *ip, icmphdr_t *icmp, void *data) |
321 |
{ |
{ |
322 |
int hlen; |
int hlen; |
323 |
u_char *cp; |
u_char *cp; |
336 |
|
|
337 |
} |
} |
338 |
|
|
339 |
|
static void |
340 |
|
print_icmp (struct ip *ip, icmphdr_t *icmp, void *data) |
341 |
|
{ |
342 |
|
print_icmp_code (icmp->icmp_code, data); |
343 |
|
print_ip_data (ip, icmp, NULL); |
344 |
|
} |
345 |
|
|
346 |
|
static void |
347 |
|
print_parameterprob (struct ip *ip, icmphdr_t *icmp, void *data) |
348 |
|
{ |
349 |
|
printf ("Parameter problem: IP address = %s\n", |
350 |
|
inet_ntoa (icmp->icmp_gwaddr)); |
351 |
|
print_ip_data (ip, icmp, data); |
352 |
|
} |
353 |
|
|
354 |
|
struct icmp_diag icmp_diag[] = { |
355 |
|
{ ICMP_ECHOREPLY, "Echo Reply", NULL }, |
356 |
|
{ ICMP_DEST_UNREACH, NULL, print_icmp, "Dest Unreachable" }, |
357 |
|
{ ICMP_SOURCE_QUENCH, "Source Quench", print_ip_data }, |
358 |
|
{ ICMP_REDIRECT, NULL, print_icmp, "Redirect" }, |
359 |
|
{ ICMP_ECHO, "Echo Request", NULL }, |
360 |
|
{ ICMP_TIME_EXCEEDED, NULL, print_icmp, "Time exceeded" }, |
361 |
|
{ ICMP_PARAMETERPROB, NULL, print_parameterprob }, |
362 |
|
{ ICMP_TIMESTAMP, "Timestamp", NULL }, |
363 |
|
{ ICMP_TIMESTAMPREPLY, "Timestamp Reply", NULL }, |
364 |
|
{ ICMP_INFO_REQUEST, "Information Request", NULL }, |
365 |
|
#ifdef ICMP_MASKREQ |
366 |
|
{ ICMP_MASKREPLY, "Address Mask Reply", NULL }, |
367 |
|
#endif |
368 |
|
}; |
369 |
|
|
370 |
|
void |
371 |
|
print_icmp_header (struct sockaddr_in *from, |
372 |
|
struct ip *ip, icmphdr_t *icmp, int len) |
373 |
|
{ |
374 |
|
int hlen; |
375 |
|
struct ip *orig_ip; |
376 |
|
char *s; |
377 |
|
struct icmp_diag *p; |
378 |
|
|
379 |
|
/* Length of the IP header */ |
380 |
|
hlen = ip->ip_hl << 2; |
381 |
|
/* Original IP header */ |
382 |
|
orig_ip = &icmp->icmp_ip; |
383 |
|
|
384 |
|
if (!(options & OPT_VERBOSE |
385 |
|
|| orig_ip->ip_dst.s_addr == ping->ping_dest.sin_addr.s_addr)) |
386 |
|
return; |
387 |
|
|
388 |
|
printf ("%d bytes from %s: ", len-hlen, s = ipaddr2str (from->sin_addr)); |
389 |
|
free (s); |
390 |
|
|
391 |
|
for (p = icmp_diag; p < icmp_diag + NITEMS(icmp_diag); p++) |
392 |
|
{ |
393 |
|
if (p->type == icmp->icmp_type) |
394 |
|
{ |
395 |
|
if (p->text) |
396 |
|
printf ("%s\n", p->text); |
397 |
|
if (p->fun) |
398 |
|
p->fun (ip, icmp, p->data); |
399 |
|
return; |
400 |
|
} |
401 |
|
} |
402 |
|
printf ("Bad ICMP type: %d\n", icmp->icmp_type); |
403 |
|
} |
404 |
|
|
405 |
void |
void |
406 |
print_ip_opt (struct ip *ip, int hlen) |
print_ip_opt (struct ip *ip, int hlen) |
407 |
{ |
{ |
418 |
case IPOPT_EOL: |
case IPOPT_EOL: |
419 |
hlen = 0; |
hlen = 0; |
420 |
break; |
break; |
421 |
|
|
422 |
case IPOPT_LSRR: |
case IPOPT_LSRR: |
423 |
printf ("\nLSRR: "); |
printf ("\nLSRR: "); |
424 |
hlen -= 2; |
hlen -= 2; |
451 |
putchar ('\n'); |
putchar ('\n'); |
452 |
} |
} |
453 |
break; |
break; |
454 |
|
|
455 |
case IPOPT_RR: |
case IPOPT_RR: |
456 |
j = *++cp; /* get length */ |
j = *++cp; |
457 |
i = *++cp; /* and pointer */ |
i = *++cp; |
458 |
hlen -= 2; |
hlen -= 2; |
459 |
if (i > j) |
if (i > j) |
460 |
i = j; |
i = j; |
514 |
putchar ('\n'); |
putchar ('\n'); |
515 |
} |
} |
516 |
break; |
break; |
517 |
|
|
518 |
case IPOPT_NOP: |
case IPOPT_NOP: |
519 |
printf ("\nNOP"); |
printf ("\nNOP"); |
520 |
break; |
break; |
521 |
|
|
522 |
default: |
default: |
523 |
printf ("\nunknown option %x", *cp); |
printf ("\nunknown option %x", *cp); |
524 |
break; |
break; |
531 |
* be >= in. |
* be >= in. |
532 |
*/ |
*/ |
533 |
static void |
static void |
534 |
tvsub (out, in) |
tvsub (struct timeval *out, struct timeval *in) |
|
register struct timeval *out, *in; |
|
535 |
{ |
{ |
536 |
if ((out->tv_usec -= in->tv_usec) < 0) { |
if ((out->tv_usec -= in->tv_usec) < 0) |
537 |
--out->tv_sec; |
{ |
538 |
out->tv_usec += 1000000; |
--out->tv_sec; |
539 |
} |
out->tv_usec += 1000000; |
540 |
out->tv_sec -= in->tv_sec; |
} |
541 |
|
out->tv_sec -= in->tv_sec; |
542 |
} |
} |
543 |
|
|
544 |
double |
double |