pete > courses > CS 431 Spring 25 > Lecture 08: helpers – ICMP & ARP


Lecture 08: helpers – ICMP & ARP

Goals


I ended the previous lecture with some foreshadowing questions:

today we will answer both of these and more


I want to show this stuff in action, and to do so, we need the ability to send packets to arbitrary addresses

to that end, I present to you the ping program

this is a standard program that is shipped on pretty much every system (though specific arguments may differ)

in its most basic usage, it sends out a specific packet to a target IP that says "please respond"

if the host to which that IP address is assigned is operational and well-behaved, it will respond accordingly

on its own, IP can’t do this, so it will not surprise you to learn that we will put something else inside the IP packet


that something else is an ICMP message

ICMP is the Internet Control Message Protocol and is used for diagnostic-ish stuff like "are you there?" requests and "yes I am" responses

ICMP is defined in RFC 792

this is the first protocol we’re looking at that is not expected to encapsulate stuff inside it

the others (ie, Ethernet, IP) have all been intended to transport somebody else’s data

ICMP is that data

therefore, one can almost imagine ICMP as our first application-level protocol (meaning a protocol that actually solves a problem on its own, rather than being a building block)

but since it’s used almost exclusively for diagnostics, it’s usually not thought of as an "application", per se


anyhoo, if you skim through the RFC, you will see that it supports several different message types

the particular message type that we’re interested in is the "Echo request"

we could carefully read through the RFC to understand how it works and how it’s encoded

an alternative is to send some packets with the characteristics that interest us and use a tool like Wireshark to dissect the actual bits that are sent and received

note that, in practice, it is important to be comfortable with both of these approaches!

knowing both the ideal (ie, the RFC) and the reality (ie, the bits shown by Wireshark) is vital to a complete understanding


for the Wireshark demonstrations, I will describe what I did to cause the packets to be sent

I will also link a file that contains those packets, so you can load it into Wireshark when reviewing the notes

download the file (right-click -> Save As) and then open it in Wireshark (File -> Open)


open up Wireshark, start it capturing on the main external interface (in VBox, this will be em0; in UTM, this will be vmnet0)

in the display filter bar at the top, enter "icmp", which will cause it to show only IP packets that contain ICMP messages

in a separate terminal window, we can run ping:

$ ping -c1 weathertop.cs.middlebury.edu
PING weathertop.cs.middlebury.edu (140.233.20.202): 56 data bytes
64 bytes from 140.233.20.202: icmp_seq=0 ttl=63 time=27.222 ms

--- weathertop.cs.middlebury.edu ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 27.222/27.222/27.222/0.000 ms

-c1 asks ping to send a single request (otherwise it will send one per second until we press ^C)

first, ping tells us that the IP address of weathertop.cs.middlebury.edu is 140.233.20.202

(we will answer the question of how the system finds this IP address on another day)

ping also tells us that the round-trip time (ie, the time elapsed between the request being sent and the response being received) is 27.222 milliseconds

back in Wireshark, we see the two packets that flew back and forth: the "Info" column identifies the first packet as an "Echo (ping) request" and the second as an "Echo (ping) reply"

(the capture file containing the packets sent and received is here: (icmp-echo.pcapng)[icmp-echo.pcapng])

note also the very left-hand column, which shows a right-facing arrow for the first packet and a left-facing arrow for the second packet: this is Wireshark associating the outgoing request with the incoming response (super useful when there are lots of intervening packets)


if we click on the first packet, the request, we see its details pop up in the pane below

we see that it is indeed an ICMP message, within an IP packet, within an Ethernet frame

it’s worth looking a bit at the Ethernet frame; most notably, the "Type" field is set to 0x0800, which is the code for IPv4, which is how everybody knows that the payload of the Ethernet frame is an IP packet

in the IP header, we see the source address is 10.0.2.15; this is the IP address of my virtual machine

the destination address is 140.233.20.202, as expected from the output of ping above

finally in the IP header, we see the Protocol field set to 1, which Wireshark tells us means its payload is ICMP

again, not surprising, but good to see confirmed


now, in the ICMP portion, we see that its type is 8, which signifies an Echo request

we see that it has a checksum, whose precise details we could look up in the RFC, but we will leave aside for now

the identifier field is a random sequence of bits, shown in both big-endian (BE) and little-endian (LE) interpretations

the idea is that the corresponding response will include the same sequence of bits, and so the receiver will know which request the response applies to

at the bottom, we find 56 bytes of random data; again, this is duplicated in the response


and let’s now look at the response

the Ethernet source and destination are swapped

as are the IP source and destination

both are to be expected, given that this packet flowed the opposite direction

the ICMP Type is now 0, which indicates an Echo reply

and the Identifier and Data fields are the same as in the corresponding request

perhaps not super exciting, but useful to see concretely, especially as you will be poking around at this level a lot over the rest of the semester


so ping is the tool we’re going to use to send packets

it is, in fact, a pretty fundamental tool for network diagnostics

it can tell us whether a host is responsive

it can also tell us how long it takes to get packets to/from that host

assuming, of course, that the host is configured to respond to echo requests, and all routers along the path are willing to forward ICMP echo requests and responses, which is not always a given


now it’s time to send packets that tickle problematic circumstances like being unable to find an applicable route

before we can do that effectively, we have to understand a bit about the structure of the network in which the virtual machine resides and is connected to

there are minor differences between how VirtualBox and UTM set things up, but the common part is the important one: any packet sent out of the virtual machine will use the host as a router

here is a diagram of the network set up by VirtualBox:

                                                            +---------------+
            +-----------+       +------------+              |  Middlebury   |
+----+ .15  |    VM     |    .2 |            | 10.3.21.72   |    Network    |
| VM +------+  Network  +-------+    host    +--------------+               +---- Internet
+----+      | 10.0.2/24 |       |            |              |    10.3/16    |
            +-----------+       +------------+              |               |
                                                            +---------------+

you can confirm the numbers using netstat and ifconfig on the VM

the network set up by UTM is similar; only the numbers are different

in this case, the "host" box is a router: it has two interfaces, each connected to a different network, and it passes packets between those networks


so now, imagine I remove the default route on the host: when a packet sent out
of the virtual machine reaches the host, the host won't have an applicable
route

and we'll be able to see what happens

since my host is Linux, here is the routing table before:

(note that commands prefixed with `host$` are run on the host; all others are
run on the virtual machine)

host$ netstat -rn Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface 0.0.0.0 10.3.0.1 0.0.0.0 UG 0 0 0 wlan0 10.3.0.0 0.0.0.0 255.255.0.0 U 0 0 0 wlan0 ~~~

then I delete the default route:

host$ sudo route del default

and here is routing table after:

host$ netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
10.3.0.0        0.0.0.0         255.255.0.0     U         0 0          0 wlan0

now I’m ready to send the ping

$ ping -c1 weathertop.cs.middlebury.edu
ping: Unknown host

the same command as before fails, because we need that route to perform the translation from the name weathertop.cs.middlebury.edu to its IP address

but we can just ping the IP directly:

$ ping -c1 140.233.20.202
PING 140.233.20.202 (140.233.20.202): 56 data bytes

--- 140.233.20.202 ping statistics ---
1 packets transmitted, 0 packets received, 100.0% packet loss

it is apparently able to send the request, but it does not get a response, as indicated by the last line of the output


here’s the packet capture: icmp-network-unreachable.pcapng

as before, we see the outgoing ICMP echo request

and as expected, we do not see a corresponding ICMP echo response

we do see an ICMP message, though: this one is labeled as "Destination unreachable (network unreachable)"

note the source IP address of this message: it matches the IP address of the host’s interface on the VM network

this makes sense because it’s the host that encountered the problem


if we look more closely at the packet in Wireshark, we see reasonable things in the Ethernet and IP headers

the ICMP message uses "Type=3" to signify an unreachable destination

and "Code=0" to signify that the thing that was unreachable was a network

it also contains a copy of the IP headers from the packet that caused the problem


so ICMP is used not only to send ping requests and responses, but also to inform senders that their packet could not be sent in the event of a failed routing-table lookup

this reinforces the idea that ICMP is a diagnostic protocol


briefly, for completeness, I can restore the default route thusly:

host$ sudo route add default gw 10.3.0.1

host$ netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         10.3.0.1        0.0.0.0         UG        0 0          0 wlan0
10.3.0.0        0.0.0.0         255.255.0.0     U         0 0          0 wlan0

host$ ping -c1 140.233.20.202
PING 140.233.20.202 (140.233.20.202): 56 data bytes
64 bytes from 140.233.20.202: icmp_seq=0 ttl=63 time=4.572 ms

--- 140.233.20.202 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 4.572/4.572/4.572/0.000 ms

so that answers the question of what happens when a packet is received by a router and the router cannot determine a route for it

what about the other question?

how do we know the destination MAC address to put in the Ethernet header?

more fully, consider this situation:

this all follows from our discussion of how routing happens, two lectures ago

but how does it know the MAC address of 10.0.2.2?

answer: it has to ask


first, I tell the system to forget about the MAC address for 10.0.2.2:

$ sudo arp -d 10.0.2.2

then I run ping -c1 140.233.20.202 and see what shows up in Wireshark

packet capture here: arp-and-ping.pcapng

now we see four packets

the final pair are the ICMP echo request and response as before

the first two are different: their protocol is ARP and the Info field is quite helpful

the first packet’s info field says "Who has 10.0.2.2? Tell 10.0.2.15"

this is exactly the question we want answered! we know the IP address of the router (10.0.2.2) but we (10.0.2.15) need its MAC address

the second packets info field is similarly helpful: "10.0.2.2 is at 52:54:00:12:35:02"

this is the information we need!


let’s look more closely at the packets themselves

first, note that both the request and reply are ARP (Address Resolution Protocol) messages encapsulated within Ethernet frames

first of all, this is because ARP is intended for use within a network and not between networks, and therefore has no use for IP

indeed, ARP needs to work before we can even think of doing IP, so ARP can’t itself use IP

next, because we don’t know the Ethernet address we’re looking for, we need to send the request to everybody: the Destination address field of the Ethernet header is set to FF:FF:FF:FF:FF:FF, which is the broadcast address we talked about previously

the ARP request itself is fairly straightforward, though there are several fields to pay attention to

the "Hardware type" field specifies what kind of link layer address we’re looking for

the "Protocol type" field specifies what kind of network layer address we have

(ARP was designed before Ethernet and IP won their respective niches, so it was designed to be flexible)

the "Hardware size" and "Protocol size" fields specify the number of octets used for the link layer and network layer addresses, respectively

it is reassuring to see that here Wireshark corroborates our understanding that Ethernet addresses are 6 octets long and IP addresses are 4 octets long

the "Opcode" field indicates that this is request, given by the value 0x0001

the "Sender MAC address" and "Sender IP address" fields identify the host making the request

the "Target MAC address" and "Target IP address" fields identify the host about which we are seeking information

of these fields, the "Target MAC address" is blank ("00:00:00:00:00:00") because that’s the information we don’t know (but want to)


the response is pretty much the same in spirit

in the Ethernet header, the destination address is the same as the source address of the request

and the source address is the MAC address of the machine that is responding

in the ARP part, the opcode is now 2, indicating a reply

the "Sender MAC address" and "Sender IP address" now contain values that describe the responder

and the "Target MAC address" and "Target IP address" now contain values that describe the requester

so the information that was originally requested is now available in the "Sender MAC address" field of the reply


having received the ARP response, FreeBSD has all the information necessary to construct the Ethernet frame

and therefore we see the ICMP echo request on the following line in Wireshark


and this sums up our answer: the Address Resolution Protocol (ARP) is used to translate from IP addresses to their corresponding MAC addresses

because packets may be sent frequently, it doesn’t make sense to send an ARP request for every packet, therefore the results are cached

which is why I needed to run that inscrutable command before ping

let’s now look at the arp command more closely

with the -a parameter, it will show the contents of the "ARP table"—that is, the list of IP-to-MAC translations it has cached

$ arp -a
? (10.0.2.15) at 08:00:27:42:28:c8 on em0 permanent [ethernet]
? (10.0.2.2) at 52:54:00:12:35:02 on em0 expires in 717 seconds [ethernet]

the first one is listed as permanent, because it corresponds to an interface that is attached to the host

the second one expires in 717 seconds

we can delete entries using the -d command, as demonstrated above


previously, we looked at what happens when a packet is unable to be routed: we get an ICMP network unreachable message back

what happens when we don’t get an ARP response?

(this one is a bit difficult to test, as it requires that we find an IP address that nobody is using; I was able to find one pretty quickly, but there is not guarantee the same IP will be unused if you try to run this later yourself)

$ ping -c1 10.3.21.101
PING 10.3.21.101 (10.3.21.101): 56 data bytes
92 bytes from 10.3.21.72: Destination Host Unreachable
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
 4  5  00 0054 c6f8   0 0000  3f  01 893a 10.0.2.15  10.3.21.101


--- 10.3.21.101 ping statistics ---
1 packets transmitted, 0 packets received, 100.0% packet loss

FreeBSD’s ping gives us lots of diagnostic information; the important part is the third line: Destination Host Unreachable

it will perhaps not surprise you to learn that this came from an ICMP message

packet capture here: icmp-host-unreachable.pcapng

pretty much the same as the "Destination network unreachable" ICMP message we saw earlier

the only difference is the Code is now 1, to indicate that a host was unreachable (rather than a network, with Code=0)

this ICMP error also includes the IP headers of the packet that caused the error, which is all the extra information that FreeBSD’s ping is showing us above (version, header lention, type of service, length, identification, etc)


next time, we’ll play some games with ping to learn more about the structure of the Internet at large, and see where that takes us

Last modified: