/*
* 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;
[...]
}
[...]
}