The Internet Protocol


If you were to conduct a survey on the Internet to ascertain the types of computers on it, you'd discover that there are only two main types of machines on-line. Normal, everyday computers ranging from Macintoshes to large UNIX servers; IBM compatibles to huge super-computers and the other type of computer you'd find would be routers (or gateways as they're sometimes called). This is a rather broad classification, but we'll explain why Macintoshes and IBM compatibles can be grouped as one and why routers are a class apart.

Router's, unlike all other machines on the Internet, are primarily concerned with IP or the Internet Protocol. As you well know, TCP/IP is actually two protocols sandwiched one above the other. IP is the part meant for routers and contains enough information for them to send the packet reliably to it's destination and TCP is meant for the servers and clients which abound on the Internet. No server is really concerned with IP, all it wants is TCP and the higher level protocols which use it, like HTTP, SMTP etc.

In this document, we'd take an in-depth look at the IP header and try to understand the importance and use of each byte in it. After you're through with this tutorial, jump over to TCP which is the next half of TCP/IP.

Here is a snapshot of the IP header -

Table 1 : IP Header format

Version
(4 bits)
IP Hdr Len
(4 bits)
Type of Service
(8 bits)
Length of the IP datagram
(16 bits)
Identification no
(16 bits)
Fragmentation
(16 bits)
Time to Live
(8 bits)
Protocol type
(8 bits)
IP Checksum
( 16 bits)
Source IP Address
(32 bits)
Destination IP Address
(32 bits)

Table 2 : Sample IP header

4500002c
00010000
1f06****
2025413983
1946167181

** - checksum value

Lets jump right in and start examining the bytes.

The first byte of the IP header is actually divided into two 4 bit sections. The first 4 bits specify the version number of the IP we're using. IP version 4 is the current standard and Ipv6 is the new proposed standard. IPv5 was experimental and was never really released. The reason IPv6 is being pushed is because of certain problems in IPv4. We'll get to that in a moment. Currently, all packets on the Internet are IPv4.

The next four bit section or nibble indicates the length of the IP header. Actually, 5 (the length in the test packet given above) isn't the length of the header. It has to be multiplied by 4 to get 20 bytes, the actual length of the header. This is the normal length of the IP header, though it can be larger in certain cases. Since the length field is 4 bits large, the largest number it can hold is 15. So the largest IP header can be only (15*4) 60 bytes large.

To know more about the other 40 bytes click here which is covered under the section ICMP

The second byte from the start is the Type of Service and this field is almost always zero. The Type of service (TOS) field was supposed to hold a number prioritising the packet. So a packet which had to reach it's destination real fast, e.g. Real Audio or Telnet, would have a larger TOS and thus it would be handled faster by the routers. A higher paying customer would have a higher TOS and thus his connections would work faster than those of a lower paying customer. Unfortunately, the Internet community couldn't standardise on the TOS and so no one really know what number to put here! Additionally router manufacturers, which were under tremendous pressure to create faster routers, decided that the overhead of processing the TOS was too much. Most routers nowadays totally ignore the TOS or put packets with the Type of Service set in a slower queue! Since the TOS field is usually ignored and since it makes he packet slower, most software doesn't use it. This meant that almost no routers manufactured in the last decade even look at the TOS field.

The next two bytes of the IP header hold the total length of the packet. This length is the length of the IP datagram , it can be IP+TCP+data or IP+UDP+data or IP+ICMP+data....and it's known as the Payload length. This is a prime example of what confusion would have reigned had the Network Byte Order not been standardised. If the size of the total packet is 40 bytes, we put 0x00 0x28 here because on the Internet the low byte comes first and the high byte comes later. This is know and the Network Byte Order.

Let me explain this in more detail.

Lets assume that we want to store the number 258 in memory. Because this is an int or an unsigned short, the computer will first put the low byte in memory ,2 and then the high byte, 1. So 1 * 256 + 2 = 258.

258

High Byte1 1 * 256=256
Low Byte2 2 * 1=2

If this number 258 were to be sent across the Internet the number 2 will be sent first and then the 1 would follow it. This is the way Intel bases machines store numbers, but Motorola based machine like the Macintosh store numbers the other way round. Like this...

Low Byte22 * 1=2
High Byte11 * 256=256

This is known as Big Endian while the Intel way is called Little Endian.

If we were to send the number 258 from an Intel processor based machine to a Motorola based machine the number would be interpreted as 512, not 258 !

High Byte11 * 1=1
Low Byte22 * 256=512

So the guys in charge had to come up with a standard and fast. In their infinite wisdom, they decided to make the Motorola way the standard and this is now called the Network Byte Order. So we working on our poor old' Pentiums have to convert all the bytes we sent to this byte order. In sockets programming, the function htons does just this, but here, we'll have to write the program ourselves.

Low Byte11 * 1=1
High Byte22 * 256=512

unsigned int ohtons(unsigned int h)
{
	unsigned char h1,h2;
	unsigned short h5;
	h1 = (unsigned char ) h & 0xff;
	h2 = (h >> 8) & 0xff;
	h5 = 256*h1 + h2 ;
	return h5;
}

What this program does is take the number 258 and break it up into it's constituent bytes. It manages to do that using bitwise ANDing. When you AND a number by 1, it's value remains the name and when you AND it by 0, the result is a zero.

258
02ff
12864321684211286432168421
0000001011111111
1514131211109876543210

0x00ff
00ff
12864321684211286432168421
0000000011111111
1514131211109876543210

0x02ff (268)
&
0x00ff
=======
0x00ff
0x00ff
00ff
12864321684211286432168421
0000000011111111
1514131211109876543210

As you can see, ANDing with 0x00ff isolates the last byte of the int. The program stores that number (256) in the variable h1.

Now that we've got the low-word, lets grab the high-word. We shift the bits in the int 8 places to the right by using >>. Now the top 8 bits become the bottom 8 bits and the original 8 bits at the bottom fall of the edge and disappear forever. The higher 8 bits are replace by zeros.

258
02ff
12864321684211286432168421
0000001011111111
1514131211109876543210

258 >> 8

0002
12864321684211286432168421
0000000000000010
1514131211109876543210

So the value of h2 in the program is 2.

258
high byte11* 256=256
low byte22 * 1=2

513
high byte22 * 256=512
low byte11* 1=1

To get the Network Byte Ordered version of the bumber 258, all we have to do is send the int back with the numbers multiplied in the reverse order. If you do that you get 513, the number we're supposed to get. The second last line of the program does just that.

If we were dealing with a 'long' the process would be slightly longer, but essentially the same.

00 * 256 ^30 * 16777216
11 * 256^ 21 * 65536
22 * 256 ^12 * 256
33 * 256^0 3 * 1

33 * 256^33 * 16777216
22 * 256^22 * 65536
11 * 256^11 * 256
00 * 256^00 * 1

So, now the length of the packet is 44 bytes i.e 0x00 0x2c. Why it's 44 bytes we will worry about later.

If you still don't know what I'm talking about, then you'd better re-read the little Endian and big Endian discussion in our WinSock tutorial.

The next two bytes after the length hold the IDentification number of the packet. This ID field is used only in a few exceptional cases. Use any ID number you want here.

The next two bytes form the fragmentation field. These two bytes are further subdivided with the first three bits constituting a flags field and the rest of the bits holding data about the packet fragments.

"What exactly are fragments and why does the packet have to be broken up in the first place?", you ask (or you should if you're IQ's greater than a chimps).

The Internet is made up of a large number of individual networks which interact with each other. Each network is owned by different individuals and each has different properties. Some are faster than others, some more reliable and some have larger capacities. On an Ethernet network, the largest default packet size is 1500 bytes. Some networks may be able to support larger packets, but everyone can handle a minimum of 1500 bytes. If we send a 2000 byte large packet on such a network, it'll be cut up or fragmented into two halves; one 1500 bytes large and the there 500 bytes. At the other end, the packet will be reassembled and that's where the ID numbers come in handy. They help identify the different parts of the fragmented package. The header's of the fragmented packets will be identical except for the fragmentation field which will change. The last 13 bits of the fragmentation field hold the address of where the next fragment starts and therefor changes in every header.

Fragmentation is rather undesirable because if even one fragment of a packet is lost in transit or corrupted, the entire packet will have to be retransmitted (more about that in TCP). Life's been made a little simple for us because the minimum packet size without fragmentation supported on the Internet is 576 bytes, including the headers. We'll be keeping our packets smaller than that and so our fragmentation field will be 0x00 0x00 permanently.

Right after the fragmentation field we have a one byte field called the Time To Live or TTL. The TTL is defined as the number of seconds a packet will survive on the Internet before being dropped by the routers. In actuality, TTL really means the number of routers the packet can cross or hop over before being killed. The reason the TTL field was implemented was because you wouldn't want a lost packet to wander around the Internet till ten minutes before eternity (or till Bill Gates heart finally thaws, which will probably happen around the same time) now would you? So the TTL field insures that a packet is terminated after a set number of routers have been passed. This field is usually set to 32 by most WinSocks and that means that the packet can cross only 31 routers before being killed by the 32nd one.

Read our WinSock tutorial to see how this number can be used to find out how many routers the packet meets along the way.

The byte field after the TTL is the protocol field. The number in here indicates the type of packet to follow. If the value is 0x06, it means that the header after IP's is TCP. If it's 17, it means the following header is UDP and so on. Our protocol fields is set o 0x06 for TCP.

Following the protocol field is the IP checksum bytes. The checksum is rather simple to calculate and a program to do so is also provided. All we do is take individual bytes as groups of two and then add the groups together. So the 20 byte header turns into 10 groups of 2 bytes each and these 10 are added together. Once we're through adding, we might get a number larger than an INT. This is called the overflow and it's added back to the total. The number is then complemented i.e. convert the number to binary and turn all the 1's to 0's and vice-versa. That's all there is to it!

chk.c

#include<stdio.h>
unsigned short checksum(unsigned short  * ip1, unsigned int len) 
{
long sum = 0;
while ( len > 1) {
sum += *ip1++;
if ( sum & 0x80000000 )
sum = ( sum & 0xffff) + ( sum >> 16);
len -= 2;
}
while ( sum >> 16)
sum = ( sum & 0xffff) + ( sum >> 16);
return ~sum;
}
main( ) 
{
unsigned int j;
unsigned int chksum;
char aa [100];
for(j=0; j<=99;j++) 
{
	a[ j ] = j;
}
chksum = checksum ( a, sizeof( a ) );
}

The program accepts the address of an array as it's first parameter and it's length as the second. It calculates the checksum and returns it. We'll be using this later when we connect to a server by actually sending it TCP/IP bytes!

Finally, we come to the last two fields which are related to each other. An IP address is a unique 32-bit number given to every machine on the Internet to help identify it. When we send data using IP, we have to specify the IP address of the Destination computer (the Destination IP address) as well as the source computer's IP address (US, in other words). A more detailed explanation of IP address has been given in our WinSock tutorial.

The Internet Protocol

IP version 4 has some peculiar problems of its own. For one, it's completely connectionless. That means that IP doesn't knock on the door before stuffing the data through the window. It just doesn't wait for any acknowledgements or for permission. It's primary concern is speed and all else is secondary to that.

Now because IP is so concerned with speed, it's a little unreliable. Unlike TCP, which keeps track of the packets sent and makes sure each one of them reaches the other side safe and sound, IP just pumps data across as fast as possible. Keeping track of packets is not much of a concern. Along with being unreliable, IP is finicky about the route it takes too. One moment it's rushing down one path, the other moment, it's zooming up another. So it may so happen that packet number 2 may follow a faster route than packet number 1 and so end up at the destination before packet 1!

IP isn't concerned with any of this at all and quite rightly too. Reliability is TCP's speciality and it's claim to fame. IP delegates all reliability issues to the protocol it carries and is thus better able to do what it's best at, sending data across the vast expanse of the Internet as fast as it's little digital legs can carry it.


The above tutorial is a joint effort of

Mr. Vijay Mukhi
Ms. Sonal Kotecha
Mr. Arsalan Zaidi


Back to the main page


Vijay Mukhi's Computer Institute
VMCI, B-13, Everest Building, Tardeo, Mumbai 400 034, India
Tel : 91-22-496 4335 /6/7/8/9     Fax : 91-22-307 28 59
e-mail : vmukhi@giasbm01.vsnl.net.in
http://www.vijaymukhi.com