
In the previous article, Understanding LAN from a Front-End Developer's Perspective: MAC Addresses, Ethernet Frames, and Switches, we built a complete picture of LAN communication: devices identify each other by MAC addresses, data is encapsulated in Ethernet frames, and switches forward frames to the correct port based on the destination MAC address. Here's a simplified frame structure:
┌─────────────────────┐
│ Destination MAC │
├─────────────────────┤
│ Source MAC │
├─────────────────────┤
│ Type │
├─────────────────────┤
│ Payload │
├─────────────────────┤
│ Frame Check Sequence│
└─────────────────────┘This model tells us one thing clearly: to actually deliver data within a LAN, you must know the destination MAC address. Yet as front-end developers, what we deal with daily are domain names, URLs, and IP addresses. Once the browser resolves a target IP (say 192.168.1.20 on your local network or 151.101.2.133 for a remote server), it provides no MAC address information whatsoever. This raises a critical question:
When you already know the target IP address, how do you find its corresponding MAC address?
This is exactly the problem that ARP (Address Resolution Protocol) solves — and it's the crucial link that bridges the IP network layer with the data link layer.
If any of these feel unfamiliar, check out the previous article in this series, Understanding LAN from a Front-End Developer's Perspective.
Picture yourself sitting at your computer at home. You open a terminal and decide to ping your phone, which is connected to the same Wi-Fi:
ping 192.168.1.20You know your phone's IP is 192.168.1.20. You hit Enter. But your computer doesn't just shout into the void, "Hey, is 192.168.1.20 there?" — it has to figure something out first:
Which network interface card does this IP address belong to? What's its MAC address?
Because ultimately, data must be packaged into an Ethernet frame and sent out through the network card, and the destination address field in the Ethernet frame header only accepts MAC addresses, not IP addresses.
Think of it like this: you know your friend's name (IP address), but the courier needs their house number (MAC address). You need a lookup book that maps "name → house number" — and that's exactly what ARP is.
This is a common point of confusion for beginners: if I already know the destination IP address, why go through the extra step of looking up the MAC address? The answer is that the two serve fundamentally different purposes.
Let's use an analogy:
The IP address answers "where you're going." The MAC address answers "who handles this step."
Imagine you're mailing a letter from Beijing to New York. The envelope bears a New York street address (the IP address). But the letter doesn't fly directly to New York — it first goes to the mailbox at your apartment gate (first hop), then to the neighborhood post office, then to the city sorting center, then to an international mail exchange...
At every segment of this chain, the container carrying the letter gets a local shipping label (MAC address) for that segment. The final destination address on the letter itself never changes, but every segment's shipping label changes to match that segment's carrier. The networking parallel:
When data needs to be physically sent within a LAN, it must be packed into an Ethernet frame, and the frame header can only hold a MAC address. Even though higher-layer protocols (like TCP/IP) know the target IP, the moment the frame leaves the network card, the operating system must decide: who is the next recipient of this frame? Is it the target device itself, or the default gateway? The physical identity of this "next hop" is the MAC address.
A concise memory aid: IP is the "destination name"; MAC is "each step's feet."
ARP's function can be summarized succinctly: within the same LAN, given a target IP address, find the target device's MAC address.
There's a crucial limitation baked into this definition: ARP only works within the local LAN. It is not a protocol you can use to query the entire internet. Your computer cannot use ARP to ask for developer.mozilla.org's MAC address, because that server sits on the other side of the internet and will never receive the broadcast you initiate inside your home Wi-Fi network. ARP can only answer questions within a directly connected network, such as:
"Device with IP address
192.168.1.20on this LAN — what's your MAC address?"
ARP is defined in RFC 826, published in 1982. It operates between the link layer and the network layer, and it's a remarkably "thin" protocol — it does one thing, and it does it with brutal simplicity and efficiency.
Let's walk through ARP's interaction flow using a concrete LAN scenario. Imagine the following devices on your home network:
Computer A
IP: 192.168.1.10
MAC: AA:AA:AA:AA:AA:AA
Phone B
IP: 192.168.1.20
MAC: BB:BB:BB:BB:BB:BB
Router R (the default gateway)
IP: 192.168.1.1
MAC: RR:RR:RR:RR:RR:RR
Computer A now needs to send data to Phone B. It knows Phone B's IP (192.168.1.20), but not its MAC address. Communication cannot begin just yet.
Computer A's operating system first checks its own ARP cache table and finds no entry for 192.168.1.20. So it constructs an ARP Request and sends it out onto the LAN. The meaning of this request is:
"I'm
192.168.1.10, my MAC address isAA:AA:AA:AA:AA:AA. Device with IP192.168.1.20, what's your MAC address?"
Since Computer A has no idea which physical device 192.168.1.20 maps to, this frame can't be sent as a directed transmission — it must use broadcast. It gets wrapped in an Ethernet frame with the destination MAC set to FF:FF:FF:FF:FF:FF, which means "all devices on this LAN."
┌───────────────────────────────────────┐
│ Destination MAC: FF:FF:FF:FF:FF:FF │ (broadcast)
├───────────────────────────────────────┤
│ Source MAC: AA:AA:AA:AA:AA:AA │
├───────────────────────────────────────┤
│ Type: 0x0806 (ARP) │
├───────────────────────────────────────┤
│ Data: Who has 192.168.1.20? │
│ (contains sender's IP & MAC) │
└───────────────────────────────────────┘When the switch receives this broadcast frame, it performs a flood operation — copying the frame to every port except the one it arrived on — ensuring every device on the LAN sees it.
Here's the actual internal structure of an ARP Request packet:
┌──────────────────────────────────────────┬──────────────────┐
│ Hardware Type (1 = Ethernet) 2 bytes │ Protocol Type │
│ │ (0x0800 = IPv4) │
├──────────────────────────────────────────┴──────────────────┤
│ │ │ │
│ Protocol Type (cont.) 2 bytes │ HW Len │ PLen │
│ │ │ (6) │ (4) │
├──────────────────────────────┴─────────────────┴────────────┤
│ HW Len (6) │ Proto Len (4)│ Operation │
│ │ │ (1 = Request, 2 = Reply) │
├───────────────────────────────┴─────────────────────────────┤
│ │
│ Sender Hardware Address (6 bytes) │
│ e.g. AA:AA:AA:AA:AA:AA │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ Sender Protocol Address (4 bytes) │
│ e.g. 192.168.1.10 │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ Target Hardware Address (6 bytes) │
│ all 0 = unknown │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ Target Protocol Address (4 bytes) │
│ e.g. 192.168.1.20 │
│ │
└─────────────────────────────────────────────────────────────┘Key fields explained:
Every device on the LAN inspects the ARP request. Phone B notices that the queried IP 192.168.1.20 matches its own, so it knows: "They're asking about me." Other devices (like Router R) see the IP doesn't match theirs and simply discard the request.
Phone B immediately constructs an ARP Reply:
"I'm
192.168.1.20, my MAC address isBB:BB:BB:BB:BB:BB."
This reply doesn't need to be broadcast, because Phone B already learned Computer A's MAC address from the Source MAC field of the ARP request. So the ARP Reply is a unicast frame, sent directly to AA:AA:AA:AA:AA:AA.
┌───────────────────────────────────────┐
│ Destination MAC: AA:AA:AA:AA:AA:AA │ (unicast)
├───────────────────────────────────────┤
│ Source MAC: BB:BB:BB:BB:BB:BB │
├───────────────────────────────────────┤
│ Type: 0x0806 (ARP) │
├───────────────────────────────────────┤
│ Data: 192.168.1.20 is at BB:BB... │
│ (contains responder's IP & MAC) │
└───────────────────────────────────────┘In the ARP Reply packet, the Operation field is set to 2, and the Target Hardware Address field is filled with the queried device's real MAC address.
Once Computer A receives this reply, it now knows that 192.168.1.20 maps to MAC BB:BB:BB:BB:BB:BB. Only after this mapping is established can Computer A construct a valid data frame and send the actual application data to Phone B. At this point, ARP's job is done — it is not responsible for transporting any subsequent application data.
If every communication required a broadcast query beforehand, the LAN would quickly drown in ARP requests and communication efficiency would plummet. So the operating system caches ARP query results, forming an ARP table (ARP cache).
This table records IP-to-MAC mappings:
IP Address MAC Address Type
192.168.1.1 RR:RR:RR:RR:RR:RR dynamic
192.168.1.20 BB:BB:BB:BB:BB:BB dynamicThe next time Computer A needs to send data to 192.168.1.20, it first consults the local ARP table. If it finds an unexpired mapping, it can use it directly to construct the Ethernet frame, bypassing the entire ARP request-reply dance.
There are two types of entries in an ARP table:
For dynamic entries, each record has an aging time. Once expired, the entry is automatically removed. Different operating systems use different default aging times:
/proc/sys/net/ipv4/neigh/default/gc_stale_time, default around 60 secondsWhy does aging time exist? Because LAN topology is dynamic. Devices may disconnect, swap network cards, or obtain new IP addresses. The aging mechanism ensures ARP table entries don't point to a network card that no longer exists forever.
The command is essentially the same across operating systems:
# macOS / Linux
arp -a
# Sample output (macOS)
# ? (192.168.1.1) at xx:xx:xx:xx:xx:xx on en0 ifscope [ethernet]
# ? (192.168.1.20) at bb:bb:bb:bb:bb:bb on en0 ifscope [ethernet]
# Windows
arp -a
# Sample output
# Internet Address Physical Address Type
# 192.168.1.1 xx-xx-xx-xx-xx-xx dynamic
# 192.168.1.20 bb-bb-bb-bb-bb-bb dynamicOn Linux/macOS, you can also use the more powerful ip neigh command:
# Linux
ip neigh show
# Sample output
# 192.168.1.1 dev eth0 lladdr xx:xx:xx:xx:xx:xx REACHABLE
# 192.168.1.20 dev eth0 lladdr bb:bb:bb:bb:bb:bb STALEip neigh shows richer states than arp:
This is the single most important point for understanding how ARP ties into real-world network behavior. When your computer needs to access a remote server on the internet — say, developer.mozilla.org (let's assume IP 151.101.2.133) — it does not broadcast "Who has 151.101.2.133?" on the LAN.
The reason is straightforward: your computer uses the subnet mask to determine that 151.101.2.133 is not on the local LAN.
Your IP: 192.168.1.10 → 11000000.10101000.00000001.00001010
Subnet Mask: 255.255.255.0 → 11111111.11111111.11111111.00000000
Your Network: 192.168.1.0 → 11000000.10101000.00000001.00000000
Target IP: 151.101.2.133 → 10010111.01100101.00000010.10000101
Subnet Mask: 255.255.255.0 → 11111111.11111111.11111111.00000000
Target Net: 151.101.2.0 → 10010111.01100101.00000010.00000000
Result: 192.168.1.0 ≠ 151.101.2.0 → different networksFor any non-local target IP, the operating system uniformly hands the packet to the default gateway. In a home network, the default gateway is usually the router's IP address — for example, 192.168.1.1. So what the computer actually needs to ARP-query is:
"Who has
192.168.1.1? Tell me your MAC address."
Router R responds to this ARP request with its MAC address RR:RR:RR:RR:RR:RR. After that, the data frame Computer A sends to the remote server looks like this:
┌─────────────────────────────────────┐
│ Destination MAC: RR:RR:RR:RR:RR:RR │ ← Router R's MAC
├─────────────────────────────────────┤
│ Source MAC: AA:AA:AA:AA:AA:AA │ ← Computer A's MAC
├─────────────────────────────────────┤
│ Type: 0x0800 (IPv4) │
├─────────────────────────────────────┤
│ ┌───────────────────────────────┐ │
│ │ Source IP: 192.168.1.10 │ │
│ ├───────────────────────────────┤ │
│ │ Destination IP: 151.101.2.133 │ │ ← Remote server's IP
│ ├───────────────────────────────┤ │
│ │ TCP segment + HTTP data │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────┘This demonstrates the beauty of layered separation: the Ethernet frame's destination MAC is the LAN's "next hop" (the router), while the IP packet's destination IP is the final server thousands of miles away. The two can point to entirely different devices.
When the router receives this frame, it decapsulates it to see the IP packet, then consults its routing table to determine the next-hop path, re-encapsulates it into a new link-layer frame, and forwards it onward. This leads to a broader principle:
Throughout a packet's journey, the IP packet's destination address typically stays the same (ignoring NAT), but the link-layer frame carrying it changes its destination MAC address at every hop along the way.
A common misconception is that the switch is responsible for resolving IP addresses to MAC addresses. That's not the case. In the standard model, responsibilities are divided as follows:
When a host sends an ARP broadcast request, the frame's destination MAC is FF:FF:FF:FF:FF:FF. The switch recognizes this as a broadcast address and performs its standard action: flood the frame to all other ports in the same broadcast domain. The switch couldn't care less which IP address the ARP request is asking about. When the ARP reply comes back as a unicast, the switch forwards it precisely based on the destination MAC. As you can see, the switch merely provides reliable transport for ARP messages — it doesn't participate in the "resolution" itself.
Here's another way to think about their collaboration:
| Actor | What It Says |
|---|---|
| ARP | "I don't know where the target is — can you broadcast for me?" |
| Switch | "Sure, you want a broadcast? I'll knock on every door." |
| ARP | "The target replied! I know its MAC now. Send directly." |
| Switch | "I've got that MAC on record. Delivering precisely." |
ARP doesn't only work when "I need to communicate." There's another very common scenario called Gratuitous ARP — a device proactively broadcasts a "special ARP request," but the IP it's querying is not someone else's — it's its own.
What does this mean? A device sends an ARP request in which:
"I'm
192.168.1.20, my MAC isBB:BB:BB:BB:BB:BB. Who has IP192.168.1.20? — Oh, that's me."
This sounds like talking to yourself, but it serves two important purposes:
Purpose 1: IP address conflict detection. When a device is newly assigned (or manually configured with) an IP address, it sends a gratuitous ARP to ask whether any other device on the LAN is already using that IP. If another device responds, an IP address conflict exists, and the current device should abandon the IP.
Purpose 2: Updating other devices' ARP caches. In failover scenarios, when a backup server takes over the primary server's IP address, it sends a gratuitous ARP to notify every device on the LAN: "The MAC address for this IP has changed — please update your ARP tables!" This quickly redirects traffic to the new device without waiting for each host's ARP cache to naturally expire.
ARP is elegantly simple and efficient, but it also has an inherent security flaw: it unconditionally trusts any reply it receives. When a device receives an ARP reply, it updates the IP-MAC mapping in its ARP table — even if it never sent a request in the first place.
This opens the door for ARP spoofing attacks. An attacker on the LAN can send forged ARP replies, claiming that the gateway's IP (e.g., 192.168.1.1) maps to the attacker's own MAC address. The victim host updates its ARP table and erroneously sends all traffic destined for the gateway to the attacker instead, leading to traffic interception or disruption.
Normal state:
192.168.1.1 → RR:RR:RR:RR:RR:RR (real router)
After attacker sends forged ARP reply:
192.168.1.1 → XX:XX:XX:XX:XX:XX (attacker's MAC)
Result: all of the victim host's outbound traffic passes through the attacker's NICUnderstanding ARP's lack of authentication is foundational to recognizing man-in-the-middle attacks within a LAN. While advanced switches support security features like DAI (Dynamic ARP Inspection), ARP's trust model is what it is.
As a final note: ARP is an IPv4 protocol. In IPv6 networks, its function is replaced by a more comprehensive protocol called NDP (Neighbor Discovery Protocol), which uses ICMPv6 messages to handle address resolution, neighbor tracking, and router discovery — all without relying on broadcast. That's a topic for another day, which we'll cover in a future article on IPv6.
Inspect your computer's ARP table
Open a terminal and run arp -a (or ip neigh show). Can you identify which entry corresponds to your router?
Observe ARP requests in action
Use ping to contact a device on your LAN that you've never communicated with before (a roommate's computer, or your router's IP). Then capture packets with Wireshark or tcpdump to find the ARP request and reply.
# macOS/Linux packet capture (requires sudo)
sudo tcpdump -i en0 arp -n
# In another terminal, ping the gateway
ping 192.168.1.1Manually add a static ARP entry On Linux or macOS, add a static ARP record manually:
# macOS
sudo arp -s 192.168.1.100 aa:bb:cc:dd:ee:ff
# Linux
sudo ip neigh replace 192.168.1.100 lladdr aa:bb:cc:dd:ee:ff dev eth0 nud permanentCheck the change with arp -a and observe why static entries have no expiration time.
Simulate an IP address conflict Assign the same IP address to two devices on the same LAN and use Wireshark to observe the gratuitous ARP interactions. See if the operating system detects the conflict and shows a warning.
This chapter revolved around one core question: Given an IP address, how do you obtain the MAC address needed for communication? The answer is ARP.
ARP MAC Address IP Address Broadcast/Unicast ARP Cache Default Gateway ARP Spoofing Gratuitous ARP NDP
With this chapter, we've filled the critical gap between "knowing the IP" and "sending the Ethernet frame." ARP elegantly maps IP to MAC within the same LAN — but this very mechanism reveals a deeper limitation: ARP only works within a broadcast domain. The moment a packet needs to leave the LAN, the entire MAC-based communication model hits a wall.
The next article pivots to a fundamental question: Why can't we just use MAC addresses for the entire Internet? What makes them fundamentally unsuitable for global-scale communication, and what kind of addressing system does the Internet need instead?