I am familiar with Layer 4 of the OSI model, the transport layer, which uses TCP or UDP. I also wanted to explore Layer 3, the Network Layer. Since I am already comfortable with bits and bytes because I have created an emulator and explored irPDA (Bluetooth OBEX) used by mobile phones for file transfer, I felt confident I could handle it.
First, I needed the packet specification to send. I looked it up on Wikipedia and found an article on ICMP. Like IP, ICMP has both v4 and v6 versions and also has a specification in RFC 792.
After obtaining the specification, I created a struct:
struct icmp_hdr
{
uint8_t type;
uint8_t code;
uint16_t checksum;
uint16_t id;
uint16_t sequence;
};
Next, I created a socket, defined the destination, and got the process ID:
int
main(void)
/* ...................... */
sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if(sock < 0){
perror("SOCK");
return -1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(TARGET_IP);
pid = getpid() & 0xFFFF;
/* ...................... */
Then, I started filling the ICMP struct. Since the ICMP packet size is 64 bytes, I created a 64-byte buffer and placed the ICMP header there:
/* ...................... */
#define CTL_MSG 8
/* ...................... */
for(int i; i < 1; i++){
/* ...................... */
memset(sendbuf, 0, sizeof sendbuf);
icmp = (struct icmp_hdr *)sendbuf;
icmp->type = CTL_MSG;
icmp->code = 0;
icmp->id = htons((uint16_t)pid);
icmp->sequence = htons((uint16_t)i);
icmp->checksum = 0;
icmp->checksum = checksum(sendbuf, sizeof sendbuf);
/* ...................... */
After that, I sent the packet and received the response. I can also verify if the response is correct, which should be an Echo Response (type 0):
if(icmp->type == 0 && ntohs(icmp->id) == (unsigned short)pid)
printf("reply: %u\n", ntohs(icmp->sequence));
I can also verify using tcpdump:
tcpdump -n icmp
BTW, need root to run it.