/* * pinger -- * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet * will be added on by the kernel. The ID field is our UNIX process ID, * and the sequence number is an ascending integer. The first TIMEVAL_LEN * bytes of the data portion are used to hold a UNIX "timeval" struct in * host byte-order, to compute the round-trip time. */ static void pinger(void) { [...] if ((options & F_TIME) || timing) { (void)gettimeofday(&now, NULL); if (options & F_TIME) icp->icmp_otime = htonl((now.tv_sec % (24*60*60)) * 1000 + now.tv_usec / 1000); if (timing) bcopy((void *)&now, (void *)&outpack[ICMP_MINLEN + phdr_len], sizeof(struct timeval)); } [...] }
typedef u_int32_t n_time; /* ms since 00:00 GMT, byte rev */
#define icmp_otime icmp_dun.id_ts.its_otime #define icmp_rtime icmp_dun.id_ts.its_rtime #define icmp_ttime icmp_dun.id_ts.its_ttime struct icmp { u_char icmp_type; /* type of message, see below */ u_char icmp_code; /* type sub code */ u_short icmp_cksum; /* ones complement cksum of struct */ union { u_char ih_pptr; /* ICMP_PARAMPROB */ struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ struct ih_idseq { n_short icd_id; n_short icd_seq; } ih_idseq; int ih_void; /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ struct ih_pmtu { n_short ipm_void; n_short ipm_nextmtu; } ih_pmtu; struct ih_rtradv { u_char irt_num_addrs; u_char irt_wpa; u_int16_t irt_lifetime; } ih_rtradv; } icmp_hun; union { struct id_ts { /* ICMP Timestamp */ n_time its_otime; /* Originate */ n_time its_rtime; /* Receive */ n_time its_ttime; /* Transmit */ } id_ts; struct id_ip { struct ip idi_ip; /* options and then 64 bits of data */ } id_ip; struct icmp_ra_addr id_radv; u_int32_t id_mask; char id_data[1]; } icmp_dun; };
Reference (1):
http://tools.ietf.org/html/rfc778
…
“The timestamp values are in milliseconds from midnight
UT and are stored right-justified in the 32-bit fields shown
above. Ordinarily, all time calculations are performed
modulo-24 hours in milliseconds.”
/* Converts a little-endian byte order unsigned long to host byte order. */ uint32 LETOHL(uint32 ul); /* * RFC 792 for basic ICMP. * RFC 1191 for ICMP_FRAG_NEEDED (with MTU of next hop). * RFC 1256 for router discovery messages. * RFC 2002 and 3012 for Mobile IP stuff. */ static void dissect_icmp(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) { [...] /* Decode the second 4 bytes of the packet. */ switch (icmp_type) { [...] case ICMP_ECHOREPLY: case ICMP_ECHO: [...] /* Interpret the first 8 bytes of the icmp data as a timestamp * But only if it does look like it's a timestamp. * * FIXME: * Timestamps could be in different formats depending on the OS */ ts.secs = tvb_get_ntohl(tvb, 8); ts.nsecs = tvb_get_ntohl(tvb, 8 + 4); /* Leave at microsec resolution for now */ if (abs((guint32) (ts.secs - pinfo->fd->abs_ts.secs)) >= 3600 * 24 || ts.nsecs >= 1000000) { /* Timestamp does not look right in BE, try LE representation */ ts.secs = tvb_get_letohl(tvb, 8); ts.nsecs = tvb_get_letohl(tvb, 8 + 4); /* Leave at microsec resolution for now */ } if (abs((guint32) (ts.secs - pinfo->fd->abs_ts.secs)) < 3600 * 24 && ts.nsecs < 1000000) { ts.nsecs *= 1000; /* Convert to nanosec resolution */ proto_tree_add_time(icmp_tree, hf_icmp_data_time, tvb, 8, 8, &ts); nstime_delta(&time_relative, &pinfo->fd->abs_ts, &ts); ti = proto_tree_add_time(icmp_tree, hf_icmp_data_time_relative, tvb, 8, 8, &time_relative); PROTO_ITEM_SET_GENERATED(ti); call_dissector(data_handle, tvb_new_subset_remaining(tvb, 8 + 8), pinfo, icmp_tree); } else { call_dissector(data_handle, tvb_new_subset_remaining(tvb, 8), pinfo, icmp_tree); } break; [...] } [...] }