Attack Mitigation: enable Reverse Path Filtering, filter `ANY` DNS requests

In a combined reflection and amplification Distributed Denial of Service (DDoS) attack, the attacker relies on two specific behaviors of the Domain Name System (DNS):

Reflection (IP Spoofing): The attacker sends a DNS request to your router. However, the attacker forges (spoofs) the packet header so the “source IP address” looks like the victim’s IP address, not the attacker’s. When the router responds, it sends the answer to the innocent victim.

Amplification (The ANY Query): The attacker sends a very small request (e.g., about 50 bytes). They intentionally use the ANY record type. The ANY query tells the DNS server to return every single piece of routing and security data it has for a domain (including A, AAAA, MX, TXT, and DNSSEC keys). This causes the response packet to be 4,000 bytes or more.

Because DNS over UDP requires no connection handshake, the router blindly sends this payload straight to the victim. The attacker achieves an amplification factor of up to 50x to 80x their original bandwidth capacity.

Out of the box, the OpenWRT One DOES NOT USE Reverse Path Filtering to check for “Martian packets” (packets arriving on the wan interface, but claiming to have originated from the lan interface), thus it cannot drop such packets. The router relies solely upon firewall rules to drop wan-originated packets.

Further, a compromised device on your lan can still launch such an attack. In addition, a malicious website could use Javascript to force the browser to send a flurry of DNS ANY requests.

If you go to Network >> DNS >> FIlter >> Filter arbitrary RR and put a check mark next to ANY, then click Save & Apply, even if such an attack could be launched, the router is filtering ANY requests, so the reflection / amplification attack won’t work.

Legitimate applications and modern operating systems almost never use ANY queries for everyday communication because they prefer explicit lookups (like querying directly for an A record). Blocking ANY on the OpenWRT One router shuts down a dangerous DDoS tool without breaking the local network’s internet access.

You can see that Reverse Path filtering is not enabled by default by logging into the router via ssh (in a Terminal window, issue ssh [email protected], enter root password), then issuing:

sysctl -a | grep "\.rp_filter"

You should see something like:

net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.br-lan.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.eth0.rp_filter = 0
net.ipv4.conf.eth1.rp_filter = 0
net.ipv4.conf.lo.rp_filter = 0
net.ipv4.conf.phy0-ap0.rp_filter = 0
net.ipv4.conf.phy1-ap0.rp_filter = 0
sysctl: error reading key 'net.ipv6.conf.all.stable_secret': I/O error
sysctl: error reading key 'net.ipv6.conf.br-lan.stable_secret': I/O error
sysctl: error reading key 'net.ipv6.conf.default.stable_secret': I/O error
sysctl: error reading key 'net.ipv6.conf.eth0.stable_secret': I/O error
sysctl: error reading key 'net.ipv6.conf.eth1.stable_secret': I/O error
sysctl: error reading key 'net.ipv6.conf.lo.stable_secret': I/O error
sysctl: error reading key 'net.ipv6.conf.phy0-ap0.stable_secret': I/O error
sysctl: error reading key 'net.ipv6.conf.phy1-ap0.stable_secret': I/O error

This means the OpenWRT One is not using Reverse Path Filtering to discard ‘Martian packets’.

The “error reading key” errors above are standard Linux security behavior. The kernel hides the cryptographic seed used for generating RFC 7217 IPv6 addresses. Linux blocks any process, including sysctl, from reading that specific data block out of memory, throwing an I/O error.

We can enable Reverse Path Filtering, in a Terminal window logged into the router via SSH, enter these lines:

# Enable Reverse Path Filtering globally
sysctl -w net.ipv4.conf.all.rp_filter=1
sysctl -w net.ipv4.conf.default.rp_filter=1

# Enable RPF on your active interfaces
sysctl -w net.ipv4.conf.eth0.rp_filter=1
sysctl -w net.ipv4.conf.eth1.rp_filter=1
sysctl -w net.ipv4.conf.br-lan.rp_filter=1

# Tell the kernel to log every dropped 'Martian' (faked) packet
sysctl -w net.ipv4.conf.all.log_martians=1
sysctl -w net.ipv4.conf.default.log_martians=1

Those settings don’t survive a router reboot, so if you don’t like the results, just reboot the router or reissue the commands with 0 instead of 1.

Under a reflection / amplification attack with Martian packet logging enabled, you’ll see high CPU usage. Leave the logging settings (the last 2 above) at 0 if you don’t want that.

If you want to make those settings survive a router reboot, copy-and-paste this into the Terminal window, then press Enter:

cat << 'EOF' > /etc/sysctl.conf
net.ipv4.conf.lo.rp_filter = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.eth1.rp_filter = 1
net.ipv4.conf.br-lan.rp_filter = 1
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
EOF

Under a reflection / amplification attack with Martian packet logging enabled, you’ll see high CPU usage. Leave the logging settings (the last 2 above) at 0 if you don’t want that.

Now you should see:

sysctl -a | grep “.rp_filter”

net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.br-lan.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.eth1.rp_filter = 1
net.ipv4.conf.lo.rp_filter = 0
net.ipv4.conf.phy0-ap0.rp_filter = 1
net.ipv4.conf.phy1-ap0.rp_filter = 1
sysctl: error reading key 'net.ipv6.conf.all.stable_secret': I/O error
sysctl: error reading key 'net.ipv6.conf.br-lan.stable_secret': I/O error
sysctl: error reading key 'net.ipv6.conf.default.stable_secret': I/O error
sysctl: error reading key 'net.ipv6.conf.eth0.stable_secret': I/O error
sysctl: error reading key 'net.ipv6.conf.eth1.stable_secret': I/O error
sysctl: error reading key 'net.ipv6.conf.lo.stable_secret': I/O error
sysctl: error reading key 'net.ipv6.conf.phy0-ap0.stable_secret': I/O error
sysctl: error reading key 'net.ipv6.conf.phy1-ap0.stable_secret': I/O error

cat /etc/sysctl.conf

net.ipv4.conf.lo.rp_filter = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.eth1.rp_filter = 1
net.ipv4.conf.br-lan.rp_filter = 1
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

Do not change:

net.ipv4.conf.lo.rp_filter = 0

If you enable Reverse Path Filtering on lo (net.ipv4.conf.lo.rp_filter = 0), the Linux kernel will try to validate the source IP of internal packets against the external routing tables. Because internal traffic does not follow standard upstream routing paths, the kernel can get confused, flag its own internal traffic as “faked,” and drop it. Obviously, that’s a Bad Thing.

Under:

Network >> Interfaces >> Devices tab >> phy0-ap0
Network >> Interfaces >> Devices tab >> phy1-ap0

Click the ‘Configure’ button, under ‘Advanced device options’, there’s a “Reverse path filter” setting.

Leave these settings disabled. Enabling Reverse Path Filtering on your WiFi interfaces risks dropping multicast packets and preventing cell phones from switching from cellular data to WiFi.

We’ve protected the network via eth0, eth1 and br-lan, instead.

You can reboot the router and ascertain that Reverse Path Filtering is still enabled by issuing the following in a Terminal window connected via ssh to the router:

sysctl net.ipv4.conf.eth0.rp_filter net.ipv4.conf.eth1.rp_filter net.ipv4.conf.br-lan.rp_filter net.i pv4.conf.all.log_martians

You should see:

net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.eth1.rp_filter = 1
net.ipv4.conf.br-lan.rp_filter = 1
net.ipv4.conf.all.log_martians = 0

If you have Martian Packet logging enabled, of course, the last one will be 1.