rXg Knowledge Base

Finding Rogue DHCP Servers and IPv6 Routers on Captive Portal VLANs

April 07, 2026

Overview

Consumer routers plugged into MAC-AUTH switch ports can poison captive portal VLANs in two ways: rogue DHCPv4 servers that steal DHCP clients, and rogue IPv6 Router Advertisements that give devices a global or ULA IPv6 address — bypassing the captive portal entirely. This guide covers how to detect and remove both.

Symptoms

  • Devices connected to the onboarding SSID get 169.254.x.x (APIPA) addresses instead of valid DHCP leases
  • Devices get 192.168.x.x or other unexpected IP ranges from a rogue DHCP server
  • Captive portal does not appear despite devices having a valid IPv4 lease
  • SmartZone or rXg client list shows IPv6 addresses (2600:, fd00:, etc.) alongside IPv4 on the captive portal VLAN
  • IoT devices (Nest thermostats, etc.) show APIPA while other devices work — IoT devices may prefer IPv6 and never send DHCPv4
  • DHCP log shows repeated DISCOVER/OFFER cycles with no REQUEST (client accepting a competing offer)

How It Happens

  1. Resident plugs a consumer router's LAN port (not WAN) into an AP switch port
  2. Switch performs MAC-AUTH, router's MAC is unknown, falls back to the onboarding VLAN (e.g., VLAN 400)
  3. The router's LAN interface has a built-in DHCP server (default on most consumer routers) and/or advertises IPv6 Router Advertisements
  4. Every device on the onboarding VLAN now competes with the rXg for DHCP, or gets IPv6 addresses that bypass PF captive portal rules entirely

Why IPv6 bypasses the captive portal: PF rdr and filter rules reference tables (members_IP23, etc.) containing only IPv4 CIDRs. IPv6 traffic falls through unmatched — no redirect, no block, full internet access. Modern devices (iOS 15+, Android 12+) prefer IPv6 when available.

Step 1: Check the DHCP Log for Rogue DHCP Signs

Run on the onboarding data plane node (e.g., vgw1-07). All commands require root.

# Normal DHCP: DISCOVER → OFFER → REQUEST → ACK
# Rogue DHCP:  DISCOVER → OFFER → (nothing) → DISCOVER → OFFER → ...
# Repeated DISCOVER/OFFER without REQUEST means the client is accepting
# a competing DHCP offer from a rogue server instead of the rXg.
grep -a 'DHCP' /var/log/dhcpd.log | tail -40

Look for: - DHCPDISCOVER followed by DHCPOFFER but no DHCPREQUEST — client is accepting a rogue offer - DHCPNAK for IPs outside the pool range (e.g., 192.168.x.x) — client has a stale lease from a rogue server - Multiple DISCOVERs from the same MAC in rapid succession with no ACK

Step 2: Capture Live DHCP Traffic

# All DHCP traffic on the onboarding VLAN
# Every OFFER should come from the rXg's IP only (e.g., 10.20.0.1)
# Any OFFER from a different source IP is a rogue DHCP server
tcpdump -i <onboarding_vlan> -n -c 30 port 67 or port 68

Look for DHCPOFFER packets with a source IP that is NOT the rXg (e.g., 192.168.0.1, 192.168.1.1, 10.0.0.1). The source MAC in that packet is the rogue device.

# Check for 192.168.x.x traffic — should not exist on the onboarding VLAN
tcpdump -i <onboarding_vlan> -n -c 10 net 192.168.0.0/16

Step 3: Check for Rogue IPv6 Routers

Even if DHCPv4 is working, a rogue IPv6 router can silently bypass the captive portal.

# Confirm the rXg itself has no IPv6 on the onboarding VLAN (should be empty)
ifconfig <onboarding_vlan> | grep inet6

# Check NDP neighbor table (should be empty if rXg doesn't serve IPv6)
ndp -an

Capture Router Advertisements

# RA = ICMPv6 type 134. Wait up to 60 seconds.
# Any output means something is advertising an IPv6 prefix on this VLAN.
tcpdump -i <onboarding_vlan> -vvn -c 5 'icmp6 && ip6[40] == 134'

If no RAs are captured (the rogue device may send them infrequently), check for general ICMPv6 activity:

# Neighbor solicitations reveal devices that HAVE IPv6 addresses
# The source link-local (fe80::) tells you who's doing the soliciting
tcpdump -i <onboarding_vlan> -n -c 20 icmp6

Check for DHCPv6 Servers

# DHCPv6 server traffic on UDP port 547 — should be empty
tcpdump -i <onboarding_vlan> -n -c 5 'udp port 547'

Step 4: Identify the Rogue Device MAC

From DHCP capture

The rogue DHCP server's MAC is directly visible in the tcpdump output as the Ethernet source of the DHCPOFFER packet.

If you captured a link-local address like fe80::a2b4:c6ff:fed8:e0f2, derive the MAC:

  1. Take the interface ID: a2b4:c6ff:fed8:e0f2
  2. Remove the ff:fe in the middle: a2b4:c6 + d8:e0:f2
  3. Flip bit 7 of the first byte: a2a0
  4. Result: a0:b4:c6:d8:e0:f2

Quick rule: Take the first byte, flip the second-to-last bit (XOR with 0x02), drop the ff:fe, reassemble.

Another example: fe80::1a60:41ff:fe84:1234 1. Interface ID: 1a60:41ff:fe84:1234 2. Remove ff:fe: 1a60:41 + 84:12:34 3. Flip bit 7: 1a18 4. Result: 18:60:41:84:12:34

Step 5: Locate the Switch Port

From the rXg admin UI

Network > Wireless > Access Points — search for the MAC. If it's not an AP, check Identities > Devices. The device record may show which switch and port it's associated with.

From the rXg CLI

cd /space/rxg/console && /usr/local/bin/bundle exec rails runner 'Device.where(mac: "<mac_no_colons>").each { |d| puts "Account: #{d.account&.login}, Switch: #{d.switch_port}" }'

From the switch directly

# Find which port has the rogue MAC
show mac-address-table address <rogue_mac>

# Find ports with multiple MACs on the onboarding VLAN
# Ports with 3+ MACs likely have a router with clients behind it
show mac-address-table vlan <onboarding_vlan_tag>

Look for ports with multiple MACs — a consumer router will show its own MAC plus the MACs of devices behind it (phones, laptops NATted through the router).

Step 6: Remove the Rogue Device

  1. Disable the switch port where the rogue device is connected (via rXg switch sync or direct switch CLI)
  2. Verify the rogue traffic has stopped: bash # Should return no results after port is disabled tcpdump -i <onboarding_vlan> -n -c 5 'icmp6 && ip6[40] == 134' tcpdump -i <onboarding_vlan> -n -c 5 port 67 or port 68
  3. Force affected devices to reconnect — disconnect them from the wireless controller or power-cycle IoT devices. Devices with cached IPv6 addresses won't switch back to DHCPv4 until their IPv6 state expires or they reconnect fresh.
  4. Verify DHCP is working: bash # Watch for new DHCPDISCOVER → OFFER → REQUEST → ACK sequences tail -f /var/log/dhcpd.log

Prevention

  • Port-security or MAC limiting on AP switch ports — limit to 1-2 MACs per port (the AP only)
  • DHCP snooping on the onboarding VLAN — only the rXg's DHCP port is trusted
  • RA Guard on the onboarding VLAN — blocks unauthorized IPv6 Router Advertisements at the switch level
  • Complete switch configuration sync — ensures all switches have consistent port security policies

Common Rogue Device Indicators

Clue Meaning
Multiple MACs on one switch port Router with clients behind it
192.168.x.x on the onboarding VLAN Rogue DHCPv4 server (consumer router LAN port)
IPv6 global (2600:, 2607:) or ULA (fd00:) on onboarding clients Rogue IPv6 RA source
DHCPNAK for IPs outside the pool range Client has stale lease from rogue server
DISCOVER/OFFER without REQUEST in dhcpd.log Client accepting competing (rogue) DHCP offer
OUI: TP-Link, Arcadyan, Netgear, ASUS Consumer router manufacturers
Inverted upload ratio (14:1 up/down) on a single session NAT gateway hiding multiple devices behind one session

Cookies help us deliver our services. By using our services, you agree to our use of cookies.