The Address Resolution Protocol (ARP) handles the mapping between an Internet Protocol (IP) address and a Media Access Control (MAC) address. Linux stores all such mappings in a local system cache called an ARP table.
In this tutorial, we explore the main Linux command to display and control the ARP table. First, we briefly touch upon ARP caching and the resulting table structure. Next, we install a tool for managing this structure. After that, we talk about ways to display the ARP table. Later, we explain proxy ARP and cache filtering. Finally, we delve into creating and removing ARP cache entries.
We tested the code in this tutorial on Debian 11 (Bullseye) with GNU Bash 5.1.4 and net-tools 2.10-alpha. It should work in most POSIX-compliant environments.
2. ARP Caching
Once we see any host by reading a response or broadcast, our local ARP cache stores data in the form of a table:
+--------------+-------------------+ | IP Address | MAC Address | +--------------+-------------------+ | 192.168.6.66 | DE-AD-BE-EF-06-66 | | 192.168.6.10 | FE-ED-1D-EA-F0-10 | | 192.168.6.1 | 01-00-01-BE-E0-01 | +--------------+-------------------+
Usually, the Linux ARP table is available via the /proc pseudo-filesystem in the /proc/net/arp file:
$ cat /proc/net/arp IP address HW type Flags HW address Mask Device 192.168.6.66 0x1 0x6 de:ad:be:ef:06:66 * eth0 192.168.6.10 0x1 0x2 fe:ed:1d:ea:f0:10 * eth0 192.168.6.1 0x1 0x2 01:00:01:be:e0:01 * eth0
Notably, there are different separators for the MAC address in the tables above. Both are valid but depend on the tool and context.
Finally, we can display and modify the system ARP cache in a more human-friendly way via the Linux arp command.
3. Installing arp
To use a command, we usually need to install it first. On Debian, arp is available from the net-tools package:
$ apt install net-tools
Here, we use apt to perform the installation.
Critically, even if we install it, the arp tool wouldn’t work under the Windows Subsystem for Linux (WSL).
4. Show ARP Table via arp
To show the current entries in the ARP cache, we just run arp without any arguments or with -e:
$ arp Address HWtype HWaddress Flags Mask Iface 192.168.6.10 ether FE-ED-1D-EA-F0-10 C eth0 192.168.6.1 ether 01-00-01-BE-E0-01 C eth0
Unlike our example from earlier, the actual table has more fields:
- Address, IPv4 address of the device
- HWtype, type of link, where ether means Ethernet
- HWaddress, MAC address of the device with – dash as a separator
- Flags, one or more of C (complete), M (permanent), and P (published)
- Mask, optional IPv4 mask (netmask)
- Iface, local interface
Another way to format the entries is the -a flag, which outputs a BSD-style list that’s arguably easier to parse:
$ arp -a ? (192.168.6.10) at FE-ED-1D-EA-F0-10 [ether] on eth0 ? (192.168.6.1) at 01-00-01-BE-E0-01 [ether] on eth0
Like with other tools, we can use -n to avoid resolving any names to numbers. As a side note, IP addresses and hostnames are both valid in most arp commands. As usual, we can map one to the other via the /etc/hosts file.
Finally, when interpreting the flags in the standard output of arp, C (complete) means we got a response to our ARP query, and the host entry is fully configured. Further, permanent (M), i.e., static entries, don’t expire and are usually added manually but without using the temp argument.
On the other hand, published (P) flag entries are related to proxy ARP.
5. Proxy ARP
While not recommended, we can designate a proxy server that handles requests to IP addresses outside the local network. Thus, the proxy server responds with its own MAC address to ARP requests for any such IP address within its scope.
Since the proxy publishes itself, its resulting ARP cache entry in affected systems is called published, as marked by the P flag:
$ arp 192.168.6.68 Address HWtype HWaddress Flags Mask Iface 192.168.6.68 ether 08-00-08-EB-E0-68 CP 255.255.255.0 eth0
This is where the mask comes into play, as it shows the range of IP addresses behind the proxy. Starting from the Linux kernel version 2.2.0, ARP entries for whole subnets aren’t allowed by default.
6. Filter Entries with arp
Naturally, we can use the HWtype (-H) or Iface (-i) fields to filter the results. To do so, we supply a value to the appropriate arp flag:
- -H for HWtype
- -i for Iface
Let’s see how each one works:
$ arp -H ether Address HWtype HWaddress Flags Mask Iface 192.168.6.10 ether FE-ED-1D-EA-F0-10 C eth0 192.168.6.1 ether 01-00-01-BE-E0-01 C eth0 $ arp -i eth1 arp: in 2 entries no match found.
In the latter case, there are no matches since we supply a missing interface or one with no ARP entries. The argument to the -H flag can be ether (Ethernet), arcnet, pronet, ax25, and netrom. Of course, each one has a different physical address format.
Alternatively, supplying an address to arp filters via the Address field:
$ arp 192.168.6.1 Address HWtype HWaddress Flags Mask Iface 192.168.6.1 ether 01-00-01-BE-E0-01 C eth0
Here, we only see the entry we requested.
7. Handling ARP Entries with arp
Indeed, we can employ arp to modify the ARP table as well.
7.1. Add a Single ARP Entry
To manually include a simple entry in the ARP table, we use -s:
$ arp -s 192.168.6.99 10:99:90:BE:EF:99 $ arp 192.168.6.99 Address HWtype HWaddress Flags Mask Iface 192.168.6.99 ether 10:99:90:BE:EF:99 CM eth0
Since we didn’t use the temp specifier at the end, the Flags field now includes the M permanent flag.
If we want to use our own MAC address, the -D flag, in combination with a local interface, can replace the HWaddr entry. This is useful for proxy ARP.
Of course, we can also specify the options we already discussed: HWtype via -H and Iface via -i.
Let’s see how those work when adding an entry:
$ arp -v -i eth0 -H ether -s 192.168.6.100 10:99:90:BE:E1:00 arp: SIOCSARP() $ arp -v 192.168.6.100 Address HWtype HWaddress Flags Mask Iface 192.168.6.100 ether 10:99:90:BE:E1:00 CM eth0 Entries: 3 Skipped: 2 Found: 1
Here, we specify the interface and hardware address type for the entry while also enabling verbose mode with -v. Verbosity shows any function calls (SIOCSARP()), as well as additional information when filtering the output.
7.2. Add Multiple ARP Entries
When many ARP entries are involved, a file might be an easier way to add them. First, we create the file in a predefined format:
HOST_OR_IP MAC_ADDRESS [temp,pub] [netmask NETMASK]
Next, we use the -f flag that tells arp to use /etc/ethers or a supplied file path as the source for each mapping.
Let’s see an example ARP table file /arps and how to apply it:
$ cat /arps 192.168.6.66 DE-AD-BE-EF-06-66 temp 192.168.6.10 FE-ED-1D-EA-F0-10 192.168.6.1 01-00-01-BE-E0-01 $ arp -v Entries: 0 Skipped: 0 Found: 0 $ arp -f /arps $ arp -v Address HWtype HWaddress Flags Mask Iface 192.168.6.66 ether DE-AD-BE-EF-06-66 C eth0 192.168.6.10 ether FE-ED-1D-EA-F0-10 CM eth0 192.168.6.1 ether 01-00-01-BE-E0-01 CM eth0 Entries: 3 Skipped: 0 Found: 3
First, we show the contents of /arps. After that, we confirm that our ARP table is empty. Finally, we use the file to add all entries, one of which lacks the M flag since we added the temp option to it in the file.
7.3. Delete ARP Entry
To remove a mapping from the system ARP table, we use the -d flag with at least a hostname or IP address:
$ arp -d 192.168.6.100 ? (192.168.6.100) at 10:99:90:be:e1:00 [ether] PERM on eth0 $ arp -d 192.168.6.100 $ arp 192.168.6.100 arp: in 2 entries no match found.
Here, we verify the ARP entry for host 192.168.6.100 exists before deleting it and confirming the result of our operation.
As with other operations, we can specify the interface for our entry with -i.
In this article, we thoroughly explored the arp command along with its options.
In conclusion, while the Linux kernel provides information from ARP in /proc, we can display and modify the ARP table in a more human-friendly manner using the arp tool.