When examining ARP behavior between routers with different subnet configurations, we encounter two fundamental cases:
Case 1:
Router1: Interface1 (20.0.0.1/24)
↔
Router2: Interface2 (40.0.0.1/24)
Case 2:
Router1: Interface1 (20.0.0.1/24)
↔
Router2: Interface2 (20.0.0.2/8)
ARP operates at Layer 2 but is influenced by Layer 3 configurations. The key factors determining ARP response are:
- Subnet mask compatibility
- Router proxy ARP settings
- Interface state and ACL configurations
Case 1: Different Subnets (20.0.0.0/24 ↔ 40.0.0.0/24)
Here's what happens at the packet level:
1. Router1 checks destination IP against its interface mask
2. Realizes 40.0.0.1 isn't in 20.0.0.0/24
3. Router1 won't ARP for off-subnet addresses by default
4. Packet gets routed through default gateway (if configured)
5. No ARP reply generated - request effectively dropped
Case 2: Overlapping Subnets (20.0.0.0/24 ↔ 20.0.0.0/8)
This creates an asymmetric routing scenario:
1. Router1 (20.0.0.1/24) sees 20.0.0.2 as local
2. Sends ARP request for 20.0.0.2
3. Router2 (20.0.0.2/8) sees 20.0.0.1 as local
4. Responds with ARP reply containing its MAC
5. Communication establishes at Layer 2
Here's how you might simulate this behavior in Python using Scapy:
from scapy.all import *
# Case 1 simulation
def test_different_subnets():
pkt = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="40.0.0.1", psrc="20.0.0.1")
# This ARP won't get response from 40.0.0.1 interface
ans, unans = srp(pkt, timeout=2)
print("Received %d replies" % len(ans))
# Case 2 simulation
def test_overlapping_subnets():
pkt = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="20.0.0.2", psrc="20.0.0.1")
# This should get response if interfaces are properly configured
ans, unans = srp(pkt, timeout=2)
print("Received %d replies" % len(ans))
Modern routers handle these cases differently based on:
- Proxy ARP settings (enabled/disabled)
- ICMP redirect behavior
- Strict uRPF checking
For Cisco routers, you might see:
interface GigabitEthernet0/1
ip address 20.0.0.1 255.255.255.0
no ip proxy-arp # Explicitly disables Case 2 behavior
When debugging such scenarios:
- Check interface IP/Mask assignments
- Verify ARP cache on both routers
- Inspect router logs for dropped packets
- Use packet captures to verify actual traffic
When dealing with ARP requests across subnet boundaries, router behavior depends critically on interface configurations. Let's examine both test cases at the packet level:
// Sample network topology representation Router1: Interface Intf1: IP: 20.0.0.1 Netmask: 255.255.255.0 (/24) Router2: Case1 Interface: IP: 40.0.0.1 Netmask: 255.255.255.0 (/24) Case2 Interface: IP: 20.0.0.2 Netmask: 255.0.0.0 (/8)
In the first scenario where both interfaces have /24 masks but different network addresses:
- Router1 sends ARP request for 40.0.0.1 from its 20.0.0.1/24 interface
- Router2 receives the request but recognizes 40.0.0.1 as its own interface
- Critical point: The request came from different subnet (20.0.0.0/24 ≠ 40.0.0.0/24)
Most enterprise routers implement RFC 1812 section 3.3.2 which states:
if (targetIP == myInterfaceIP) { if (sourceIP is in same subnet) { send_arp_reply(); } else { // Typically drop for security reasons increment_counter(discarded_arp_from_wrong_subnet); } }
The second case presents an interesting edge case:
Router1: 20.0.0.1/24 (network 20.0.0.0) Router2: 20.0.0.2/8 (network 20.0.0.0)
Behavior depends on router implementation:
- Cisco IOS: Will respond because source (20.0.0.1) falls within 20.0.0.0/8
- Linux with proxy_arp disabled: Will ignore due to different netmasks
- Juniper: Depends on 'arp-subnet-consistency' configuration
When writing network automation scripts, always account for these scenarios:
# Python example checking ARP response likelihood import ipaddress def will_arp_respond(src_ip, src_mask, target_ip, target_mask): src_net = ipaddress.IPv4Network(f"{src_ip}/{src_mask}", strict=False) target_net = ipaddress.IPv4Network(f"{target_ip}/{target_mask}", strict=False) if src_net != target_net: return False # Standard routers won't respond return True # Potential response case
For debugging purposes, always capture ARP traffic at both ends:
# tcpdump commands for verification router1# tcpdump -i intf1 'arp' router2# tcpdump -i intf2 'arp'