is it dns? / wiki ← back to the live monitor

๐Ÿงฌ Layer 2: Ethernet, MACs, ARP, switches

Layer 2 is where computers on the same wire find each other. DNS doesn't run here, but every DNS packet crosses your L2 segment twice (query out, answer back) and gets a fresh L2 frame on every hop in between. When DNS looks broken in a way that smells like "only sometimes," L2 is the prime suspect.

What Layer 2 actually does#

L2 moves frames between devices on the same local network segment. A frame is a packet plus an envelope that says:

  • where it's going (destination MAC address)
  • where it came from (source MAC address)
  • what kind of payload it's wrapping (IPv4? IPv6? ARP? 802.1Q VLAN tag?)
  • a CRC at the end so the receiver can detect corruption

That's it. L2 has no concept of routing, no notion of the Internet, no awareness of DNS. It just hands frames between two devices that share a wire (or a switch fabric pretending to be a wire). A frame lives for exactly one link: every router along the path strips the L2 header and builds a fresh one for the next link, which is why MAC addresses never survive past the first router.

MAC addresses#

Every Ethernet interface has a 48-bit address burned in at the factory:

b8:27:eb:1a:2b:3c
โ””โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜
   โ”‚        โ””โ”€ NIC-specific (assigned by the vendor)
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ OUI (Organizationally Unique Identifier, identifies the vendor)

Useful properties:

  • First 24 bits identify the vendor. b8:27:eb is Raspberry Pi; 00:50:56 is VMware; 00:14:22 is Dell; 00:1c:7f is Check Point. Look up unknown OUIs at Wireshark's OUI lookup.
  • Locally administered bit (the 0x02 bit of the first octet) means "this MAC was set by software, not burned in." VMs, containers, and bonded interfaces commonly use these.
  • Broadcast MAC is ff:ff:ff:ff:ff:ff: every device on the segment processes a frame with this destination.
  • Multicast MACs have the low bit (0x01) of the first octet set. IPv4 multicast maps into 01:00:5e (RFC 1112 s6.4), IPv6 multicast/NDP into 33:33 (RFC 2464 s7).

Show all MAC addresses on this host:

ip -br link

macOS users: ip is a Linux tool. See the macOS equivalents note in the Useful CLI section below.

Or peek the ARP cache to see who is on the segment with you:

ip neigh

ARP: the L2 โ‡„ L3 bridge#

When your laptop wants to talk to the resolver at 198.51.100.53, it knows the IP but not the MAC. It can't put a frame on the wire without the destination MAC. So it asks, using ARP (RFC 826):

"Who has 198.51.100.53? Tell 198.51.100.42."
(broadcast; every device on the L2 segment receives this)

The resolver replies:

"198.51.100.53 is at 00:00:5e:00:53:53"
(unicast; back to the asker)

Your laptop caches that mapping (on Linux an entry stays fresh for a randomized 15 to 45 seconds before the kernel revalidates it, per arp(7); other OSes hold entries for minutes) and finally puts the DNS query on the wire. Every IP conversation on Ethernet starts this way; ARP is the universal handshake before anything else can happen at L3+.

One catch: ARP only works on-link. If the resolver sits on a different subnet, your host ARPs for its default gateway instead, and it is the gateway's MAC that lands in your cache; the resolver's own MAC never appears on your segment.

To watch ARP in action, flush the cache, fire a fresh DNS query, then check the neighbor table. The resolver's MAC (or your gateway's, if the resolver is off-subnet) will now be cached:

sudo ip neigh flush dev eth0
dig +short @198.51.100.53 example.com
ip neigh
sudo ip neigh flush dev eth0
nslookup example.com 198.51.100.53
ip neigh

Replace eth0 with your interface name from ip -br link (macOS: en0 is the usual name for the primary interface; flush a single entry with sudo arp -d <ip> instead). Flushing the cache needs root; reading it doesn't.

198.51.100.53 is an RFC 5737 documentation address used here as a stand-in for a real resolver, and 00:00:5e:00:53:53 comes from the MAC block IANA reserves for documentation (RFC 9542 s2.1.4, 00-00-5e-00-53-00 through -ff; RFC 9542 obsoleted RFC 7042 in 2024). Substitute the IP of the resolver on your network. See ip-address-spaces for the documentation ranges.

IPv6 uses NDP (Neighbor Discovery Protocol, RFC 4861) instead of ARP for the same job, riding ICMPv6 multicast. Same idea, prettier packets.

Switches and broadcast domains#

A switch is an L2 device. It learns "MAC X lives on port 4" by inspecting frames as they pass, and forwards each frame only to the port the destination MAC was last seen on. A frame for a MAC it hasn't learned yet is flooded to every port in the VLAN (unknown unicast), so a cold MAC table delays nothing. A broadcast frame (ff:ff:ff:ff:ff:ff) goes to every port in the same VLAN.

The set of ports that share a broadcast goes by one name: a broadcast domain. Everything in a broadcast domain can ARP for everything else. Everything outside it has to go through a router (L3).

This matters for DNS because:

  • The resolver and the client must either share a broadcast domain (ARP directly), or have an L3 route between them (each with their own ARP to the next router). See foundations-osi for the layer-by-layer loop that verifies this path before you touch any DNS configuration.
  • A misconfigured switch port (wrong VLAN, no tag, broken trunk) silently drops your DNS query at L2. The application sees a timeout and blames DNS.

802.1Q VLAN tags ride at L2 too, a 4-byte header inserted between the source MAC and the EtherType. A misconfigured trunk port (wrong allowed VLAN list, or trunk-vs-access mismatch) is the same class of silent-drop failure as a wrong-VLAN ARP: the frame never reaches the resolver and DNS gets the blame. See foundations-vlans for the full picture of how VLANs segment broadcast domains and where the common misconfigurations hide.

Useful CLI#

MAC address of every interface:

ip -br link

ARP cache (L2 to L3 mapping):

ip neigh

Watch ARP requests live (requires sudo):

sudo tcpdump -ni eth0 arp

Or with tshark:

sudo tshark -i eth0 -Y arp

On a Linux bridge host, inspect the forwarding database to see which MAC is on which port:

bridge fdb show

macOS equivalents: ip and bridge are Linux tools. On macOS, use ifconfig to list interfaces and their MACs, arp -a to view the ARP cache, and sudo arp -d <ip> to flush a specific entry. tcpdump works the same way on macOS.

In Wireshark, the L2 filters you'll reach for most often:

eth.addr == 00:00:5e:00:53:53     # frames to/from a specific MAC
arp                               # only ARP traffic
vlan.id == 101                    # only frames tagged for VLAN 101

A fuller filter list lives on the Wireshark filters page.

What L2 problems look like from a DNS perspective#

SymptomLikely L2 cause
dig retries with ;; communications error to <resolver>#53: timed out and ends ;; no servers could be reached, while ip neigh shows the resolver INCOMPLETE or FAILEDARP for the resolver never got an answer: wrong VLAN at the client's port, so the query never made it onto the wire
Works for a while, then dies for ~30s, then works againNot ARP re-resolution itself (that takes under a second): the classic ~30s hole is legacy 802.1D spanning tree re-converging after a topology change (15s listening + 15s learning), or a flapping link
One host can resolve, another on the same subnet can'tSwitch port is configured for a different VLAN than the resolver's: same L3 subnet on paper, different L2 segment in reality
arp -d "fixes" it temporarilyStale ARP entry; an IP was moved between MACs (HA failover, VM migration) and the cache didn't refresh
Duplicate IP warnings in syslogTwo devices with the same IP: the loser's ARP entry keeps getting overwritten; DNS queries arrive at the wrong host

See also#