I'm trying to code a simple version of the ping command.
After I successfully resolve the address of the destination (www.googlg.com
in my case),
I send an ICMP_ECHO
request to the destination using sendto(2)
but in the receiving process the function recvmsg(2)
hangs and after the wait time, the function return EAGAIN
error.
I'm not sure if the icmp header is not set properly, or the parameters of the recvmsg
funtions are wrong. This issue only happens for google.com
but other websites works fine.
This is the code I use for sending the ICMP_ECHO
request:
void send_v4()
{
char buff[64];
struct icmp *icmp;
// Setup the ICMP packet header
icmp = (struct icmp *)buff;
icmp->icmp_id = getpid();
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0;
icmp->icmp_seq = 1;
memset(icmp->icmp_data, 0x00, 56);
// Setup data section
gettimeofday((struct timeval *)(icmp->icmp_data), NULL);
// Send full packet
int ret = sendto(proto_v4.sockfd, buff, sizeof(buff), 0, proto_v4.dst_sa, proto_v4.dst_ai->ai_addrlen);
if (ret == -1)
printf("sendto failed with error code: %d\n", ret);
}
And this is code I use to receive the response:
void proc_v4()
{
char buff[256];
ssize_t received;
struct iovec iov;
struct msghdr msghdr;
struct ip *ip;
struct icmp *icmp;
struct timeval tvcurr;
struct timeval tvrecv;
double time;
memset(buff, 0x00, 256);
iov.iov_base = buff;
iov.iov_len = sizeof(buff);
msghdr.msg_iov = &iov;
msghdr.msg_iovlen = 1;
received = recvmsg(proto_v4.sockfd, &msghdr, 0);
if (received == -1)
perror("recvmsg");
ip = (struct ip *)(iov.iov_base);
if (ip->ip_p == IPPROTO_ICMP)
printf("IPPROTO_ICMP\n");
icmp = (struct icmp *)(iov.iov_base + (ip->ip_hl << 2));
if (icmp->icmp_type == ICMP_ECHOREPLY)
printf("ICMP_ECHOREPLY %d\n", icmp->icmp_id);
char buf[256];
inet_ntop(
proto_v4.dst_ai->ai_family,
&((struct sockaddr_in *)proto_v4.dst_sa)->sin_addr,
buf,
256
);
tvrecv = *(struct timeval *)(icmp->icmp_data);
gettimeofday(&tvcurr, NULL);
time = (tvcurr.tv_sec - tvrecv.tv_sec) * 1000;
time += (tvcurr.tv_usec - tvrecv.tv_usec) / 1000.0;
printf("%ld %ld\n", (tvcurr.tv_usec - tvrecv.tv_usec), (tvcurr.tv_usec - tvrecv.tv_usec) % 1000);
printf("%d bytes from %s (%s): icmp_seq=%d ttl=%d time=%.2lf ms\n", 64, buf, buf, icmp->icmp_seq, ip->ip_ttl, time);
}