Tuesday, October 4, 2016

Implementing a Ping client in Python - Part III

Introduction


This is Part-3 of the N Part Series where we develop a Ping client in Python.


Until now, we understood the structure of the ICMP Packet, and also looked at python code to serialize and deserialize the packet from the network.

In the current installment, we will complete the program. First, let us implement the checksum.

ICMP Header Checksum


A checksum is a 16bit value used for error checking the header and the data. A checksum allows the receiver to make sure that the data it received did not get corrupted or altered in transit. The transmitter adds a checksum to the outgoing packet, this checksum is calculated by looking at the packet. The receiver calculates a checksum on the received packet, and compares it with the checksum in the packet. If they match, then there was no corruption on the wire.

As per Wikipedia:

The checksum field is the 16 bit one's complement of the one's complement sum of all 16-bit words in the header and text. If a segment contains an odd number of header and text octets to be checksummed, the last octet is padded on the right with zeros to form a 16-bit word for checksum purposes. The pad is not transmitted as part of the segment. While computing the checksum, the checksum field itself is replaced with zeros.

Using this definition, we have the following checksum function



Socket Introduction


The Wikipedia article on Sockets gives some background info on this topic. For our case, since we are going to be dealing with a lower level protocol like ICMP, we will be creating a Raw socket.

In order to create a RAW socket, you need to be a superuser. On UNIX machines, you will need to use "sudo" to run the program. On windows, you need to be a member of the Administrator group to run the program

The python documentation for Socket is a great resource as well.

A raw socket is created as follows:

sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)
sock.setsockopt(IPPROTO_IP, IP_HDRINCL, 0)
sock.bind(('127.0.0.1', 0))

Since we are only sending the ICMP packet, and not it's encapsulating IP packet, we will need to indicate to the network driver using setsockopt(IPPROTO_IP, IP_HDRINCL, 0). This will let the network driver encapsulate our data in an IP packet.

Main Entry Point


Now that we have all the scaffolding in place for the program, here is the main() function that ties it all together.

Note a couple of imports.
On my mac, I run this program as
sudo python ping.py

Complete Program


The complete program is checked into Github. I encourage you to check it out.

https://github.com/ferozed/ping-python

Conclusion

This concludes our 3 part series. I hope you liked this, and learned something about low level network programming in Python.