The curious case of ARP Netmask
4 min read

The curious case of ARP Netmask

Why would an ARP entry conatin a netmask?
The curious case of ARP Netmask

Earlier today, while working on a project at my workplace, I came along with a need - parsing the ARP table on a Linux host using C++.

The task was easy enough: On linux systems, the virtual filesystem mounted under /proc contains the path /proc/net/arp which tells you everything you need to know - all you have to do is read this path as a file in which each line is an entry, and you’re pretty much done.

Searching Google for code examples that parse the ARP table on Linux systems leads to SO answers that do exactly that, so I figured that this is a good way to do it and went about writing the code.

While writing the code, I noticed something strange in this file - something that felt like it doesn't belong here. Can you spot it?

Hint: Does one of the fields looks out of place?
Hint: Does one of the fields looks out of place?

ARP Protocol

Before I go into the field that caught my eye in the file, let’s talk a bit about the ARP protocol.

As anyone who ever took even the most basic networking class can tell you, ARP (Address Resolution Protocol) is a link-layer protocol who’s goal is to assist the transition from the Internet layer (L3) to the link layer (L2). The idea is to allow entities on the third layer to resolve L3 addresses (such as IPv4, being the most common example) into MAC addresses to which packets can be sent.

ARP is a very simple protocol. In the ARP protocol, each message contains either a single request or a single response - no more, no less. Whenever a host needs to know what is the MAC address that an IP on the network resolves to, it sends an ARP request - “who-has”, which is exactly what the host is asking - “who has this IP address?”. This message is broadcasted across the LAN until someone who posses the queried IP address responds with an “is-at” reply, which contains their MAC address.

Image by
Image by

This protocol is of course vulnerable to an attack known as “ARP Spoofing”, wherein a malicious host responds to the “who-has” request, thus impersonating the target computer and intercepting packets meant to be sent to the target computer. But this is not the focal point of this post, so let’s ignore that.


Let’s go back to the image shown before. In the image, you can find all of the fields you would’ve expect - IP-to-MAC binding, flags, the interface on which this record is valid…and a field called “Mask”. Huh?

This seemed peculiar to me - usually, in the networking world, a mask (or a net mask) is a way to specify that a rule or an entry applies to a broad range of IP addresses rather than a single one.

But this makes no sense in the world of ARP - in this world, there cannot possibly be a record that connects a whole region of the network to a single MAC address - this wouldn’t be logical!

Or would it? This was interesting enough to go down the rabbit hole.

I figured that the best place to learn more about this field would be at the man page for the proc VFS (man proc).

Scrolling to the part about /proc/net/arp:

As you can see, I saw no mention of the mysterious Mask field.

But it did lead me on to the headers of the relevant kernel headers (those that define ARP structs), where I found this comment:


Proxy ARP

Proxy ARP? I’ve never heard about that - let’s research! Iv'e Googled a bit about the topic, and this is what I've found.

Apparently, Proxy ARP (Defined in RFC 925) is an extension to ARP that allows a host on the network to declare itself as a Proxy ARP - that is, it declares that it will answer ARP requests on behalf of the proxied host, thus allowing hosts that otherwise couldn’t have talked to reach each other.

I’ve found this example, taken from here, to explain where Proxy ARP is needed:

After reading a bit about this extension to the ARP protocol, I immediately understood why the mask field is there and what is it used for - the idea is to allow network applianced to answer ARP requests with a net mask that states what part of the network this appliance can proxy L2 traffic for.

While this isn’t the most useful feature of all times, it is nice to know that this exists and to be aware that while working with networks you might encounter such configurations.

Is it any good? Probably not.

Is it nice to understand all of the fields in /proc/net/arp? YES!


As I wrote before, it’s things like that that make me adore computer networking so much. The fact that the entire modern network infrastructure is compatible with this unknown, non implemented, and poorly designed feature is nothing but a work of miracle in my mind.

And as always, these are the things I find joy in - digging into the unknown parts of computer systems, and understanding the rough corners where abominations such as this forsaken protocol lie.

And now, back to parsing!