Examining ICMP Packets

In the past few articles, we examined the frames that were captured by the tcpdump utility during a brief telnet session. We've had a chance to look at IP headers, TCP headers, and ARP packets and had left off at the ICMP packets. Before we take a look at these packets, let's do a brief overview of the ICMP protocol.

ICMP stands for the Internet Control Message Protocol, and it was designed to send control messages between routers and hosts. For example, an ICMP packet may be sent when a router is experiencing congestion or when a destination host is unavailable.

An ICMP packet has a slightly different structure than we've seen before. An ICMP header follows the IP header in an IP packet, but it is not considered to be a Layer 4 header like TCP or UDP. Instead, ICMP is considered to be an integral part of IP; in fact, every vendor's implementation of IP is required to include ICMP.

Here is a picture of the fields an ICMP header adds to an IP packet:

8

16

32 bits

Type

Code

Checksum

Identifier

Sequence number

Data

You'll note that an ICMP header is composed of six fields. Interestingly, the Data field does not contain the actual ICMP "message." Instead, the Type and the Code fields contain numeric values, and each numeric value represents a specific ICMP message. Every ICMP packet must have a Type value, but only some ICMP types have an associated non-zero Code value.

RFC 1700 contains the possible values for each ICMP type and code; I've summarized these into the following table:

You'll note that the ICMP types that do have associated codes use the Code field to further explain the message value in the Type field. For example, ICMP Type 3 represents "destination unreachable." There can be many reasons why a destination is unreachable; accordingly, every ICMP Type 3 packet will also use one of the codes to explain why the destination was unreachable.

In our dump file, packets 4-9 contained ICMP information. These packets were created right after ARP had determined the destination MAC address and just before the TCP 3-way handshake. Let's take a look at packets 4 and 5:

Notice that these are normal IP packets with the expected IP header fields. Immediately following the IP header is the ICMP header which is followed by some strange-looking data. The tcpshow utility did not show all of the ICMP fields, but you can see that Packet No. 4 was an echo-request and Packet No. 5 was an echo-reply. If we look up these names in the chart, we'll see that Packet 4 contains an ICMP Type 8 Code 0 message, and Packet 5 contains an ICMP Type 0 Code 0 message.

Let's look at these same packets using Ethereal. Because Ethereal is so verbose, I'll just show the frame number and the ICMP header:

Notice that Ethereal interprets all of the ICMP fields, including the Type and Code numbers. It also indicates the name of the utility that issued these ICMP packets -- before TCP initiated its 3-way handshake, three "ping" packets were sent out to verify connectivity between my telnet client and the telnet server. The first ping packet contained the echo-request and it was followed by the desired echo-reply.

Packets 6 and 7 contained the next echo-request/echo-reply pair. These packets were identical, except they both contained a sequence number of 01:00, instead of the sequence number of 00:00 you saw in Packets 4 and 5. Packets 8 and 9 contained the last echo-request/echo-reply pair and both shared a sequence number of 02:00. However, all six packets contained the same Identifier value of 0xdd00; this means that they were all issued from the same ping command.

To summarize, whenever you run the ping utility, you will send out ICMP Type 8 Code 0 packets. Each packet will have the same identifier, but every packet's sequence number will be increased by 1. If you have connectivity to the other host, you should receive back ICMP Type 0 Code 0 packets with the same identifier. If you don't receive all the packets back in sequence, you don't have a very reliable connection.

You've probably used the ping utility yourself to test the connection between two hosts running TCP/IP; you may have not known that ping uses ICMP. Here is an interesting article on ping by the author of the utility.

The traceroute utility is another utility that uses ICMP messages, but its usage is different from that of the ping utility. When you type traceroute hostname, three UDP packets are sent out with a TTL (time to live) value of 1. These three packets will arrive at the router closest to you which will decrease the TTL by one, meaning the TTL will now be 0. When routers notice a TTL of 0, they respond by sending an ICMP packet of Type 11 Code 0, or "time exceeded" as "time to live exceeded in transit." The traceroute utility will make note of the IP address of the router that sent back the three ICMP packets, calculate the time it took to receive each of the packets, then send out three more UDP packets, this time with a TTL of 2.

Because these packets have a TTL of 2, ICMP packets should be returned by the router that is two hops away from you. Once these packets are received and noted, traceroute sends out three more packets with a TTL of 3. The traceroute utility will continue this pattern until you either reach your final destination or you've gone through the default maximum of 30 routers. The results will be sent to your screen like so:

Note that the traceroute utility numbered each hop, gave the name and IP address of the associated router, and recorded the time it took to receive an ICMP response to each of the three UDP packets that were sent to each router.

The ping and traceroute utilities are the most common utilities used by users that involve the ICMP protocol. However, there is another ICMP type that you should be aware of as it can affect network performance if there are routers between you and your final destination.

When I captured the packets involved in the telnet session, both the telnet client and the telnet server were cabled onto the same LAN and none of the packets had to pass through a router. During the TCP 3-way handshake, each host indicated the maximum segment size (MSS) it was capable of receiving. The tcpshow utility did not interpret this data, but it can be seen using Ethereal:

Because both computers were cabled onto the same LAN, they both understood and agreed upon a MSS of 1,460 bytes. Note that this is a maximum "segment" size, meaning a segment of data without including the extra bytes needed for the headers and frame. In this example, both hosts agreed that they wouldn't send a segment of data that was bigger than a 1,460-byte chunk.

What would happen if these two same hosts were not on the same LAN and their packets had to pass through a network that could only accept frames with a maximum transmission unit (MTU) size of 576 bytes? Because the two end hosts had already agreed upon a segment size of 1,460 bytes, they would be creating their IP packets accordingly. When these IP packets arrive at the router, which is cabled to the network with the smaller MTU, it will have to re-package every packet into smaller segments that will fit into the smaller size frames of that network. The destination host will then have to reassemble all of the fragmented packets back into the original agreed-upon sized segment. This creates more work and definitely slows things down.

To help prevent this, TCP uses something called Path-MTU Discovery. TCP will send out IP packets using the agreed MSS size, but will set the DF (don't fragment) bit to 1. If this packet is received by a router that needs to fragment the packet so that it will fit over a network that uses smaller-sized frames, the router will respond with an ICMP Type 3 Code 4 packet which translates to "destination unreachable as fragmentation needed" and "DF bit set." When the host receives this ICMP packet, it knows that it needs to start sending smaller packets.

The last ICMP type I'd like to cover is Source Quench, or ICMP Type 4 Code 0. This message is sent whenever a router is being overwhelmed by packets. It basically tells the host to slow down the rate it is sending packets so it can have a chance to deal with the packets it has already received. This is an important message -- if the host does not slow down its transmission rate, the router will run out of buffer space to store packets and will have to start throwing packets away. Every packet that is thrown away will have to be re-transmitted which will make the original situation worse.

The ICMP types we've covered do have implications when you start creating packet filter rules on your FreeBSD system. Next week, we will start looking at creating these rules, I'd like to summarize the ICMP types and codes that we'll need to be mindful of:

ICMP Type

Code

Used By

0

0

Ping

3

4

Path-MTU Discovery

4

0

Source Quench

8

0

Ping

11

0

traceroute

Dru Lavigne
is a network and systems administrator, IT instructor, author and international speaker. She has over a decade of experience administering and teaching Netware, Microsoft, Cisco, Checkpoint, SCO, Solaris, Linux, and BSD systems. A prolific author, she pens the popular FreeBSD Basics column for O'Reilly and is author of BSD Hacks and The Best of FreeBSD Basics.