ICMP Echo

opensource.apple.com: ping.c

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

Wireshark-bugs: For ICMP Time Response, In detail pane, Timestamp is incorrectly decoded for MS Windows

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

Leave a Reply

Your email address will not be published. Required fields are marked *