pete > courses > CS 431 Spring 25 > Lecture 08: helpers – ICMP & ARP
Lecture 08: helpers – ICMP & ARP
Goals
- describe the purpose of ICMP
- use ping to send ICMP echo requests
- construct ICMP requests and decode/interpret ICMP responses
- describe the purpose of ARP
- construct ARP requests and decode ARP responses
I ended the previous lecture with some foreshadowing questions:
- what happens if the routing table is consulted and a route isn’t found?
- if the application layer tells the network layer "please send this data to IP address 1.2.3.4", how does the system know which MAC address is associated with IP 1.2.3.4?”
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:
- I run the ping command above, with 140.233.20.202 as the destination IP address
- FreeBSD consults its routing table and determines that the default route is the one to use
- this means that the packet should be sent through 10.0.2.2
- so it constructs an IP packet with source IP of 10.0.2.15 (the IP address of the interface on the FreeBSD VM), a destination IP of 140.233.20.202 (as requested when I ran ping)
- it encapsulates this IP packet within an Ethernet frame, whose source MAC is the MAC address of the interface on the FreeBSD VM and whose destination MAC is the MAC address of 10.0.2.2
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