having trouble with the timestamp field in icmp packet when sending echo request from ping utility

208 views
Skip to first unread message

ahmed

unread,
Jul 6, 2023, 8:53:09 AM7/6/23
to golang-dev
I have that function that sends icmp echo requests, my problem is when I add timestamp to the packet and then I check with wireshark I see it cannot parse it correctly normally u will see timestamp shown in the packet info maybe I am not doing the timestamp correctly ?

```go
func Request(sockfd int, ip string) (*Icmp, error) {
   
    seqN++

    targetIpB := net.ParseIP(ip).To4()

    targetIP := &syscall.SockaddrInet4{
        Addr: [4]byte{
            targetIpB[0], targetIpB[1],
            targetIpB[2], targetIpB[3],
        },
    }

    icmp := &Icmp{
        id: uint16(rand.Intn(65536)),
        typ: EchoRequest,
        sqn: uint16(seqN),
    }
   
    icmp.data = make([]byte, 8)    

    binary.BigEndian.PutUint64(icmp.data, uint64(time.Now().UnixNano()))

    icmp.checksum = checksum(icmp.Bytes())

    if err := syscall.Sendto(sockfd, icmp.Bytes(), 0, targetIP); err != nil {
        return nil, err
    }

    buf := make([]byte, 1024)

    n, _, err := syscall.Recvfrom(sockfd, buf, 0)

    if err != nil {
        return nil, err
    }

    return FromBytes(buf[20:n]), nil
}
```

and then I tried looking up ping utility from iputils they do it like that
https://github.com/iputils/iputils/blob/ee0a515e74b8d39fbe9b68f3309f0cb2586ccdd4/ping/ping.c#L1519

```c
int ping4_send_probe(struct ping_rts *rts, socket_st *sock, void *packet,
             unsigned packet_size __attribute__((__unused__)))
{
    struct icmphdr *icp;
    int cc;
    int i;

    icp = (struct icmphdr *)packet;
    icp->type = ICMP_ECHO;
    icp->code = 0;
    icp->checksum = 0;
    icp->un.echo.sequence = htons(rts->ntransmitted + 1);
    icp->un.echo.id = rts->ident;            /* ID */

    rcvd_clear(rts, rts->ntransmitted + 1);

    if (rts->timing) {
        if (rts->opt_latency) {
            struct timeval tmp_tv;
            gettimeofday(&tmp_tv, NULL);
            memcpy(icp + 1, &tmp_tv, sizeof(tmp_tv));
        } else {
            memset(icp + 1, 0, sizeof(struct timeval));
        }
    }

    cc = rts->datalen + 8;            /* skips ICMP portion */

    /* compute ICMP checksum here */
    icp->checksum = in_cksum((unsigned short *)icp, cc, 0);

    if (rts->timing && !rts->opt_latency) {
        struct timeval tmp_tv;
        gettimeofday(&tmp_tv, NULL);
        memcpy(icp + 1, &tmp_tv, sizeof(tmp_tv));
        icp->checksum = in_cksum((unsigned short *)&tmp_tv, sizeof(tmp_tv), ~icp->checksum);
    }

    i = sendto(sock->fd, icp, cc, 0, (struct sockaddr *)&rts->whereto, sizeof(rts->whereto));

    return (cc == i ? 0 : i);
}
```
what I noticed is that timeval struct contains two fields seconds and microseconds, and it writes that, I modified the function and added these

```go
binary.BigEndian.PutUint32(icmp.data, uint32(time.Now().Unix()))
binary.BigEndian.PutUint32(icmp.data, uint32(time.Now().UnixMicro()))
```

but also it doesn't seem to work as expected the timestamp still doesn't show up.

my packet looks like this:

https://media.discordapp.net/attachments/1126303228947075102/1126457885518483516/image.png

ping utility looks like this and it has timestamp field

https://cdn.discordapp.com/attachments/1126303228947075102/1126457885275205632/image.png
Reply all
Reply to author
Forward
0 new messages