I see you may not want this anymore, but had a little time to look at it today and I think the following works.
The dump of the returned message looks like this:
Code:
45 00 00 30 00 00 00 00 3C 01
AC D1 08 08 08 08 C0 A8 01 44
00 00 B8 F0 46 0F 01 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
I believe it is interpreted like this:
Version/IHL: 45 IPv4; length 5 * 32-bits = 20 bytes
ToS: 00 Type of Service (low priority)
Length: 00 30 Total length: 48 bytes (big endian)
Identification: 00 00
flags & offset: 00 00
TTL: 3C Time To Live (max hops before discarding)
Protocol: 01
Checksum: AC D1
Source IP: 08 08 08 08
Destination IP: 12 34 56 78 my address, which I've changed
Type: 00 ICMP_ECHOREPLY
Code: 00
Checksum: B8 F0
Data:
ID: 46 0F this is the PID we sent
Sequence: 01 00 the sequence number we sent
Payload: 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 dummy 20-byte payload
Code:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <libgen.h>
#include <netinet/in.h>
#include <netinet/ip_icmp.h>
#include <sys/socket.h>
#define BUFFER_SIZE 1024
#define PING_ADDRESS "8.8.8.8"
bool pinger (char *address);
int main()
{
// Check that user has root access.
if (geteuid() != 0) {
fprintf(stderr, "%s: must be run as root or with 'sudo'\n",
program_invocation_short_name);
exit(EXIT_FAILURE);
}
printf("Pinging %s was %ssuccessful.\n", PING_ADDRESS,
pinger(PING_ADDRESS) ? "" : "un");
return 0;
}
uint16_t checksum(void* addr, unsigned count)
{
uint16_t* buf = addr;
uint32_t sum = 0;
for ( ; count > 1; count -= 2)
sum += *buf++;
// Add left-over byte, if any
if (count > 0)
sum += *(unsigned char*)addr;
// Fold 32-bit sum to 16 bits
while (sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
return (uint16_t)~sum;
}
bool do_error(const char *msg) {
fprintf(stderr, "%s: %s error: %s (%s)",
program_invocation_short_name, __func__, msg, strerror(errno));
return false;
}
bool pinger (char *address)
{
char buffer[BUFFER_SIZE] = {0};
struct icmp icmp_hdr = {0};
struct sockaddr_in dest_addr = {0};
struct sockaddr_in from_addr = {0};
socklen_t fromlen = {0};
int sockfd = {0};
icmp_hdr.icmp_type = ICMP_ECHO;
icmp_hdr.icmp_code = 0;
icmp_hdr.icmp_cksum = 0;
icmp_hdr.icmp_id = getpid();
icmp_hdr.icmp_seq = 1;
printf("PID: %04X\n", (unsigned)icmp_hdr.icmp_id);
icmp_hdr.icmp_cksum = checksum(&icmp_hdr, sizeof icmp_hdr);
dest_addr.sin_family = AF_INET;
dest_addr.sin_addr.s_addr = inet_addr(address);
memset(&dest_addr.sin_zero, 0, sizeof(dest_addr.sin_zero));
// Create a raw socket.
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)
return do_error("socket failed");
// Send icmp request.
if (sendto(sockfd, &icmp_hdr, sizeof(struct icmp), 0,
(struct sockaddr *) &dest_addr, sizeof(struct sockaddr_in)) == -1)
return do_error("sendto failed");
// Receive icmp response.
ssize_t len = recvfrom(sockfd, buffer, BUFFER_SIZE, 0,
(struct sockaddr *) &from_addr, &fromlen);
if (len == -1)
return do_error("recvfrom failed");
for (ssize_t i = 0; i < len; ++i)
printf("%02X ", (unsigned char)buffer[i]);
printf("\n");
return true;
}